Repository navigation
feat(api): a parameter value on a where: threshold gets the rate at which the objective moves past it - #2074
Conversation
…hich the objective moves past it A marginal no longer holds every mask as built. A value whose rise switches columns or rows on or off is priced from the same solve: a switched-on column at its reduced cost, as far as its bounds and the zero-slack rows that come with it allow; a jump as an infinite rate. What one solve cannot decide keeps the rate as built and is named in a warning. The marginal moves from readback into its own module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA1Q4XLWBq2jJFFLFWR
|
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
114 files changed ·
|
Merging this PR will degrade performance by 67.75%1 warning
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
…s them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA1Q4XLWBq2jJFFLFWR
…ts pull request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA1Q4XLWBq2jJFFLFWR
…shold The tutorial section this branch rewrote has left for the how-to, which now prices solar at -75 and says what an infinite rate and a warning mean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA1Q4XLWBq2jJFFLFWR
The threshold module and its tests follow the name: _engine/parameter_dual.py and tests/test_parameter_dual_thresholds.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018B3nA1Q4XLWBq2jJFFLFWR
Note
The following content was generated by AI.
parameter_dualnow prices a value on awhere:threshold by what its rise switches on or off, from the same solve and with no re-solve. A jump is±inf. What one solve cannot decide keeps the rate as built, and a warning names it.What each threshold reports, how, verification, what is left out
What a rise past a threshold reports
upper: p_max-sum(p * cost)p <= avail * p_max, solaravail = 0.42 * p <= 2 * avail * p_maxp >= p_minunderwhere: p_min > 0, gasupper: 100p >= 10underwhere: p_min > 0, gasp <= 30underwhere: tight <= 0, windwhere: retire <= 0, gasp >= ramp * p_max, solarramp = 2where: … and sum(p_min, over=generator) <= 0when:cases: when: p_min > 0p * p <= 1e6underwhere: p_min > 0(gurobi,QCPDual)Signs mirror under
maximize. A bool parameter has no rise, so nothing crosses. Each finite case matches a forward re-solve at rel 1e-5. Each infinite case is checked by a forward re-solve that moves the objective the same way by more than 1e3 times the step, or loses its solution.How
_risenraises every value of the parameter by1e-9 × max(1, |v|). The masks that read it at their own coordinate are evaluated again, and the coordinates that change are the crossings. Each crossing is charged to the parameter row its coordinate projects onto.varied_label), so variables and parameter rows share one compile without colliding, and a variable × parameter product is a quadratic term. One pass gives each row's slack at the solve, its columns, and its rate in each parameter row.The parameter dual moves from
_engine/readback.pyto_engine/parameter_dual.py, and the architecture table follows.Result.parameter_dualraises the notes asSpecsolveWarning. The how-to What a change is worth, from #2073, now prices solar at -75, and says what an infinite rate and a warning mean.The reader was
marginalwhen this PR opened. #2073 renamed itparameter_dual(the reason is in #2073), and3dc9195carries the rename here, to the module and the test files too.Verified
fb3d219:pixi run check5910 passed, 579 skipped, 4 xfailed.docs-build(strict): no issues.docs-test: 116 passed.864d079, after merging feat(api): a result gives the rate at which its objective moves with each value of a parameter #2073's how-to:pixi run check5911 passed.docs-build(strict),docs-test(116 passed), andtest_doc_examples,test_docs_siteandtest_changelog(162 passed) are clean.3dc9195, after merging the rename:pixi run check5927 passed, 579 skipped, 4 xfailed.docs-build(strict): no issues.docs-test: 116 passed. The rendered how-to prints solar at -75.Not run:
test-via-pyarrow,test-floors,test-bench.Mutation table
Taken before the rename, so the paths read
marginal.py, nowparameter_dual.py. Each guard was deleted in turn, and the full suite was run each time. The rows marked tool come fromtools/mutate.py. The rows marked hand replace a branch or a constant the tool cannot express, with the same precautions (git checkout --restore,__pycache__dropped on both sides). The tree came back clean after every run.The first run left six survivors, and one range the tool could not apply. Each got a probe in
3c7d44f, and the second run, on3c7d44f, caught them all.54fe6ff)3c7d44fwhen:on a threshold is named_RISE = 0)Left out
when:flips, and masks read through a shift, sum, lookup or count. These stay as built and warned, because a flip cannot be charged to one parameter row cheaply there.Coverage that moved
test_a_value_a_mask_reads_is_held_where_the_mask_put_it, from #2073'stests/test_parameter_dual.py, asserted the held-as-built 0.tests/test_parameter_dual_thresholds.pyreplaces it.🤖 Generated with Claude Code
https://claude.ai/code/session_018B3nA1Q4XLWBq2jJFFLFWR