feat(model): Model.assign_coords — reassign coordinates on an existing model - #955
feat(model): Model.assign_coords — reassign coordinates on an existing model#955olivier-lacroix wants to merge 1 commit into
Conversation
Merging this PR will degrade performance by 2.89%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | test_to_lp[qp-n=1000] |
1.9 MB | 2.6 MB | -24.93% |
| ❌ | test_to_lp[nodal_balance_sparse-severity=50] |
2.8 MB | 3.7 MB | -24.16% |
| ❌ | test_to_lp[merge_balance-severity=0] |
2.7 MB | 3.3 MB | -18.23% |
| ❌ | test_to_lp[nodal_balance-severity=50] |
3.3 MB | 3.8 MB | -14.18% |
| ⚡ | test_to_lp[sparse_network-n=10] |
1,338.9 KB | 722.4 KB | +85.34% |
| ⚡ | test_to_lp[expression_arithmetic-n=250] |
46.7 MB | 41.2 MB | +13.29% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing olivier-lacroix:feat/model-assign-coords (3c7c47e) with master (718c0c1)
Footnotes
-
181 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
|
The performance changes look spurious, but let me know if I missed anything |
…ment Add a public API to reassign coordinate values on an existing model, e.g. m.assign_coords(snapshot=new_snapshots), mirroring xarray.Dataset.assign_coords semantics for an existing model: values-only replacement (no relabeling, no reindexing, no shape change) across all variables, constraints (dense and CSR-backed), expressions and parameters carrying the dimension. Containers may hold subsets of a dimension (e.g. a piecewise commitment gate on a subset of generators): the new values must match the length of the full-index carrier, and every container is mapped through the master's old -> new correspondence, preserving subset relations. The per-container mutation goes through a new order-safe helper (assign_coords_multiindex_safe) and a shared validator (validate_coords_reassignment), single-sourcing the per-item invariants (existing coordinate, index-like values, matching length). Unlike plain Dataset.assign_coords, the helper preserves the dataset's variable and coordinate order, which would otherwise break downstream dimension inference. Under v1 semantics, Model.solve() raises when containers carry labels on a shared dimension that are neither equal nor subsets of one another - the mislabeling trap no construction-time check catches; under legacy, non-aligned containers remain documented positional behavior (convention §8) and the guard is a no-op. Internal dims (underscore-prefixed) are exempt, as the piecewise machinery labels them per-container on purpose. Typical use is advancing the window in rolling-horizon optimization with the persistent solver interface. Closes PyPSA#767
3317861 to
3c7c47e
Compare
Intent
Closes #767.
Note
The following content was generated by AI (opencode).
Changes proposed in this Pull Request
New public API
Model.assign_coords(**coords_kwargs): reassign coordinatevalues across an existing model — variables, constraints (dense and
CSR-backed), expressions, and
parameters— without changing its shape:m.assign_coords(snapshot=new_snapshots). No relabeling, no reindexing;the order of each dataset's variables and coordinates is preserved (plain
Dataset.assign_coordsmoves updated coords to the end, which breaksdownstream dim inference — the pitfall flagged in the issue).
piecewise commitment gate on a subset of generators). New values must
match the full-index carrier's length; every container is then mapped
through the master's
old → newcorrespondence, preserving subsetrelations.
_assign_coordsmethods backed by two new helpers inlinopy/common.py(
assign_coords_multiindex_safe,validate_coords_reassignment) thatsingle-source the per-item invariants. Container-level
assign_coordspassthroughs are unchanged, so internal coordinate relabels — e.g. the
piecewise formulation's adjacent-piece pairing (§10) — keep working as
before.
Model.solve()raises when containers carry labelson a shared user dimension that are neither equal nor subsets of one
another (the mislabeling trap nothing else catches). No-op under legacy
semantics, where non-aligned containers are documented positional
behavior (§8). Internal dims (underscore-prefixed, e.g.
_breakpoint_piece) are exempt — the piecewise machinery labels themper-container on purpose; the invariant is now documented in
linopy/constants.py.test/test_assign_coords.py— propagation across allcontainer types, order preservation, values-only invariants, validation
errors, subset mapping, guard behavior; 100% branch coverage of the
added code, suite green under both legacy and v1 semantics.
Model.assign_coordsentry indoc/api.rst(Modifying amodel), release-notes entry, and a "Reassigning coordinates" section in
examples/manipulating-models.ipynb(incl. the detached-passthroughcaveat).
Checklist
AGENTS.md).doc.doc/release_notes.rstof the upcoming release is included.