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
ROADMAP Track 1 item 3 — coordinate helpers in where, index(dim, i)
with negative i from the end — has no issue, though the table marks it "blocks 4". Filing it because two other issues now point at it and because
the workaround it replaces fails silently.
constraints:
ramp:
foreach: [snapshot, generator]where: "snapshot > index(snapshot, 0)"# every snapshot but the first
1. The workaround fails silently
Today the boundary is written as a literal — where: "snapshot > 0" — which is
correct only while the instance is 0-based. Same YAML, horizon relabelled from [0, 1, 2] to [1, 2, 3], ramp limit of 20 against a price of [50, 1, -1]:
index
ramp rows built
p
objective
[0, 1, 2]
2
[100, 100, 0]
5100.0
[1, 2, 3]
3
[100, 100, 80]
5020.0
On the 1-based index snapshot > 0 is true everywhere, so the row roll wraps
onto — precisely the row the clause exists to exclude — comes back, and the ramp
limit quietly becomes cyclic. status == ok in both runs. No warning, different
answer.
Worth separating from its sibling: the seeding form (where: "snapshot == 0")
fails loudly on a shifted index — with no row to seed it the recurrence is
infeasible, status=warning and the objective is nan. It is the > 0 form
that is silent, and it is the more common one: five of the nine boundary clauses
in examples/ports/ are > 0.
Nine clauses across four ported models currently rest on the instance happening
to start at zero:
2. It blocks item 4, which is the ledger's open row
ROADMAP item 4 (window sum, sum_next_n) is marked needs 3. Item 4 is what min_up_time needs — the row docs/ports.md
records as the thing a port could not say. So this is the first of two steps
toward the corpus's one acknowledged expressiveness gap.
#300 (a datetime dimension
cannot appear in a where) lists this as its option 2, and for the dominant
case it is the stronger answer. index(snapshot, 0) says the first snapshot
on any dtype and survives the horizon moving; a date literal only helps when
comparing against a specific known date, and still hardcodes it. The two are
complementary — a policy start year wants the literal, a boundary condition
wants this — but the boundary condition is what the corpus actually writes nine
times.
Design notes
Locality is coordinate-space. The helper reads the frame's own coordinate
column and never touches bound data, so it should not need a new plan node —
it resolves to a literal at load time or to a rank over the coordinate index.
Ordering is a real precondition.index(dim, i) is positional, and SPEC §8
step 4 says a dimension derived from parameter tables gets sorted distinct
values rather than a declared order. So index means something well-defined
only against a declared or source-supplied index, and it should say so — or
refuse on a derived dimension, which is the fail-loud reading. This is the same
caveat roll/shift already carry, and it becomes more load-bearing here.
The grammar needs widening. SPEC §6 gives atom ::= NAME | NAME COMPARATOR value with value ::= NUMBER | NAME_OR_STRING. A call on the right-hand side
is not currently expressible, so this is a where-grammar change and not only a
new helper.
Open: whether index() is confined to where (as ROADMAP's wording
suggests) or is also legal in expressions, where it would overlap with item 1's at(x, over=dim, index=value).
Note
The following content was generated by AI.
ROADMAP Track 1 item 3 — coordinate helpers in
where,index(dim, i)with negative
ifrom the end — has no issue, though the table marks it"blocks 4". Filing it because two other issues now point at it and because
the workaround it replaces fails silently.
1. The workaround fails silently
Today the boundary is written as a literal —
where: "snapshot > 0"— which iscorrect only while the instance is 0-based. Same YAML, horizon relabelled from
[0, 1, 2]to[1, 2, 3], ramp limit of 20 against a price of[50, 1, -1]:p[0, 1, 2][100, 100, 0][1, 2, 3][100, 100, 80]On the 1-based index
snapshot > 0is true everywhere, so the rowrollwrapsonto — precisely the row the clause exists to exclude — comes back, and the ramp
limit quietly becomes cyclic.
status == okin both runs. No warning, differentanswer.
Worth separating from its sibling: the seeding form (
where: "snapshot == 0")fails loudly on a shifted index — with no row to seed it the recurrence is
infeasible,
status=warningand the objective isnan. It is the> 0formthat is silent, and it is the more common one: five of the nine boundary clauses
in
examples/ports/are> 0.Nine clauses across four ported models currently rest on the instance happening
to start at zero:
2. It blocks item 4, which is the ledger's open row
ROADMAP item 4 (window sum,
sum_next_n) is marked needs 3. Item 4 is whatmin_up_timeneeds — the rowdocs/ports.md
records as the thing a port could not say. So this is the first of two steps
toward the corpus's one acknowledged expressiveness gap.
3. It is the better half of #300
#300 (a datetime dimension
cannot appear in a
where) lists this as its option 2, and for the dominantcase it is the stronger answer.
index(snapshot, 0)says the first snapshoton any dtype and survives the horizon moving; a date literal only helps when
comparing against a specific known date, and still hardcodes it. The two are
complementary — a policy start year wants the literal, a boundary condition
wants this — but the boundary condition is what the corpus actually writes nine
times.
Design notes
Locality is coordinate-space. The helper reads the frame's own coordinate
column and never touches bound data, so it should not need a new plan node —
it resolves to a literal at load time or to a rank over the coordinate index.
Ordering is a real precondition.
index(dim, i)is positional, and SPEC §8step 4 says a dimension derived from parameter tables gets sorted distinct
values rather than a declared order. So
indexmeans something well-definedonly against a declared or source-supplied index, and it should say so — or
refuse on a derived dimension, which is the fail-loud reading. This is the same
caveat
roll/shiftalready carry, and it becomes more load-bearing here.The grammar needs widening. SPEC §6 gives
atom ::= NAME | NAME COMPARATOR valuewithvalue ::= NUMBER | NAME_OR_STRING. A call on the right-hand sideis not currently expressible, so this is a where-grammar change and not only a
new helper.
Open: whether
index()is confined towhere(as ROADMAP's wordingsuggests) or is also legal in expressions, where it would overlap with item 1's
at(x, over=dim, index=value).