Repository navigation
Conversation
Documentation build overview
75 files changed ·
|
Merging this PR will regress 1 benchmark2 warnings
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
The two branches both knew which declaration owns which column and row at which coordinate. Merged, `file_names` reads `readback.declared`, the one home #1793 puts beside the handoff, and keeps its label cleaning as polars expressions over each run's coordinate frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CM4oeTkzkk5G5zE6zgikSE
…dexed by its labels Rebased onto the rebased #1795 as one commit: the branch's net diff over its old base, with the changelog and Model's methods kept from both sides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HhMcpuGcaXgttYMf9Jg2q
6c41b90 to
7b54e64
Compare
…mes and dimensions Rebased onto the rebased #1793 as one commit: the branch's net diff over its old base, without the sinks import that only the retired check(sink=) used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HhMcpuGcaXgttYMf9Jg2q
# Conflicts: # docs/howto/solvers.md
…and pyomo is named among the sinks that take a model to_pyomo asks the check first, so the clash refusal and its suggested rename have one path. The pyomo capability table sits in EXPORTS beside SOLVERS and WRITERS, so another sink's refusal names pyomo as a taker. check refuses rename= for any sink but pyomo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HhMcpuGcaXgttYMf9Jg2q
# Conflicts: # src/specsolve/api.py # src/specsolve/relational/engines/polars/engine.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HhMcpuGcaXgttYMf9Jg2q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011T4ckkidC1vKWRnqZKnfVn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011T4ckkidC1vKWRnqZKnfVn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DSYMFAGbSZpZ4ECVdXGMxc
Note
The following content was generated by AI.
Model.to_pyomo(rename=None)returns apyomo.environ.ConcreteModel. Each variable becomes aVar, each constraint aConstraintand eachsos:set anSOSConstraint. Each keeps its declared name and is indexed by the labels the build produced (m.p[0, 'wind']).Model.check('pyomo', rename=...)refuses what the export refuses, without building it. It needs the new[pyomo]extra, which requires pyomo 6.8 or later.Naming was set by a second prompt: "Maybe we should expose a rename dict and raise otherwise? It should be predictable and deterministic!" The export renames nothing by itself. A clash is refused, and the error suggests a
rename. The check was set by a third: "Maybe rename= should be added to check() instead??? We dont want to change specs for pyomo i think. But we also dont want much complexity...?"Stacked on #1795
The base is
claude/festive-galileo-9481hq, the named LP/MPS files in #1795, which lands first. This PR addsDeclaredbesideHandoff.Declaredrecords which declaration owns each column, row and set, and at which coordinate. A sink cannot read the engine'sBuiltModel, so the export readsDeclaredinstead. The branch takes #1795 by merge commits, with no rebase.Names: exact, or renamed by the caller
A pyomo model has one namespace. Before it adds any component, the export decides every name: the declared name, or the name
renamegives. It refuses the export if a name:start_upandshut_downinpypsa_min_up_down,pypsa_unit_commitmentandpypsa_linearized_uc. The later declaration, in the order variables → constraints → sos, is the one to rename.rcorslack. pyomo's solver interfaces load results into components with these names. mathspec already reservesdual.ConcreteModelhas, such aswrite,nameorcomponent.objective, when the model has an objective.One
SpecsolveErrorlists every clash. It also suggests arename: the caller's own rename, plus<name>_<kind>for each clash, or<name>_<kind>_2and up when that name is in use too. Paste it back to export:The export also validates
rename:variables,constraintsorsosis refused with a "did you mean".The check
pyomo.component_names(declared, rename, objective=...). The engine'scheck('pyomo', rename=...)andto_pyomoboth call it, so the messages are the same; a test asserts they are equal.EXPORTS = {'pyomo': PYOMO_CAPABILITIES}besideSOLVERSandWRITERS, every capability native. Another sink's refusal now lists pyomo among the sinks that take the model, and an unknown sink name listspyomoamong the names there are.renamefor any other sink is refused:rename= is read by pyomo, not by '.lp'.ConcreteModel, socheck('pyomo')without the extra refuses with the extra's message, asto_pyomodoes. A solver's check needs no package.to_pyomodoes not callcheckitself: pyomo's table refuses no construct, so the only refusal iscomponent_names, which the export calls anyway. A call tocheckthere would be a guard the suite cannot reach.What the model holds
whereremoved has no entry, and a row the build dropped is not in the component. One dim indexes by the bare label, more dims by a tuple, and a dimensionless declaration is a scalar component. A label keeps its type:int,stranddatetimestay as they are.LinearExpression, plus quadratic terms. This is the same structure that alinopy.Modelholds.LinearExpressionkeeps a row whose coefficients are all zero as a relation. A plain sum would let pyomo reduce0 >= 10to a Python bool.SOSConstraintper declaration, indexed by the members' coordinate without the ordering dim. If the ordering dim is the variable's only dim, the declaration is one scalar set.m.objective. A spec without an objective gets none.sinks/pyomo.pyreads the handoff andDeclared. pyomo is imported only whento_pyomo()orcheck('pyomo')is called, so a bare install stays pyomo-free.pyomo>=6.8, in the extra and in the dev group. Pyomo 6.7 readsnp.float_, which NumPy 2 removed: 6.7.0, 6.7.2 and 6.7.3 fail at import, and 6.7.1 fails 54 of the new tests.Verification
94a6179:pixi run check(4756 passed, 522 skipped, 1 xfailed).pixi run docs-buildran onf50d74c, before the rebase ontomainand the check, and was not run again.tests/test_pyomo_model.py, all passing with Gurobi present:appsi_highs.gurobi_direct.rename.Model.rowreads at that coordinate, and the component has no extra rows.x_constraint→x_constraint_2); each reserved kind of name is refused;objectiveis free when the model has no objective; an invalidrenameis refused.check('pyomo')refuses a clash in the export's words; it takes the suggestedrename; a model with SOS checks clean for pyomo whilecheck('highs')names pyomo as a taker;renamefor.lpis refused; without pyomo, both the export and its check name the extra.ConcreteModelattribute nameobjectivealways reserved (by hand)objectivenever reserved (by hand)LinearExpression(by hand)None, notSkipNone, notSkip(), notNonerenamerefusal for a sink other than pyomo (tools.mutate,engine.py:150-151)check(tools.mutate,engine.py:154-155)Not done
Params: new data means a new export.Model.updaterebuilds specsolve's side, and nothing updates an exported pyomo model in place.Expressioncomponents:expressions:entries do not become pyomoExpressions, and the export adds no dimensionSets. Rows are flat, as in linopy.🤖 Generated with Claude Code
https://claude.ai/code/session_01Rf94H9iybapukHJU5KaB7r
https://claude.ai/code/session_01CM4oeTkzkk5G5zE6zgikSE
https://claude.ai/code/session_01V3XyQpbHm6dhHbSkGcvxTb
https://claude.ai/code/session_017HhMcpuGcaXgttYMf9Jg2q