Widen the CSRConstraint fast path in Model.add_constraints
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- python
- Domain
- performance
Research direction
Start in linopy/model.py around lines 1313-1345 and inspect the CSRConstraint handling in linopy/constraints.py:1427-1441. Trace how mask, penalty, freeze, chunking, and expression right-hand sides affect the sparse path, then define tests showing which cases retain CSR storage without changing existing soft-constraint rules. Done means the agreed cases no longer densify and the current sparse opt-ins remain compatible.
Written by the indexing model from the issue text.
Description
[!NOTE]
The following content was generated by AI.
Describe the feature you'd like to see
Widen the conditions under which Model.add_constraints keeps a CSRConstraint. Child of #756.
The sparse constraint path is narrow. add_constraints keeps the sparse object only when isinstance(con, CSRConstraint) and freeze and mask is None (linopy/model.py:1333). Any mask=, any penalty=, freeze=False (the default), or a set self.chunk reconstructs the full dense rectangle at model.py:1345.
Upstream of that, csr_rhs (linopy/constraints.py:1427-1441) returns None for a non-constant right-hand side, or one carrying helper dims or dims outside the grid, so to_constraint falls back to dense. An rhs that is itself an expression is a common case and always densifies.
The result is that a build which stayed sparse through every expression operation can still densify at the last step, silently.
Implementation ideas
mask=: a mask is a row selection on the CSR store, the same primitive the sparsewhereneeds. These two should probably be implemented together.- Expression rhs: move the rhs to the left-hand side before building the constraint, which is what the dense path effectively does, then the existing constant-rhs path applies.
penalty/soft constraints are deliberately incompatible with freezing today (model.py:1313); worth confirming that is a permanent rule rather than a gap.
Separately, note that the sparse route currently needs three independent opt-ins to work end to end: semantics="v1", then sparse_groupby=True or a per-call sparse=True, then freeze_constraints=True. Reducing that to one decision would be worth discussing under #756.
- Dominant language
- Python
- Stars
- 257
- Forks
- 87
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 32
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from PyPSA/linopy
-
bug solver interface
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
documentation sparse
Difficulty 3/5 1-2 days Newbie friendliness 68/100
-
Make the sparse path observable and controllable (.is_sparse, densify warning, per-call sparse=) Openenhancement sparse
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
enhancement performance sparse
Difficulty 4/5 3-5 days Newbie friendliness 68/100
-
enhancement performance sparse
Difficulty 4/5 3-5 days Newbie friendliness 52/100
Similar issues
-
essnmx good first issue
Difficulty 1/5 Under an hour Newbie friendliness 95/100
-
[Feature] 奇物选择添加优先级 Open
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
syfoud/Simulated_Scepter#174 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Giskard-AI/giskard-oss#2840 · 1 comment ·
-
A claim comment carrying the issue number is silently declined while the workflow reports success Openarea: repo bug perceived difficulty: 2
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
yeti-platform/yeti#1380 ·