Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CM4oeTkzkk5G5zE6zgikSE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CM4oeTkzkk5G5zE6zgikSE # Conflicts: # CHANGELOG.md
Merging this PR will degrade performance by 14.76%
|
Documentation build overview
120 files changed ·
|
…aint by its declaration and coordinate Rebased onto main after #1806 as one commit: the branch's net diff, with the changelog, the two write docstrings and the engine's write resolved against Model.check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HhMcpuGcaXgttYMf9Jg2q
9ad14fa to
3f473c5
Compare
…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
Model.check(sink, names=True) refuses what write(names=True) refuses, so the check answers for a named file too. 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_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
# Conflicts: # CHANGELOG.md
Scope added later: "Move the name clash checks into Model.check!"
Note
The following content was generated by AI.
sps.write(..., names=True)andModel.write(path, names=True)writep(0,wind)andbalance(0)in place ofx0andc0, in both LP and MPS files.Model.check('.lp', names=True)refuses what the named write refuses, without writing. The default is unchanged, byte for byte. This PR replaces #1792.Why this replaces #1792
#1792 was the same branch. While the stack was inverted so that this PR lands before the pyomo export (#1793), this branch's head was merged into
feat/pyomo-modelwhile that was still #1792's base. GitHub then marked #1792 as merged intofeat/pyomo-modeland deleted the branch. Nothing reachedmain. The branch is restored and opened again here againstmain.What a name is, and why
declaration(label,label). A declaration with no dims istotal(). A bare name can be an LP keyword: HiGHS and Gurobi both fail on a scalar namedend,storbounds. HiGHS also misreadsfreeandinf.\w(Unicode letters, digits,_) and!"#$%&'.;?@`{|}~. Every other character becomes_. The set is what HiGHS's LP reader takes back, probed character by character. Gurobi reads the same set, and non-ASCII letters, back. MPS takes everything except a space, but one rule keeps the two files naming a model the same way.(,)and,belong to the name, so a label cannot contain them.a banda_bboth clean toa_b. A reader would merge the two columns into one, or refuse the duplicate row, so the write raisesSpecsolveErrorand names both coordinates.explicit_coordinate_nameswritesp[0,wind]with brackets changed to parentheses. It appends#labelfor uniqueness and cleans only spaces in a label. This PR drops the#label, so JuMP'svariable_by_namefinds a name without knowing the solver index. The refusal replaces it as the uniqueness guarantee.readback.file_namesspells each declaration's label frame from the build with polars expressions into aNamesvalue (inwriters/base.py, numbered by default). Both writers look names up in it by solver index.The check
Model.check(sink, *, names=False). Withnames=True, the engine'scheckcalls the samereadback.file_namesthatwritecalls, so the collision is refused in the same words. A test asserts the two messages are equal, for.lpand.mps.names=Truewith a sink that writes no file is refused:names= is read by a written file (.lp, .mps), not by 'highs'.A caller who passes it to a solver asked a question that sink cannot answer.writestill checks the suffix's capabilities first, then spells the names once.Base of a stack
#1793 (the pyomo export) stacks on this PR, and #1797 (the linopy export) on that. Merge this PR first.
Verification
cfe9f24, rebased ontomainafter feat(sinks): a built model checks whether a sink takes it without a solve, and check no longer takes a sink #1806:pixi run check(lint, format, pyrefly, and the suite: 4666 passed, 522 skipped, 1 xfailed), clean.pixi run docs-build,test-floors(polars 1.30) anddocs-testran on commits before the rebase and were not run again.cmpon the LP and MPS files of the dispatch and MILP fixtures: identical.tests/test_named_files.py:examples/ports/) reaches the same optimum through a named LP and MPS file.Model.rowreads at that coordinate. That includes a masked variable and a constraint whose middle row is dropped, so later rows renumber.checkwithnamesrefuses the collision in the write's words; withoutnamesthe same model checks clean;namesfor a solver is refused.Mutation table (full suite each time; the tree came back clean after every row). The first four rows were taken before the rebase, on code the rebase did not change:
tools.mutate, in_refuse_a_shared_name)replace_all(by hand)test_a_quadratic_constraint_declared_first_keeps_its_namescheck(tools.mutate,engine.py:143-144)namesfor a sink that writes no file (tools.mutate,engine.py:144-145)Sorting each label frame and sorting the declarations by
startboth survived the suite, so both sorts were removed. The names rely on the build's order, which the probe above holds.Not done or not checked
p(2030_01_01_06_00_00.000000). It is faithful and unique, but long.s0,s1.mainplus the check: the old branch merged into the pyomo branch and back, so the rebase took the net diff rather than replaying each commit.🤖 Generated with Claude Code
https://claude.ai/code/session_01CM4oeTkzkk5G5zE6zgikSE
https://claude.ai/code/session_01V3XyQpbHm6dhHbSkGcvxTb
https://claude.ai/code/session_017HhMcpuGcaXgttYMf9Jg2q