⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Conversation

@FBumann
Copy link
Contributor

@FBumann FBumann commented Feb 9, 2026

Piecewise Linear Constraints

Superset of #559 — includes the SOS2 formulation from that PR plus incremental and disjunctive methods.

Summary

  • SOS2 (convex combination): add_piecewise_constraints(..., method="sos2") — general PWL for any breakpoint order, uses SOS2 variables
  • Incremental (delta): add_piecewise_constraints(..., method="incremental") — pure LP for strictly monotonic breakpoints, no SOS2/binary variables
  • Disjunctive (disaggregated convex combination): add_disjunctive_piecewise_constraints(...) — for disconnected segments (forbidden zones), uses binary + SOS2
  • Auto selection: method="auto" picks incremental when breakpoints are monotonic, SOS2 otherwise

Features

  • Single variable or dict of variables (shared interpolation weights)
  • N-dimensional coordinate support via xarray
  • NaN-based masking with skip_nan_check option
  • Documentation with mathematical formulations and comparison table
  • Tutorial notebook with worked examples and visualizations

Test plan

  • Unit tests for all three formulations
  • Dict (multi-variable) linking tests
  • Monotonicity check tests
  • Notebook executes end-to-end
  • Docs build without new warnings

Checklist

  • Code changes are sufficiently documented
  • Unit tests for new features were added
  • A note for the release notes doc/release_notes.rst of the upcoming release is included
  • I consent to the release of this PR's code under the MIT license

FBumann and others added 15 commits January 25, 2026 13:38
Add `add_piecewise_constraint` method to Model class that creates
piecewise linear constraints using SOS2 formulation.

Features:
- Single Variable or LinearExpression support
- Dict of Variables/Expressions for linking multiple quantities
- Auto-detection of link_dim from breakpoints coordinates
- NaN-based masking with skip_nan_check option for performance
- Counter-based name generation for efficiency

The SOS2 formulation creates:
1. Lambda variables with bounds [0, 1] for each breakpoint
2. SOS2 constraint ensuring at most two adjacent lambdas are non-zero
3. Convexity constraint: sum(lambda) = 1
4. Linking constraints: expr = sum(lambda * breakpoints)
…_SUFFIX = "_fill".

  linopy/model.py —
  - Added method: str = "sos2" parameter to add_piecewise_constraints()
  - Updated docstring with the new parameter and incremental formulation notes
  - Refactored: extracted _add_pwl_sos2() (existing SOS2 logic) and added _add_pwl_incremental() (new delta formulation)
  - Added _check_strict_monotonicity() static method
  - method="auto" checks monotonicity and picks accordingly
  - Numeric coordinate validation only enforced for SOS2

  test/test_piecewise_constraints.py — Added TestIncrementalFormulation (10 tests) covering: single variable, two breakpoints, dict case, non-monotonic error, decreasing monotonic, auto-select incremental/sos2, invalid method, extra coordinates. Added TestIncrementalSolverIntegration (Gurobi-gated).
…f(dim).rename()

  2. Filling-order constraints: replaced per-segment individual add_constraints calls with a single vectorized constraint via xr.concat + LinearExpression
  3. Mask computation: replaced loop over segments with vectorized slice + rename
  4. Coordinate lists: unified extra_coords/lambda_coords — lambda_coords = extra_coords + [bp_dim_index], eliminating duplicate list comprehensions
  Files Modified

  1. linopy/constants.py — Added 3 constants:
    - PWL_BINARY_SUFFIX = "_binary"
    - PWL_SELECT_SUFFIX = "_select"
    - DEFAULT_SEGMENT_DIM = "segment"
  2. linopy/model.py — Three changes:
    - Updated imports to include the new constants
    - Updated _resolve_pwl_link_dim with an optional exclude_dims parameter (backward-compatible) so auto-detection skips both dim and segment_dim
    - Added _add_dpwl_sos2 private method implementing the disaggregated convex combination formulation (binary indicators, per-segment SOS2 lambdas, convexity, and linking
  constraints)
    - Added add_disjunctive_piecewise_constraints public method with full validation, mask computation, and dispatch
  3. test/test_piecewise_constraints.py — Added 7 test classes with 17 tests:
    - TestDisjunctiveBasicSingleVariable (3 tests) — equal segments, NaN padding, single-breakpoint segments
    - TestDisjunctiveDictOfVariables (2 tests) — dict with segments, auto-detect link_dim
    - TestDisjunctiveExtraDimensions (1 test) — extra generator dimension
    - TestDisjunctiveValidationErrors (5 tests) — missing dim, missing segment_dim, same dim/segment_dim, non-numeric coords, invalid expr
    - TestDisjunctiveNameGeneration (2 tests) — shared counter, custom name
    - TestDisjunctiveLPFileOutput (1 test) — LP file contains SOS2 + binary sections
    - TestDisjunctiveSolverIntegration (3 tests) — min/max picks correct segment, dict case with solver
Create dedicated documentation page covering all three PWL formulations:
SOS2 (convex combination), incremental (delta), and disjunctive
(disaggregated convex combination). Includes math formulations, usage
examples, comparison table, generated variables reference, and solver
compatibility. Update index.rst, api.rst, and sos-constraints.rst.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add 17 new tests covering masking details, expression inputs,
multi-dimensional cases, multi-breakpoint segments, and parametrized
multi-solver testing. Disjunctive tests go from 17 to 34 unique methods.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@FBumann FBumann changed the title Feat/add piecewise variants feat: add piecewise linear constraint API (SOS2, incremental, disjunctive) Feb 9, 2026
@FBumann FBumann marked this pull request as ready for review February 10, 2026 12:56
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.

1 participant