Skip to content

feat(piecewise): active_fill for partial active gates (alt. to #797, #796)#798

Merged
FabianHofmann merged 5 commits into
masterfrom
feat/piecewise-active-fill
Jun 30, 2026
Merged

feat(piecewise): active_fill for partial active gates (alt. to #797, #796)#798
FabianHofmann merged 5 commits into
masterfrom
feat/piecewise-active-fill

Conversation

@FBumann

@FBumann FBumann commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

(placeholder — Felix to rewrite)

Note

The following content was generated by AI.

Alternative to #797. Closes #796. Same goal (partial active gate), but exposes the fix as an active_fill parameter on add_piecewise_formulation instead of a standalone active_gate helper. The first two commits are #797's helper approach; the third refactors it into the parameter, so the evolution is visible in history while the net diff is just the parameter design.

What

add_piecewise_formulation(..., active=status, active_fill=1):

  • active_fill=None (default) → a partial active (subset of the indexed dim, or masked) raises — the function stays strict.
  • active_fill=0|1 → opt in to gating the missing entries as always-off / always-on.

The function derives its own coordinate, so the caller supplies nothing extra (no coords, no helper, no import).

Why a parameter instead of the active_gate helper (#797)

  • No caller boilerplate — the helper needed an explicit coords argument; the function already knows its coordinate.
  • Strict by defaultactive_fill=None rejects a partial gate, so accidental partial coverage surfaces as an error rather than a silent always-on/off.
  • Transitional, and honestly scopedactive_fill is documented as slated for removal once v1 arithmetic semantics make active.reindex(coords).fillna(value) correct on its own. It's a parameter whose implementation is legacy-specific, not throwaway public surface elsewhere.

Changes (net)

  • linopy/piecewise.pyactive_fill parameter; _resolve_active folds the coverage guard (raise when None) and the padding (where(has_terms, fill) when set) into one place.
  • test/test_piecewise_active_fill.py — parametrized over both gap shapes (strict-subset, masked) × resolution/validation/solver (incremental, sos2, disjunctive); covers active_fill=0/1, None-raises, active_fill without active, and lower-dimensional broadcast.
  • Docs: piecewise guide + release notes.

Tests

test_piecewise_active_fill.py + test_piecewise_constraints.py: 248 passed. ruff / blackdoc / mypy clean.

🤖 Generated with Claude Code

FBumann and others added 3 commits June 29, 2026 14:58
…#796)

`add_piecewise_formulation(active=...)` assumed the gate covered the whole
indexed dimension. A gate defined over only a subset of coordinate labels
(or with masked entries) silently forced the uncovered entries to zero —
breaking mixed committable / non-committable formulations (PyPSA#1755).

- Add `linopy.active_gate(active, coords, fill_value=1)`: pads a partial
  gate to full coverage, treating missing/masked entries as always-active
  (1) or always-off (0). Lives in its own module `linopy/_active_gate.py`
  as a temporary legacy stopgap; under v1 the bare
  `active.reindex(coords).fillna(fill_value)` idiom suffices and the helper
  is expected to be deprecated.
- `add_piecewise_formulation` now rejects an under-defined `active` (strict
  subset or masked) with an actionable error instead of mis-solving. A
  lower-dimensional gate still broadcasts and is accepted.
- Docs (api, piecewise guide, release notes) and tests in a dedicated
  `test/test_piecewise_active_gate.py` (parametrized over both partial
  shapes and incremental/sos2/disjunctive paths).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ction

Apply review suggestion (#797): replace the hand-rolled vars/term-dim
reduction with the public `has_terms` property in `active_gate` and the
coverage validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…meter

Per PR #797 review: instead of a standalone `active_gate` helper, gate a
partial `active` via an `active_fill` parameter on `add_piecewise_formulation`.
The function derives its own coordinate, so the caller supplies nothing extra;
`active_fill=None` (default) keeps the function strict (partial `active`
raises), and `0`/`1` opt into always-off / always-on.

- Drop `linopy/_active_gate.py` and the `active_gate` export.
- Add `active_fill: int | None` to `add_piecewise_formulation`; fold the
  guard + padding into `_resolve_active`.
- `active_fill` is transitional (removed once v1 makes
  `active.reindex(coords).fillna(value)` sufficient) — documented as such.
- Tests renamed to test_piecewise_active_fill.py; docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@FBumann FBumann requested a review from FabianHofmann June 29, 2026 14:25
@codspeed-hq

codspeed-hq Bot commented Jun 29, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 138 untouched benchmarks
⏩ 138 skipped benchmarks1


Comparing feat/piecewise-active-fill (feed36e) with master (1dbde37)

Open in CodSpeed

Footnotes

  1. 138 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.

…ls or masked

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@FBumann

FBumann commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

@FabianHofmann Id argue this is more ergonomic than #797. And handling the removal of this isn't harder...
Its probably easier...

@FabianHofmann FabianHofmann left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's pull that in. I spent some time with trying to find a way without the active_fill. but in the end this is fail fast and explicit. just as we want.

@FabianHofmann FabianHofmann merged commit fe798b1 into master Jun 30, 2026
24 checks passed
@FabianHofmann FabianHofmann deleted the feat/piecewise-active-fill branch June 30, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add_piecewise_formulation: support a partial active gate (treat missing/null entries as always-active)

2 participants