docs: the README shows the math a model prints, in all three formats - #449
Conversation
Documentation build overview
47 files changed ·
|
dc37122 to
c77504f
Compare
6aac0f5 to
9c1e8aa
Compare
9c1e8aa to
7f9ca89
Compare
The README described the typesetter and never showed it. The dispatch model
now stands beside the equations printed from it, in the Markdown that GitHub
renders as math. `tools/home_math.py` writes the block from
`examples/dispatch.yaml`, so nothing in it is hand-typed.
The visible block carries no legend and no symbol table. Three legend tables
are half the length of the document, and a derived symbol is the file's own
name, so the equations read without them: 44 lines become 23. A smaller model
does not do this. The same model cut to two parameters, with no `where:` and
no upper bound, prints 45 lines, because dropping the table adds the
convention note. Four folded blocks hold the whole document: with the symbol
table and its legend, as LaTeX, and as Typst.
The Typst block is printed with no table, which makes it the evidence for what
a derived symbol looks like. A parameter is upright, so `load` prints as
\mathrm{load}_t and `p_max` as \mathrm{p}^{\mathrm{max}}_g. Three pages claimed
\mathit{load}_t and p^{\mathrm{max}}_g for the same two names, and
docs/reference/notation.md contradicted the legend printed further down its
own page.
The README also named a variable the example does not declare: the model
declares `p`, and three sentences called it `dispatch`.
README.md: n 88, avg 12.7, median 11, over25 13. Every sentence over 25 words
is in a section this commit does not touch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EQ6np3vx2fqJB5PfQjquRJ
7f9ca89 to
f25159f
Compare
|
|
||
| With no table, the symbols are **derived** from the names in the file, such as | ||
| $\mathit{load}_t$ and $p^{\mathrm{max}}_g$. A derived symbol names one | ||
| $\mathrm{load}_t$ and $\mathrm{p}^{\mathrm{max}}_g$. A derived symbol names one |
There was a problem hiding this comment.
Could we change p to dispatch and p_nom/p_max to capacity for ease of reading in the docs? I already updated that in the README in my previous PR but would be good to be consistent across all docs pages. I doubt anyone except a PyPSA person understands p!
| `symbols` is optional. Drop it and the same model prints as | ||
| $\mathrm{load}_t$ and $\mathrm{p}^{\mathrm{max}}_g$, with no setup. Pass a dict, | ||
| a YAML path or a `SymbolTable`. A key that names nothing in the model is an | ||
| error, rather than a symbol that silently never applies. Every spelling is | ||
| printed as written, and `notation` says which language it is written in. A | ||
| render in the other notation is refused. |
There was a problem hiding this comment.
confusing paragraph as it first talks about what happens if symbol isn't there then goes onto say what symbol should be and what happens when it is there. Should start by saying everything symbol does and then say it's optional and without it you get X
| snippet, and ``docs/index.md`` holds the math, which is a tabbed block and | ||
| would be raw markup on GitHub. The third tab is the call that produced the | ||
| other two. | ||
| Two files carry it. ``README.md`` holds the YAML, which the site pulls in as a |
There was a problem hiding this comment.
Two files carry it. is an unnecessary sentence that the skill should be able to handle removing (has this been rewritten with the latest skill available?
| `SymbolTable`; a key naming nothing in the model is an error, not a symbol that | ||
| silently never applies. Every spelling is printed verbatim — `notation` says | ||
| which language they are, and a render in the other one refuses. | ||
| `symbols` is optional. Drop it and the same model prints as |
There was a problem hiding this comment.
Repetition w.r.t. typeset.md. Can we share this text between them?
| `snapshot` and `generator`; the data it expects, such as `load` and `cost`; the | ||
| decisions the solver makes, such as `dispatch`; and the rules those decisions obey, such | ||
| as `sum(dispatch, over=generator) == load`. The file [below](#example) is a complete | ||
| decisions the solver makes, such as `p`; and the rules those decisions obey, such |
There was a problem hiding this comment.
I made these dispatch for the reason stated in previous comment.
| That file is a complete model. Nothing outside it changes what it means. | ||
|
|
||
| <!--- --8<-- [start:load] --> | ||
| ### What that file says |
There was a problem hiding this comment.
Not a good header name. Maybe latest skill would modify it appropriately?
| Neither needs data or a solver, so a repository of models compiles in CI with | ||
| nothing bound to any of them. **A `Spec` holds the file as written, and a | ||
| `Program` holds the model it builds**, with every macro expanded and every curve | ||
| turned into its variables and constraints. An engine reads the second. |
There was a problem hiding this comment.
| turned into its variables and constraints. An engine reads the second. | |
| turned into its variables and constraints. An engine reads the `Program`. |
|
@bryn thanks for your review! |
`p` and `p_max` are PyPSA's spellings, so a reader without that background
had to guess what the decision was. The gallery models and the reference
pages now name the decision `dispatch` and its bound `capacity`, and
`p_min` becomes `min_output`.
The six `pypsa*.yaml` files keep `Generator_p_nom` and `Generator_p_max_pu`,
which are PyPSA's own API and are the point of those files. The golden
fixture and the operator probes keep `p` too: their subject is which
construct prints what, not what a model calls things.
Also on this page: `docs/howto/print.md` said a parameter with no symbol
table prints as $\mathit{load}_t$, and it prints $\mathrm{load}_t$.
Two headings that narrated rather than named a subject become `The math it
prints` and `Spec` and `Program`, in the README and on the site homepage
together.
The `How` tab on the homepage repeated six sentences of
`docs/reference/typeset.md`. It now says what `symbols` does, then that it
is optional, and leaves the rest to the link it already carried.
`tests.fixtures.DISPATCH_MODEL` stays on `p` and `p_max`. It is an inline
dict that 11 test files vary; renaming it moved 87 assertions and changed
nothing a reader sees. Its docstring no longer claims to be
`examples/dispatch.yaml` name for name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FerXtCLtx64Mag9uKnA6FZ
main renamed a declaration's `foreach:` to `dims:` (#429), and this branch renamed the example models' `p`, `p_max` and `p_min` to `dispatch`, `capacity` and `min_output`. Every conflict is both edits on one line, so each takes main's key with this branch's names. The five generated pages and the golden typesetter output were re-rendered rather than merged by hand. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZKoWvZmUg8XxUK3nKxMZr
#437 renamed `lookups:` to `relations:` and a walk operator's `over=` to `along=` on the same lines this branch renamed `p` to `dispatch`, so eight files conflicted. Every conflict takes main's keyword with this branch's names. `README.md` also takes this branch's `sum(dispatch, over=generator)`: main writes `consume=`, which no version of the language has parsed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjQuLw7nctEbY7ACCGsaLP
#437 wrote `sum(consume=)` into the README's opening paragraph and its prior art section. No version of the language has parsed `consume=`: the keyword that reduces a dimension away is `over=`, as `BUILTINS['sum'].usage` and `docs/reference/language/operators.md` both say. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjQuLw7nctEbY7ACCGsaLP
Brings the branch up to 0b4f046, which carries #437's relations rename and #449's gallery renames. Deliberately 0b4f046 rather than main: main also carries #474, which #481 reverts, and merging it here would resurrect it. Seven files conflicted. The renames main made are taken, and this branch's new nodes are kept alongside them: - The frame-check message keeps this branch's `leaf` phrase, which the two expression-comparison nodes need because they carry no name, with main's wording and `where-relation` spelling for the four named cases. - `_comparison` takes main's dotted-column body, with this branch's `expressions:` check in front of it. - `_expression_comparison` and main's `_relation_column` are both kept. - `LookupNode` is `RelationNode`, and a translation's `partition` is now a `Walk`, so `names_read` reads `.name` off it. - The new cases spell `shift`/`sum_back` with `along=` and `window=`. 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
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
Brings the branch up to 0b4f046. Deliberately 0b4f046 rather than main: main also carries #474, which #481 reverts — and #474 adds `walk_regions` to `program.py`, which this branch renames throughout. One file conflicted. `tests/test_lowering.py` carries both renames at once: this branch drops the `Node` suffix, and #449 renamed the gallery's `p` and `p_max` to `dispatch` and `capacity`. The merged file takes #449's values with this branch's type names, and its two API decisions hold — the mask constant is built with `Multiply(Variable(...), Parameter(...))` rather than the deleted operator sugar, and the domain is read off `program.variables` rather than the deleted `program.variable()`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017VApqcmBKLXtKTmk3ajmtK
Second round: Bryn's review asked for
dispatchandcapacityin place ofpandp_max, across the docs rather than the README alone.Third round:
mainrenamed a declaration'sforeach:todims:(#429) while this branch renamed the same lines, so the branch is merged up in0ac8bc9.Fourth round:
mainrenamedlookups:torelations:and a walk operator'sover=toalong=(#437), again on the lines this branch renamed, so the branch is merged up again inb3ef80d.Note
The following content was generated by AI.
What this changes
The README described the typesetter and never showed it.
examples/dispatch.yamlnow stands beside the equations printed from it, in the Markdown GitHub renders as math.tools/home_math.pywrites the block, so nothing in it is hand-typed.The example models also drop PyPSA's spellings. The decision is
dispatch, its bound iscapacity, andp_minismin_output.The README also names
sum's own keyword again. #437 wrotesum(consume=)into the opening paragraph and the prior art section, and no version of the language has parsed that: the keyword isover=.The rename, and the four places that keep
ppandp_maxare PyPSA's names, so a reader without that background had to guess what the decision was. Renamed inexamples/dispatch.yaml,commitment.yaml,sos.yaml,piecewise.yamlandpiecewise_lp.yaml, in the sidecar symbol table, in the pages generated from all of them, and in the reference and how-to pages that show the same YAML by hand.Four places keep
pon purpose:examples/pypsa*.yamlGenerator_p_nomandGenerator_p_max_puare PyPSA's own API. Renaming them is what would make those files wrongtests/typesetting/golden/model.yaml, and sodocs/reference/notation.mdtheta,spareandheadroom. Its subject is which construct prints whatexamples/operators/*.yamltests.fixtures.DISPATCH_MODELexamples/dispatch.yamlname for namedocs/reference/notation.mdstill moved by 8 lines, because itspiecewise:sections come fromsos.yamland the twopiecewise*.yamlfiles rather than from the fixture.How the two merges with
mainwere resolvedBoth merges are the same collision.
mainrenamed a key or a keyword on the very lines this branch renamedp,p_maxandp_min, so git could not merge them, and every conflict takesmain's keyword with this branch's names.0ac8bc9, against #429, which renamedforeach:todims:on every variable, constraint and cased expression. Thirteen files conflicted.examples/dispatch.yaml,commitment.yaml,piecewise.yaml,piecewise_lp.yaml,sos.yamlmain'sdims:, this branch's namesdocs/howto/regimes.md,docs/reference/language/absence.md,declarations.md,index.mdtests/test_lowering.pymain's assertion messages say "the frame is the dims"README.md,docs/examples/dispatch.md,docs/examples/commitment.mdb3ef80d, against #437, which renamedlookups:torelations:andshift's andsum_back'sover=toalong=. Eight files conflicted.examples/commitment.yamlmain'salong=, this branch'sdispatchdocs/reference/language/absence.md,dimensions.md,index.mdtests/test_lowering.pydocs/examples/commitment.mddocs/reference/notation.md\mathrmcorrection belowREADME.mdsum(dispatch, over=generator), for the reason in What this changesprettier --writethen repadded the ten-rule table ondocs/reference/language/index.mdafter each merge, whose cells changed width.The other five review comments
symbolsparagraph ondocs/index.mdled with what happens withoutsymbols. It now says whatsymbolsdoes, then that it is optional.docs/reference/typeset.md. Rather than share the text through a snippet, the homepage keeps the one fact a newcomer needs and leaves the rest to the link it already carried. A homepage summary beside a reference page is not two homes for one fact.Two files carry it.counted what the next two sentences said. The whole module docstring is rewritten around the constraint that made the tool exist: GitHub renders the Markdown math but not a tabbed block.### What that file saysand### How a tool reads itnarrate rather than name a subject, which.claude/skills/docs-writing/SKILL.mdrules out. They are now### The math it printsand### `Spec` and `Program`, inREADME.mdanddocs/index.mdtogether — the second page already carried both headings from docs: the pages read in plain English, arranged by what each is for #442, so leaving it would have split them.An engine reads the second.is applied verbatim.One claim that was wrong, and one this PR withdraws
A model with no symbol table prints
\mathrm{load}_t, not\mathit{load}_t. A parameter is given, so it derives upright.docs/reference/notation.mdwas contradicting the legend printed further down its own page, anddocs/howto/print.mdcarried the same error — that page is fixed here too, and Bryn did not flag it. #437 rewrote that same paragraph onmainand kept\mathit, which is why the page conflicts again inb3ef80d;tests/typesetting/golden/latex.outprints\mathrm{load}and settles it.Withdrawn: an earlier version of this body said the README was wrong to call the variable
dispatch, because the file declaredp. Bryn's review settles it the other way, and the file now declaresdispatch.Why the visible block is short, and why a smaller model is not what does it
The ask was to shrink the model. Measured on
62ce3a4withto_markdown(numbered=False), counting non-empty lines of the printed document:dispatch.yaml, derived symbols, with the legenddispatch.yaml, symbol table and legenddispatch.yaml, derived symbols, no legendThe legend is the lever, not the model: three tables and their headings are half the document. So the visible block drops the legend and the table. That costs nothing a reader needs, now less than ever — a derived symbol is the file's own name, and after the rename that name is
\mathrm{capacity}_g. The legend, the conventional symbols and both other formats are one click away in the folds.An earlier version of this table carried a fourth row, for
dispatch.yamlcut to two parameters with nowhere:and no upper bound, and claimed 45 lines. That number does not reproduce: the same cut measures 43 here. It was load-bearing for nothing — 43 and 45 are both far from 23 — so the row is dropped rather than restated.examples/dispatch.yamlkeeps every construct it had, which keeps it whole for the four tests that read it and for the gallery page whose prose explains itswhere:.The prose
Written to
.claude/skills/docs-writing/SKILL.md: a heading names a subject rather than narrating one, a full stop separates independent clauses, and the argument for the block lives in this PR rather than on the page.The
Howtab intools/home_math.pyis prose ondocs/index.mdthat #442 could not reach, since it lives in the generator. It went through the same pass, and it links Typeset the math at the construct's first mention.How the block regenerates, and the formatter
readme_block()intools/home_math.pyadds a second marker region to the file that already owned the README's YAML block:tests/test_docs.py::test_the_generated_page_is_current[home:readme]fails if it drifts.Prettier pads the legend tables the typesetter emits unpadded, so the generated block sits inside a
<!-- prettier-ignore-start -->range. That range is load-bearing: with it stripped,prettier --write README.mdrewrites 9 lines of the legend tables, measured on62ce3a4..prettierignore's note thathome_mathneeds no entry was written before the README carried tables, so it now names the range as the second way out.Verified, and not
Pixi's installer host is denied by this session's egress policy, so
pixi run cidid not run as one gate. Run instead on a Python 3.13 venv (pydantic,pyparsing,pyyaml,pytest,mkdocs,mkdocs-material,mkdocstrings[python],ruff) and a localprettier@3with the repository's own.prettierrc.yaml, on the head commit5a54ace:pytest testsprettier --check **/*.mdruff check ./ruff format --check .--checkschema,notation,spec_math,gallery,home_mathall currentpython -m tests.typesetting.golden.outfiles re-render byte for bytemkdocs build --strictThe earlier round's numbers were taken on
0ac8bc9and read 1206 passed; the merge with #437 brought main's new tests in, so they are re-run above rather than carried over.mkdocs build --strictneeded one local edit to run at all: the proxy answershttps://docs.python.org/3/objects.invwith 403, andmkdocstringsaborts the strict build on an inventory it cannot fetch. The build above dropped theinventories:key, andmkdocs.ymlis unchanged in the tree. Every other strict check — nav, cross-links, anchors — ran.Not run:
pixi run lint(the whole hook set:reuse,typos,pyrefly, the whitespace fixers) andpixi run compile-tex.Not done: no
src/change, so no behaviour moved.src/math_spec/typesetting/symbols.py's_derive_name_symboldocstring showsp_maxin its chosen spelling, which is correct for itsgiven=Falsedefault and was left alone.🤖 Generated with Claude Code
https://claude.ai/code/session_01LjQuLw7nctEbY7ACCGsaLP