Skip to content

Models

Every model in the repo, what it says, and what it exercises. Three questions, in the order you probably have them: can it say my model? · is it readable? · does it get the right answer?

dispatch least-cost generation against a load profile
storage dispatch plus a cyclic battery
transport a network — generators on buses, lines between them
piecewise per-generator convex cost curves
walkthrough the model behind every pipeline stage, printed
Dantzig transport GAMS model library #1
PyPSA LOPF rung 1 PyPSA's own transport model
PyPSA LOPF rung 2 rung 1 plus generator ramp limits
PyPSA LOPF rung 3 rung 2 plus storage carrying energy in time
PyPSA LOPF rung 4 rung 3 with the horizon closed on itself
PyPSA LOPF rung 5 passive AC lines under Kirchhoff's voltage law
PyPSA unit commitment which units are on — the corpus's MILP
Dantzig, economies of scale GAMS trnspwl — piecewise sqrt shipping cost
Stigler's diet the cheapest year of food — where LP started
Facility location OR-Library cap71 — which warehouses to open
Travelling salesman TSPLIB gr17, MTZ — yes, it fits

Does it get the right answer?

✔ means the optimum did not come from us. Every model on this page is run by the test suite, so "there is a test" distinguishes nothing. What the badge marks is narrower, and it is the only check that can catch a shared misreading — both lanes of the implementation agreeing on a meaning the modeller did not intend, which passes every farkas-against-farkas test green.

model reference optimum
Dantzig transport published with GAMS model library #1 153.675
PyPSA LOPF rung 1 PyPSA 1.2.4, running its own linopy 22000.0
PyPSA LOPF rung 2 PyPSA 1.2.4, running its own linopy 18200.0
PyPSA LOPF rung 3 PyPSA 1.2.4, running its own linopy 15253.178322993519
PyPSA LOPF rung 4 PyPSA 1.2.4, running its own linopy 17228.77962151063
PyPSA LOPF rung 5 PyPSA 1.2.4, running its own linopy 17000.0
PyPSA unit commitment PyPSA 1.2.4, running its own linopy 24900.0
Dantzig, economies of scale linopy 0.9.0's own piecewise formulation 8.786852757777865
Stigler's diet linopy 0.9.0; corroborated by Laderman (1947), $39.69/yr 0.10866227820675685
Facility location published by OR-Library (cap71) 932615.750
Travelling salesman published by TSPLIB (gr17) 2085

The objective is not the only thing checked. Every port that has a dual solution also records the reference's shadow prices and is asserted against them — for the PyPSA models that is buses_t.marginal_price, the nodal price, which is the output this audience reads most often after the cost.

That matters because an objective is one number and hides a great deal. A dual vector is where two implementations most reliably disagree quietly: which side of a constraint the price belongs to, and what sign an inequality's carries. Dantzig transport is in that set specifically because both of its constraints are inequalities pointing opposite ways. Unit commitment is not: a MILP has no dual solution, and farkas refuses to invent one.

How a port is put together, the ladder it climbs, and the ledger of what a port could not say: ports.md.

Can it say my model?

Read off the resolved plan of each model rather than its text, so it cannot drift from what the engine builds. Regenerate with uv run python -m tools.constructs; a test fails if it is stale.

model verified sum group_sum roll / shift where bounds piecewise MILP
dispatch · · · · ·
piecewise · · · · ·
storage · · · · ·
transport · · · · · ·
walkthrough · · · · ·
facility_location 932616 · · · ·
pypsa_cyclic_storage 17228.8 · · ·
pypsa_kvl 17000 · · · ·
pypsa_ramp 18200 · · ·
pypsa_storage 15253.2 · · ·
pypsa_transport 22000 · · · · ·
pypsa_unit_commitment 24900 · ·
stigler_diet 0.108662 · · · · ·
transport_dantzig 153.675 · · · · ·
transport_pwl 8.78685 · ·
tsp_mtz 2085 · ·

No holes left. Every construct in the table now has at least one model behind it whose optimum came from somebody else. The column was worth keeping precisely because it named each gap out loud before it was filled: roll / shift went first (ramp limits), then integrality (unit commitment), and piecewise last (economies of scale).

That is a floor, not a ceiling. A tick means one verified model exercises the construct — not that every shape of it is covered, and not that the constructs are exercised in combination. The table's job from here is to stay honest as the language grows, which is why it is generated from the resolved plan rather than maintained by hand.