Repository navigation
chore(main): release 0.0.1-alpha.55 - #437
Merged
fluxopt-release[bot] merged 1 commit intoJul 31, 2026
Merged
fluxopt-release[bot] merged 1 commit into
fluxopt-release[bot] merged 1 commit into
Conversation
Contributor
Author
|
🤖 Created releases: 🌻 |
FBumann
added a commit
that referenced
this pull request
Jul 31, 2026
FBumann
pushed a commit
that referenced
this pull request
Sep 10, 2026
…ges keep the math they print The pin was the stack head as it stood, which forked before math-spec's alpha.85 — so regenerating every gallery page with that typesetter reverted #446's GitHub math delimiters across 62 files, and rung 10's description to the prose #442 had rewritten. Neither was this change's to make. The stack's own #437 branch had already been rebased onto main; only #443's one commit was left behind it. Rebased onto that head, and the pin follows it. The rebase brings #444 with it: a grouped position carries the walk it counts within rather than naming its pieces, so the predicate reads `partition` straight and rebuilds no walk of its own — and the linopy lane now holds a grouped position to the same one-dimension rule as every other walk. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SrEY2ZhFD1YXamRn4FzpMa
FBumann
added a commit
that referenced
this pull request
Sep 15, 2026
…h-spec 0.0.0-alpha.89 does (#1646) > **Prompt:** Let's update lpspec to the latest mathspec version > [!NOTE] > The following content was generated by AI. The pin moves to `v0.0.0-alpha.89`, whose one feature ([#437](energy-models/mathspec#437)) replaced `lookups:` with `relations:` and renamed two operator keywords. Both lanes read the new plan; every model, example, rung and page is written in it. Either lane still builds the single-valued map the old lookup was — two columns, one of them the key. A wider table is refused at `lowered`, so `check`, `build` and an archive refuse the same file. <details><summary>What the language change is</summary> A relation is a table with one column per dimension it relates, and `key:` names the columns a row is identified by. The declaration fixes no direction: the operator says which column it consumes and which it produces. `shift(over=, …)` became `shift(along=, …)`, and `sum_back(over=, within=)` became `sum_back(along=, window=)`. | before | after | | --- | --- | | `lookups: {gen_bus: {over: generator, into: bus}}` | `relations: {gen_bus: {columns: [generator, bus], key: generator}}` | | `shift(soc, over=snapshot, offset=1)` | `shift(soc, along=snapshot, offset=1)` | | `sum_back(started, over=hour, within=min_up)` | `sum_back(started, along=hour, window=min_up)` | </details> <details><summary>What moved in the source</summary> - **`relations.py`** is new: the one reading of a declared relation — `refusal`, and the accessors that are well-defined once a wider table has been turned away. Documented in [ARCHITECTURE](docs/about/architecture.md)'s module table. - **Both lanes read the plan's new shape**: `Walk` on `GroupSum`, `At`, `Translate.partition`, `Window.partition` and `DimensionPositionNode.partition`; `RelationComparisonNode`, `RelationPairComparisonNode` and `RelationDefinedNode` in `where`. - **`sources.py`** reads a relation's table under its declared *roles* and hands on the `(key dim, relation)` frame both lanes already read, so a self-map supplies cleanly and no reader downstream changed shape. The checks are the ones it ran before: keys are labels, values are labels, one row per key, no null. - **The engine reads the plan directly**, not `lpspec.relations`: its subpackage may import only `lpspec.errors` and `math_spec.program` (hard rule 2), and `Walk` already carries everything it asked `DimensionDeclaration.targets` for. `_Walk.of`, `_named_amount` and `_grouped_into` take the walk instead of a partition name, which drops a `compiler.program` lookup from `_grouped_into`. - **The PyPSA parity runner** reads a relation's `key:` where it read `lookup.over`, and the projection keeps the dimensions a relation's `columns:` name. Second commit; it is why `differential/` is a separate `chore`. </details> <details><summary>What I deliberately did not do</summary> **The new reach is not implemented.** A bare relation, a key of several columns, a walk with a column joined on, and `within=` on a partition are all refused rather than built. Following a pin is not the PR that grows two lanes a new join shape, and the refusal names the rewrite its shape asks for: ``` relation 'gen_bus' declares no key, and this package builds the single-valued map: one row per key, so a walk reaches one label rather than a set of them. Declare key: on it — one of ['generator', 'bus'], whichever holds each label once — or carry the membership as a bool parameter over ['generator', 'bus'] and select on it with a where string. ``` ``` relation 'zone_of' has 3 columns keyed by 2, and this package builds the single-valued map: two columns, one of them the key, so a walk trades one dimension for one other and joins on nothing. Split it into one relation per pair — 'zone_of' over ['generator', 'period', 'bus'] becomes a map per value column, each keyed by the same single column — or carry the wider table as a parameter over its dimensions and select on it with a where string. ``` Worth its own issue, since the relational lane is close: `_remap_fragment` already trades tuples of dims, and a joined column is that join on more keys. </details> <details><summary>Coverage that moved</summary> `test_a_hand_built_node_whose_tuples_disagree_is_refused` asserted a guard the new IR makes unreachable — `GroupSum` derives `coordinate`, `over` and `into` from `walks`, so the two tuples cannot disagree. The `zip(strict=True)` it certified is still there and still reachable, by the route that now exists: a walk onto two columns at once. It is `test_a_hand_built_walk_onto_two_columns_is_refused` in the same file, with the same purpose in its docstring. `tests/test_sum_by_lookups.py` is `tests/test_sum_by_relations.py`. `tests/test_assertions.py`'s ratchet falls 208 → 207. </details> <details><summary>The new guard, deleted and re-run</summary> `relations.refusal`'s loop deleted, whole suite re-run: ``` FAILED tests/test_label_coords.py::test_a_relation_wider_than_a_map_is_refused_with_the_rewrite_named[a-bare-relation-is-a-set-per-label-and-not-a-map] FAILED tests/test_label_coords.py::test_a_relation_wider_than_a_map_is_refused_with_the_rewrite_named[a-key-of-two-columns-joins-on-one-the-walk-does-not-trade] 2 failed, 3964 passed, 251 skipped, 1 xfailed ``` | guard | caught by | | --- | --- | | `relations.refusal`'s shape loop | the two cases above, and nothing else | Its complement, `test_the_map_the_wider_shapes_are_rewritten_to_is_the_one_that_loads`, keeps the pair from passing by refusing everything. </details> <details><summary>PyPSA parity</summary> Every rung matches, and `references.json` and the written tables come back **byte-identical** — so no objective, dual or structural comparison moved. The rung projections changed in layout only, because the first commit hand-edited files the harness generates; they and the ladder pages that embed them are regenerated by the harness and by `tools.ladder`. ``` rung_01_transport: MATCH · 45 rows, 16 columns · duals on 45 rows · 10 equal · 0 region rung_02_storage: MATCH · 103 rows, 48 columns · duals on 103 rows, 2 negated · 27 equal · 0 region rung_03_expansion: MATCH · 2 of 59 names differ · duals on 184 rows, 4 negated · 57 equal · 3 region rung_04_ramps: MATCH · 64 rows, 20 columns · duals on 64 rows, 2 negated · 12 equal · 0 region rung_05_global_constraints: MATCH · 2 of 24 names differ · duals on 102 rows, 2 negated · 23 equal · 2 region rung_06_kvl: MATCH · 2 of 21 names differ · duals on 123 rows · 19 equal · 3 region rung_07_commitment: MATCH · 116 rows, 44 columns · no duals — mixed-integer · 20 equal · 0 region · 3 recorded rung_08_modular_big_m: MATCH · 191 rows, 80 columns · no duals — mixed-integer · 36 equal · 0 region rung_09_multilink: MATCH · 92 rows, 32 columns · duals on 92 rows · 8 equal · 0 region rung_10_quadratic_costs: MATCH · 60 rows, 24 columns · duals on 60 rows · 8 equal · 0 region rung_11_ac_dc_meshed: MATCH · 2 of 19 names differ · duals on 468 rows · 17 equal · 1 region · 1 recorded rung_12_linearized_uc: MATCH · 128 rows, 44 columns · duals on 128 rows, 1 negated, 2 names differ · 24 equal · 0 region · 3 recorded rung_13_losses: MATCH · 2 of 23 names differ · duals on 150 rows · 22 equal · 0 region · 1 recorded rung_14_stochastic: MATCH · 3 of 18 names differ · duals on 87 rows, 1 names differ · 17 equal · 0 region · 2 recorded rung_15_multi_period: MATCH · 80 rows, 31 columns · duals on 80 rows · 14 equal · 0 region rung_16_link_delay: MATCH · 52 rows, 20 columns · duals on 52 rows · 8 equal · 0 region every rung matches PyPSA as deep as the engines allow, and says how deep that is ``` Run a second time on the regenerated tree with no further change, which is what the job's `git diff --exit-code -- differential/pypsa` step asks. </details> <details><summary>What was verified, and what was not</summary> Every gate the required check runs, plus the docs build, the bench harness and the parity runner, on `14de16e`: ``` ruff check . All checks passed! ruff format --check . 321 files already formatted pyrefly check 0 errors (both configs) pytest tests -n 4 3967 passed, 251 skipped, 1 xfailed mkdocs build --strict Documentation built in 10.01 seconds pytest bench/test_harness.py 145 passed, 10 skipped differential/pypsa/parity.py <corpus> every rung matches ``` Generated output was regenerated by its own generator and the diff read: `tools.gallery_math` (47 pages), `tools.ladder` (the ladder page and 16 rungs), the parity runner (`references.json`, `rungs/`, `tables/`), `uv lock`. The YAML fences the gallery pages carry byte for byte, and the two PyPSA reference `build()` fences, were refreshed from their files. **Not run, and why.** `pixi` is not installed in this environment, so the gates ran in a `uv` venv on the pinned `ruff==0.16.1` and `pyrefly==1.2.0` rather than through `pixi run check`. On an unpinned `pyrefly 1.3.1` six errors appear, all in `api.py`, `frames.py` and `assembly.py`, none of which this diff touches. No benchmark was taken: nothing here claims a number, and the machine was not idle — CodSpeed reports the PR does not alter performance. </details> 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01RuEnfVdQZKP2fxRWrgJRH1 --------- 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.
🤖 I have created a release beep boop
0.0.1-alpha.55 (2026-07-31)
Performance
This PR was generated with Release Please. See documentation.