Skip to content

Pin math-spec alpha.76 and drop the Power walk workaround - #946

Open
FBumann wants to merge 1 commit into
spec-builderfrom
spec/power-children
Open

Pin math-spec alpha.76 and drop the Power walk workaround#946
FBumann wants to merge 1 commit into
spec-builderfrom
spec/power-children

Conversation

@FBumann

@FBumann FBumann commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #922 — merge that one first.

Note

The following content was generated by AI.

Changes proposed in this Pull Request

#922 carries a workaround in linopy/spec/nodes.py: math-spec's
program.children() had no branch for Power, so every walk stopped there and
a parameter written d ** 2 was invisible to it — linopy shipped its own
children() that descended into a power's base and exponent.

energy-models/math-spec#404 fixed that upstream (a Power branch plus an
assert_never so a new node type can't be forgotten again), released as
alpha.76. So:

  • The spec dependency group pins the math-spec tag v0.0.0-alpha.76
    instead of the alpha.75 commit hash 67aeedb.
  • linopy/spec/nodes.py drops its children() wrapper; walk and _dims
    call math_spec.program.children directly, and coverage.py imports it from
    math-spec too.
  • The notebook's "upstream note" section is now just "Where the code lives".

The two coverage tests for a parameter hidden under a power
(test_a_parameter_under_a_power_is_still_checked_for_coverage, constant side
and divisor) are unchanged and now exercise the upstream walk.

Verification (608e141)
uv run --group spec --extra dev pytest test/test_spec_*.py test/test_io.py -q
520 passed, 190 skipped

uv run --group spec --extra dev mypy linopy benchmarks
Success: no issues found in 82 source files

Checklist

  • AI-generated content is marked (see AGENTS.md).
  • Code changes are sufficiently documented; i.e. new functions contain docstrings and further explanations may be given in doc.
  • Unit tests for new features were added (if applicable).
  • A note for the release notes doc/release_notes.rst of the upcoming release is included. — no user-visible change; Build and change models via math-spec #922 is unreleased.

🤖 Generated with Claude Code

https://claude.ai/code/session_017AvhrToZD5bch9Zcdtiduo

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

Build cost — v1 vs legacy

v1 build peak & time relative to legacy, on this commit — not a comparison against master (that is CodSpeed).

peak — v1 / legacy time — v1 / legacy
peak v1/legacy time v1/legacy
Full table (time + peak, mean)
benchmarks/drivers/test_build.py::test_build[basic-n=10]
                 time (s)         peak (KiB) 
 name                mean   │           mean 
─────────────────────────────────────────────
 (legacy)   0.0765 (1.10)   │   15.03 (1.00) 
 (v1)        0.0697 (1.0)   │    15.00 (1.0) 

benchmarks/drivers/test_build.py::test_build[basic-n=250]
                  time (s)         peak (MiB) 
 name                 mean   │           mean 
──────────────────────────────────────────────
 (legacy)   0.08716 (1.11)   │   12.04 (1.00) 
 (v1)        0.07853 (1.0)   │    12.04 (1.0) 

benchmarks/drivers/test_build.py::test_build[cumsum-severity=0]
                  time (s)        peak (KiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.03314 (1.09)   │   15.20 (1.0) 
 (v1)        0.03039 (1.0)   │   15.20 (1.0) 

benchmarks/drivers/test_build.py::test_build[cumsum-severity=100]
                  time (s)        peak (MiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.05461 (1.06)   │   44.93 (1.0) 
 (v1)        0.05139 (1.0)   │   44.93 (1.0) 

benchmarks/drivers/test_build.py::test_build[cumsum-severity=50]
                  time (s)        peak (MiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.03758 (1.07)   │   11.51 (1.0) 
 (v1)        0.03498 (1.0)   │   11.51 (1.0) 

benchmarks/drivers/test_build.py::test_build[expression_arithmetic-n=10]
                  time (s)         peak (KiB) 
 name                 mean   │           mean 
──────────────────────────────────────────────
 (legacy)   0.08537 (1.06)   │   24.34 (1.06) 
 (v1)        0.08067 (1.0)   │    23.04 (1.0) 

benchmarks/drivers/test_build.py::test_build[expression_arithmetic-n=250]
                  time (s)         peak (MiB) 
 name                 mean   │           mean 
──────────────────────────────────────────────
 (legacy)   0.09747 (1.06)   │   16.12 (1.00) 
 (v1)        0.09188 (1.0)   │    16.12 (1.0) 

benchmarks/drivers/test_build.py::test_build[knapsack-n=10000]
                  time (s)          peak (KiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)   0.02044 (1.07)   │   752.18 (1.10) 
 (v1)        0.01913 (1.0)   │    685.15 (1.0) 

benchmarks/drivers/test_build.py::test_build[knapsack-n=100]
                  time (s)        peak (KiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.02006 (1.08)   │   3.12 (1.33) 
 (v1)         0.0186 (1.0)   │    2.34 (1.0) 

benchmarks/drivers/test_build.py::test_build[kvl_cycles-severity=0]
                  time (s)          peak (MiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)   0.07042 (1.27)   │   126.16 (1.44) 
 (v1)        0.05561 (1.0)   │     87.71 (1.0) 

benchmarks/drivers/test_build.py::test_build[kvl_cycles-severity=100]
                 time (s)          peak (MiB) 
 name                mean   │            mean 
──────────────────────────────────────────────
 (legacy)   0.0694 (1.26)   │   126.16 (1.44) 
 (v1)       0.05491 (1.0)   │     87.71 (1.0) 

benchmarks/drivers/test_build.py::test_build[kvl_cycles-severity=50]
                 time (s)          peak (MiB) 
 name                mean   │            mean 
──────────────────────────────────────────────
 (legacy)   0.0703 (1.23)   │   126.16 (1.44) 
 (v1)       0.05734 (1.0)   │     87.71 (1.0) 

benchmarks/drivers/test_build.py::test_build[masked-n=100]
                  time (s)          peak (KiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)   0.04669 (1.01)   │    715.12 (1.0) 
 (v1)        0.04604 (1.0)   │   787.73 (1.10) 

benchmarks/drivers/test_build.py::test_build[masked-n=10]
                  time (s)        peak (KiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.04579 (1.11)   │   4.54 (1.27) 
 (v1)        0.04128 (1.0)   │    3.57 (1.0) 

benchmarks/drivers/test_build.py::test_build[merge_balance-severity=0]
                 time (s)          peak (KiB) 
 name                mean   │            mean 
──────────────────────────────────────────────
 (legacy)   0.3225 (1.05)   │   704.12 (1.09) 
 (v1)        0.3086 (1.0)   │    643.85 (1.0) 

benchmarks/drivers/test_build.py::test_build[merge_balance-severity=100]
                time (s)        peak (MiB) 
 name               mean   │          mean 
───────────────────────────────────────────
 (legacy)   0.342 (1.06)   │   18.34 (1.0) 
 (v1)       0.3236 (1.0)   │   18.34 (1.0) 

benchmarks/drivers/test_build.py::test_build[merge_balance-severity=50]
                 time (s)       peak (MiB) 
 name                mean   │         mean 
───────────────────────────────────────────
 (legacy)   0.3333 (1.05)   │   9.54 (1.0) 
 (v1)        0.3179 (1.0)   │   9.54 (1.0) 

benchmarks/drivers/test_build.py::test_build[milp-n=10]
                  time (s)        peak (KiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.06412 (1.08)   │   3.77 (1.12) 
 (v1)        0.05936 (1.0)   │    3.37 (1.0) 

benchmarks/drivers/test_build.py::test_build[milp-n=50]
                  time (s)          peak (KiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)   0.06455 (1.09)   │   216.59 (1.10) 
 (v1)        0.05927 (1.0)   │    196.23 (1.0) 

benchmarks/drivers/test_build.py::test_build[nodal_balance-severity=0]
                  time (s)         peak (KiB) 
 name                 mean   │           mean 
──────────────────────────────────────────────
 (legacy)   0.03297 (1.08)   │   938.49 (1.0) 
 (v1)        0.03043 (1.0)   │   938.49 (1.0) 

benchmarks/drivers/test_build.py::test_build[nodal_balance-severity=100]
                  time (s)       peak (MiB) 
 name                 mean   │         mean 
────────────────────────────────────────────
 (legacy)   0.03529 (1.09)   │   9.66 (1.0) 
 (v1)        0.03248 (1.0)   │   9.66 (1.0) 

benchmarks/drivers/test_build.py::test_build[nodal_balance-severity=50]
                  time (s)       peak (MiB) 
 name                 mean   │         mean 
────────────────────────────────────────────
 (legacy)   0.03411 (1.08)   │   5.32 (1.0) 
 (v1)        0.03155 (1.0)   │   5.32 (1.0) 

benchmarks/drivers/test_build.py::test_build[nodal_balance_sparse-severity=0]
                  time (s)       peak (MiB) 
 name                 mean   │         mean 
────────────────────────────────────────────
 (legacy)   0.01908 (1.01)   │   1.47 (1.0) 
 (v1)        0.01895 (1.0)   │   1.47 (1.0) 

benchmarks/drivers/test_build.py::test_build[nodal_balance_sparse-severity=100]
                  time (s)       peak (MiB) 
 name                 mean   │         mean 
────────────────────────────────────────────
 (legacy)   0.01907 (1.02)   │   1.47 (1.0) 
 (v1)        0.01878 (1.0)   │   1.47 (1.0) 

benchmarks/drivers/test_build.py::test_build[nodal_balance_sparse-severity=50]
                  time (s)       peak (MiB) 
 name                 mean   │         mean 
────────────────────────────────────────────
 (legacy)   0.01903 (1.02)   │   1.47 (1.0) 
 (v1)        0.01873 (1.0)   │   1.47 (1.0) 

benchmarks/drivers/test_build.py::test_build[piecewise-n=1000]
                 time (s)          peak (KiB) 
 name                mean   │            mean 
──────────────────────────────────────────────
 (legacy)   0.1614 (1.05)   │   946.85 (1.06) 
 (v1)        0.1532 (1.0)   │    891.54 (1.0) 

benchmarks/drivers/test_build.py::test_build[piecewise-n=10]
                 time (s)         peak (KiB) 
 name                mean   │           mean 
─────────────────────────────────────────────
 (legacy)   0.1585 (1.06)   │   12.01 (1.00) 
 (v1)        0.1502 (1.0)   │    11.99 (1.0) 

benchmarks/drivers/test_build.py::test_build[qp-n=1000]
                  time (s)          peak (KiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)   0.04109 (1.07)   │   147.70 (1.06) 
 (v1)        0.03841 (1.0)   │    139.87 (1.0) 

benchmarks/drivers/test_build.py::test_build[qp-n=10]
                  time (s)        peak (KiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.04084 (1.08)   │   2.60 (1.09) 
 (v1)        0.03792 (1.0)   │    2.38 (1.0) 

benchmarks/drivers/test_build.py::test_build[rolling-severity=0]
                  time (s)          peak (KiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)   0.03414 (1.08)   │   696.75 (1.03) 
 (v1)        0.03166 (1.0)   │    673.70 (1.0) 

benchmarks/drivers/test_build.py::test_build[rolling-severity=100]
                 time (s)         peak (MiB) 
 name                mean   │           mean 
─────────────────────────────────────────────
 (legacy)   0.1003 (1.07)   │   137.97 (1.0) 
 (v1)       0.09335 (1.0)   │   137.97 (1.0) 

benchmarks/drivers/test_build.py::test_build[rolling-severity=50]
                  time (s)        peak (MiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.06284 (1.05)   │   69.22 (1.0) 
 (v1)        0.05984 (1.0)   │   69.22 (1.0) 

benchmarks/drivers/test_build.py::test_build[sos-n=1000]
                  time (s)          peak (KiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)   0.03893 (1.11)   │   402.33 (1.00) 
 (v1)        0.03522 (1.0)   │    402.30 (1.0) 

benchmarks/drivers/test_build.py::test_build[sos-n=10]
                  time (s)        peak (KiB) 
 name                 mean   │          mean 
─────────────────────────────────────────────
 (legacy)   0.03856 (1.09)   │   3.19 (1.19) 
 (v1)        0.03528 (1.0)   │    2.69 (1.0) 

benchmarks/drivers/test_build.py::test_build[sparse_network-n=10]
                  time (s)         peak (KiB) 
 name                 mean   │           mean 
──────────────────────────────────────────────
 (legacy)   0.04284 (1.09)   │   29.00 (1.54) 
 (v1)        0.03915 (1.0)   │    18.84 (1.0) 

benchmarks/drivers/test_build.py::test_build[sparse_network-n=250]
                  time (s)         peak (MiB) 
 name                 mean   │           mean 
──────────────────────────────────────────────
 (legacy)   0.05651 (1.13)   │   37.95 (1.43) 
 (v1)        0.05009 (1.0)   │    26.51 (1.0) 

benchmarks/drivers/test_build.py::test_build[storage-n=10]
                  time (s)          peak (KiB) 
 name                 mean   │            mean 
───────────────────────────────────────────────
 (legacy)    0.08126 (1.0)   │    410.93 (1.0) 
 (v1)       0.08192 (1.01)   │   427.84 (1.04) 

benchmarks/drivers/test_build.py::test_build[storage-n=250]
                  time (s)         peak (MiB) 
 name                 mean   │           mean 
──────────────────────────────────────────────
 (legacy)    0.08954 (1.0)   │     9.94 (1.0) 
 (v1)       0.09229 (1.03)   │   10.22 (1.03) 

📊 Interactive plots + CSV: download the semantics-report-v1-vs-legacy artifact from this run.

Report-only · not a gate · refreshed on every push · obsolete once legacy is dropped.

@FBumann

FBumann commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author

@FabianHofmann Im going to merge this.
I fixed the bug in mathspec.

And i pinned a proper tag of mathspec instead of a hash. Revert if you disagree

math-spec's `program.children()` had no branch for `Power`, so every walk
stopped there and a parameter written `d ** 2` was invisible to it. linopy
worked around it with its own `children()` in `linopy/spec/nodes.py`.

energy-models/math-spec#404 fixed it upstream, so the `spec` group pins the
release that carries it, `v0.0.0-alpha.76`, and the walks call
`math_spec.program.children` directly. The coverage tests for a constant side
and a divisor hidden under a power stay as they are and now exercise the
upstream walk.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017AvhrToZD5bch9Zcdtiduo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant