Skip to content

Conversation

@FBumann
Copy link
Contributor

@FBumann FBumann commented Jan 25, 2026

Add Piecewise Linear Constraint API

Summary

Add add_piecewise_constraints method to Model class for creating piecewise linear constraints using SOS2 formulation.

Features

  • Single Variable or LinearExpression support
  • Dict of Variables/Expressions for linking multiple quantities (e.g., power-efficiency curves)
  • Auto-detection of link_dim from breakpoints coordinates
  • NaN-based masking with skip_nan_check option for performance
  • Counter-based name generation for efficiency

Design decision

Is this something the linopy package wants to add? And if, do you want to see this as a helper method, that adds variables and constraints itself, or store sth like a PWL-Constraint object?
This implementation adds variables and (sos-)constraints, which i prefer over adding other classes of constraints.
This kind of relies on #549 to be widely uses, as it uses sos2 internally

As a convention, we could establish that such internally added variables/constraints get a prefix starting with an double underscore. This would simplify filtering.

Usage

# Single variable
m.add_piecewise_constraints(x, breakpoints, dim='bp')

# Expression
m.add_piecewise_constraints(x + y, breakpoints, dim='bp')

# Multiple linked variables (e.g., power-efficiency curve)
m.add_piecewise_constraints(
    {'power': power, 'efficiency': efficiency},
    breakpoints,
    link_dim='var',
    dim='bp'
)

SOS2 Formulation

The method creates:

  1. Lambda (λ) variables with bounds [0, 1] for each breakpoint
  2. SOS2 constraint ensuring at most two adjacent λ values are non-zero
  3. Convexity constraint: Σλ = 1
  4. Linking constraints: expr = Σ(λ × breakpoint) for each expression

Known Limitations

Supported (continuous):     NOT supported (discontinuous):
      /\                          /\
     /  \                        /  \
    /    \____                  /    \       ____
                                           gap
  • Returns only convexity constraint; access lambda via model.variables[f"{name}_lambda"]
  • No removal/modification support after creation
  • Single breakpoint dimension for all linked expressions

Future Work

Checklist

  • Code changes are sufficiently documented; i.e. new functions contain docstrings and further explanations may be given in doc.
  • Unit tests for new features were added (if applicable).
  • 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.

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)
@FBumann FBumann marked this pull request as ready for review January 26, 2026 09:07
@RobbieKiwi
Copy link
Contributor

It could be nice to have a linear formulation as well to cover the strictly monotonic case

@FBumann
Copy link
Contributor Author

FBumann commented Jan 30, 2026

@RobbieKiwi Yes why not?
But id like to add this quickly, together with the sos reformulation, and then build on top of it :).
What formulation do you have in mind?
continuous δᵢ ∈ [0,1] with filling-order constraints δᵢ₊₁ ≤ δᵢ ?
Or just skipping the sos2 and relying on convexity ?

@RobbieKiwi
Copy link
Contributor

Yeah makes more sense for a future PR. I was thinking continuous with filling-order constraints, I don't like relying on the objective to make the mapping work correctly

@FBumann
Copy link
Contributor Author

FBumann commented Jan 30, 2026

Yeah makes more sense for a future PR. I was thinking continuous with filling-order constraints, I don't like relying on the objective to make the mapping work correctly

Ok perfect. We should bundle those under a "method" or sth. Just to have it linked here: FBumann#10

@FBumann
Copy link
Contributor Author

FBumann commented Feb 9, 2026

@RobbieKiwi @FabianHofmann Is there a blocker to this PR? Or is the blocker in #549 ?
It would really make my own library much simpler.
I also already prepared follow ups FBumann#10 and FBumann#20

Create dedicated documentation page for the add_piecewise_constraints
method covering the SOS2 (convex combination) formulation with math,
usage examples, generated variables/constraints reference, and solver
compatibility. Update index.rst toctree, api.rst, and add cross-ref
from sos-constraints.rst.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@FBumann
Copy link
Contributor Author

FBumann commented Feb 9, 2026

I added some docs. If you want to, we can also merge all 3 as a single new feature. WOuld add full generalized support for piecewise linear formulation, both for linear, sos2 and dicontinous formulations

@RobbieKiwi
Copy link
Contributor

By the way there is an issue with readthedocs, nothing to do with your changes, I am fixing it here #574


Examples
--------
Single variable piecewise constraint:
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of a single variable piecewise constraint?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought fording a variable into such bounds would be useful to someone.
Im not completely sure about the actual use case. But i don't see why we should strip it.

@FBumann
Copy link
Contributor Author

FBumann commented Feb 9, 2026

@RobbieKiwi if you prefer, we can make a bigger combined feature PR: #576

@RobbieKiwi
Copy link
Contributor

RobbieKiwi commented Feb 9, 2026

@RobbieKiwi if you prefer, we can make a bigger combined feature PR: #576

This PR looks good to me, but I can't approve PRs you need to check with the others

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.

2 participants