Repository navigation
fix(language): two files that declare their dimensions in different orders load to the same program - #911
Conversation
…rders load to the same program The dims the loader derives for a named condition, for a named expression that declares no dims:, for a piecewise curve and for a comparison of two expressions in a condition are sorted by name, rather than read in the order dimensions: declares. Printed indices of these entries follow, and the golden output and generated pages are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6
Documentation build overview
24 files changed ·
|
brynpickering
left a comment
There was a problem hiding this comment.
My general preference is to follow the order defined in dimensions as the user might have good reason to order it like that. However, this will mean that diffs become harder. If the user changes the order of dimensions in one version compared to the last then the diff will be riddled with changes that are immaterial (dims list reordering).
So, agreed that this is the safest approach. It will match the dimension order on dump anyway since those keys get ordered by name (right?).
Yes. I also think that having a custom order would be appreciated, but making this work early with composition will be quite hard... We might revisit this in the future. |
Co-authored-by: Bryn Pickering <17178478+brynpickering@users.noreply.github.com>
The order of dimensions: no longer reaches a node, which is the rule #911 set for the dims the loader derives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6
…over (#899) * fix(language)!: a named expression whose dims: names a dimension its body does not carry is refused at load Closes #896. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(changelog): link the line to its pull request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * fix(composition): a sum built only from terms takes no dimension its terms do not carry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * chore(composition): reflow the module docstring Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * feat(program): each expression node states the dimensions it is read over Closes #897. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(changelog): link the line to its pull request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * refactor(dimensions): each node is held to its operator's dim rule as it is built Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * fix(dimensions): a dim fault resolution meets is a DimensionError again, listed with every other Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(errors): say which class a load with several faults raises Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(errors): a rule on a whole entry still names the first entry that breaks it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(language): say which dimensions a named expression is indexed over, rather than its frame Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(reading): a node states its dims in the order dimensions: declares, whatever order its entry declares Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * feat(program): a node states its dims sorted by name The order of dimensions: no longer reaches a node, which is the rule #911 set for the dims the loader derives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6 --------- Co-authored-by: Claude <noreply@anthropic.com>
The big-M assumptions print their condition's indices sorted by name, as #911 prints every derived frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6
…ut is absent rather than zero, and a committable extendable unit is assumed to have its big-M (#912) * docs(pypsa): a PyPSA schedule, weight or limit that the data leaves out is absent rather than zero Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(changelog): link the line to its pull request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2crTbivTGt2WzGpTebdmf * docs(pypsa): regenerate the gallery pages on the merged base The big-M assumptions print their condition's indices sorted by name, as #911 prints every derived frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6 --------- Co-authored-by: Claude <noreply@anthropic.com>
Note
The following content was generated by AI.
What this changes
The dims that the loader derives for an entry are sorted by name. The order of
dimensions:no longer reaches any value of the program. Entries that declaredims:keep the order the file writes.The four derived orders, and what a reader sees
NamedCondition.dims)dimensions:declaresdims:dimensions:declaresPiecewise.frame), and so the dims of the variables and constraints its expansion writesdimensions:declares, in the order the links are metExpressionComparison.dims)dimensions:declaresWhat a reader sees:
cost_curve_lamover[generator, snapshot, bp]instead of[snapshot, generator, bp].dims: [snapshot, bus]prints asinjection_(t,b) = generator_injection_(b,t) + …, because its terms declare nodims:.given: conditions:restates the condition's dims) are regenerated with their tools, not edited.docs/several-files.mdshows printed output and is not generated, so it is edited by hand.Why
On
main(ed6af52), the same file loaded to a different program in 23 of the 53 examples when onlydimensions:was reversed. The canonical form sortsdimensions:, so it changed the program too. A consumer needs one fixed order, not the author's order. A sort by name is that order, with nothing to keep in step across files. This is also what letsmergestay as it is.Verification
The test.
test_the_order_of_dimensions_reaches_no_value_of_the_programreversesdimensions:in every example and asserts that the program is equal, before and afterexpand(). Oned6af52it fails for 23 of the 53 examples. It passes with this change.test_the_form_declares_the_same_specnow compares the dims of each constraint and variable in their order, not as a set. Its docstring said that sortingvariables:could reorder the dims of a constraint the expansion writes. That is no longer true.reading.mdsaid the same, and is corrected.Gates on
ae0e4ec:pixi run lintpasses.pixi run testpasses: 2976 passed, 1 skipped.pixi run docs-buildpasses.compile-texwas not run, because the container cannot download the TeX bundle. CI runs it.Mutation table. Each change was made by hand and the full suite was run. The file was restored with
git checkout --,__pycache__was dropped before and after each run, and the tree came back clean each time.test_the_fragments_are_what_the_splitter_writes,test_a_named_condition_stands_where_its_name_is_written_with_its_condition_under_itdims:in declaration ordertest_the_composed_sum_prints_its_terms_by_name,test_every_python_step_prints_what_the_page_showstest_the_form_declares_the_same_spec, the golden output,test_a_curve_prints_over_the_frame_its_expansion_builds_one_per_coordinate_ofCoverage moved.
test_the_emitted_foreach_follows_file_orderis nowtest_the_emitted_frame_is_sorted_by_name_whatever_order_the_file_declares, with the same two orders ofdimensions:and one expected frame.Not done
main. feat(program): each expression node states the dimensions it is read over #899 adds them. Once this PR merges, feat(program): each expression node states the dimensions it is read over #899 takesmainand sorts its node dims by name too. Its named-expression frame then needs no special case.ParameterDefinedand the others) keep the order of the entry they read, which is an order the file writes.scope.in_declaration_orderstays as it is until a release. It is a separate PR there.🤖 Generated with Claude Code
https://claude.ai/code/session_01D2S9sN1jLGGMCCwqwVyGD6