feat(program): a model says whether an axis may be built a window at a time, and what each coordinate needs from its neighbours - #374
Merged
Conversation
…at a time, before a driver cuts one A rolling horizon or a myopic pathway asks one thing of a model before it starts: would windowing change the answer? separability reports the overlap two windows need and, where none would do, names each declaration and the construct tying the axis together. A reduction means opposite things by position — in a constraint a sum ties every window to every other, in the objective it is additively separable. Squashed from the four commits of claude/separable-along and rebased onto main alone, dropping the closed #247 serialisation base it was stacked on. Co-Authored-By: Claude <noreply@anthropic.com>
…a time, and what each coordinate needs from its neighbours One dataclass and one attribute beside the Footprint the program already answers: program.separability[dim] says how far a row reads behind and ahead along the axis, which declarations tie it together and the modelling change that would lift each, which reaches only data can decide and the parameter or lookup that decides them, and which masks count a position a window would restart. windowable and independent are the two verdicts a rolling-horizon driver and a scenario sweep ask before cutting a slice. Carries #248 rebased onto alpha.67, where a mask is a Mask and its leaves come off Mask.atoms rather than a walk of its own. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FPBsP3UM6esCBREVmjMEhZ
Documentation build overview
11 files changed ·
|
… verdict folds a parameter's values in Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NgEyTfEbZzdTFavr43bRgr
…and nothing reads it for a scenario sweep Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NgEyTfEbZzdTFavr43bRgr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
The following content was generated by AI.
Supersedes #248 and #370. #248 branched before alpha.66 moved the where nodes into
program.py, and GitHub refuses to retarget a stacked PR, so this is #248's feature rebased onto alpha.67 in one commit — a mask's leaves now come offMask.atomsrather than a walk of its own — plus the five changes below. Same shape and placement as #248: one dataclass and one attribute besideFootprint.Three changes read from the consumer that will call it (
lpspec.strategy.EachWindow):halobecomesahead, and what a row reads behind is not reported. A translation reads ahead for a negative offset (t - offset), which a window must overlap to cover. A positive offset and a trailing window read behind, and a window starts where the driver puts it: what its first rows meet there is the edge policy, the opening state a rolling horizon seeds.abs(reach)could not tell the two apart, and only one of them is the model's question.coupled(a sum in a constraint, a grouping, a wrap, a set, anat()) no window satisfies.undecidedlists each read whose values set the reach — a named offset, a partition, anat()— as aReachof the declaration, the parameter or lookup, and what it stands as; the same shape ascoupledrefused PyPSA's link delay, which rolls routinely.restartsnames aposition()a window restarts, which a rolling horizon seeding its opening state means.windowableis false while anything is coupled or undecided; a restart does not count against it.reading.mdsaid it could.One more, from a follow-up question ("can we say what would make it windowable?"):
Each
coupledentry names the change that would lift it, after a dash: a horizon total becomes a rollingsum_back(within=n), a wrap an opening-state seed atposition(t) == 0, a grouping is windowed along the dimension it groups into, a set needs a window holding it whole. Named and not applied — every one changes what the model means, and math-spec'sAdvicealready takes that line.at()moves fromcoupledtoundecided, naming the lookup whose values set its reach.Two more, from the lpspec review:
The verdict folds a parameter's values in itself. lpspec's first driver parsed
undecided's joined string back apart, re-walked the tree for theTranslatewhose offset it named, and applied its own sign rule — and that copy had already drifted (it skipped variable bounds). Nowundecidedis structured andSeparability.resolved(least)takes each named parameter's least value and returns the same verdict withaheadwidened, so the rule that a negative offset reads ahead, and a positive one reads behind and asks nothing, has one home. A reach a lookup decides — a partition, a coordinate — is not a value, so it stays undecided and the driver refuses or resolves it; a name nothing waits on is aKeyErrorrather than a silent zero.behindandindependentare gone. No driver read either: lpspec's window cannot overlap backwards, and its scenario sweep slices a column the spec never declares, so the model never sees that axis. A namedsum_backwidth is therefore not undecided either — it reads behind only. They come back the day a driver asks, knowing then what shape it wants.Verified
After merging main (alpha.70) and change 6:
pixi run lint(lefthook: prettier, ruff, typos),pixi run typecheck(main's three pre-existingyamlstub errors in this env and nothing new),pytest: 1049 passed — the twenty of #248 as reworked here less the fourindependentcases, plus five forresolved: both signs of an offset, a folded value widening a static reach, a static reach and a lookup's surviving the fold, and the refused name.reading.mdgains one executed line (the remedy) and the page test's claim count follows. Not run:mkdocs build --strict,compile-tex.Coverage moved: the six coupling cases split into two structural (
coupled), three data-decided (undecided, asserting the name), and one restart (asserting it stays windowable); a negative-offset case, theat()case, fourindependentcases and the remedy wording are new.🤖 Generated with Claude Code
https://claude.ai/code/session_01FPBsP3UM6esCBREVmjMEhZ