Changelog¶
[1.2.0] — 2026-05-12¶
Added¶
polar_high.solversmodule: multi-solver dispatch behind a singlesolve(problem, solver_name=..., io_api=..., env=..., **options)entry point. HiGHS remains the default; Gurobi, CPLEX, FICO Xpress, and COPT are supported on a bring-your-own-license basis (we ship no binaries and no licenses).polar_high.solvers.available_solvers: runtime registry of installed solver Python wrappers, populated at import time. Tells you which wrappers are installed; license checks fire inside the adapter.IOMode.MPSfile-based fallback for users with a solver's CLI binary onPATHbut no matching Python wrapper. Writes a temp MPS viahighspy, invokes the CLI, parses the resulting.solfile. Coversgurobi_cl,cplex, Xpressoptimizer, andcopt_cmd.polar_high.solvers._lp_view.LpView: frozen, solver-agnostic extraction surface that every adapter consumes. Engine-private attribute access (Problem._build_lp_arraysetc.) is confined to this single module.- Optional install extras:
polar-high[gurobi],polar-high[cplex],polar-high[xpress],polar-high[copt]. Each pulls only the vendor's Python wrapper (plusscipywhere vectorized loads need it). docs/guide/solvers.md: user-facing guide covering detection, per-solver install, theio_api='mps'escape hatch, theenv=passthrough (Gurobi WLS example), and license troubleshooting.
Changed¶
Problem.solve(streaming=False)now routes throughpolar_high.solvers._highs.run. Behaviour and return type unchanged —streaming=Trueretains the existing HiGHS-only per-familyaddRowspath.- COPT adapter auto-routes through the
copt_cmdCLI fallback wheneverhighspyis already loaded in the interpreter. COPT 8.x's native core conflicts with HiGHS in-process (Highs.run()segfaults oncecoptpyis imported); the auto-route keeps both solvers usable from the samepolar-highvenv at the cost of a per-solve MPS write + subprocess invocation. Requirescopt_cmdon PATH (not shipped by thecoptpypip wheel); a cleanSolverNotAvailableErroris raised when it is missing. Details indocs/guide/solvers.md.
[1.1.4] — 2026-05-11¶
Added¶
Problem.peek_lp_ranges(): build the LP into numpy arrays and return the abs-value ranges of finite non-zero entries on each axis (matrix, cost, bounds, rhs) — same numbers HiGHS prints in its "Coefficient ranges" diagnostic, but available beforepassModel()runs. Optionaltop_kreturns the worst offenders per axis as(abs_value, col_name, row_name_or_side)triples. Lets callers pickuser_bound_scale/user_cost_scaleor refuse to solve a catastrophically scaled LP without paying for a full solve. Usesnp.argpartitionso the cost isO(n_nonzeros)..github/dependabot.yml: weekly dependency PRs for GitHub Actions and Python (pip) ecosystems. The initial commit (c3836f5) was the GitHub-provided template with an emptypackage-ecosystem; this release fills it in so the bot actually opens PRs.
Changed¶
engine.py: factor the non-streaming LP-build out ofsolve()into a private_build_lp_arrays()helper.solve()andpeek_lp_ranges()now share the same arrays — diagnostics are byte-for-byte what HiGHS sees.engine.py: for constraint families with > 50 000 rows, collect term plans one at a time instead ofpl.collect_all. Peak memory drops fromO(n_terms × frame)toO(frame), preventing stalls under memory pressure on large network models.engine.py: HiGHS no longer suppressed viah.silent()— solver progress and the "Coefficient ranges" line now print to stdout by default. Passoptions={"output_flag": False}to silence.
[1.1.3] — 2026-05-07¶
Changed¶
docs/guide/debugging.md: expanded with worked examples; doc snippets are now wired to test fixtures (tests/fixtures/debug_example.py,tests/fixtures/lagrangian_example.py,tests/fixtures/quickstart_example.py) so they're exercised by the test suite and can't silently rot.mkdocs.yml: dropdedent_sectionsfrom thesnippetspymdownx config — incompatible with the multi-fixture snippet layout.
[1.1.2] — 2026-05-05¶
Added¶
docs/guide/loading-data.md: new guide page on going from CSV / parquet / database tables toParamandVar, including the long-format vs. wide-format trade-off and how column names become dimension names.
Changed¶
docs.yml: drop thedevalias deploy onmainpushes; only tagged releases publish a versioned doc site.
[1.1.1] — 2026-05-05¶
Fixed¶
pyproject.toml: add Python 3.13 classifier. CI's test matrix already covers 3.13; the classifier was missing so the pyversions badge was reading "3.11 | 3.12" only.release.yml:skip-existing: trueon the PyPI publish step. Re-tagging the same version now no-ops on PyPI's duplicate-file rejection instead of showing the run as failed.
[1.1.0] — 2026-05-05¶
Changed¶
- BREAKING: renamed package
polar-high-opt→polar-high(Python modulepolar_high_opt→polar_high). All imports, PyPI install name, repo and docs URLs move with it. - BREAKING:
Problem.solve()defaults changed:streaming=True(per-familyaddRowsinstead of one bigpassModel; lower peak memory; numerically identical) andkeep_solver=False(the livehighspy.Highsis dropped after primal/dual extraction; passkeep_solver=Trueto retain it for post-solve inspection likesol.highs.writeModel(...)). - BREAKING:
polar_highsetsPOLARS_MAX_THREADS=1at import. Rayon coordination overhead exceeds the parallel speedup on typical LP-build workloads (see benchmark page). Override by setting the env var beforeimport polar_high. - COO row/column indices use
int32whennnz < 2^31, falling back toint64only when needed. Cuts working-set memory in the matrix-assembly phase. _Term.framecache is no longer populated duringProblem.solve()— the lazy plan is collected into a local that goes out of scope per family. Re-solves rebuild from the lazy plan as before.
Added¶
- Benchmark suite under
benchmark/: denseN×NLP (replicates linopy's benchmark) and a sparse network-flow LP with irregular edge→node topology. Reproducible via subprocess-isolated cells inbenchmark/run.py; figures rendered bybenchmark/plot.py. - New
docs/compare/benchmark.mdwith five figures and the story for each (build-only headline, threads scaling at fixed N, threading benefit on the network LP, network LP, linopy-format replication). Threadingsection indocs/guide/performance.mddocumenting the default-1 choice and the override pattern.- Tiny dispatch LP (wind + coal × 3 hours) replaces the abstract
i / jplaceholder in README anddocs/quickstart.md.
[1.0.1] — 2026-05-05¶
Added¶
- GitHub Actions: tests on push/PR (Python 3.11–3.13), docs deploy on main + tag (mike), PyPI release on tag (trusted publishing).
- Ruff lint + format configured in
pyproject.toml;[lint]optional-dependency added. - README badges: PyPI version, Python versions, license, tests CI, docs CI, ruff.
Changed¶
- Repo / docs URLs moved from
jkiviluo/polar-hightonodal-tools/polar-high; documentation site is hosted athttps://nodal-tools.fi/polar-high/. - One-time
ruff formatreflow across the source tree.
Fixed¶
- Dead intra-doc anchor link in
guide/performance.md(thevars-and-params.md"Param × Param" heading slugifies to a single hyphen, not two).
Removed¶
- Two dangling unused locals (
engine.pyandtest_warm_problem.py).
[1.0.0] — 2026-05-05¶
First public release.
Added¶
Var,Param,Expr— building blocks for indexed expressions expressed as polars DataFrames.Sum,Where,Lag— aggregation, filtering, and time-shift primitives that compile to LP rows efficiently.Problem— assemble an LP/MIP and solve via HiGHS (highspy).WarmProblem— re-solve with parameter / RHS / objective updates while preserving the basis.LagrangianProblem— generic dual-subgradient driver for Lagrangian decomposition of coupled subproblems.Solution— primal values, constraint duals, reduced costs, and a livehighspy.Highshandle for advanced post-solve inspection.- MkDocs + mike documentation site under
docs/.