Repository navigation
feat(language): a model declares what it assumes of its data, and the typeset math prints it - #471
Conversation
… typeset math prints it An `assumptions:` block holds predicates in the where grammar; each holds at every coordinate of the frame its two masks name, a missing row reading as false. The program carries each as `AssumptionDeclaration(holds, where)` with `assumption_message` for the consumer that binds the data. A where may now compare two parameters coordinate by coordinate, which the block's own examples need. The typesetter prints an Assumptions section: every declared entry, then what each `piecewise:` block assumes of its breakpoints, labelled by the block. Docs sentence lengths (n / median / over 25): declarations.md 71 / 13 / 9, piecewise.md 75 / 16 / 13, expressions.md 133 / 15 / 23. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HceuCYNepeQX8SdZtiMf1
…r a curve's checks Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HceuCYNepeQX8SdZtiMf1
… the assumptions branch An assumption's predicate now takes arithmetic on either side, as every where does on the base branch; the golden fixture carries one of each kind. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HceuCYNepeQX8SdZtiMf1
| assumptions: | ||
| floor_below_capacity: | ||
| description: a floor above the capacity leaves `upper` and `lower` no output to agree on | ||
| holds: "p_min <= p_max" |
There was a problem hiding this comment.
I don't see the need to introduce a new term here. We can just use where?
There was a problem hiding this comment.
I think we should deliberately use a different term here!
It has a very distinct meaning here. It should check an assumption, and not filter!
It uses the where engine underneath, but that's an implementation detail.
There was a problem hiding this comment.
I was more thinking that when saying it aloud "assumption A is valid when Y holds, otherwise raise" makes sense, as does "raise where Y doesn't hold" or "refuse on A where Y doesn't hold". I guess this leads to a question purely on naming. #268 uses refusals.
In writing this, I have come round to assumptions as "assumption A is valid when Y holds, otherwise raise" sounds OK.
| assumptions: | ||
| floor_below_capacity: | ||
| description: a floor above the capacity leaves `upper` and `lower` no output to agree on | ||
| holds: "p_min <= p_max" |
There was a problem hiding this comment.
I see you've removed the difference between a strict and non-strict assumption (error vs warn). That's probably fine, although there are some non-strict assumptions in calliope math which are nice to have there. I'm not sure whether I would keep them and force the user to change their data on an error or delete them because it's annoying to get an error every time just because of some data mismatches which will be ignored in the math...
There was a problem hiding this comment.
Agreed
We need to expose a Warning and error type then
Should be easy
Brings this branch onto #469 as rebuilt on the alpha.90 release, so it picks up #437's relations rename and #449's gallery renames. Nine files conflicted, and three more merged cleanly while still written in the old vocabulary, which was the larger half of the work: - The typesetting union this branch adds was named `RelationNode`, which main now uses for a resolved `by=`. The alias is `AlignedComparison`, and `_relation` reads a relation column through `_value_read` and a position group through `_position_group`, as main's `_predicate` does. - `_comparison` keeps main's dotted-column body and this branch's parameter pair, which is taken only where neither side names a column. - `_parameter_pair_error` and main's `_relation_pair_error` are both kept. - `examples/commitment.yaml` assumed `p_min <= p_max`, which #449 renamed to `min_output <= capacity`. - The new cases spell `shift`/`sum_back` with `along=` and `window=`. - The expressions page said two parameters cannot be compared, which this branch makes false; it now states both pair forms. The generated schema, goldens and pages are regenerated, not hand-merged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017VApqcmBKLXtKTmk3ajmtK
Its base now carries main through alpha.91, which is where the relations plan and the alpha.90 revert reach this branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014pdMgEVkGBfh1f2AyiCSKA
…gned form The merge left main's per-node dispatch below the aligned one that already answers for it, so four kinds of comparison had a second, unreachable printing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014pdMgEVkGBfh1f2AyiCSKA
|
Superseeded by #589 |
Note
The following content was generated by AI.
Stacked on #469, which lets every
wherecompare arithmetic. Replaces #465, whose base GitHub would not change. A file states what it assumes of its data underassumptions:, in the where grammar. The program carries each entry as two masks for the engine to check. The typeset document prints every assumption, and what eachpiecewise:block assumes of its breakpoints, under one heading.What this changes
The surface, the program, the rendering
Surface. An eleventh declaration key,
assumptions:. An entry is a bare where string, or a mapping withholds:, an optionalwhere:and adescription:. It holds at every coordinate of the product of the dimensions its two masks name, a missing row reading as false as in anywhere; a parameter supplied only where it applies takes awhere:naming it. There is nodims:, because a predicate widens nothing. A predicate naming a variable is refused, and so is one that folds to a literal. With #469 underneath, either side may be arithmetic:p_min <= 0.5 * p_max,sum(p_max, over=generator) >= budget, a translation with itsedge=and aposition()guard inwhere:. Reference:docs/reference/language/declarations.md#assumptions.Two parameters may be compared by name, coordinate by coordinate, in any where string, the narrower one read at every coordinate of the wider. Both are numbers, or both share a dtype, so two labels or two flags compare too, which the arithmetic path of #469 does not admit. The exclusivity check reads the pair as one subject ordered three ways plus a missing row, so a case
whenmay use it.ParameterPairComparisonNodejoins the closedWhereNodeunion.Program.
Program.assumptionsmaps each name toAssumptionDeclaration(holds, where), andassumption_messagewords the refusal, beside the existingCheckunion andcheck_messagefor curves.Rendering. A fourth section, Assumptions, after Variable domains: each declared entry as a line, a lone comparison aligned on its relation as a constraint is; then each
piecewise:block's checks, labelled<block> increasing,curvature,breakpoints,points. The increasing x-axis is an inequality between neighbours under the plain translation; the shape a method is exact for is prose, as a paper writes it; the two conditions on apoints:mask are stated of the set the mask admits (Format.set_ofis the one new format method).typeset_declarationtakes an assumption name. The notation page shows the derived assumptions under eachmethod:row, andexamples/commitment.yamlgains the one assumption its math needs,p_min <= p_max.Why
An assumption about the numbers is a rule two engines must not answer differently, so it is language; the numbers are the engine's, so the engine checks. The language already does this once, for
piecewise:checks, and this generalises that mechanism to what the author writes, and prints both.Verified
Run in a
uvvenv (Python 3.12) becausepixiis not installable in this environment:pytest -n autoon this head: 1276 passed, 12 skipped. Five pre-existingtest_docs.pyhook tests are deselected here because they importmkdocs, which the venv lacks; they fail identically onmainin this environment.ruff check,ruff format --check,pyrefly check,prettier --check docs: clean.typstpackage. Generated artefacts regenerated and read: schema JSON, the three golden files,notation.md,commitment.md.docs-build --strictandcompile-tex.Not run locally:
compile-tex,docs-build --strict,reuse,typos,taplo,zizmor.Mutation table
Each guard deleted in turn, the suite run, the file restored from a copy and the tree checked clean.
TestAssumptions[a-predicate-that-is-always-true],[...-always-false]TestAssumptions[a-variable-in-the-predicate],[a-variable-in-the-where]TestRulesDecidedWithoutData[where-against-a-parameter-of-another-dtype],TestAssumptions[two-parameters-of-different-dtypes]test_a_parameter_pair_carries_the_union_of_both_dims_left_firstwhentest_a_parameter_pair_with_a_row_missing_compares_false_under_every_comparatoradded as the probe, and it fails with the guard deletedCoverage moved, defaults departed from, and what was left out
where-against-a-parameterasserted that two parameters cannot be compared; it is nowwhere-against-a-parameter-of-another-dtype, and acceptance is covered underTestAssumptions.test_a_name_declared_as_none_of_the_three_is_refusedbecame..._of_the_four_....validation.pymessage for a variable-free comparison now points atassumptions:rather than at data preparation, and the limits page's unit-checking row says why a range is not the same refusal.lpcurves and eight assumptions, four of them arithmetic, so the walk's line census reaches every new arm.Program.assumptions, the pair node and the expression comparison at the data door) is the next PR, stacked on this one's pin. Checks the language could derive from use, a divisor being nonzero and named bounds not crossing, are a separate change. datarecord is untouched.🤖 Generated with Claude Code
https://claude.ai/code/session_013HceuCYNepeQX8SdZtiMf1
Generated by Claude Code