You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Process GP-02 — Triggered by internal initiative to fix, improve, or extend GemsPy. Not driven by a new GEMS Language version.
Deviation from standard workflow — Step 3: extended impact analysis on results is required. You must explicitly state whether solver results are expected to change, and if so, document the reasoning.
Depends on / follows on from #272 — this is a bigger, riskier phase-2 exploration on top of that plan's inter-block warm-start (§6), not a replacement for it. Not worth pursuing unless the gates below (in particular, profiling) come back favorable; #272 should ship first regardless.
Affected Component
Optimization problem construction (simulation/) — specifically _OptimizationProblemBuilder/build_problem, the shared core every resolution mode and most of the test suite depends on.
Type of Change
Major: this is exactly the kind of change the GP-02 template's own example calls out ("e.g. rolling horizon") — a structural rearchitecture of problem construction, not an additive plumbing change. Still intended to be opt-in and backward-compatible in its outward behavior, but the internal blast radius is large.
Description
Explores replacing #272's file-based inter-block warm-start (rebuild a fresh linopy.Model per block, transfer only the basis) with keeping one persistent linopy.Model per scenario in _run_sequential, rolling its data forward block-by-block in place instead of rebuilding — using linopy's 0.8.0/0.9.0 native stateful-Solver / in-place-update API. This is tier (c) ("no rebuild at all") applied to inter-block resolution specifically, exploiting the fact that GEMS parameters/variables are already indexed on an explicit time dimension as part of the domain model, so block-to-block the shape of the problem is already identical for a fixed block_length — only the data differs.
Explicitly scoped to _run_sequential only, same as #272 — not just for now. A persistent, stateful rolling model is structurally the opposite of what _run_parallel needs (independent, dispatchable blocks for a future concurrent implementation), so it isn't a candidate even in principle. _run_benders/decomposed problems are out of scope too.
The central open technical question — does linopy's in-place update cover constraint and objective coefficients, not just variable bounds (GEMS constraint/objective expressions can reference time-varying parameters directly, e.g. an efficiency or price time series multiplying a variable) — has been verified yes, directly against the installed linopy 0.9.0 source (not just release notes): linopy.persistent.diff.ModelDiff carries coefficient-level deltas for both constraints and the objective, dispatched to real in-place highspy.Highs calls (changeCoeff, changeColsCost, etc.) for HiGHS — one of exactly four backends (HiGHS, Gurobi, Xpress, Mosek) with supports_persistent_update = True. The remaining risk narrows to RebuildReason.SPARSITY (a coefficient going from exactly-zero to nonzero between blocks forces a fallback rebuild), with a concrete guard identified: disable linopy's default sanitize_zeros=True on the persistent/rolling code path.
Two architectures were considered; see the plan for why "build the full horizon once, activate one block at a time" was rejected (it reintroduces the exact scalability problem block-decomposition exists to solve) in favor of the genuinely-rolling, block-sized persistent model.
A dedicated spike confirming the coefficient-update behavior holds on a real GEMS model (not just the mechanism existing in the abstract), via Solver._last_rebuild_reason introspection, with sanitize_zeros disabled.
If any of the three comes back unfavorable, #272's file-based design remains the right one and this issue should be closed as not-planned rather than pursued further.
Results Impact
Same intent as #272: no change to the optimal objective value, only to how it's reached. Same degenerate-tie caveat applies (possibly more acutely — a rolling model may go through many consecutive in-place updates within one scenario without ever re-deriving from scratch, which is a separate, additional numerical-drift concern beyond the degenerate-tie issue; the plan recommends a periodic forced full-rebuild reset boundary, at minimum at every scenario boundary, as a safety valve).
Process GP-02 — Triggered by internal initiative to fix, improve, or extend GemsPy. Not driven by a new GEMS Language version.
Full design doc (current, updated in place as decisions are made):
docs/design/warm-start-plan-rolling-window.mdon branchclaude/gemspy-warmstart-possibilities-5qo718.Depends on / follows on from #272 — this is a bigger, riskier phase-2 exploration on top of that plan's inter-block warm-start (§6), not a replacement for it. Not worth pursuing unless the gates below (in particular, profiling) come back favorable; #272 should ship first regardless.
Affected Component
Optimization problem construction (
simulation/) — specifically_OptimizationProblemBuilder/build_problem, the shared core every resolution mode and most of the test suite depends on.Type of Change
Major: this is exactly the kind of change the GP-02 template's own example calls out ("e.g. rolling horizon") — a structural rearchitecture of problem construction, not an additive plumbing change. Still intended to be opt-in and backward-compatible in its outward behavior, but the internal blast radius is large.
Description
Explores replacing #272's file-based inter-block warm-start (rebuild a fresh
linopy.Modelper block, transfer only the basis) with keeping one persistentlinopy.Modelper scenario in_run_sequential, rolling its data forward block-by-block in place instead of rebuilding — using linopy's0.8.0/0.9.0native stateful-Solver / in-place-update API. This is tier (c) ("no rebuild at all") applied to inter-block resolution specifically, exploiting the fact that GEMS parameters/variables are already indexed on an explicittimedimension as part of the domain model, so block-to-block the shape of the problem is already identical for a fixedblock_length— only the data differs.Explicitly scoped to
_run_sequentialonly, same as #272 — not just for now. A persistent, stateful rolling model is structurally the opposite of what_run_parallelneeds (independent, dispatchable blocks for a future concurrent implementation), so it isn't a candidate even in principle._run_benders/decomposed problems are out of scope too.The central open technical question — does linopy's in-place update cover constraint and objective coefficients, not just variable bounds (GEMS constraint/objective expressions can reference time-varying parameters directly, e.g. an efficiency or price time series multiplying a variable) — has been verified yes, directly against the installed linopy 0.9.0 source (not just release notes):
linopy.persistent.diff.ModelDiffcarries coefficient-level deltas for both constraints and the objective, dispatched to real in-placehighspy.Highscalls (changeCoeff,changeColsCost, etc.) for HiGHS — one of exactly four backends (HiGHS, Gurobi, Xpress, Mosek) withsupports_persistent_update = True. The remaining risk narrows toRebuildReason.SPARSITY(a coefficient going from exactly-zero to nonzero between blocks forces a fallback rebuild), with a concrete guard identified: disable linopy's defaultsanitize_zeros=Trueon the persistent/rolling code path.Two architectures were considered; see the plan for why "build the full horizon once, activate one block at a time" was rejected (it reintroduces the exact scalability problem block-decomposition exists to solve) in favor of the genuinely-rolling, block-sized persistent model.
Gated behind, in order:
Solver._last_rebuild_reasonintrospection, withsanitize_zerosdisabled._run_sequentialrun time on a realistic study — if rebuild is already cheap relative to solving, this design buys little over [GP-02] Warm-start: reuse solver basis for heuristic solves and sequential inter-block resolution #272's file-based approach.If any of the three comes back unfavorable, #272's file-based design remains the right one and this issue should be closed as not-planned rather than pursued further.
Results Impact
Same intent as #272: no change to the optimal objective value, only to how it's reached. Same degenerate-tie caveat applies (possibly more acutely — a rolling model may go through many consecutive in-place updates within one scenario without ever re-deriving from scratch, which is a separate, additional numerical-drift concern beyond the degenerate-tie issue; the plan recommends a periodic forced full-rebuild reset boundary, at minimum at every scenario boundary, as a safety valve).
Validation Strategy
Solver._rebuilds/_in_place_updates/_last_rebuild_reasonrather than only inferring from timing.Process Checklist
Step 1 — Issue Creation
Step 2 — Triage
Step 3 — Impact Analysis⚠️ extended results analysis required
Step 4 — Implementation
_OptimizationProblemBuilderrolling-window support implementedStep 5 — Testing & Validation
Step 6 — CI Validation
mypy)black,isort)pytest)Step 7 — Review & Merge
Step 8 — Versioning
pyproject.tomlversion bumpedStep 9 — Supporting Files
AGENTS.mdreviewed for impact and updated if neededStep 10 — Release