Skip to content

[GP-02] Sequential mode: configurable carry-over-length, correct stitching for block-overlap != 1 - #274

Open
aoustry wants to merge 8 commits into
mainfrom
claude/issue-271-optimization-config-r9i6ns
Open

[GP-02] Sequential mode: configurable carry-over-length, correct stitching for block-overlap != 1#274
aoustry wants to merge 8 commits into
mainfrom
claude/issue-271-optimization-config-r9i6ns

Conversation

@aoustry

@aoustry aoustry commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Process ID

Process: GP-02

Description

Closes #271.

In sequential-subproblems mode, the carry-over that stitches block N to block N+1 was hardcoded: it extracted block N's last timestep and pinned it to block N+1's first timestep. That pairing only refers to the same absolute timestep when block-overlap == 1; for block-overlap >= 2 it silently pinned the wrong pair of timesteps.

This PR makes the carry-over an explicit resolution setting and fixes the absolute-timestep alignment:

  • carry-over-length added to ResolutionConfig (optional; omitted → defaults to block-overlap, i.e. full pin of the overlap zone). Explicit 0 is legal and distinct from unset: blocks overlap for lag-constraint history but are not stitched at all.
  • Validation: 0 <= carry-over-length <= block-overlap (no special case at block-overlap == 0), plus the previously missing range check 0 <= block-overlap < block-length.
  • Runtime: _extract_carry_over now extracts effective_carry_over_length values starting at the earliest shared timestep (local index block_length - block_overlap) instead of always the last one; Phase 5 pins the next block's first k timesteps against them (clamped for truncated final blocks). Scalar initial_values keep the legacy single-timestep pin for direct build_problem callers.
  • Docs: docs/user-guide/optim-config.md documents the three parameters with an annotated timeline diagram (from the issue discussion), defaults, validation, and a breaking-change warning; docs/CHANGELOG.md gains a BREAKING entry with the migration note.

Breaking change: with block-overlap: 0 (the default) nothing is carried between blocks any more — the previous implicit single-timestep seeding is gone. Configs relying on state continuity (e.g. storage state-of-charge) must set block-overlap: 1 (and optionally carry-over-length: 1).

Impact Analysis

Affected modules:

  • optim_config/ResolutionConfig schema: new field + validators (src/gems_craft/optim_config/parsing.py).
  • gems_runner/session/_run_sequential / _extract_carry_over generalized to a multi-timestep window.
  • gems_runner/simulation/optimization.py Phase 5 carry-over constraints generalized; build_problem docstring updated.
  • docs/ — user guide + changelog.

Solver output values expected to change: yes, for sequential mode only:

  • block-overlap >= 2: outputs change because the previous stitching was incorrect (wrong absolute timestep pinned); the new behaviour pins each shared timestep to its matching absolute timestep.
  • block-overlap: 0: outputs change because blocks no longer inherit the previous block's final state (breaking change above).
  • block-overlap: 1: no change — the new default is identical to the old hardcoded single-timestep pin; the existing e2e tests (test_rolling_horizon_suboptimality.py, test_optim_modes.py) pass unmodified.
  • frontal / parallel-subproblems / benders-decomposition: unaffected.

Test coverage: 13 new unit tests for the validators and default resolution; new e2e module test_sequential_carry_over_length.py (block-length 6, block-overlap 3, carry-over 3/1/0 over an aperiodic 12-step demand) asserting every pinned shared timestep is identical in both blocks — all four cases fail against the previous runtime behaviour and pass with the fix.

Checklist

  • Unit tests pass (pytest) — 604 passed, 6 skipped, 2 xfailed
  • Type checking passes (mypy)
  • Formatting passes (black, isort)
  • pyproject.toml version bumped if applicable — not applicable (version bumps are handled via the feat(release): workflow)
  • AGENTS.md reviewed for impact and updated if needed — no update needed (resolution-mode internals are not described there)

claude added 3 commits August 14, 2026 15:15
Add 'carry-over-length' to ResolutionConfig (issue #271): optional, defaults
to block-overlap via effective_carry_over_length, validated as
0 <= carry-over-length <= block-overlap with no special case at
block-overlap == 0. Also add the previously missing range check
0 <= block-overlap < block-length.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BsEZdPwCrguejkXxz33FS
…ial mode

The sequential carry-over always extracted block N's last timestep and
pinned it to block N+1's first timestep, which only refers to the same
absolute timestep when block-overlap == 1; for overlap >= 2 it silently
stitched the wrong pair of timesteps (issue #271).

_extract_carry_over now extracts effective_carry_over_length values
starting at local index block_length - block_overlap (the earliest shared
timestep), re-indexed to time 0..k-1, and Phase 5 pins the next block's
first k timesteps against them. Scalar initial_values (no time dim) keep
the legacy single-timestep pin for direct build_problem callers.

Behavioural consequence: with block-overlap: 0 nothing is carried between
blocks any more (the previous implicit single-timestep seeding is gone) —
state continuity now requires block-overlap >= 1.

The new e2e test fails against the previous runtime behaviour for all four
of its cases and passes with this fix; existing block-overlap: 1 e2e tests
pass unmodified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BsEZdPwCrguejkXxz33FS
Document the new 'carry-over-length' resolution setting: parameter table
entry, expanded sequential-subproblems section with an annotated timeline
diagram (block-length / block-overlap / carry-over-length), default and
explicit-zero semantics, validation rules, and a breaking-change warning
for block-overlap: 0 configs. Add the corresponding CHANGELOG entries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BsEZdPwCrguejkXxz33FS
Comment thread docs/user-guide/optim-config.md Outdated
aoustry and others added 5 commits August 14, 2026 17:19
With block-overlap: 0 no carry-over constraint is created: each block's
initial state is free (block 1 serves its t=7 peak by pre-charging from a
free SoC, which the old implicit single-timestep seeding made impossible),
and the sequential result is identical to parallel-subproblems mode, which
solves the same windows independently by construction. The test fails
against the pre-#271 runtime behaviour.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BsEZdPwCrguejkXxz33FS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GP-02] Sequential mode: make carry-over-length a config, correct for block-overlap != 1

2 participants