Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

オープン
#1,020 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
35/100
issue の種類
リファクタリング
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
numpy, pandas, python
領域
backend

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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.
主要言語
Python
スター
260
フォーク
89
平均マージ
2日 16時間
マージ済み PR(30日)
30

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

PyPSA/linopy のほかの issue

PyPSA/linopy の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。