Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

One named densification chokepoint and a dispatch table for CSR-backed expressions

Aperta
#1,020 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
35/100
Tipo di issue
Refactoring
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
numpy, pandas, python
Ambito
backend

Direzione di ricerca

Start with linopy/expressions.py, especially _densify, the .data property, and the listed CSR branches; read the dispatch-table notes in issues #971 and #1011 for context. Review the partial fallbacks in linopy/constraints.py as well, then run the proposed parametrized tests in test/test_csr.py. Done means dispatch entries preserve CSR backing under no_densify(), fallbacks warn with the operation name without densifying the receiver, and the existing twin-build tests pass.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

refactor sparse

[!NOTE]
The following content was generated by AI.

Describe the feature you'd like to see

Child of #1019 (step 1). Blocked on legacy semantics removal (#845, #846): the methods this touches carry the is_v1() gates, and the dispatch table should be built once, against the v1-only code. Internal refactor of linopy/expressions.py; no change to results or to the public API. Code links point to master at 69dd5c97.

Problem

A CSR-backed LinearExpression falls back to dense in two ways. Explicit overrides call self._densify(reason) with a hand-written string. Every method without an override reads self.data (linopy/expressions.py:2443), which converts the receiver in place and for good through _densify_all (:3698) with the generic reason ".data read". There are 34 explicit branch points on _csr / is_sparse / _try_csr_* / _sparse_* (:2443-3100, groupby :485-669, _try_csr_merge :3740), and the implicit set (shift, diff, coeffs, vars, to_quadexpr, simplify, loc, densify_terms, the const setter, ...) is nowhere listed.

import warnings
import numpy as np, pandas as pd, linopy

linopy.options["semantics"] = "v1"
linopy.options["warn_on_densify"] = True
i, t = pd.RangeIndex(20, name="i"), pd.RangeIndex(5, name="t")
m = linopy.Model(sparse=True)
x = m.add_variables(0, 1, coords=[i, t], name="x")
g = pd.Series(np.arange(20) % 3, index=i, name="g")

for op in ["shift(t=1)", "diff('t')", "coeffs", "to_quadexpr()", "isnull()"]:
    s = x.groupby(g).sum()
    assert s.is_sparse
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        eval(f"s.{op}")
    msgs = [str(x.message) for x in w if "dens" in str(x.message).lower()]
    print(f"{op:16} sparse after: {s.is_sparse!s:5}  warning: {msgs}")

Output on master (69dd5c97):

shift(t=1)       sparse after: False  warning: ['Sparse (CSR) backing densified: `.data` read, e.g. by an operation without a sparse path.']
diff('t')        sparse after: False  warning: ['Sparse (CSR) backing densified: `.data` read, e.g. by an operation without a sparse path.']
coeffs           sparse after: False  warning: ['Sparse (CSR) backing densified: `.data` read, e.g. by an operation without a sparse path.']
to_quadexpr()    sparse after: False  warning: ['Sparse (CSR) backing densified: `.data` read, e.g. by an operation without a sparse path.']
isnull()         sparse after: True   warning: []
Proposed direction
  • One chokepoint _delegate(name, ...) on LinearExpression. If name has a sparse implementation, call it. Otherwise convert with reason=name and call the dense implementation on the converted copy. The receiver keeps its backing.
  • The 34 if self._csr blocks become a dispatch table mapping frontend methods to CSRLinearExpression counterparts (sum to summed, __neg__/__mul__ to scaled, sel/isel/where to taken, reindex to reindexed, fillna to filled, rename to renamed, @ to contracted, constant arithmetic to with_const, ...). The table is the authoritative list of backing-preserving operations; #971 documents it, #1011 adds rows.
  • .data becomes a plain read through the chokepoint with reason "data". Setters that must mutate (const, data assignment) go through the chokepoint with their own reason.
  • Partial fallbacks (_selected :2582, _sparse_matmul :2904, _try_csr_merge :3740, csr_rhs in linopy/constraints.py:1689) return a reason string instead of calling _densify_all themselves.
  • Expected warning after the change: Sparse (CSR) backing densified by shift, one name per operation.
Tests
  • One parametrized test in test/test_csr.py over the dispatch table: each entry keeps the backing under no_densify(); each fallback warns with its own operation name and leaves the receiver sparse.
  • Existing twin-build tests (assert_sparse_matches, assert_frozen_equal) pass unchanged.
Lingua principale
Python
Stelle
259
Fork
89
Merge medio
1g 18h
PR unite (30g)
26

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di PyPSA/linopy

Tutte le issue di PyPSA/linopy

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.