Conversation
Documentation build overview
39 files changed ·
|
FBumann
pushed a commit
that referenced
this pull request
Aug 29, 2026
…ing for one already walked the whole program It was a method taking a dimension, which meant a walk per axis and a caller that had to know which axis to ask about. Every construct that ties an axis names the axis it ties, so one walk answers for all of them: measured at 831us against 844us for the single axis it replaced, on the largest model shipped (#248). So it is a cached mapping like the footprint beside it, complete over the declared dimensions — an axis nothing mentions is trivially windowable rather than absent. A reduction collapsing several axes now couples each of them, which the per-axis form could not get wrong and this one could. Co-Authored-By: Claude <noreply@anthropic.com>
FBumann
pushed a commit
that referenced
this pull request
Aug 30, 2026
…ing for one already walked the whole program It was a method taking a dimension, which meant a walk per axis and a caller that had to know which axis to ask about. Every construct that ties an axis names the axis it ties, so one walk answers for all of them: measured at 831us against 844us for the single axis it replaced, on the largest model shipped (#248). So it is a cached mapping like the footprint beside it, complete over the declared dimensions — an axis nothing mentions is trivially windowable rather than absent. A reduction collapsing several axes now couples each of them, which the per-axis form could not get wrong and this one could. Co-Authored-By: Claude <noreply@anthropic.com>
FBumann
force-pushed
the
claude/separable-along
branch
from
August 30, 2026 07:13
aac6faf to
d48505b
Compare
FBumann
pushed a commit
that referenced
this pull request
Aug 30, 2026
…ing for one already walked the whole program It was a method taking a dimension, which meant a walk per axis and a caller that had to know which axis to ask about. Every construct that ties an axis names the axis it ties, so one walk answers for all of them: measured at 831us against 844us for the single axis it replaced, on the largest model shipped (#248). So it is a cached mapping like the footprint beside it, complete over the declared dimensions — an axis nothing mentions is trivially windowable rather than absent. A reduction collapsing several axes now couples each of them, which the per-axis form could not get wrong and this one could. Co-Authored-By: Claude <noreply@anthropic.com>
FBumann
force-pushed
the
claude/separable-along
branch
from
August 30, 2026 07:17
d48505b to
c5065c2
Compare
FBumann
pushed a commit
that referenced
this pull request
Aug 30, 2026
…ing for one already walked the whole program It was a method taking a dimension, which meant a walk per axis and a caller that had to know which axis to ask about. Every construct that ties an axis names the axis it ties, so one walk answers for all of them: measured at 831us against 844us for the single axis it replaced, on the largest model shipped (#248). So it is a cached mapping like the footprint beside it, complete over the declared dimensions — an axis nothing mentions is trivially windowable rather than absent. A reduction collapsing several axes now couples each of them, which the per-axis form could not get wrong and this one could. Co-Authored-By: Claude <noreply@anthropic.com>
FBumann
force-pushed
the
claude/separable-along
branch
from
August 30, 2026 18:19
c5065c2 to
5f083ef
Compare
FBumann
pushed a commit
that referenced
this pull request
Aug 31, 2026
…ing for one already walked the whole program It was a method taking a dimension, which meant a walk per axis and a caller that had to know which axis to ask about. Every construct that ties an axis names the axis it ties, so one walk answers for all of them: measured at 831us against 844us for the single axis it replaced, on the largest model shipped (#248). So it is a cached mapping like the footprint beside it, complete over the declared dimensions — an axis nothing mentions is trivially windowable rather than absent. A reduction collapsing several axes now couples each of them, which the per-axis form could not get wrong and this one could. Co-Authored-By: Claude <noreply@anthropic.com>
FBumann
force-pushed
the
claude/separable-along
branch
from
August 31, 2026 18:08
5f083ef to
5918b28
Compare
FBumann
changed the base branch from
claude/the-waist-as-a-value
to
claude/what-counts-as-a-verb
August 31, 2026 18:08
…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>
FBumann
force-pushed
the
claude/separable-along
branch
from
August 31, 2026 18:29
5918b28 to
b207667
Compare
FBumann
added a commit
that referenced
this pull request
Aug 31, 2026
…bproblem is a call rather than a second file A myopic pathway, a rolling horizon and a Benders subproblem share one move: a variable stops being a decision and becomes a number somebody else chose. fix takes every name in one call and validates once at the end. Two translations are decisions, not copies: a where-masked variable becomes coverage: masked, and a binary or integer variable becomes an int parameter — never a float, never a bool that would read as a mask. Rebased onto the parameter-coverage branch (#243) it needs for Coverage, off the closed #247/#248 stack it was authored on; only the fix additions are kept. Co-Authored-By: Claude <noreply@anthropic.com>
FBumann
marked this pull request as ready for review
August 31, 2026 20:48
FBumann
added a commit
that referenced
this pull request
Sep 2, 2026
…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
FBumann
added a commit
that referenced
this pull request
Sep 2, 2026
…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
FBumann
added a commit
that referenced
this pull request
Sep 2, 2026
…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
FBumann
added a commit
that referenced
this pull request
Sep 2, 2026
…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
FBumann
added a commit
that referenced
this pull request
Sep 2, 2026
…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
Contributor
Author
|
Superseeded by #374 |
FBumann
added a commit
that referenced
this pull request
Sep 2, 2026
…a time, and what each coordinate needs from its neighbours (#374) * feat(program): a model says whether a horizon may be solved a window 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> * feat(program): a model says whether an axis may be built a window at 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 * refactor(program): an undecided reach says what it stands as, and the 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 * refactor(program): a verdict reports only what a window reads ahead, 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 --------- Co-authored-by: Claude <noreply@anthropic.com>
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.
What this changes
One dataclass and one attribute, beside the
Footprintthe program already answers.A rolling-horizon or myopic driver asks one thing of a model before it starts: would windowing change the answer? Storage carried over a snapshot survives being cut into overlapping windows. An annual budget does not — and both window into pieces that solve, so nothing else says so.
Why it belongs here, and in this shape
It is the locality
ceiling.mdalready argues in — pointwise, bounded halo, global — asked about a dimension rather than about an operator. The language owns those words and never answered the question with them.Derived, not declared. Not a
PiecewiseDeclaration: nothing writes it, and aseparable:key would let a file claim what the compiler can check. The precedent isFootprint.On the
Program, not theSpec. Locality lives inTranslate,WindowandSum— lowered nodes. ASpecholds expression strings, so answering there means parsing twice.Two arguments in this section were wrong, and the review corrected both. I first put it in a module beside
boundedness.pyand defended that on dependency direction;where_parserimports onlyerrorsandexpression_parser, so there was no direction to protect, andProgram.dimension(name)already shows a parameterised accessor is idiomatic here. Then I defended a function over acached_propertyon the grounds that a property would have to walk every axis eagerly — and dismissed the cost with a measurement of ten walks read as one. Measured properly, on the shipped example: one walk answering every axis is 831 µs against 844 µs for a single axis, because every construct that ties an axis names the axis it ties. So the walk is per-program, not per-dimension, and the shape is acached_propertyreturning a mapping keyed by dimension.The crux
A reduction means opposite things by position. In a constraint, a sum over the axis ties every window to every other. In the objective it is additively separable — an objective is a sum, so summing the windows' objectives is summing the model's. A verdict treating the two alike would refuse every windowable model there is; the mutation table below shows it fails six tests.
Two bugs the tests caught, and one was the motivating case
A
cases:mask did not reach the walk. The first version reported acases:block seeded withposition(h) == 0as windowable. It is not: the seed fires once over a horizon and once per window.children(Cases)returns a region's value and not itswhen, so no expression walk reaches a mask written insidecases:— and a rolling horizon seeding its opening state is exactly that shape. The masks a block is judged on are now collected during the walk rather than read off the declaration alone. Worth knowing for any future analysis pass: that is a trapdoor inchildren, not in this module.Converting to a mapping introduced a second one.
Sum.overis a tuple, and the per-axis version had only ever been asked about one axis at a time. A mutation coupling only the first axis of a multi-axis reduction survived all 902 tests — a hole the conversion opened and nothing existing could see.test_a_reduction_over_several_axes_couples_every_one_of_themis that hole closed.What it does not decide
Whether the modeller wanted the window. A
position(t) == 0seed is a horizon's start or a window's start depending on intent, and both are models somebody means. This reports that windowing changes which rows it selects and stops.What lpspec removes or changes
Nothing today; one thing worth having.
solve_overalready sweeps an axis, andstrategy.pyalready drives a build a slice at a time — neither asks whether slicing is sound, because nothing could answer. A driver can now refuse, or warn, before solving windows whose answer is wrong.That is the whole of it: no verb changes, nothing binds differently, and a consumer that ignores this is exactly as correct as it is today.
Verified
Toolchain at the versions
pixi.tomlpins:ruff format --check/ruff check(0.16.1) clean,pyrefly(1.2.0) 0 errors,pytest -q905 passed, 0 skipped (885 on the base — 20 new).reuse,typos,prettier --check,render_tex(27 models) andmkdocs build --strictwere run on the top of the stack (#250), which contains these commits.The
reading.mdsection is executed — that page's Python blocks run against a real model and every# valueline is checked. Its own example is the page's own model, which separates along neither axis, and the report names the three constraints thepiecewise:block emitted — a coupling introduced by an expansion, named under the name the expansion gave it.Method for the 831 µs / 844 µs above:
timeiton the shippedreading.mdmodel,_separabilities(program)against the single-axis version at the same base commit, best of five, cache bypassed each call. It is the whole reason the walk is not held per dimension, so it is quoted here rather than left in the tree.Not run:
zizmor,taplo, and thetectonichalf ofcompile-tex.mkdocs build --strictneededdocs.python.org/objects.invdropped frommkdocs.yml, which this environment's proxy refuses.Mutation table
sum_backhalo is the width rather than width − 1Deliberately not done
No public where-walker. A where tree is not an expression tree, so this needed a small recursion of its own. It is private, with one caller; it belongs beside
childreninwhere_parserthe day there are two, and the docstring says so.halois a plainint, neverint | None. It is how far the program reads across the axis, which is true whether or not anything couples — overlap alone is only enough where nothing does. The two questions are already separate (windowable, thenhalo), and aNonea caller must check twice is worse than one they read after the verdict. An earlier version of this description, and of the docstring, saidhalowas "meaningful only where nothing is coupled"; that was wrong about what the number is, and the review fixed both.Stack: seventh, on #247 → #246 → #245 → #244 → #243 → #242 → #168.
Generated by Claude Code
Closes #298