Repository navigation
Conversation
…ents in place rather than loading the model again Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA4oeSor7jjZ4vwux1G
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA4oeSor7jjZ4vwux1G
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
Documentation build overview
110 files changed ·
|
…erf/push-coefficients
…solver Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA4oeSor7jjZ4vwux1G
Merging this PR will improve performance by 97.63%1 warning
Performance Changes
Tip Curious why performance improved? Comment Comparing Footnotes
|
Note
The following content was generated by AI.
A held HiGHS, Gurobi or Xpress solver now takes a linear row's changed coefficients in place and re-solves warm, instead of loading the whole model again. On top of #2071,
update(...).solve()with a new coefficient takes 0.12–0.48× the time.What changed
Solver.keepsasks for the same options and digest, and for every coefficient of a quadratic constraint's linear part as loaded: Gurobi loads a quadratic row whole, as aQConstr. It no longer asks the same of a linear row.Solver.pushis now the family's: it finds the matrix entries that moved by more than 1e-12 relative (the tolerancekeepsused), reads each entry's row offrow_starts, hands them to_change_coefficients, and then calls the member's_pushfor bounds, costs and right-hand sides. The held copy of the coefficients takes the pushed values, so it mirrors what the solver holds._change_coefficients: HiGHSchangeCoeff, GurobichgCoeff(each one call per entry, the only form either library has), XpresschgMCoef(one call).Handoff.structure's docstring,docs/howto/faster.mdanddocs/development/architecture.md(the labels paragraph and the "Structure digest" entry) say a linear row's coefficients are taken in place.coefficientwindow now expects a push rather than a load (RELOADS), andbench/README.mdsays so. That window exists for the case where an efficiency multiplies a variable, and this PR changes what that case costs. The first push of this PR left it expecting a load, and CI'sMemory (heap)job failed on it;test_a_window_takes_the_path_its_change_namesfailed the same way locally (8 cases) before the fix.An entry that appears or disappears, such as a coefficient falling to zero, moves the digest, so that model still loads again.
Probes, and coverage that moved
tests/test_update.py:test_a_moved_coefficient_is_taken_in_place_and_taken_back, on every solver:eff * p <= capper generator, after another constraint.effdoubles, then goes back. Each answer equals a fresh build's on the same solver, and the solver loads once.test_a_quadratic_constraint_whose_linear_part_moved_loads_again(Gurobi):eff * p + p * pin one row. The objective matches a fresh build and the solver loads twice.a coefficient movednow keeps the solver. Its value went from 0.5 to 0.8, because at 0.5 plantsaandbtie in the north: the warm solve stopped at the other optimum, with the same objective but another primal, and the rung compares primals. At 0.8aalone is cheapest.test_new_numbers_are_read_again_on_the_old_labels_only_where_nothing_else_can_move: a coefficient and a divisor now load once; a coefficient falling to zero still loads twice.tests/test_order.py::test_a_coefficient_moved_by_one_part_in_a_billion_loads_the_solver_againis now…_reaches_the_loaded_solver: it reads HiGHS's held matrix and finds the moved values, with one load.bench/test_harness.py::test_a_window_takes_the_path_its_change_namesholds thecoefficientwindow to a push on every case's 2xs and xs rungs.Mutation table
Each guard broken by one text substitution, the full suite run (
pytest -q -n 4, all three solvers installed), the file restored withgit checkout --,__pycache__dropped on both sides, the tree clean after each. Atec085fe; the bench change after it touches no guard.keepsA/B of update and solve, HiGHS, this container (4 cores, not the publishing machine)
Base #2071's head
83a8ab7, headec085fe. One fresh process per measurement, base and head alternated ABBA for three rounds. Each process builds and solves once, then times 6 calls ofmodel.update({param: …}).solve(), each with the values ×0.9–1.1 at the same coordinates, and reports the median; the table gives the median over the three processes. Started once the load average fell below 1.5: 1.43 before, 1.00 after.etaetaetaetaload, control: no coefficient movesPer-process medians, ms: storage xs base 116.3 / 116.1 / 117.9, head 55.8 / 56.8 / 53.6; storage s base 1475.4 / 1472.5 / 1484.4, head 452.3 / 463.7 / 452.2; network s base 2270.8 / 2298.5 / 2245.0, head 292.9 / 282.4 / 278.4; network m base 64880.0 / 65118.9 / 65267.5, head 8588.6 / 8809.8 / 8744.7; control base 38.3 / 42.5 / 40.7, head 37.1 / 43.4 / 45.8. The control's two ranges overlap, which reads as noise: both sides compare the coefficients once per solve.
The gain is the load skipped and the warm start kept; neither is separated here.
Gates at 75bffa8, on mathspec 0.4.0
No pixi in this container, so each gate ran in a uv environment synced from #2065's
uv.lock(--group dev --group docs --all-extras, Python 3.12, polars 2.0.0; highspy, gurobipy 13.0.3 and xpress 9.9.1 installed):ruff check .,ruff format --check .(0.16.9): clean.pyrefly checkon the package (1.3.1): 0 errors, atec085fe.pytest -q -n 4: 5952 passed, 459 skipped, 4 xfailed.pytest bench/test_harness.py(test-bench): 482 passed, 15 skipped.pytest tests/test_docs_math.py tests/test_docstring_links.py(docs-test): 116 passed.Not run:
docs-build, the floors environment,test-via-pyarrow, andbench/test_ladder.pyitself, whosebenchmarkfixture this environment does not have.Not done. HiGHS and Gurobi take one call per moved entry; neither library has a call that takes several. The A/B is HiGHS only. The
onewindow's README line went stale with #2069 and #2070; that fix is on #2070 and merged up. Stacked on #2071.🤖 Generated with Claude Code
https://claude.ai/code/session_018B3nA4oeSor7jjZ4vwux1G