From 4d273fe0cfe2f1be56fb44c8f9b2d9fb33b3b0e0 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:20:08 +0200 Subject: [PATCH 01/16] feat: PiecewiseFormulation return type, model groups, rename to add_piecewise_formulation - Add PiecewiseFormulation dataclass grouping all auxiliary variables and constraints created by a piecewise formulation - Add _groups registry on Model to track grouped artifacts - Model repr hides grouped items from Variables/Constraints sections and shows them in a new "Groups" section - Rename add_piecewise_constraints -> add_piecewise_formulation - Export PiecewiseFormulation from linopy Co-Authored-By: Claude Opus 4.6 (1M context) --- doc/api.rst | 2 +- doc/piecewise-linear-constraints.rst | 30 +++--- doc/release_notes.rst | 2 +- examples/piecewise-linear-constraints.ipynb | 14 +-- linopy/__init__.py | 9 +- linopy/constraints.py | 28 +++-- linopy/model.py | 42 ++++++-- linopy/piecewise.py | 102 ++++++++++++++---- linopy/variables.py | 28 +++-- test/test_piecewise_constraints.py | 110 ++++++++++---------- 10 files changed, 239 insertions(+), 128 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index 1ad7d869..434a77b8 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -18,7 +18,7 @@ Creating a model model.Model.add_variables model.Model.add_constraints model.Model.add_objective - model.Model.add_piecewise_constraints + model.Model.add_piecewise_formulation piecewise.breakpoints piecewise.segments piecewise.tangent_lines diff --git a/doc/piecewise-linear-constraints.rst b/doc/piecewise-linear-constraints.rst index bb9eebbd..6decb39c 100644 --- a/doc/piecewise-linear-constraints.rst +++ b/doc/piecewise-linear-constraints.rst @@ -24,7 +24,7 @@ Quick Start fuel = m.add_variables(name="fuel") # Link power and fuel via a piecewise linear curve - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0, 30, 60, 100]), (fuel, [0, 36, 84, 170]), ) @@ -38,12 +38,12 @@ of adjacent breakpoints. API --- -``add_piecewise_constraints`` +``add_piecewise_formulation`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python - m.add_piecewise_constraints( + m.add_piecewise_formulation( (expr1, breakpoints1), (expr2, breakpoints2), ..., @@ -97,7 +97,7 @@ linopy provides two distinct tools for piecewise linear modelling. :widths: 30 35 35 * - - - ``add_piecewise_constraints`` + - ``add_piecewise_formulation`` - ``tangent_lines`` * - **Constraint type** - Equality: :math:`y = f(x)` @@ -117,7 +117,7 @@ linopy provides two distinct tools for piecewise linear modelling. ``tangent_lines`` does **not** work with equality. Writing ``fuel == tangent_lines(...)`` creates one equality per segment, which is overconstrained (infeasible except at breakpoints). - Use ``add_piecewise_constraints`` for equality. + Use ``add_piecewise_formulation`` for equality. **When is the tangent-line bound tight?** @@ -137,7 +137,7 @@ The simplest form --- pass Python lists directly in the tuple: .. code-block:: python - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0, 30, 60, 100]), (fuel, [0, 36, 84, 170]), ) @@ -149,7 +149,7 @@ Equivalent, but explicit about the DataArray construction: .. code-block:: python - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, linopy.breakpoints([0, 30, 60, 100])), (fuel, linopy.breakpoints([0, 36, 84, 170])), ) @@ -161,7 +161,7 @@ When you know marginal costs (slopes) rather than absolute values: .. code-block:: python - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0, 50, 100, 150]), ( cost, @@ -180,7 +180,7 @@ Different generators can have different curves. Pass a dict to .. code-block:: python - m.add_piecewise_constraints( + m.add_piecewise_formulation( ( power, linopy.breakpoints( @@ -206,7 +206,7 @@ For disconnected operating regions (e.g. forbidden zones), use .. code-block:: python - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, linopy.segments([(0, 0), (50, 80)])), (cost, linopy.segments([(0, 0), (125, 200)])), ) @@ -222,7 +222,7 @@ are symmetric --- there is no distinguished "x" or "y": .. code-block:: python - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0, 30, 60, 100]), (fuel, [0, 40, 85, 160]), (heat, [0, 25, 55, 95]), @@ -263,7 +263,7 @@ non-zero, so every expression is interpolated within the same segment. .. code-block:: python - m.add_piecewise_constraints((power, xp), (fuel, yp), method="sos2") + m.add_piecewise_formulation((power, xp), (fuel, yp), method="sos2") Incremental (Delta) Formulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -279,7 +279,7 @@ For **strictly monotonic** breakpoints. Uses fill-fraction variables .. code-block:: python - m.add_piecewise_constraints((power, xp), (fuel, yp), method="incremental") + m.add_piecewise_formulation((power, xp), (fuel, yp), method="incremental") **Limitation:** All breakpoint sequences must be strictly monotonic. @@ -330,7 +330,7 @@ linked expressions) are forced to zero: .. code-block:: python commit = m.add_variables(name="commit", binary=True, coords=[time]) - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [30, 60, 100]), (fuel, [40, 90, 170]), active=commit, @@ -352,7 +352,7 @@ You don't need ``expand_dims``: y = m.add_variables(name="y", coords=[time]) # 1D breakpoints auto-expand to match x's time dimension - m.add_piecewise_constraints((x, [0, 50, 100]), (y, [0, 70, 150])) + m.add_piecewise_formulation((x, [0, 50, 100]), (y, [0, 70, 150])) NaN masking ~~~~~~~~~~~ diff --git a/doc/release_notes.rst b/doc/release_notes.rst index d1c7efea..40cd98d5 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -11,7 +11,7 @@ Upcoming Version - Comparison operators (``==``, ``<=``, ``>=``) fill missing RHS coords with NaN (no constraint created) - Fixes crash on ``subset + var`` / ``subset + expr`` reverse addition - Fixes superset DataArrays expanding result coords beyond the variable's coordinate space -* Add ``add_piecewise_constraints()`` for piecewise linear equality constraints with SOS2, incremental, and disjunctive formulations: ``m.add_piecewise_constraints((power, x_pts), (fuel, y_pts))``. Supports N-variable linking (e.g. CHP with fuel/power/heat), per-entity breakpoints, and unit commitment via the ``active`` parameter. +* Add ``add_piecewise_formulation()`` for piecewise linear equality constraints with SOS2, incremental, and disjunctive formulations: ``m.add_piecewise_formulation((power, x_pts), (fuel, y_pts))``. Supports N-variable linking (e.g. CHP with fuel/power/heat), per-entity breakpoints, and unit commitment via the ``active`` parameter. * Add ``tangent_lines()`` for piecewise linear inequality bounds — returns a ``LinearExpression`` with one tangent line per segment, no auxiliary variables. Use with regular ``add_constraints``. * Add ``linopy.breakpoints()`` factory for convenient breakpoint construction from lists, Series, DataFrames, DataArrays, or dicts. Supports slopes mode. * Add ``linopy.segments()`` factory for disjunctive (disconnected) breakpoints. diff --git a/examples/piecewise-linear-constraints.ipynb b/examples/piecewise-linear-constraints.ipynb index 7f6a473a..1c050925 100644 --- a/examples/piecewise-linear-constraints.ipynb +++ b/examples/piecewise-linear-constraints.ipynb @@ -3,7 +3,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "# Piecewise Linear Constraints Tutorial\n\nThis notebook demonstrates linopy's piecewise linear (PWL) constraint formulations.\nEach example builds a separate dispatch model where a single power plant must meet\na time-varying demand.\n\n| Example | Plant | Limitation | Formulation |\n|---------|-------|------------|-------------|\n| 1 | Gas turbine (0-100 MW) | Convex heat rate | SOS2 |\n| 2 | Coal plant (0-150 MW) | Monotonic heat rate | Incremental |\n| 3 | Diesel generator (off or 50-80 MW) | Forbidden zone | Disjunctive |\n| 4 | Concave efficiency curve | Inequality bound | Tangent lines |\n| 5 | Gas unit with commitment | On/off + min load | Incremental + `active` |\n| 6 | CHP plant (N-variable) | Joint power/fuel/heat | N-variable SOS2 |\n| 7 | Fleet of generators | Per-entity breakpoints | Per-generator curves |\n\n**API:** Each `(expression, breakpoints)` tuple links a variable to its breakpoints.\nAll tuples share interpolation weights, coupling them on the same curve segment.\n\n```python\nm.add_piecewise_constraints((power, x_pts), (fuel, y_pts))\n```" + "source": "# Piecewise Linear Constraints Tutorial\n\nThis notebook demonstrates linopy's piecewise linear (PWL) constraint formulations.\nEach example builds a separate dispatch model where a single power plant must meet\na time-varying demand.\n\n| Example | Plant | Limitation | Formulation |\n|---------|-------|------------|-------------|\n| 1 | Gas turbine (0-100 MW) | Convex heat rate | SOS2 |\n| 2 | Coal plant (0-150 MW) | Monotonic heat rate | Incremental |\n| 3 | Diesel generator (off or 50-80 MW) | Forbidden zone | Disjunctive |\n| 4 | Concave efficiency curve | Inequality bound | Tangent lines |\n| 5 | Gas unit with commitment | On/off + min load | Incremental + `active` |\n| 6 | CHP plant (N-variable) | Joint power/fuel/heat | N-variable SOS2 |\n| 7 | Fleet of generators | Per-entity breakpoints | Per-generator curves |\n\n**API:** Each `(expression, breakpoints)` tuple links a variable to its breakpoints.\nAll tuples share interpolation weights, coupling them on the same curve segment.\n\n```python\nm.add_piecewise_formulation((power, x_pts), (fuel, y_pts))\n```" }, { "cell_type": "code", @@ -164,7 +164,7 @@ "fuel = m1.add_variables(name=\"fuel\", lower=0, coords=[time])\n", "\n", "# breakpoints are auto-broadcast to match the time dimension\n", - "m1.add_piecewise_constraints(\n", + "m1.add_piecewise_formulation(\n", " (power, x_pts1),\n", " (fuel, y_pts1),\n", " name=\"pwl\",\n", @@ -298,7 +298,7 @@ "power = m2.add_variables(name=\"power\", lower=0, upper=150, coords=[time])\n", "fuel = m2.add_variables(name=\"fuel\", lower=0, coords=[time])\n", "\n", - "m2.add_piecewise_constraints(\n", + "m2.add_piecewise_formulation(\n", " (power, x_pts2),\n", " (fuel, y_pts2),\n", " name=\"pwl\",\n", @@ -440,7 +440,7 @@ "cost = m3.add_variables(name=\"cost\", lower=0, coords=[time])\n", "backup = m3.add_variables(name=\"backup\", lower=0, coords=[time])\n", "\n", - "m3.add_piecewise_constraints(\n", + "m3.add_piecewise_formulation(\n", " (power, x_seg),\n", " (cost, y_seg),\n", " name=\"pwl\",\n", @@ -1970,7 +1970,7 @@ "# The active parameter gates the PWL with the commitment binary:\n", "# - commit=1: power in [30, 100], fuel = f(power)\n", "# - commit=0: power = 0, fuel = 0\n", - "m6.add_piecewise_constraints(\n", + "m6.add_piecewise_formulation(\n", " (power, x_pts6),\n", " (fuel, y_pts6),\n", " active=commit,\n", @@ -2770,7 +2770,7 @@ "heat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n", "\n", "# N-variable: all three linked through shared interpolation weights\n", - "m7.add_piecewise_constraints(\n", + "m7.add_piecewise_formulation(\n", " (power, bp_chp.sel(var=\"power\")),\n", " (fuel, bp_chp.sel(var=\"fuel\")),\n", " (heat, bp_chp.sel(var=\"heat\")),\n", @@ -2873,7 +2873,7 @@ "fuel = m8.add_variables(name=\"fuel\", lower=0, coords=[gens, time])\n", "\n", "# Per-entity breakpoints: each generator gets its own curve\n", - "m8.add_piecewise_constraints(\n", + "m8.add_piecewise_formulation(\n", " (power, x_gen),\n", " (fuel, y_gen),\n", " name=\"pwl\",\n", diff --git a/linopy/__init__.py b/linopy/__init__.py index aa14b767..fb54c6c4 100644 --- a/linopy/__init__.py +++ b/linopy/__init__.py @@ -20,7 +20,13 @@ from linopy.io import read_netcdf from linopy.model import Model, Variable, Variables, available_solvers from linopy.objective import Objective -from linopy.piecewise import breakpoints, segments, slopes_to_points, tangent_lines +from linopy.piecewise import ( + PiecewiseFormulation, + breakpoints, + segments, + slopes_to_points, + tangent_lines, +) from linopy.remote import RemoteHandler try: @@ -38,6 +44,7 @@ "Model", "Objective", "OetcHandler", + "PiecewiseFormulation", "QuadraticExpression", "RemoteHandler", "Variable", diff --git a/linopy/constraints.py b/linopy/constraints.py index bb6d8e68..a846b681 100644 --- a/linopy/constraints.py +++ b/linopy/constraints.py @@ -733,25 +733,35 @@ def _formatted_names(self) -> dict[str, str]: """ return {format_string_as_variable_name(n): n for n in self} - def __repr__(self) -> str: - """ - Return a string representation of the linopy model. - """ - r = "linopy.model.Constraints" - line = "-" * len(r) - r += f"\n{line}\n" - + def _format_items(self, exclude: set[str] | None = None) -> str: + """Format constraint items, optionally excluding names in a group.""" + r = "" + count = 0 for name, ds in self.items(): + if exclude and name in exclude: + continue + count += 1 coords = ( " (" + ", ".join([str(c) for c in ds.coords.keys()]) + ")" if ds.coords else "" ) r += f" * {name}{coords}\n" - if not len(list(self)): + if count == 0: r += "\n" return r + def __repr__(self) -> str: + r = "linopy.model.Constraints" + line = "-" * len(r) + r += f"\n{line}\n" + r += self._format_items() + return r + + def _repr_filtered(self, exclude: set[str]) -> str: + """Format items excluding grouped names (used by Model.__repr__).""" + return self._format_items(exclude) + @overload def __getitem__(self, names: str) -> Constraint: ... diff --git a/linopy/model.py b/linopy/model.py index 2a635680..5c33f964 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -12,7 +12,7 @@ from collections.abc import Callable, Mapping, Sequence from pathlib import Path from tempfile import NamedTemporaryFile, gettempdir -from typing import Any, Literal, overload +from typing import TYPE_CHECKING, Any, Literal, overload from warnings import warn import numpy as np @@ -70,7 +70,7 @@ from linopy.matrices import MatrixAccessor from linopy.objective import Objective from linopy.piecewise import ( - add_piecewise_constraints, + add_piecewise_formulation, ) from linopy.remote import RemoteHandler @@ -97,6 +97,9 @@ ) from linopy.variables import ScalarVariable, Variable, Variables +if TYPE_CHECKING: + from linopy.piecewise import PiecewiseFormulation + logger = logging.getLogger(__name__) @@ -228,6 +231,7 @@ class Model: "_auto_mask", "_solver_dir", "_relaxed_registry", + "_groups", "solver_model", "solver_name", "matrices", @@ -284,6 +288,7 @@ def __init__( self._chunk: T_Chunks = chunk self._force_dim_names: bool = bool(force_dim_names) self._auto_mask: bool = bool(auto_mask) + self._groups: dict[str, PiecewiseFormulation] = {} self._relaxed_registry: dict[str, str] = {} self._solver_dir: Path = Path( gettempdir() if solver_dir is None else solver_dir @@ -493,17 +498,38 @@ def __repr__(self) -> str: """ Return a string representation of the linopy model. """ - var_string = self.variables.__repr__().split("\n", 2)[2] - con_string = self.constraints.__repr__().split("\n", 2)[2] + grouped_names = self._grouped_names() + var_string = self.variables._repr_filtered(grouped_names) + con_string = self.constraints._repr_filtered(grouped_names) model_string = f"Linopy {self.type} model" - return ( + result = ( f"{model_string}\n{'=' * len(model_string)}\n\n" f"Variables:\n----------\n{var_string}\n" - f"Constraints:\n------------\n{con_string}\n" - f"Status:\n-------\n{self.status}" + f"Constraints:\n------------\n{con_string}" ) + if self._groups: + result += "\nGroups:\n-------\n" + for group in self._groups.values(): + n_vars = len(group.variables) + n_cons = len(group.constraints) + result += ( + f" * {group.name} ({group.method}):" + f" {n_vars} variables, {n_cons} constraints\n" + ) + + result += f"\nStatus:\n-------\n{self.status}" + return result + + def _grouped_names(self) -> set[str]: + """Return all variable/constraint names that belong to a group.""" + names: set[str] = set() + for group in self._groups.values(): + names.update(group.variables) + names.update(group.constraints) + return names + def __getitem__(self, key: str) -> Variable: """ Get a model variable by the name. @@ -791,7 +817,7 @@ def add_sos_constraints( variable.attrs.update(attrs_update) - add_piecewise_constraints = add_piecewise_constraints + add_piecewise_formulation = add_piecewise_formulation def add_constraints( self, diff --git a/linopy/piecewise.py b/linopy/piecewise.py index c5de3563..3d8e9e14 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -8,6 +8,7 @@ from __future__ import annotations from collections.abc import Sequence +from dataclasses import dataclass from numbers import Real from typing import TYPE_CHECKING, Literal, TypeAlias @@ -35,10 +36,11 @@ ) if TYPE_CHECKING: - from linopy.constraints import Constraint + from linopy.constraints import Constraint, Constraints from linopy.expressions import LinearExpression from linopy.model import Model from linopy.types import LinExprLike + from linopy.variables import Variables # Accepted input types for breakpoint-like data BreaksLike: TypeAlias = ( @@ -54,6 +56,38 @@ ) +# --------------------------------------------------------------------------- +# Result type +# --------------------------------------------------------------------------- + + +@dataclass(repr=False) +class PiecewiseFormulation: + """ + Result of ``add_piecewise_formulation``. + + Groups all auxiliary variables and constraints created by a single + piecewise formulation. + """ + + name: str + method: str + variables: Variables + constraints: Constraints + + def __repr__(self) -> str: + n_vars = len(self.variables) + n_cons = len(self.constraints) + r = f"PiecewiseFormulation '{self.name}' ({self.method})\n" + r += f" Variables ({n_vars}):\n" + for vname in self.variables: + r += f" * {vname}\n" + r += f" Constraints ({n_cons}):\n" + for cname in self.constraints: + r += f" * {cname}\n" + return r + + # --------------------------------------------------------------------------- # DataArray construction helpers # --------------------------------------------------------------------------- @@ -559,13 +593,13 @@ def _broadcast_points( # --------------------------------------------------------------------------- -def add_piecewise_constraints( +def add_piecewise_formulation( model: Model, *pairs: tuple[LinExprLike, BreaksLike], method: Literal["sos2", "incremental", "auto"] = "auto", active: LinExprLike | None = None, name: str | None = None, -) -> Constraint: +) -> PiecewiseFormulation: r""" Add piecewise linear equality constraints. @@ -576,14 +610,14 @@ def add_piecewise_constraints( Example — 2 variables:: - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0, 30, 60, 100]), (fuel, [0, 36, 84, 170]), ) Example — 3 variables (CHP plant):: - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0, 30, 60, 100]), (fuel, [0, 40, 85, 160]), (heat, [0, 25, 55, 95]), @@ -609,7 +643,7 @@ def add_piecewise_constraints( Returns ------- - Constraint + PiecewiseFormulation """ if method not in ("sos2", "incremental", "auto"): raise ValueError( @@ -618,7 +652,7 @@ def add_piecewise_constraints( if len(pairs) < 2: raise TypeError( - "add_piecewise_constraints() requires at least 2 " + "add_piecewise_formulation() requires at least 2 " "(expression, breakpoints) pairs." ) @@ -680,12 +714,16 @@ def add_piecewise_constraints( lin_exprs = [_to_linexpr(expr) for expr in all_exprs] active_expr = _to_linexpr(active) if active is not None else None + # Snapshot existing names to detect what the formulation adds + vars_before = set(model.variables) + cons_before = set(model.constraints) + if disjunctive: if method == "incremental": raise ValueError( "Incremental method is not supported for disjunctive constraints" ) - return _add_disjunctive( + _add_disjunctive( model, name, lin_exprs, @@ -694,18 +732,32 @@ def add_piecewise_constraints( bp_mask, active_expr, ) + resolved_method = "sos2" + else: + # Continuous: stack into N-variable formulation + resolved_method = _add_continuous( + model, + name, + lin_exprs, + bp_list, + link_coords, + bp_mask, + method, + active_expr, + ) + + # Collect newly created variable and constraint names + new_vars = [n for n in model.variables if n not in vars_before] + new_cons = [n for n in model.constraints if n not in cons_before] - # Continuous: stack into N-variable formulation - return _add_continuous( - model, - name, - lin_exprs, - bp_list, - link_coords, - bp_mask, - method, - active_expr, + result = PiecewiseFormulation( + name=name, + method=resolved_method, + variables=model.variables[new_vars], + constraints=model.constraints[new_cons], ) + model._groups[name] = result + return result def _stack_along_link( @@ -729,8 +781,12 @@ def _add_continuous( bp_mask: DataArray | None, method: str, active: LinearExpression | None = None, -) -> Constraint: - """Dispatch continuous piecewise equality to SOS2 or incremental.""" +) -> str: + """ + Dispatch continuous piecewise equality to SOS2 or incremental. + + Returns the resolved method name ("sos2" or "incremental"). + """ from linopy.expressions import LinearExpression link_dim = "_pwl_var" @@ -774,7 +830,7 @@ def _add_continuous( rhs = active if active is not None else 1 if method == "sos2": - return _add_sos2( + _add_sos2( model, name, target_expr, @@ -783,8 +839,9 @@ def _add_continuous( link_dim, rhs, ) + return method else: - return _add_incremental( + _add_incremental( model, name, target_expr, @@ -794,6 +851,7 @@ def _add_continuous( rhs, active, ) + return method def _add_sos2( diff --git a/linopy/variables.py b/linopy/variables.py index 0dfca099..15874029 100644 --- a/linopy/variables.py +++ b/linopy/variables.py @@ -1485,15 +1485,14 @@ def __dir__(self) -> list[str]: ] return base_attributes + formatted_names - def __repr__(self) -> str: - """ - Return a string representation of the linopy model. - """ - r = "linopy.model.Variables" - line = "-" * len(r) - r += f"\n{line}\n" - + def _format_items(self, exclude: set[str] | None = None) -> str: + """Format variable items, optionally excluding names in a group.""" + r = "" + count = 0 for name, ds in self.items(): + if exclude and name in exclude: + continue + count += 1 coords = ( " (" + ", ".join(str(coord) for coord in ds.coords) + ")" if ds.coords @@ -1506,10 +1505,21 @@ def __repr__(self) -> str: if ds.attrs.get("semi_continuous", False): coords += " - semi-continuous" r += f" * {name}{coords}\n" - if not len(list(self)): + if count == 0: r += "\n" return r + def __repr__(self) -> str: + r = "linopy.model.Variables" + line = "-" * len(r) + r += f"\n{line}\n" + r += self._format_items() + return r + + def _repr_filtered(self, exclude: set[str]) -> str: + """Format items excluding grouped names (used by Model.__repr__).""" + return self._format_items(exclude) + def __len__(self) -> int: return self.data.__len__() diff --git a/test/test_piecewise_constraints.py b/test/test_piecewise_constraints.py index dbc038fd..5d4175bc 100644 --- a/test/test_piecewise_constraints.py +++ b/test/test_piecewise_constraints.py @@ -282,7 +282,7 @@ def test_sos2(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50, 100]), (y, [5, 2, 20, 80]), method="sos2", @@ -299,7 +299,7 @@ def test_auto_selects_incremental_for_monotonic(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") # Both breakpoint sequences must be monotonic for incremental - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50, 100]), (y, [0, 5, 20, 80]), ) @@ -311,7 +311,7 @@ def test_auto_nonmonotonic_falls_back_to_sos2(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") # Non-monotonic y-breakpoints force SOS2 - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 30, 100]), (y, [5, 20, 15, 80]), ) @@ -323,7 +323,7 @@ def test_multi_dimensional(self) -> None: gens = pd.Index(["gen_a", "gen_b"], name="generator") x = m.add_variables(coords=[gens], name="x") y = m.add_variables(coords=[gens], name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( ( x, breakpoints( @@ -346,7 +346,7 @@ def test_with_slopes(self) -> None: y = m.add_variables(name="y") # slopes=[-0.3, 0.45, 1.2] with y0=5 -> y_points=[5, 2, 20, 80] # Non-monotonic y-breakpoints, so auto selects SOS2 - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50, 100]), (y, breakpoints(slopes=[-0.3, 0.45, 1.2], x_points=[0, 10, 50, 100], y0=5)), ) @@ -422,7 +422,7 @@ def test_creates_delta_vars(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50, 100]), (y, [5, 10, 20, 80]), method="incremental", @@ -438,7 +438,7 @@ def test_nonmonotonic_raises(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") with pytest.raises(ValueError, match="strictly monotonic"): - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 30, 100]), (y, [5, 20, 15, 80]), method="incremental", @@ -448,7 +448,7 @@ def test_sos2_nonmonotonic_succeeds(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 30, 100]), (y, [5, 20, 15, 80]), method="sos2", @@ -460,7 +460,7 @@ def test_two_breakpoints_no_fill(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 100]), (y, [5, 80]), method="incremental", @@ -474,7 +474,7 @@ def test_creates_binary_indicator_vars(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50, 100]), (y, [5, 10, 20, 80]), method="incremental", @@ -488,7 +488,7 @@ def test_creates_order_constraints(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50, 100]), (y, [5, 10, 20, 80]), method="incremental", @@ -500,7 +500,7 @@ def test_two_breakpoints_no_order_constraint(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 100]), (y, [5, 80]), method="incremental", @@ -513,7 +513,7 @@ def test_decreasing_monotonic(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [100, 50, 10, 0]), (y, [80, 20, 5, 2]), method="incremental", @@ -531,7 +531,7 @@ def test_equality_creates_binary(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, segments([[0, 10], [50, 100]])), (y, segments([[0, 5], [20, 80]])), ) @@ -547,7 +547,7 @@ def test_method_incremental_raises(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") with pytest.raises(ValueError, match="disjunctive"): - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, segments([[0, 10], [50, 100]])), (y, segments([[0, 5], [20, 80]])), method="incremental", @@ -558,7 +558,7 @@ def test_multi_dimensional(self) -> None: gens = pd.Index(["gen_a", "gen_b"], name="generator") x = m.add_variables(coords=[gens], name="x") y = m.add_variables(coords=[gens], name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( ( x, segments( @@ -607,14 +607,14 @@ def test_wrong_arg_types_raises(self) -> None: m = Model() x = m.add_variables(name="x") with pytest.raises(TypeError, match="at least 2"): - m.add_piecewise_constraints((x, [0, 10, 50])) + m.add_piecewise_formulation((x, [0, 10, 50])) def test_invalid_method_raises(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") with pytest.raises(ValueError, match="method must be"): - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50]), (y, [5, 10, 20]), method="invalid", # type: ignore @@ -625,7 +625,7 @@ def test_mismatched_breakpoint_sizes_raises(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") with pytest.raises(ValueError, match="same size"): - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50]), (y, [5, 10]), ) @@ -634,7 +634,7 @@ def test_non_tuple_arg_raises(self) -> None: m = Model() x = m.add_variables(name="x") with pytest.raises(TypeError, match="tuple"): - m.add_piecewise_constraints(x, [0, 10, 50]) # type: ignore + m.add_piecewise_formulation(x, [0, 10, 50]) # type: ignore # =========================================================================== @@ -648,8 +648,8 @@ def test_auto_name(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") z = m.add_variables(name="z") - m.add_piecewise_constraints((x, [0, 10, 50]), (y, [5, 10, 20])) - m.add_piecewise_constraints((x, [0, 20, 80]), (z, [10, 15, 50])) + m.add_piecewise_formulation((x, [0, 10, 50]), (y, [5, 10, 20])) + m.add_piecewise_formulation((x, [0, 20, 80]), (z, [10, 15, 50])) assert f"pwl0{PWL_DELTA_SUFFIX}" in m.variables assert f"pwl1{PWL_DELTA_SUFFIX}" in m.variables @@ -657,7 +657,7 @@ def test_custom_name(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50]), (y, [5, 10, 20]), name="my_pwl", @@ -680,7 +680,7 @@ def test_broadcast_over_extra_dims(self) -> None: x = m.add_variables(coords=[gens, times], name="x") y = m.add_variables(coords=[gens, times], name="y") # Points only have generator dim -> broadcast over time - m.add_piecewise_constraints( + m.add_piecewise_formulation( ( x, breakpoints( @@ -712,7 +712,7 @@ def test_nan_masks_lambda_labels(self) -> None: y = m.add_variables(name="y") x_pts = xr.DataArray([0, 10, 50, np.nan], dims=[BREAKPOINT_DIM]) y_pts = xr.DataArray([0, 5, 20, np.nan], dims=[BREAKPOINT_DIM]) - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, x_pts), (y, y_pts), method="sos2", @@ -730,7 +730,7 @@ def test_sos2_interior_nan_raises(self) -> None: x_pts = xr.DataArray([0, np.nan, 50, 100], dims=[BREAKPOINT_DIM]) y_pts = xr.DataArray([0, np.nan, 20, 40], dims=[BREAKPOINT_DIM]) with pytest.raises(ValueError, match="non-trailing NaN"): - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, x_pts), (y, y_pts), method="sos2", @@ -747,7 +747,7 @@ def test_sos2_equality(self, tmp_path: Path) -> None: m = Model() x = m.add_variables(name="x", lower=0, upper=100) y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0.0, 10.0, 50.0, 100.0]), (y, [5.0, 2.0, 20.0, 80.0]), method="sos2", @@ -763,7 +763,7 @@ def test_disjunctive_sos2_and_binary(self, tmp_path: Path) -> None: m = Model() x = m.add_variables(name="x", lower=0, upper=100) y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, segments([[0.0, 10.0], [50.0, 100.0]])), (y, segments([[0.0, 5.0], [20.0, 80.0]])), ) @@ -790,7 +790,7 @@ def test_equality_minimize_cost(self, solver_name: str) -> None: m = Model() x = m.add_variables(lower=0, upper=100, name="x") cost = m.add_variables(name="cost") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 100]), (cost, [0, 10, 50]), ) @@ -805,7 +805,7 @@ def test_equality_maximize_efficiency(self, solver_name: str) -> None: m = Model() power = m.add_variables(lower=0, upper=100, name="power") eff = m.add_variables(name="eff") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0, 25, 50, 75, 100]), (eff, [0.7, 0.85, 0.95, 0.9, 0.8]), ) @@ -819,7 +819,7 @@ def test_disjunctive_solve(self, solver_name: str) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, segments([[0.0, 10.0], [50.0, 100.0]])), (y, segments([[0.0, 5.0], [20.0, 80.0]])), ) @@ -924,7 +924,7 @@ def test_incremental_creates_active_bound(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") u = m.add_variables(binary=True, name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50, 100]), (y, [5, 10, 20, 80]), active=u, @@ -938,7 +938,7 @@ def test_active_none_is_default(self) -> None: m = Model() x = m.add_variables(name="x") y = m.add_variables(name="y") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 10, 50]), (y, [0, 5, 30]), method="incremental", @@ -951,7 +951,7 @@ def test_active_with_linear_expression(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") u = m.add_variables(binary=True, name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 100]), (y, [0, 10, 50]), active=1 * u, @@ -977,7 +977,7 @@ def test_incremental_active_on(self, solver_name: str) -> None: x = m.add_variables(lower=0, upper=100, name="x") y = m.add_variables(name="y") u = m.add_variables(binary=True, name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 100]), (y, [0, 10, 50]), active=u, @@ -997,7 +997,7 @@ def test_incremental_active_off(self, solver_name: str) -> None: x = m.add_variables(lower=0, upper=100, name="x") y = m.add_variables(name="y") u = m.add_variables(binary=True, name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 100]), (y, [0, 10, 50]), active=u, @@ -1021,7 +1021,7 @@ def test_incremental_nonzero_base_active_off(self, solver_name: str) -> None: x = m.add_variables(lower=0, upper=100, name="x") y = m.add_variables(name="y") u = m.add_variables(binary=True, name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [20, 60, 100]), (y, [5, 20, 50]), active=u, @@ -1044,7 +1044,7 @@ def test_unit_commitment_pattern(self, solver_name: str) -> None: fuel = m.add_variables(name="fuel") u = m.add_variables(binary=True, name="commit") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [p_min, p_max]), (fuel, [fuel_at_pmin, fuel_at_pmax]), active=u, @@ -1067,7 +1067,7 @@ def test_multi_dimensional_solver(self, solver_name: str) -> None: x = m.add_variables(lower=0, upper=100, coords=[gens], name="x") y = m.add_variables(coords=[gens], name="y") u = m.add_variables(binary=True, coords=[gens], name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 100]), (y, [0, 10, 50]), active=u, @@ -1097,7 +1097,7 @@ def test_sos2_active_off(self, solver_name: str) -> None: x = m.add_variables(lower=0, upper=100, name="x") y = m.add_variables(name="y") u = m.add_variables(binary=True, name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, [0, 50, 100]), (y, [0, 10, 50]), active=u, @@ -1116,7 +1116,7 @@ def test_disjunctive_active_off(self, solver_name: str) -> None: x = m.add_variables(lower=0, upper=100, name="x") y = m.add_variables(name="y") u = m.add_variables(binary=True, name="u") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, segments([[0.0, 10.0], [50.0, 100.0]])), (y, segments([[0.0, 5.0], [20.0, 80.0]])), active=u, @@ -1141,7 +1141,7 @@ def test_sos2_creates_lambda_and_link(self) -> None: m = Model() power = m.add_variables(lower=0, upper=100, name="power") fuel = m.add_variables(name="fuel") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0.0, 50.0, 100.0]), (fuel, [0.0, 20.0, 60.0]), method="sos2", @@ -1154,7 +1154,7 @@ def test_incremental_creates_delta(self) -> None: m = Model() power = m.add_variables(lower=0, upper=100, name="power") fuel = m.add_variables(name="fuel") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0.0, 50.0, 100.0]), (fuel, [0.0, 20.0, 60.0]), method="incremental", @@ -1166,7 +1166,7 @@ def test_auto_selects_method(self) -> None: m = Model() power = m.add_variables(lower=0, upper=100, name="power") fuel = m.add_variables(name="fuel") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0.0, 50.0, 100.0]), (fuel, [0.0, 20.0, 60.0]), ) @@ -1177,7 +1177,7 @@ def test_single_pair_raises(self) -> None: m = Model() power = m.add_variables(name="power") with pytest.raises(TypeError, match="at least 2"): - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0.0, 50.0, 100.0]), ) @@ -1186,7 +1186,7 @@ def test_three_variables(self) -> None: power = m.add_variables(lower=0, upper=100, name="power") fuel = m.add_variables(name="fuel") heat = m.add_variables(name="heat") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0.0, 50.0, 100.0]), (fuel, [0.0, 20.0, 60.0]), (heat, [0.0, 30.0, 80.0]), @@ -1202,7 +1202,7 @@ def test_custom_name(self) -> None: m = Model() power = m.add_variables(lower=0, upper=100, name="power") fuel = m.add_variables(name="fuel") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (power, [0.0, 50.0, 100.0]), (fuel, [0.0, 20.0, 60.0]), name="chp", @@ -1269,7 +1269,7 @@ def test_non_numeric_breakpoint_coords_raises(self) -> None: coords={BREAKPOINT_DIM: ["a", "b", "c"]}, ) with pytest.raises(ValueError, match="numeric coordinates"): - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, x_pts), (y, y_pts), method="sos2", @@ -1283,7 +1283,7 @@ def test_missing_breakpoint_dim_on_second_arg_raises(self) -> None: good = xr.DataArray([0, 10, 50], dims=[BREAKPOINT_DIM]) bad = xr.DataArray([0, 5, 20], dims=["wrong"]) with pytest.raises(ValueError, match="missing"): - m.add_piecewise_constraints((x, good), (y, bad)) + m.add_piecewise_formulation((x, good), (y, bad)) def test_segment_dim_mismatch_raises(self) -> None: """Segment dim on only one breakpoint array raises.""" @@ -1293,7 +1293,7 @@ def test_segment_dim_mismatch_raises(self) -> None: x_pts = segments([[0, 10], [50, 100]]) y_pts = breakpoints([0, 5]) # same breakpoint count but no segment dim with pytest.raises(ValueError, match="segment dimension"): - m.add_piecewise_constraints((x, x_pts), (y, y_pts)) + m.add_piecewise_formulation((x, x_pts), (y, y_pts)) def test_disjunctive_three_pairs(self) -> None: """Disjunctive with 3 pairs works (N-variable).""" @@ -1302,7 +1302,7 @@ def test_disjunctive_three_pairs(self) -> None: y = m.add_variables(name="y") z = m.add_variables(name="z") seg = segments([[0, 10], [50, 100]]) - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, seg), (y, seg), (z, seg), @@ -1326,7 +1326,7 @@ def test_disjunctive_interior_nan_raises(self) -> None: dims=[SEGMENT_DIM, BREAKPOINT_DIM], ) with pytest.raises(ValueError, match="non-trailing NaN"): - m.add_piecewise_constraints((x, x_pts), (y, y_pts)) + m.add_piecewise_formulation((x, x_pts), (y, y_pts)) def test_expression_name_fallback(self) -> None: """LinExpr (not Variable) gets numeric name in link coords.""" @@ -1334,7 +1334,7 @@ def test_expression_name_fallback(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") # Non-monotonic so auto picks SOS2 (which creates lambda vars) - m.add_piecewise_constraints( + m.add_piecewise_formulation( (1.0 * x, [0, 50, 10]), (1.0 * y, [0, 20, 5]), method="sos2", @@ -1349,7 +1349,7 @@ def test_incremental_with_nan_mask(self) -> None: y = m.add_variables(coords=[gens], name="y") x_pts = breakpoints({"a": [0, 10, 50], "b": [0, 20]}, dim="gen") y_pts = breakpoints({"a": [0, 5, 20], "b": [0, 8]}, dim="gen") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, x_pts), (y, y_pts), method="incremental", @@ -1364,7 +1364,7 @@ def test_scalar_coord_dropped(self) -> None: y = m.add_variables(name="y") bp = breakpoints([0, 10, 50]) bp_with_scalar = bp.assign_coords(extra=42) - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, bp_with_scalar), (y, [0, 5, 20]), method="sos2", From cb92dc90da87e2434532a0cde0755a01526e24e6 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:28:18 +0200 Subject: [PATCH 02/16] docs: update notebook to show PiecewiseFormulation repr Reorder cells so add_piecewise_formulation is the last statement, letting Jupyter display the PiecewiseFormulation repr automatically. Add print(m) cell to show the grouped model repr. Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/piecewise-linear-constraints.ipynb | 1570 ++++++++++++++++--- 1 file changed, 1321 insertions(+), 249 deletions(-) diff --git a/examples/piecewise-linear-constraints.ipynb b/examples/piecewise-linear-constraints.ipynb index 1c050925..be18e1c2 100644 --- a/examples/piecewise-linear-constraints.ipynb +++ b/examples/piecewise-linear-constraints.ipynb @@ -16,8 +16,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.166974Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:36.934172Z", - "start_time": "2026-04-01T11:08:36.927037Z" + "end_time": "2026-04-01T17:27:05.899439Z", + "start_time": "2026-04-01T17:27:05.021330Z" } }, "source": [ @@ -105,7 +105,7 @@ " plt.tight_layout()" ], "outputs": [], - "execution_count": null + "execution_count": 1 }, { "cell_type": "markdown", @@ -129,8 +129,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.185683Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:36.947252Z", - "start_time": "2026-04-01T11:08:36.944290Z" + "end_time": "2026-04-01T17:27:05.948816Z", + "start_time": "2026-04-01T17:27:05.906263Z" } }, "source": [ @@ -139,8 +139,17 @@ "print(\"x_pts:\", x_pts1.values)\n", "print(\"y_pts:\", y_pts1.values)" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_pts: [ 0. 30. 60. 100.]\n", + "y_pts: [ 0. 36. 84. 170.]\n" + ] + } + ], + "execution_count": 2 }, { "cell_type": "code", @@ -153,30 +162,67 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.200161Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:36.999555Z", - "start_time": "2026-04-01T11:08:36.951114Z" + "end_time": "2026-04-01T17:27:05.986206Z", + "start_time": "2026-04-01T17:27:05.952679Z" } }, - "source": [ - "m1 = linopy.Model()\n", - "\n", - "power = m1.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\n", - "fuel = m1.add_variables(name=\"fuel\", lower=0, coords=[time])\n", - "\n", - "# breakpoints are auto-broadcast to match the time dimension\n", - "m1.add_piecewise_formulation(\n", - " (power, x_pts1),\n", - " (fuel, y_pts1),\n", - " name=\"pwl\",\n", - " method=\"sos2\",\n", - ")\n", - "\n", - "demand1 = xr.DataArray([50, 80, 30], coords=[time])\n", - "m1.add_constraints(power >= demand1, name=\"demand\")\n", - "m1.add_objective(fuel.sum())" + "source": "m1 = linopy.Model()\n\npower = m1.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m1.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand1 = xr.DataArray([50, 80, 30], coords=[time])\nm1.add_constraints(power >= demand1, name=\"demand\")\nm1.add_objective(fuel.sum())\n\n# breakpoints are auto-broadcast to match the time dimension\nm1.add_piecewise_formulation(\n (power, x_pts1),\n (fuel, y_pts1),\n name=\"pwl\",\n method=\"sos2\",\n)", + "outputs": [ + { + "data": { + "text/plain": [ + "PiecewiseFormulation 'pwl' (sos2)\n", + " Variables (1):\n", + " * pwl_lambda\n", + " Constraints (2):\n", + " * pwl_convex\n", + " * pwl_x_link" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } ], - "outputs": [], - "execution_count": null + "execution_count": 3 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:27:05.990643Z", + "start_time": "2026-04-01T17:27:05.988955Z" + } + }, + "source": "print(m1)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Linopy LP model\n", + "===============\n", + "\n", + "Variables:\n", + "----------\n", + " * power (time)\n", + " * fuel (time)\n", + "\n", + "Constraints:\n", + "------------\n", + " * demand (time)\n", + "\n", + "Groups:\n", + "-------\n", + " * pwl (sos2): 1 variables, 2 constraints\n", + "\n", + "Status:\n", + "-------\n", + "initialized\n" + ] + } + ], + "execution_count": 4 }, { "cell_type": "code", @@ -189,15 +235,80 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.267514Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.057492Z", - "start_time": "2026-04-01T11:08:37.002487Z" + "end_time": "2026-04-01T17:27:06.053338Z", + "start_time": "2026-04-01T17:27:06.004296Z" } }, "source": [ "m1.solve(reformulate_sos=\"auto\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2026-12-18\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-fywnqlto.lp\n", + "Reading time = 0.00 seconds\n", + "obj: 12 rows, 18 columns, 39 nonzeros\n", + "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", + "\n", + "CPU model: Apple M3\n", + "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", + "\n", + "Optimize a model with 12 rows, 18 columns and 39 nonzeros (Min)\n", + "Model fingerprint: 0x0c548251\n", + "Model has 3 linear objective coefficients\n", + "Model has 3 SOS constraints\n", + "Variable types: 18 continuous, 0 integer (0 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 2e+02]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+00, 1e+02]\n", + " RHS range [1e+00, 8e+01]\n", + "\n", + "Presolve removed 8 rows and 13 columns\n", + "Presolve time: 0.00s\n", + "Presolved: 4 rows, 5 columns, 10 nonzeros\n", + "Variable types: 4 continuous, 1 integer (1 binary)\n", + "Found heuristic solution: objective 231.0000000\n", + "\n", + "Root relaxation: cutoff, 2 iterations, 0.00 seconds (0.00 work units)\n", + "\n", + " Nodes | Current Node | Objective Bounds | Work\n", + " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", + "\n", + " 0 0 cutoff 0 231.00000 231.00000 0.00% - 0s\n", + "\n", + "Explored 1 nodes (2 simplex iterations) in 0.00 seconds (0.00 work units)\n", + "Thread count was 8 (of 8 available processors)\n", + "\n", + "Solution count 1: 231 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 2.310000000000e+02, best bound 2.310000000000e+02, gap 0.0000%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Dual values of MILP couldn't be parsed\n" + ] + }, + { + "data": { + "text/plain": [ + "('ok', 'optimal')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 5 }, { "cell_type": "code", @@ -210,15 +321,78 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.327130Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.072609Z", - "start_time": "2026-04-01T11:08:37.068099Z" + "end_time": "2026-04-01T17:27:06.065261Z", + "start_time": "2026-04-01T17:27:06.058441Z" } }, "source": [ "m1.solution[[\"power\", \"fuel\"]].to_pandas()" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + " power fuel\n", + "time \n", + "1 50.0 68.0\n", + "2 80.0 127.0\n", + "3 30.0 36.0" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
powerfuel
time
150.068.0
280.0127.0
330.036.0
\n", + "
" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 6 }, { "cell_type": "code", @@ -231,16 +405,30 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.339680Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.172658Z", - "start_time": "2026-04-01T11:08:37.081859Z" + "end_time": "2026-04-01T17:27:06.205889Z", + "start_time": "2026-04-01T17:27:06.068279Z" } }, "source": [ "bp1 = linopy.breakpoints({\"power\": x_pts1.values, \"fuel\": y_pts1.values}, dim=\"var\")\n", "plot_pwl_results(m1, bp1, demand1, color=\"C0\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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XZdevnXrVlWsWPG0xy0QTyoYT47dR9izZ48OHDiQ6nYDoZA/f35X4yDSiikBGUr8KWnbV9LhvVLuolKZK6VobpgBAFKHWCXyrtODFnRPmDBBNWvWdJXOz2b16tVuMfEiRYqkyff2Bdz2ejlz5iSQQVj/0T169Kj27dvn9osXLx7qJgFIytoPpDkPSod2/XMsbwmp9TPSpddnupGXIUOG6I033nD9aYkSJdStWzc9+uij/v7U/nY9/vjjevXVV11/e9VVV2ncuHEqX758qJsPAGGPWCXyrtNTHXRbCvimTZv8+1u2bHFBs83PLl26tH+Yfdq0afrf//532tcvXbpUX3/9tatobvO9bX/AgAG67bbbdMEFFygtLhZ8AbcVagPCXY4cOdxH+w9t71tSzYEwDLjfvd2634THD+32Hr/p9UwVeD/zzDMugLa6LJdddplWrlyp7t27u/Q5q8linn32Wb3wwgvuOeXKldPgwYPVqlUrrV27VtmzZw/1jwAAYYtYJTKv01MddFvnawGzz8CBA93Hrl27avLkye7zt99+290Z6Ny582lfb2ni9rjdRbd52tZZW9Dte53z5ZvDbSPcQEbhe7/a+5egGwizlHIb4U4ccDt2LEqa85BU6dpMk2puBU7btWuna6+91u2XLVtWb731lpYvX+72rX8fNWqUG/m255nXX39dRYsW1axZs3TLLbeEtP0AEM6IVSLzOj3VQXfjxo1dh3smvXv3dltSrGr5smXLFGzMjUVGwvsVCFM2hzswpfw0HunQTu/zyl2tzODKK6/UK6+8og0bNqhChQr67rvv9MUXX/hXGLEMN0uNbN68uf9rbBTc6rNY9lpSQXdSBVGBYLFsy8cee0x//vknJxmOZdc+8cQT6tSpU9icEa79Mo60+F0FdckwAAAyNCualpbPywAeeughFxTbCiR2R99SIZ966il16dLFPW4Bt7GR7UC273ssMZb+RHqygPunn37ipCMBmwYTTkE3IgtBd5iw7AFbNm369On6448/9O2336p69ern/bqWxm/pfjbv/mx/iPbu3etGN3wZDfb9LYUwvS1atMhNYbDzYNUCgyU9fsbx48fr448/1ocffhi07wEgiLLnS9nzrJp5JvHuu+/qzTff1NSpU92cbus/+vfv7wqq2VSyczFo0KAE08h8S38CweAb4bYivakpfLTn4DF+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UhNwB7riX1KdXsFoEQAAQMShIg4AZEbnGnCblRNStpwYAAAAzoqgGwAym/MJuH3s6wm8AQAA0j/oXrJkidq2basSJUooKipKs2bN8j924sQJPfjgg6pSpYpy5crlnnP77bdr165dCV6jbNmy7msDtxEjRpz/TwMAkS4tAm4fAu+ItXPnTt12220qWLCgcuTI4fr1lStX+h/3eDx67LHHVLx4cfd48+bNtXHjxpC2GQCATBN0HzlyRNWqVdPYsWNPe+zo0aP65ptvNHjwYPdxxowZWr9+va6//vrTnjts2DDt3r3bv/Xr1+/cfwoAgNfCp8P79RD2/vjjD1111VXKli2bZs+erbVr1+p///ufLrjgnyr2zz77rF544QWNHz9eX3/9tbvR3qpVKx07diykbQcAIFMUUmvTpo3bkpIvXz7NnTs3wbEXX3xRderU0fbt21W6dGn/8Tx58qhYsWLn0mYAQHKaPJx2I92+10NEeeaZZ1SqVClNmjTJf6xcuXIJRrlHjRqlRx99VO3atXPHXn/9dRUtWtRlv91yyy0haTcAABE7p/vgwYMufTx//vwJjls6uaWtXXHFFXruued08uTJZF8jLi5Ohw4dSrABAJLQ6AGpySNpc2rsdez1EFE++OAD1apVSzfeeKOKFCni+ulXX33V//iWLVu0Z88el1IeeNO9bt26Wrp0aZKvST8OAIhkQQ26Lc3M5nh37txZefPm9R+/99579fbbb2vhwoW688479fTTT+uBB5K/sBs+fLjr0H2b3YEHAAQx8Cbgjlg///yzxo0bp/Lly+vTTz/V3Xff7frtKVOmuMct4DY2sh3I9n2PJUY/DgCIZEFbp9uKqt10000uDc0670ADBw70f161alXFxMS44Ns65djY2NNea9CgQQm+xka6CbwB4AzylZKis0nxJ1J/mgi4I1p8fLwb6bYb4sZGutesWePmb3ft2vWcXpN+HAAQyaKDGXBv27bNzfEOHOVOiqWkWXr51q1bk3zcAnF7jcANAJCEuMPSzLukWXd5A+78ZVJ3mgi4I55VJL/00ksTnIfKlSu72izGV49l7969CZ5j+8nVaqEfBwBEsuhgBdy2dMi8efPcvO2zWb16taKjo93cMQDAOdrzg/RKY+m7t6SoaG8Afe+3KU81J+CG5CqX28ojgTZs2KAyZcr4i6pZcD1//vwEGWhW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UvL+RWRJyXUbIkfJkiXdoM+qVavcoEXTpk3Vrl07118hHXkiWJ06dTx9+vTx7586dcpTokQJz/Dhw0ParnC3b98+GyrzLF682O0fOHDAky1bNs+0adP8z1m3bp17ztKlS0PY0vDx559/esqXL++ZO3eup1GjRp777rvPHefcndmDDz7oadCgQbKPx8fHe4oVK+Z57rnn/MfsnMbGxnreeustTyS79tprPT169EhwrEOHDp4uXbq4zzl3ybO/XTNnzvTvp+RcrV271n3dihUr/M+ZPXu2JyoqyrNz5840/M0CqXv/Aomv24ALLrjA89prr3Ei0lHEjnQfP37c3fGxFEGf6Ohot7906dKQti3cHTx40H0sUKCA+2jn0e6iBp7LSpUqqXTp0pzLv9kd52uvvTbBOeLcnd0HH3ygWrVq6cYbb3QpcldccYVeffVV/+NbtmzRnj17EpzXfPnyuakikf7/+Morr9T8+fO1YcMGt//dd9/piy++UJs2bdw+5y7lUnKu7KOllNv71ceeb/2KjYwDQLhctyGyp569/fbbLuvB0syRfrIqQv3666/ujVe0aNEEx23/p59+Clm7wl18fLybj2wpv5dffrk7ZhejMTEx7oIz8bm0xyKd/XGz6QuWXp4Y5+7Mfv75Z5cibdNAHn74YXcO7733Xvd+69q1q//9ldT/40h/7z300EM6dOiQuwGWJUsW9/fuqaeecinQhnOXcik5V/bRbgwFypo1q7vIjfT3IoDwum5D5Pnhhx9ckG1Toqz20syZM3XppZeGulkRJWKDbpz7iO2aNWvciBnObseOHbrvvvvcnCor1ofUXyzYyOHTTz/t9m2k295/Nq/Wgm4k791339Wbb76pqVOn6rLLLtPq1avdhZcVWuLcAUBk4LoNpmLFiu46wLIepk+f7q4DbO4/gXf6idj08kKFCrnRn8QVtm2/WLFiIWtXOOvbt68rDrRw4UJXlMHHzpel6x84cCDB8zmX3tR7K8xXo0YNN+plm/2Rs4JM9rmNlHHukmeVohN3CJUrV9b27dv97z3fe433XkL333+/G+2+5ZZbXMX3f/3rX65on1W15dylTkreZ/YxcRHOkydPuorm9CkAwum6DZHHMgQvueQS1axZ010HWOHF0aNHh7pZESU6kt989sazOY+Bo2q2zxyHhKwui/3htlSUBQsWuCWIAtl5tOrSgefSlqawwCjSz2WzZs1cSo/dXfRtNnJrKb6+zzl3ybN0uMTLnNgc5TJlyrjP7b1oAU3ge89Sqm0ObaS/944ePermEweyG432d85w7lIuJefKPtqNR7vR5mN/L+1829xvAAiX6zbA+qa4uDhORDqK6PRymydq6RUW+NSpU0ejRo1yhQW6d+8e6qaFXWqSpai+//77bs1H3/xEKyRk69XaR1uP1s6nzV+0NQD79evnLkLr1aunSGbnK/EcKltqyNac9h3n3CXPRmatIJill990001avny5XnnlFbcZ35rnTz75pMqXL+8uLGxtakuhtnVJI5mt2WtzuK2goaWXf/vtt3r++efVo0cP9zjnLiFbT3vTpk0JiqfZjTH7m2bn8GzvM8vAaN26tXr16uWmP1hxSbvotUwDex4QyvcvIsvZrtsQWQYNGuSKqNrfgj///NO9NxYtWqRPP/001E2LLJ4IN2bMGE/p0qU9MTExbgmxZcuWhbpJYcfeJkltkyZN8j/nr7/+8txzzz1uCYKcOXN6brjhBs/u3btD2u5wFbhkmOHcndmHH37oufzyy93yTJUqVfK88sorCR635ZwGDx7sKVq0qHtOs2bNPOvXrw/Sby/jOHTokHuf2d+37Nmzey666CLPI4884omLi/M/h3P3j4ULFyb5d65r164pPle//fabp3Pnzp7cuXN78ubN6+nevbtbLhAI9fsXkSUl122IHLZ8aJkyZVysU7hwYdd/ffbZZ6FuVsSJsn9CHfgDAAAAAJAZReycbgAAAAAAgo2gGwAAAACAICHoBgAAAAAgSAi6AQAAAAAIEoJuAAAAAACChKAbAAAAAIAgIegGAAAAACBICLoBAAAAAAgSgm4AAAAgA+rWrZvat28f6mYAOAuCbiCTdb5RUVFui4mJ0SWXXKJhw4bp5MmToW4aAABIBV9/ntw2ZMgQjR49WpMnT+a8AmEua6gbACBttW7dWpMmTVJcXJw++eQT9enTR9myZdOgQYNCeqqPHz/ubgQAAICz2717t//zd955R4899pjWr1/vP5Y7d263AQh/jHQDmUxsbKyKFSumMmXK6O6771bz5s31wQcf6I8//tDtt9+uCy64QDlz5lSbNm20ceNG9zUej0eFCxfW9OnT/a9TvXp1FS9e3L//xRdfuNc+evSo2z9w4IDuuOMO93V58+ZV06ZN9d133/mfb3fg7TVee+01lStXTtmzZ0/X8wAAQEZmfblvy5cvnxvdDjxmAXfi9PLGjRurX79+6t+/v+vvixYtqldffVVHjhxR9+7dlSdPHpcFN3v27ATfa82aNe66wF7TvuZf//qXfv311xD81EDmRNANZHI5cuRwo8zWMa9cudIF4EuXLnWB9jXXXKMTJ064jrxhw4ZatGiR+xoL0NetW6e//vpLP/30kzu2ePFi1a5d2wXs5sYbb9S+fftcx71q1SrVqFFDzZo10++//+7/3ps2bdJ7772nGTNmaPXq1SE6AwAARI4pU6aoUKFCWr58uQvA7Qa89dlXXnmlvvnmG7Vs2dIF1YE30e3G+RVXXOGuE+bMmaO9e/fqpptuCvWPAmQaBN1AJmVB9bx58/Tpp5+qdOnSLti2Ueerr75a1apV05tvvqmdO3dq1qxZ/rvjvqB7yZIlrvMNPGYfGzVq5B/1ts582rRpqlWrlsqXL6///ve/yp8/f4LRcgv2X3/9dfdaVatWDcl5AAAgklgf/+ijj7q+2aaWWaaZBeG9evVyxyxN/bffftP333/vnv/iiy+6fvrpp59WpUqV3OcTJ07UwoULtWHDhlD/OECmQNANZDIfffSRSw+zTtZSxW6++WY3yp01a1bVrVvX/7yCBQuqYsWKbkTbWEC9du1a7d+/341qW8DtC7ptNPyrr75y+8bSyA8fPuxewzenzLYtW7Zo8+bN/u9hKe6Wfg4AANJH4E3uLFmyuL66SpUq/mOWPm4sW83Xp1uAHdifW/BtAvt0AOeOQmpAJtOkSRONGzfOFS0rUaKEC7ZtlPtsrEMuUKCAC7hte+qpp9ycsWeeeUYrVqxwgbelphkLuG2+t28UPJCNdvvkypUrjX86AABwJlY8NZBNIQs8ZvsmPj7e36e3bdvW9feJBdZ2AXDuCLqBTMYCXSuSEqhy5cpu2bCvv/7aHzhbaplVQb300kv9nbClnr///vv68ccf1aBBAzd/26qgv/zyyy6N3BdE2/ztPXv2uIC+bNmyIfgpAQBAWrA+3eqvWH9u/TqAtEd6ORABbA5Xu3bt3Hwum49tqWS33XabLrzwQnfcx9LH33rrLVd13NLLoqOjXYE1m//tm89trCJ6/fr1XcXUzz77TFu3bnXp54888ogrwgIAADIGW1rUiqB27tzZZbZZSrnVg7Fq56dOnQp184BMgaAbiBC2dnfNmjV13XXXuYDZCq3ZOt6BKWcWWFsH65u7bezzxMdsVNy+1gJy65QrVKigW265Rdu2bfPPFQMAAOHPpqJ9+eWXrq+3yuY23cyWHLPpYnbzHcD5i/LYlTcAAAAAAEhz3L4CAAAAACBICLoBAAAAAAgSgm4AAAAAAIKEoBsAAAAAgCAh6AYAAAAAIEgIugEAAAAACBKCbgAAAAAAgoSgGwAAAACAICHoBgAAAAAgSAi6AQAAAAAIEoJuAAAAAACChKAbAAAAAAAFx/8Drszp20UZwFsAAAAASUVORK5CYII=" + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 7 }, { "cell_type": "markdown", @@ -264,8 +452,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.490084Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.180064Z", - "start_time": "2026-04-01T11:08:37.176417Z" + "end_time": "2026-04-01T17:27:06.210795Z", + "start_time": "2026-04-01T17:27:06.208665Z" } }, "source": [ @@ -274,8 +462,17 @@ "print(\"x_pts:\", x_pts2.values)\n", "print(\"y_pts:\", y_pts2.values)" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_pts: [ 0. 50. 100. 150.]\n", + "y_pts: [ 0. 55. 130. 225.]\n" + ] + } + ], + "execution_count": 8 }, { "cell_type": "code", @@ -288,29 +485,32 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.501307Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.578537Z", - "start_time": "2026-04-01T11:08:37.187530Z" + "end_time": "2026-04-01T17:27:06.269733Z", + "start_time": "2026-04-01T17:27:06.218536Z" } }, - "source": [ - "m2 = linopy.Model()\n", - "\n", - "power = m2.add_variables(name=\"power\", lower=0, upper=150, coords=[time])\n", - "fuel = m2.add_variables(name=\"fuel\", lower=0, coords=[time])\n", - "\n", - "m2.add_piecewise_formulation(\n", - " (power, x_pts2),\n", - " (fuel, y_pts2),\n", - " name=\"pwl\",\n", - " method=\"incremental\",\n", - ")\n", - "\n", - "demand2 = xr.DataArray([80, 120, 50], coords=[time])\n", - "m2.add_constraints(power >= demand2, name=\"demand\")\n", - "m2.add_objective(fuel.sum())" + "source": "m2 = linopy.Model()\n\npower = m2.add_variables(name=\"power\", lower=0, upper=150, coords=[time])\nfuel = m2.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand2 = xr.DataArray([80, 120, 50], coords=[time])\nm2.add_constraints(power >= demand2, name=\"demand\")\nm2.add_objective(fuel.sum())\n\nm2.add_piecewise_formulation(\n (power, x_pts2),\n (fuel, y_pts2),\n name=\"pwl\",\n method=\"incremental\",\n)", + "outputs": [ + { + "data": { + "text/plain": [ + "PiecewiseFormulation 'pwl' (incremental)\n", + " Variables (2):\n", + " * pwl_delta\n", + " * pwl_inc_binary\n", + " Constraints (4):\n", + " * pwl_inc_link\n", + " * pwl_fill\n", + " * pwl_inc_order\n", + " * pwl_x_link" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } ], - "outputs": [], - "execution_count": null + "execution_count": 9 }, { "cell_type": "code", @@ -323,15 +523,60 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.604427Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.626072Z", - "start_time": "2026-04-01T11:08:37.583238Z" + "end_time": "2026-04-01T17:27:06.317497Z", + "start_time": "2026-04-01T17:27:06.278796Z" } }, "source": [ "m2.solve(reformulate_sos=\"auto\");" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2026-12-18\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-3b6ea5d8.lp\n", + "Reading time = 0.00 seconds\n", + "obj: 30 rows, 24 columns, 69 nonzeros\n", + "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", + "\n", + "CPU model: Apple M3\n", + "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", + "\n", + "Optimize a model with 30 rows, 24 columns and 69 nonzeros (Min)\n", + "Model fingerprint: 0x31378744\n", + "Model has 3 linear objective coefficients\n", + "Variable types: 15 continuous, 9 integer (9 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 1e+02]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+00, 2e+02]\n", + " RHS range [5e+01, 1e+02]\n", + "\n", + "Presolve removed 30 rows and 24 columns\n", + "Presolve time: 0.00s\n", + "Presolve: All rows and columns removed\n", + "\n", + "Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n", + "Thread count was 1 (of 8 available processors)\n", + "\n", + "Solution count 1: 323 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 3.230000000000e+02, best bound 3.230000000000e+02, gap 0.0000%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Dual values of MILP couldn't be parsed\n" + ] + } + ], + "execution_count": 10 }, { "cell_type": "code", @@ -344,15 +589,78 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.681822Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.636391Z", - "start_time": "2026-04-01T11:08:37.631610Z" + "end_time": "2026-04-01T17:27:06.331446Z", + "start_time": "2026-04-01T17:27:06.326994Z" } }, "source": [ "m2.solution[[\"power\", \"fuel\"]].to_pandas()" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + " power fuel\n", + "time \n", + "1 80.0 100.0\n", + "2 120.0 168.0\n", + "3 50.0 55.0" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
powerfuel
time
180.0100.0
2120.0168.0
350.055.0
\n", + "
" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 11 }, { "cell_type": "code", @@ -365,16 +673,30 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.699334Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.743315Z", - "start_time": "2026-04-01T11:08:37.644492Z" + "end_time": "2026-04-01T17:27:06.406354Z", + "start_time": "2026-04-01T17:27:06.335595Z" } }, "source": [ "bp2 = linopy.breakpoints({\"power\": x_pts2.values, \"fuel\": y_pts2.values}, dim=\"var\")\n", "plot_pwl_results(m2, bp2, demand2, color=\"C1\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAFUCAYAAAA57l+/AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAYedJREFUeJzt3Qd4FFXbxvE7Cb33XlWq0qSJotKkiAiC9UVFRFQUFfG1gIBgAVE/GyJYQX3FgoKVIlJF6QrSRECkN+k1gWS/6znrLkkIkECSbf/fdQ3LzM7unplsMvOc85xzojwej0cAAAAAACDdRaf/WwIAAAAAAIJuAAAAAAAyEC3dAAAAAABkEIJuAAAAAAAyCEE3AAAAAAAZhKAbAAAAAIAMQtANAAAAAEAGIegGAAAAACCDEHQDAAAAAJBBCLoBAACAABs4cKCioqIU6uwYevbsGehiAEGFoBvIJKNHj3YXIt+SI0cOVa5c2V2Ytm/f7vaZP3++e+6VV1456fXt27d3z40aNeqk56644gqVLl3av96kSRNddNFFGXxEAAAgLdf9UqVKqVWrVnr99dd14MCBoDx5EyZMcBUAANIPQTeQyZ5++ml99NFHeuONN3TppZdqxIgRatSokQ4fPqyLL75YuXLl0uzZs0963S+//KIsWbLo559/TrI9Li5OCxYs0GWXXZaJRwEAANJy3bfr/QMPPOC29erVSzVq1NDvv//u369fv346cuRIUATdgwYNCnQxgLCSJdAFACJNmzZtVK9ePff/u+66S4ULF9bLL7+sr7/+WrfccosaNmx4UmC9atUq/fPPP/rPf/5zUkC+aNEiHT16VI0bN1YosMoFq1gAACDSrvumT58+mjZtmq655hpde+21WrlypXLmzOkq1m0BEH5o6QYCrFmzZu5x3bp17tGCZ0s3X7NmjX8fC8Lz5cunu+++2x+AJ37O97r0sHfvXj388MOqUKGCsmfPrjJlyuj222/3f6YvXe7vv/9O8roZM2a47faYPM3dKgYsBd6C7b59+7objfPOOy/Fz7dW/8Q3J+Z///uf6tat625KChUqpJtvvlkbN25Ml+MFACAQ1/7+/ftr/fr17hp3qj7dU6ZMcdf3AgUKKE+ePKpSpYq7jia/9n722Wdue4kSJZQ7d24XzCe/Tv7000+64YYbVK5cOXd9L1u2rLveJ25dv+OOOzR8+HD3/8Sp8T4JCQl67bXXXCu9pcsXLVpUrVu31sKFC086xq+++srdA9hnXXjhhZo0aVI6nkEgtFCdBgTY2rVr3aO1eCcOnq1F+4ILLvAH1pdccolrBc+aNatLNbcLqu+5vHnzqlatWudcloMHD+ryyy93te533nmnS3e3YPubb77Rpk2bVKRIkTS/565du1wtvwXKt956q4oXL+4CaAvkLS2+fv36/n3t5mPu3Ll68cUX/duee+45d2Ny4403usyAnTt3atiwYS6I/+2339yNCAAAoea2225zgfIPP/yg7t27n/T88uXLXSV1zZo1XYq6Ba9WIZ88G853rbTg+PHHH9eOHTv06quvqkWLFlq8eLGrsDZjx4512WY9evRw9xw2joxdT+36bs+Ze+65R1u2bHHBvqXEJ9etWzdX+W7XdbsmHz9+3AXzdu1OXGFu9zDjxo3Tfffd5+5RrA97p06dtGHDBv/9DhBRPAAyxahRozz2K/fjjz96du7c6dm4caPn008/9RQuXNiTM2dOz6ZNm9x++/fv98TExHi6devmf22VKlU8gwYNcv9v0KCB59FHH/U/V7RoUc9VV12V5LOuvPJKz4UXXpjmMg4YMMCVcdy4cSc9l5CQkOQ41q1bl+T56dOnu+32mLgctm3kyJFJ9t23b58ne/bsnkceeSTJ9hdeeMETFRXlWb9+vVv/+++/3bl47rnnkuy3dOlST5YsWU7aDgBAsPBdLxcsWHDKffLnz++pU6eO+/9TTz3l9vd55ZVX3LrdM5yK79pbunRpd//g8/nnn7vtr732mn/b4cOHT3r9kCFDklx3zf3335+kHD7Tpk1z2x988MFT3iMY2ydbtmyeNWvW+LctWbLEbR82bNgpjwUIZ6SXA5nMap4tHcvSuqz119LFxo8f7x993GqErVbb13fbWpotpdwGXTM2YJqvlvvPP/90Lb/plVr+5Zdfuhbz66677qTnznYaE6uZ79q1a5JtlipvteSff/65XdX92y09zlr0LfXNWC25pbJZK7edB99i6XOVKlXS9OnTz6pMAAAEA7sHONUo5r5MLhvzxa6Fp2PZY3b/4HP99derZMmSblA0H1+Ltzl06JC7ntq9hV2HLXMsNfcIdi/w1FNPnfEewe51zj//fP+63dfYtf+vv/464+cA4YigG8hk1lfK0rYsYFyxYoW7ANn0IYlZEO3ru22p5DExMS4YNXaBtD7SsbGx6d6f21Ld03uqMatMyJYt20nbb7rpJtffbM6cOf7PtuOy7T6rV692NwMWYFtFReLFUuAthQ4AgFBl3boSB8uJ2fXQKtotjdu6ZllFvVVWpxSA23UyeRBsXdQSj79iqd3WZ9vGRrFg366lV155pXtu3759ZyyrXadtyjN7/Zn4Ks8TK1iwoPbs2XPG1wLhiD7dQCZr0KDBSQOFJWdBtPWzsqDagm4bsMQukL6g2wJu6w9treE20qkvIM8Mp2rxjo+PT3F74pr1xNq1a+cGVrMbCDsme4yOjnaDvPjYjYV93sSJE13FQ3K+cwIAQKixvtQW7PrGb0np+jlr1ixXSf/999+7gcgsI8wGYbN+4CldF0/FrtFXXXWVdu/e7fp9V61a1Q24tnnzZheIn6klPa1OVbbE2W1AJCHoBoJQ4sHUrCU48RzcVstcvnx5F5DbUqdOnXSbgstSwZYtW3bafaym2jfKeWI2CFpa2MXeBoixwVtsyjS7kbBB3Oz4EpfHLtAVK1ZU5cqV0/T+AAAEM99AZcmz3RKzyujmzZu7xa6VgwcP1pNPPukCcUvhTpwZlphdO23QNUvrNkuXLnVd0j744AOXiu5jmXeprVy3a/LkyZNd4J6a1m4AJ5BeDgQhCzwt0Jw6daqbhsPXn9vH1m0qDktBT8/5uW1k0SVLlrg+5qeqnfb10bLa98Q16G+//XaaP89S52yU1Hfffdd9buLUctOxY0dXWz5o0KCTasdt3UZGBwAg1Ng83c8884y71nfu3DnFfSy4Ta527dru0TLeEvvwww+T9A3/4osvtHXrVjd+SuKW58TXUvu/Tf+VUqV4SpXrdo9gr7FrcnK0YAOnR0s3EKQsmPbVgidu6fYF3Z988ol/v5TYAGvPPvvsSdtPd4F/9NFH3YXaUrxtyjCb2ssu+jZl2MiRI90gazbXpqWz9+nTx1/b/emnn7ppQ9Lq6quvdn3Z/vvf/7obArugJ2YBvh2DfZb1S+vQoYPb3+Y0t4oBm7fcXgsAQLCyLlJ//PGHu05u377dBdzWwmxZa3Z9tfmuU2LThFkFd9u2bd2+No7Jm2++qTJlypx07bdrsW2zgUvtM2zKMEtb901FZunkdk21a6allNugZjYwWkp9rO3abx588EHXCm/XZ+tP3rRpUzfNmU3/ZS3rNj+3paXblGH2XM+ePTPk/AFhIdDDpwORIjVThyT21ltv+acBSe7XX391z9myffv2k573TdWV0tK8efPTfu6uXbs8PXv2dJ9rU36UKVPG06VLF88///zj32ft2rWeFi1auGm/ihcv7unbt69nypQpKU4Zdqapyzp37uxeZ+93Kl9++aWncePGnty5c7ulatWqbkqTVatWnfa9AQAI9HXft9g1tUSJEm6aT5vKK/EUXylNGTZ16lRP+/btPaVKlXKvtcdbbrnF8+eff540Zdgnn3zi6dOnj6dYsWJuGtK2bdsmmQbMrFixwl1r8+TJ4ylSpIine/fu/qm8rKw+x48f9zzwwANuSlKbTixxmey5F1980V2HrUy2T5s2bTyLFi3y72P72zU6ufLly7v7CSASRdk/gQ78AQAAAKTNjBkzXCuzjY9i04QBCE706QYAAAAAIIMQdAMAAAAAkEEIugEAAAAAyCD06QYAAAAAIIPQ0g0AAAAAQAYh6AYAAAAAIINkUQhKSEjQli1blDdvXkVFRQW6OAAApIrN0nngwAGVKlVK0dHUe/twXQcAhPN1PSSDbgu4y5YtG+hiAABwVjZu3KgyZcpw9v7FdR0AEM7X9ZAMuq2F23dw+fLlC3RxAABIlf3797tKY991DF5c1wEA4XxdD8mg25dSbgE3QTcAINTQNSrl88F1HQAQjtd1OpQBAAAAAJBBCLoBAAAAAMggBN0AAAAAAGSQkOzTnVrx8fE6duxYoIsBnFbWrFkVExPDWQIAAIggxCqRc5+eJVznS9u2bZv27t0b6KIAqVKgQAGVKFGCwZWAYJIQL63/RTq4XcpTXCp/qRRNBRkA4NwQq0TefXpYBt2+gLtYsWLKlSsXgQyC+o/u4cOHtWPHDrdesmTJQBcJgFnxjTTpcWn/lhPnI18pqfVQqfq1YXWOZs2apRdffFGLFi3S1q1bNX78eHXo0ME9Z9li/fr104QJE/TXX38pf/78atGihZ5//nmVKlXK/x67d+/WAw88oG+//VbR0dHq1KmTXnvtNeXJkyeARwYAwYlYJfLu07OEY5qGL+AuXLhwoIsDnFHOnDndo/1C2/eWVHMgCALuz2+3y23S7fu3erff+GFYBd6HDh1SrVq1dOedd6pjx45JnrObjV9//VX9+/d3++zZs0cPPfSQrr32Wi1cuNC/X+fOnV3APmXKFBeod+3aVXfffbfGjBkTgCMCgOBFrBKZ9+lhF3T7+nBbCzcQKnzfV/v+EnQDAU4ptxbu5AG3Y9uipElPSFXbhk2qeZs2bdySEmvZtkA6sTfeeEMNGjTQhg0bVK5cOa1cuVKTJk3SggULVK9ePbfPsGHDdPXVV+ull15K0iIOAJGOWCUy79PDLuj2OZeceyCz8X0FgoT14U6cUn4Sj7R/s3e/ipcrEu3bt8/9zbI+bmbOnDnu/76A21gKuqWZz5s3T9ddd91J7xEbG+sWn/3792dS6RFpxo4dqwEDBujAgQOBLgqCQN68efXMM8/o+uuvD3RRuPeLsPv0sA26AQBIMxs0LT33CzNHjx7V448/rltuuUX58uXz9020lLvEsmTJokKFCrnnUjJkyBANGjQoU8qMyGYB9x9//BHoYiCIWHeZYAi6EVkIuoOoo/4999yjL774wvWZ++2331S7du1zft+BAwfqq6++0uLFi8/4B2j79u16++233XqTJk3c57/66qvKbDNmzFDTpk3defC1pGSEzDjGkSNH6vvvv3eDCwEIAVlypG4/G808wlha3Y033uiuVyNGjDin9+rTp4969+6dpKW7bNmy6VBKIClfC7dlXqRpEKTTZrwgKNjglmlg404kJCSQ9YCT3HHHHW5MMIuZMgpBd5BMFWP94UaPHu0CzvPOO09FihRRZrGWCBtldunSpYok48aNc3Pvpdbff/+tihUrpqlCxAYmsjSmn376SZdfHpmpqEDIsL/53z9yhp2ivDd6dk2IwIB7/fr1mjZtmr+V29g0Kr6RXX2OHz/uRjS351KSPXt2twCZxQLuTZs2pf4FA/NnZHGQHgam4ecpqUyZMtq8eTPn/hyD0w8++CBJRlPNmjVd9pM9Z5VbSBln5lQj1756kfTBNdKX3byPtm7bM8jatWvdBeHSSy91Nyn2Rc4s7777rvvc8uXLn9P7xMXFKZTYHwrr25ORsmXLpv/85z96/fXXM/RzAJyDhARp1ovS6LbSwW1SHl9rWPI+XP+ut34+bAZRS0vAvXr1av34448nzQzSqFEj10JgU475WGBuLUoNGzYMQIkBABmldevWLmvAGqMmTpzoslNtVotrrrnGVbgiZQTdp5oqJnlakW+qmAwIvK1myOY3tZFgraN+hQoV3HZ7TJ76bC2sljLuYzc6d911l4oWLepaHpo1a6YlS5ak6fM//fRTtWvX7qTt9ovTs2dPN3qttbxbCrqlFfpY+awV9/bbb3efbdPDmNmzZ7tWXRti39IFH3zwQTcljc9HH33kBtyxgNcqGCwoTd5KknzKGhtZ97LLLnPHa7/kdp6s3FZZkCNHDl100UWaOXNmktfZuo2wa60pVqHxxBNPJPljYOnlvXr1SnI8gwcPdq3TVjYbldeXbm+sldvUqVPHfb693lh2gn1O7ty5XTq8ldNag3zs3H7zzTc6cuRIGn4qADLFwZ3S/zpK056VPAlSzZulBxZKN34k5UuWimot3GE2XZg5ePCg64Lk64a0bt0693+7JlnAbX0fbXqwjz/+2E11Y9lRtvgqWqtVq+Zuwrp376758+fr559/dteOm2++mZHLASDM2H213b+XLl1aF198sfr27auvv/7aBeCWtZua+GTgwIEupnn//ffd/XaePHl03333uWvMCy+84N7fxgp57rnnknz2yy+/rBo1arh7bosx7DV2DfOxz7d78cmTJ7trk72vr5LAxz7DujfZflaJ/NhjjyWJbzJKZATddiLjDp15ObpfmvjYaaaKsTzwx737peb9UvkDtNTup59+2qW92JfCpl1JrRtuuMEFrPZFt1YG+/I3b97cpfWlhu23YsWKJKPO+lj6iLW4202UldG+6NYqnphNB2Nzt1rKtQXl1mJvX+5OnTrp999/12effeaCcLsB87GbOAvW7ZfP+k5YEG0VDymxX9qrrrrKtZjYtDWJ+3g/+uijeuSRR9xnW0uLBbe7du1yz1n6kE1XU79+ffc51v/wvffe07PPPnva8/F///d/7lzYe9ovco8ePbRq1Sr3nJ0HYy099nOy9HQL4jt06KArr7zSHa+N4muVD4lHObT3s/1sFF8AQWTdT9LIxtJf06UsOaX2w6XrRkrZ83gD617LpC7fSZ3e8z72Whp2AbexgNoqE20xdjNi/7cBqOxvqVUaWlqu3SBZBaZv+eWXX/zvYQF51apV3fXH/vY2btw4SaUlACB8WVBt8YDdG6c2Plm7dq173rrYfvLJJ+4+vW3btu56Yw1nQ4cOVb9+/ZLcP1v6umWPLl++3MUpllVlQXPyxjqLT6yRb9asWa4C+b///W+Se30Lzi3gtxjFyjR+/PgMP0eR0af72GFpcHrME2pTxWyRnk/lYC99t0jZcp9xN2tJtpZVm/ftVP3fUmJfFAsE7Uvt6xtnXzILZG1ANl/L8+nYF9Fqd1KaR9VqkF555RUXQFapUsX1+bZ1a81I/Etmga+P1Wp17tzZ34JcqVIl98thQakFvtYqbS3JPtZ/3Z634NhqqqxGysdaUm666Sb3HmPGjHGp2olZIG/BvbH3tl9a+4W1X74333zTld/mk7Xy283gli1b3Ki7diN5qj4ndrNowbaxfe14p0+f7o7fauuM1Yr5fk72i2rT51hKzfnnn++2Wc1a8rn97GecuPUbQIDH7Jj1kjTzeW/rdpEq0o0fSMWS/u66FPIImBbMsnZOV8ufmhYA665jf6cBAGfHGmlONeNDRrH7Wat4TQ92r20NUKmNTxISElzgazFQ9erVXZq6NXRNmDDB3afbvbcF3nYf7uuqlDxD1RrT7r33Xnffn7hxzwYy9t2XW7xgjZs+lkVsg3l27NjRrdu+1jKe0SIj6A5T1oJrgWry/nWWxmy1R6nhS3m2YDi5Sy65JEmLrbUmW+2QpWX4JoZP3kJuZbJfOGv1SHzDZr9YlrJoAanVeFlaie1rI5Tbc74KAPul87EWbkvbttbylCait/L4WIu8lWXlypVu3R7t+cTlt7RvO19Wg2apLCmxwSB87LUpDRCU/EbTWulbtWrlymtz01rfx+QjpFqqvdW8AQiwA9ulcXdJ62Z512t3lq5+MVUVpAAAZBQLuEN5oDe737d759TGJxUqVEgytlLx4sXd/X7ihjHblvg+3LJNbcpJmwbQZr2wTFKbytLusa2Ry9ijL+A2dk/uew9rKLNs1cTjjfhiiIxOMY+MoDtrLm+rc2pGrv04FfP2df4idSPX2ueeA/vSJf8CWO2Nj32h7YtkfYqTS+1UW75R0i349bXkpoX1qUjMymRTn1k/7uQs0LW+3Rag2mKBuX2mBdu2nnwgNksx+fLLL136u/XfyAzJRzO3Px6+SoFTGTVqlDtea2m3CgJLhbFUeKu08LEW8bM5vwDS0V8zpC+7S4d2eP8+t31Zqn0LpxgAEHBpyXYNxs+0Bi8b/yi18UnWFO65T3cfbt1RLbPUun5aX29r+LJW9W7durkYwhd0p/QemdFn+0wiI+i21s7UtGKc38w7UI4NmpZiv+5/p4qx/TJh5FoL0hJ3/LcaHWst9rH+EVYrZjU0vsHX0spqgmyAAwtsK1eunOS55H2Q586d61K9U2p1Tlwme68LLrggxectRd36XT///PP+OVlPldZi+1i6ufUBsV/cxK3gvvJcccUV7v9W02Ut6L6+49aibgG7r9bN2OA+VqNmfefPhi+93Vr6k/P1h7R0FWthtzRLX9BttXpWC+frLwkgAOnkM4dKM1/w/m0vVl26YbRUtAo/CgBAUEivNO9AsL7Vdo//8MMPu/vsc41PUmL3+RaAW9atrzX8888/V1pYd0+rELAYJ3kMYTFMRoqMgdRSywLp1kODZqoY6y9tgwDYHM/2Re7SpUuSgNdSmS3As4G8fvjhB1cDZAPbPPnkk6n+xbUvrb2P1RQlZy3QNqCO9a+wAQ6GDRvmpgQ4HesHbWWw4NdGv7UpZmxEQ18wbK3dFrzae/31119ugB4bVO1UrA+I9RG3c2GpJIkNHz7cDXxg2++//37XWu/rL279sjdu3OhGhbfnrQxPPfWUO56znUPQRlG0NHFr0d6+fbtLUbFKEAu0bQA167NtPwc75sT9uu3nZ33XE6e6AMgkVon6YXtv0G0B98W3S3dNJeAGAOAsxMbG+lPhf/31VzfzT/v27V0rtM1olB7xSUqsQc8yfn0xhMVI1h87rSyWsYY962NuMYLFDDZwc0Yj6E7ORqa1KWGCYKoYC+ZsADL7EluqtX15Ewdu1oJrgw1YTU3Xrl1dS7VN0WLBn/WBSC0b/Mym30qeRm2/ONb/wvpVW1BrX9IzDc5mfaJtxME///zTTRvmGwHXN1Cbtd7biIFjx451Ldf2pbfA+nRsMDPrJ22Bt72vj73WFhst0SoNLID3pcvbNAZ2bmwgB3veBlmw9BNL/T5bVmNng7699dZb7njsD4ylstgvrA3oZuffzo+dK0ux97EKi8SDzwHIJGumekcn//snKVseqeO70rXDpGzn1vUHAIBIZY1P1lpsrdg2Y5ENdGb3x9bAZY2D6RWfJGf38zaTkg2uZlMFWzdV69+dVjYA9G233eYaM61ywLJgr7vuOmW0KE8wJLmnkaVZW3qAtTRaanRilsZrrY/WpyClwcHSlI5ofbwPbpfyFPf24c6kFu7MZl8BG1DAUkJuuSX4+zdajZn9fG1aL5vCJpjZlAa+ygL7zp5Kun1vAUjxx6UZg6WfXva2bhev4U0nL5Jyt5dguX5FMs4LMoqlulqLnFXG20CqqTbw1NdsBImB+zLnu5DOuOcLPaf7maX2+hUZfbrPRoRMFWOsRsrmU7UUdqQv65P/4YcfnjbgBpCO9m2WvrxL2vDvHNL17pRaDZay5uQ0AwCAgCDohmMtxsHeahyKrF8LgEyyeoo07m7pyG4pW17p2tekizpx+gEAQEARdCPkWB+SEOwVASCjxB+Tpj0j/fyad71ETW86eWEGLwQAAIFH0A0ACF17N0pfdpM2/jvFYf3uUstnpayMjQAAAIIDQTcAIDStmih91UM6skfKns87MvmFHQJdKgAAgMgIupNPfwUEM76vQBocj5OmDpLmvOFdL1VHun6UVKgipxEAAASdsAu6s2XLpujoaG3ZssXNCW3rNjo3EIysb3pcXJx27tzpvrf2fQVwGnvWS1/cKW1e6F1v2EO6apCUJTunDQAABKWwC7otcLE51GyqJgu8gVCQK1culStXzn1/AZzCyu+kr++Tju6TcuSX2r8pVbuG0wUAAMIn6B4yZIjGjRunP/74Qzlz5tSll16qoUOHqkqVKkkmD3/kkUf06aefKjY2Vq1atdKbb76p4sWL+/fZsGGDevTooenTpytPnjzq0qWLe+8sWdKnDsBaCy2AOX78uOLj49PlPYGMEhMT4777ZGQAp0knnzJAmjfCu166rjedvGB5ThkAAAh6aYpyZ86cqfvvv1/169d3AW3fvn3VsmVLrVixQrlz53b7PPzww/r+++81duxY5c+fXz179lTHjh31888/u+ctCG7btq1KlCihX375xbVI33777cqaNasGDx6cbgdmAYy9py0AgBC1529pbFdpy6/e9UY9peZPSVnoigEAAMIw6J40aVKS9dGjR6tYsWJatGiRrrjiCu3bt0/vvfeexowZo2bNmrl9Ro0apWrVqmnu3Lm65JJL9MMPP7gg/ccff3St37Vr19Yzzzyjxx9/XAMHDqRPKwDAa8U30tc9pVhLJy8gXTdSqtKGswMACE8D82fiZ+1L80vuuOMOffDBB+7/1rBpmcXWeGoNsemVsRyuzqkDqQXZplChQu7Rgu9jx46pRYsW/n2qVq3qfiBz5sxx6/ZYo0aNJOnmloK+f/9+LV++/FyKAwAIB8djpQmPSp/f5g24yzSQ7p1NwA0AQIC1bt3aZSqvXr3adSm2RtMXX3wx0MWSDUwclkG3TXHUq1cvXXbZZbrooovctm3btrmW6gIFCiTZ1wJse863T+KA2/e877mUWN9wC8oTLwCAMLRrrfTeVdL8t73rlz0kdZ0gFSgb6JIBABDxsmfP7roJly9f3o3RZY2t33zzjfbs2eNavQsWLOgGCG7Tpo0LzH2z9RQtWlRffPGF//xZtnPJkiX967Nnz3bvffjwYbe+d+9e3XXXXe51+fLlc1nUS5Ys8e9vwb69x7vvvusG0c6RI0d4Bt3Wt3vZsmVuwLSMZoOsWf9w31K2LDdfABB2lo2T3rpS2rpEyllI+s9Y6aqnpRjG5gAAIBjZ4NrWymyp5wsXLnQBuGU2W6B99dVXuyzoqKgo1xV5xowZ7jUWoK9cuVJHjhxxA3T7xg6zccMsYDc33HCDduzYoYkTJ7ps6osvvljNmzfX7t27/Z+9Zs0affnll26g78WLFyvsgm4bHO27775zo4+XKVPGv91qPeykW81EYtu3b3fP+fax9eTP+55LSZ8+fVwqu2/ZuHHj2RQbABCMjh2VvntY+qKrFHdAKtfIm05euWWgSwYAAFJgQbWN0TV58mTXldiCbWt1vvzyy1WrVi19/PHH2rx5s7766iu3f5MmTfxB96xZs1SnTp0k2+zxyiuv9Ld6z58/3w3MXa9ePVWqVEkvvfSSy6ZO3FpuceeHH37o3qtmzZrhE3TbybWAe/z48Zo2bZpryk+sbt26rlP91KlT/dtWrVrlpghr1KiRW7fHpUuXupoLnylTpri0gerVq6f4uZZqYM8nXgAAYeCfNdK7LaSF73vXG/eWunwn5S8d6JIBAIBkrOHVpny2dG5LIb/ppptcK7cNpNawYUP/foULF3bTSluLtrGA2gbT3rlzp2vVtoDbF3Rba7jNamXrxtLIDx486N7DPsu3rFu3TmvXrpWPpbhb+nkoyJLWlHIbmfzrr79W3rx5/X2wLeXbUgvssVu3burdu7cbXM2C4wceeMAF2jZyubEpxiy4vu222/TCCy+49+jXr597bwuuAQAR4vex0ne9pLiDUq4iUse3pAtODMQJAACCS9OmTTVixAg3jlepUqVcsG2t3GdSo0YNFx9awG3Lc88957Kchw4dqgULFrjA+9JLL3X7WsBt/b19reCJJR47zDdlddgF3XaCja8WwsemBbMaDvPKK68oOjpanTp1cgOg2cjkb775pn/fmJgYV0NiHe8tGLeT1aVLFz399NPpc0QAgOB27Ig08THp1w+96+UbS53elfKdGFAFAAAEH4vdLrjggiTbbHro48ePa968ef7AedeuXS7j2ZfJHBUV5VLPrfHWZqxq3Lix679t8eJbb73l0sh9QbT137aGWQvoK1SooHCQJa3p5WdiqQbDhw93y6lYKsCECRPS8tEAgHCw809pbBdpxwq7BEtXPCpd+bgUw/yeAACEIutz3b59e3Xv3t0F0JYR/cQTT6h06dJuu4813No0YxZgW7q4sQHWrP/3o48+6t/PRkS3xtkOHTq4zOjKlStry5Yt+v7773Xddde510fUPN0AAKTakk+lt5t4A+7cxaTbxkvNniTgBgAgxFnms43vdc0117iA2RprrZHVxvvysX7d8fHxSbKm7f/Jt1mruL3WAvKuXbu6oPvmm2/W+vXrT5p6OlREeVLTfB1kbJ5u6z9uI5kzqBoABLm4w9KER6XF//OuV7xC6viulDc0L5zngusX5wWZy2bZsRGUrcVt06ZNqX/hwPwZWSykh4H7Mue7kM6OHj3qBgQLhbmlceafWWqv6+TzAQAyzo4/vOnkO20eziipSR/piv9K0TGcdQAAEBEIugEAGeO3j6XvH5GOH5HyFPcOlmat3AAAABGEPt0AgPQVe1Aaf6/09X3egPu8ptK9swm4g9SsWbPUrl07N/WL9aP76quvkjxvvdAGDBjgpm+x6UFtgJvVq1cn2Wf37t3q3LmzS62z6Vxs+lCb8gUAABB0AwDS0/bl0jtNpSWfSFHRUrN+0q3jpDzFOM9B6tChQ6pVq9YpZx2xkWNff/11jRw50k0HY1O62HSg1sfNxwJumwJmypQpblpQC+TvvvvuTDwKAACCF+nlAIBzZ2Ny2rzbNv/28aNS3pJSp/ekCpdxdoNcmzZt3JISa+V+9dVX1a9fP/+0Lx9++KEbPdZaxG002ZUrV2rSpElasGCBfxqXYcOG6eqrr9ZLL73kWtABAIhkpJcDAM5N7AFpXHfp2we9AfcFLbzp5ATcIc9Ga922bZtLKfexUVobNmyoOXPmuHV7tJTyxPOm2v7R0dGuZRwAcLKEhAROSwT9rGjpBgCcvW1LpbF3SLvWSFExUvP+0qUPSdHU6YYDC7hN8nlRbd33nD0WK5a0+0CWLFlUqFAh/z7JxcbGuiXxlCsAEAmyZcvmKiW3bNmiokWLunUbTwPBx7K94uLitHPnTvczs5/V2SLoBgCczZVIWvi+NKmPFB8r5SstXf++VO4SzibOaMiQIRo0aBBnCkDEseDN5nveunWrC7wR/HLlyqVy5cq5n93ZIugGAKTN0f3eVPLl473rlVpJ142UchXiTIaZEiVKuMft27e70ct9bL127dr+fXbs2JHkdcePH3cjmvten1yfPn3Uu3fvJC3dZcuWzaCjAIDgYi2mFsTZ38r4+PhAFwenERMT47K3zjUbgaAbAJB6WxZ708n3rJOis0jNn5Ia9SSdPExZa4wFzlOnTvUH2RYgW1/tHj16uPVGjRpp7969WrRokerWreu2TZs2zfWBs77fKcmePbtbACBSWRCXNWtWtyD8EXQDAFKXTr7gXWlyXyk+TspfVrp+lFS2PmcvxNl82mvWrEkyeNrixYtdn2xrienVq5eeffZZVapUyQXh/fv3dyOSd+jQwe1frVo1tW7dWt27d3fTih07dkw9e/Z0I5szcjkAAATdAIAzObpP+uYBacXX3vUqV0vth5NOHiYWLlyopk2b+td9ad9dunTR6NGj9dhjj7m5vG3ebWvRbty4sZsiLEeOHP7XfPzxxy7Qbt68uevz1qlTJze3NwAAIOgGAJzO5l+96eR710vRWaWrnpYu6WF5cZy3MNGkSRM3QuvpUiCffvppt5yKtYqPGTMmg0oIAEBoI70cAHAyC8LmjZR+6C8lHJMKlJNuGC2V9vbZBQAAQOowkSoARIKZL0gDC3gfz+TIHumzW6VJT3gD7mrtpHt+IuAGAAA4C7R0A0C4s0B7+nPe//ser3ws5X03LZTGdpX2bZBiskktn5Ua3E06OQAAwFki6AaASAm4fVIKvC2dfM5w6cenpITjUsEK3nTyUnUyt7wAAABhhqAbACIp4E4p8D68W/rqPunPid5t1TtI174u5cifeWUFAAAIUwTdABBpAbePPb9vo7RmmrR/kxSTXWo9WKrXjXRyAACAdELQDQCRGHD7/Pqh97HQ+d508pI1M7RoAAAAkYbRywEgUgPuxC68joAbAAAgAxB0A0CkB9zmp5dSN50YAAAA0oSgGwAiPeD2sdcTeAMAAKQrgm4ACHXpEXD7EHgDAACkK4JuAAh10wcH9/sBAABEMIJuAAh1TfsG9/sBAABEMIJuAAh1Vz4mNX0yfd7L3sfeDwAAAOmCoBsAwkF6BN4E3AAAAOmOoBsAwkFCvJRw/OxfT8ANAACQIbJkzNsCADLNgW3Sl3dJf//kXS9ZS9q6JPWvJ+AGAADIMLR0A0AoWztNGtnYG3BnzS11fEe6Z1bqU80JuAEAADIULd0AEIrij0szhkg//Z8kj1T8IumG0VKRSt7nfYOhnW7+bgJuAACADEfQDQChZv8W6Ytu0oZfvOt1u0qth0hZcybd73SBNwE3AABApiDoBoBQsvpHafzd0uFdUra8UrtXpRrXn3r/lAJvAm4AAIBMQ9ANAKGSTj79WWn2K971EjW96eSFzz/za/2B92CpaV/m4QYAAMhEBN0AEOz2bfKmk2+c612v311q+ayUNUfq38MCb1/wDQAAgExD0A0AwezPydL4e6Qje6Ts+aRrh0kXdgh0qQAAAJBKBN0AEIzij0lTB0m/DPOul6wt3TBKKnReoEsGAACAjJyne9asWWrXrp1KlSqlqKgoffXVV0mev+OOO9z2xEvr1q2T7LN792517txZ+fLlU4ECBdStWzcdPHgwrUUBgPC0d4M0qs2JgLvhvVK3Hwi4AQAAIiHoPnTokGrVqqXhw4efch8Lsrdu3epfPvnkkyTPW8C9fPlyTZkyRd99950L5O++++6zOwIACCd/fC+NvFzatEDKkV+66X9Sm6FSluyBLhkAAAAyI728TZs2bjmd7Nmzq0SJEik+t3LlSk2aNEkLFixQvXr13LZhw4bp6quv1ksvveRa0AEg4hyPk358Spr7pne9dF3p+lFSwfKBLhkAAAAys6U7NWbMmKFixYqpSpUq6tGjh3bt2uV/bs6cOS6l3BdwmxYtWig6Olrz5s3LiOIAQHDb87f0fqsTAXejnlLXSQTcAAAAYSDdB1Kz1PKOHTuqYsWKWrt2rfr27etaxi3YjomJ0bZt21xAnqQQWbKoUKFC7rmUxMbGusVn//796V1sAAiMFd9IX/eUYvdJOQpIHUZIVa/mpwEAABAm0r2l++abb9a1116rGjVqqEOHDq7PtqWSW+v32RoyZIjy58/vX8qWLZuuZQaATHc8VprwqPT5bd6Au0x96d6fCLgRdOLj49W/f39XmZ4zZ06df/75euaZZ+TxePz72P8HDBigkiVLun0sg2316tUBLTcAAGGdXp7YeeedpyJFimjNmjVu3fp679ixI8k+x48fdyOan6ofeJ8+fbRv3z7/snHjxowuNgBknN1/Se+1lOa/7V2/9EGp60SpQDnOOoLO0KFDNWLECL3xxhtuXBZbf+GFF9x4LD62/vrrr2vkyJGuq1ju3LnVqlUrHT16NKBlBwAgIubp3rRpk+vTbbXfplGjRtq7d68WLVqkunXrum3Tpk1TQkKCGjZseMqB2WwBgJC3fLz0zYNS7H4pZyHpupFS5VaBLhVwSr/88ovat2+vtm3buvUKFSq4WUnmz5/vb+V+9dVX1a9fP7ef+fDDD1W8eHE3rahlwAEAEMnSHHTbfNq+Vmuzbt06LV682PXJtmXQoEHq1KmTa7W2Pt2PPfaYLrjgAlfjbapVq+b6fXfv3t3ViB87dkw9e/Z0F2VGLgcQto4dlX54Ulrwrne97CXS9e9L+UsHumTAaV166aV6++239eeff6py5cpasmSJZs+erZdfftl/H2BjslhKuY91BbOKdBvPJaWgO6PHarHBWk81Tgwii01dCwAhF3QvXLhQTZs29a/37t3bPXbp0sWln/3+++/64IMPXGu2BdEtW7Z0fb8St1R//PHHLtBu3ry5G7XcgnRLSwOAsLRrrTS2i7RtqXe9cW+p6ZNSTIYnGwHn7IknnnBBcdWqVd2AqNbH+7nnnlPnzp3d877g1lq2E7P1UwW+NlaLVdJnFPvczZs3Z9j7I/TkzZs30EUAEMHSfMfXpEmTJIOnJDd58uQzvoe1iI8ZMyatHw0AoWfpF9K3D0lxB6VchaWOb0sXnGgRBILd559/7irL7bp94YUXuuy2Xr16uYp1q3A/GzZWi6/S3lhQn56DpJ5qjJgz2r8l3cqADJKv1FkF3NYABACBQjMLAGSEY0ekSU9Ii0Z718tfJnV696xuGIFAevTRR11rty9N3GYnWb9+vWuttqDbF+Bu377dP36Lb7127doBGavFsvLOysD86V0UpLeBmzinAEJOho9eDgAR55/V0rst/g24o6QrHpVu/4aAGyHp8OHDritYYpZmbgOgGptKzALvqVOnJmm5tlHMbfBUAAAiHS3dAJCelnwmffewdOyQlLuo1PEd6fwT42AAoaZdu3auD3e5cuVcevlvv/3mBlG788473fNRUVEu3fzZZ59VpUqVXBBu83pb+nmHDh0CXXwAAAKOoBsA0kPcYWnio9Jv//OuV7jcm06e9yz7lgJBwubjtiD6vvvu044dO1wwfc8992jAgAH+fWymkkOHDunuu+92A6k2btxYkyZNUo4cOQJadgAAggFBNwCcqx1/SGPvkHau9KaTN3nCm1IeHcO5RcizQahsHm5bTsVau59++mm3AACApAi6AeBc/PaxNOG/0rHDUp7i3tbtildwTgEAAOAQdAPA2Yg7JH3/iLTkE+/6eU28/bfzFON8AgAAwI+gGwDSavsKaWwX6Z8/pahoqUlf6fLepJMDAADgJATdAJBaHo/020fShMek40ekvCW96eQVGnMOAQAAkCKCbgBIjdiD3qnAln7uXT+/udTxbSl3Ec4fAAAATomgGwASS4iX1v8iHdzuHRit/KXSjpXedPJda6SoGKlZP+myXlJ0NOcOAAAAp0XQDQA+K76RJj0u7d9y4pzkKCDFHZQSjkv5Skud3pPKN+KcAQAAIFUIugHAF3B/frt13E56Po7u9T6WrC3dOk7KXZjzBQAAgFQjNxIALKXcWriTB9yJHdop5SzAuQIAAECaEHQDgPXhTpxSnpL9m719vQEAAIA0IOgGgDMF3D42uBoAAACQBgTdACLbup+k6c+lbl8bzRwAAABIAwZSAxCZ9m2SfugnLR//74ao0/TpjpLylfJOHwYAAACkAUE3gMhy7Kg0Z5j008vSscNSVLRU706pdF3pq/v+3Slx8G3BuKTWz0vRMYEoMQAAAEIYQTeAyODxSKsmSpP7SHv+9m4rd6l09QtSiRre9Wx5Tp6n21q4LeCufm1gyg0AAICQRtANIPz9s8YbTK/50buet6TU8lnpok5S1L8t2cYC66ptvaOU26Bp1ofbUspp4QYAAMBZIugGEL5iD0izXpTmvCklHJOis0qX9pQu/6+UPU/Kr7EAu+LlmV1SAAAAhCmCbgDhmUq+dKz0Q3/p4DbvtkotvWnihc8PdOmAc7Ju3TpVrFiRswgAQIgg6AYQXrYukSY8Jm2c610vWNEbbFdpHeiSAeni/PPPV/ny5dW0aVP/UqZMGc4uAABBiqAbQHg4vFua9oy0aLTkSZCy5pIuf0Rq1FPKmiPQpQPSzbRp0zRjxgy3fPLJJ4qLi9N5552nZs2a+YPw4sWZUx4AgGBB0A0gtCXES4tGSdOelY7s8W67sKPU8hkpP61/CD9NmjRxizl69Kh++eUXfxD+wQcf6NixY6pataqWL18e6KICAACCbgAhbf0caeKj0ral3vViF3qnAKvQONAlAzJFjhw5XAt348aNXQv3xIkT9dZbb+mPP/7gJwAAQJCgpRtA6Nm/VZoyQFr6uXc9R36paT+p3p1SDH/WEP4spXzu3LmaPn26a+GeN2+eypYtqyuuuEJvvPGGrrzyykAXEQAA/Iu7UwCh43icNPdN7zRgcQclRUkX3y41HyDlLhLo0gGZwlq2Lci2EcwtuL7nnns0ZswYlSxZkp8AAABBiKAbQGhYPUWa9IS0a413vUx9qc0LUumLA10yIFP99NNPLsC24Nv6dlvgXbhwYX4KAAAEqehAFwAATmv3X9KYm6WPr/cG3LmLSR1GSnf+QMCNiLR37169/fbbypUrl4YOHapSpUqpRo0a6tmzp7744gvt3Lkz0EUEAACJ0NINIDjFHZJ+eln6ZZgUHytFZ5Ea3itd+biUI1+gSwcETO7cudW6dWu3mAMHDmj27Nmuf/cLL7ygzp07q1KlSlq2bBk/JQAAggBBN4Dg4vFIy8dLP/SX9m/ybjuvqdRmqFS0SqBLBwRlEF6oUCG3FCxYUFmyZNHKlSsDXSwAAPAvgm4AwWP7cmni49LfP3nXC5STWg2Wql4jRUUFunRAUEhISNDChQvdqOXWuv3zzz/r0KFDKl26tJs2bPjw4e4RAAAEB/p0Awi8I3ulCY9JIy/3BtxZckhN+kj3z5eqtSPgBhIpUKCAGjVqpNdee80NoPbKK6/ozz//1IYNG/TBBx/ojjvuUPny5dP1nG3evFm33nqr+7ycOXO6PuQW+Pt4PB4NGDDADfBmz7do0UKrV6/m5wYAAC3dANLFzBek6YOlpn2lKx9L/esSEqTfPpKmDpIO7/Juq3at1PJZqWD6Bg1AuHjxxRddS3blypUz5fP27Nmjyy67zH3mxIkTVbRoURdQWyq7j/Ulf/31113Qb1OZ9e/fX61atdKKFSuUI0eOTCknAADBivRyAOkQcD/n/b/vMTWB96aF0oT/Slt+864XqeLtt30+abHA6dgc3bacyfvvv58uJ9JGSC9btqxGjRrl32aBdeJW7ldffVX9+vVT+/bt3bYPP/xQxYsX11dffaWbb745XcoBAECoIr0cQPoE3D62bttP5eAO6av7pHebewPu7Pm8/bZ7/EzADaTC6NGjXV9umzrMWqFPtaSXb775RvXq1dMNN9ygYsWKqU6dOnrnnXf8z69bt07btm1zKeU++fPnV8OGDTVnzhx+pgCAiEdLN4D0C7h9Umrxjj8mzX9bmvG8FLvfu612Z6nFQClPMX4KQCr16NFDn3zyiQt2u3bt6vpa28jlGeWvv/7SiBEj1Lt3b/Xt21cLFizQgw8+qGzZsqlLly4u4DbWsp2YrfueSy42NtYtPvv3//s3AQCAMERLN4D0DbhTavFeO10acZk0ua834C5VR+r2o9ThTQJuII1sdPKtW7fqscce07fffutSv2+88UZNnjzZpXpnxGjpF198sQYPHuxaue+++251795dI0eOPOv3HDJkiGsN9y12DAAAhCuCbgDpH3D72H5vNJA+6iD9s0rKVUS6dph01zSpbH3OPHCWsmfPrltuuUVTpkxxg5VdeOGFuu+++1ShQgUdPHgwXc+rjUhevXr1JNuqVavmRks3JUqUcI/bt29Pso+t+55Lrk+fPtq3b59/2bhxY7qWGQCAkA66Z82apXbt2qlUqVKKiopyg6QklpppQ3bv3q3OnTsrX758buqTbt26pftNAoAAB9w+FmwrSmp4r/TAIuni26Vo6vuA9BIdHe2ux3b9jY+PT/cTayOXr1plv8cn2BRlvmnJbFA1C66nTp2aJF3cBnuzqc1OVWlg9wCJFwAAwlWa73wPHTqkWrVqufS2lPimDbG0M7vg5s6d200bcvToUf8+FnAvX77c1dB/9913LpC3dDUAYRZw+3mkXIWlnAXSuVBAZLL+0Nav+6qrrnJThy1dulRvvPGGa33OkydPun7Www8/rLlz57r08jVr1mjMmDF6++23df/997vnLeDv1auXnn32WTfompXl9ttvd5XzHTp0SNeyAAAQEQOptWnTxi0pSc20IStXrtSkSZPcQCw2GqoZNmyYrr76ar300kvuIg0gnAJupX06MQCnZGnkn376qesHfeedd7rgu0iRIhl2xurXr6/x48e7lPCnn37atWzbtd4q0H2sf7lVylsFuo2q3rhxY3etZ45uAADSeZ7uM00bYkG3PVpKuS/gNra/pcdZy/h111130vsyyikQ4gG3D4E3cM4sk6xcuXI677zzNHPmTLekZNy4cel2tq+55hq3nIq1dltAbgsAAMjAoDs104bYo83zmaQQWbK46U5ONbWIjXI6aNCg9CwqgNSaPjj934/WbuCsWeq2BbkAACA0hMQ83ZbSZvODJh6ghelFgEzStG/6tXT73g/AWRs9ejRnDwCAEJKuQwinZtoQ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" + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 12 }, { "cell_type": "markdown", @@ -403,8 +725,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.852387Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.762965Z", - "start_time": "2026-04-01T11:08:37.758436Z" + "end_time": "2026-04-01T17:27:06.418987Z", + "start_time": "2026-04-01T17:27:06.416214Z" } }, "source": [ @@ -415,8 +737,25 @@ "print(\"x segments:\\n\", x_seg.to_pandas())\n", "print(\"y segments:\\n\", y_seg.to_pandas())" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x segments:\n", + " _breakpoint 0 1\n", + "_segment \n", + "0 0.0 0.0\n", + "1 50.0 80.0\n", + "y segments:\n", + " _breakpoint 0 1\n", + "_segment \n", + "0 0.0 0.0\n", + "1 125.0 200.0\n" + ] + } + ], + "execution_count": 13 }, { "cell_type": "code", @@ -429,29 +768,32 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.866931Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.845482Z", - "start_time": "2026-04-01T11:08:37.775373Z" + "end_time": "2026-04-01T17:27:06.470016Z", + "start_time": "2026-04-01T17:27:06.421487Z" } }, - "source": [ - "m3 = linopy.Model()\n", - "\n", - "power = m3.add_variables(name=\"power\", lower=0, upper=80, coords=[time])\n", - "cost = m3.add_variables(name=\"cost\", lower=0, coords=[time])\n", - "backup = m3.add_variables(name=\"backup\", lower=0, coords=[time])\n", - "\n", - "m3.add_piecewise_formulation(\n", - " (power, x_seg),\n", - " (cost, y_seg),\n", - " name=\"pwl\",\n", - ")\n", - "\n", - "demand3 = xr.DataArray([10, 70, 90], coords=[time])\n", - "m3.add_constraints(power + backup >= demand3, name=\"demand\")\n", - "m3.add_objective((cost + 10 * backup).sum())" + "source": "m3 = linopy.Model()\n\npower = m3.add_variables(name=\"power\", lower=0, upper=80, coords=[time])\ncost = m3.add_variables(name=\"cost\", lower=0, coords=[time])\nbackup = m3.add_variables(name=\"backup\", lower=0, coords=[time])\n\ndemand3 = xr.DataArray([10, 70, 90], coords=[time])\nm3.add_constraints(power + backup >= demand3, name=\"demand\")\nm3.add_objective((cost + 10 * backup).sum())\n\nm3.add_piecewise_formulation(\n (power, x_seg),\n (cost, y_seg),\n name=\"pwl\",\n)", + "outputs": [ + { + "data": { + "text/plain": [ + "PiecewiseFormulation 'pwl' (sos2)\n", + " Variables (2):\n", + " * pwl_binary\n", + " * pwl_lambda\n", + " Constraints (4):\n", + " * pwl_select\n", + " * pwl_convex\n", + " * pwl_x_link\n", + " * pwl_y_link" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } ], - "outputs": [], - "execution_count": null + "execution_count": 14 }, { "cell_type": "code", @@ -464,15 +806,75 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.955741Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.920203Z", - "start_time": "2026-04-01T11:08:37.848081Z" + "end_time": "2026-04-01T17:27:06.522256Z", + "start_time": "2026-04-01T17:27:06.479790Z" } }, "source": [ "m3.solve(reformulate_sos=\"auto\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2026-12-18\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-x2n7iuy8.lp\n", + "Reading time = 0.00 seconds\n", + "obj: 18 rows, 27 columns, 48 nonzeros\n", + "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", + "\n", + "CPU model: Apple M3\n", + "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", + "\n", + "Optimize a model with 18 rows, 27 columns and 48 nonzeros (Min)\n", + "Model fingerprint: 0xf675751b\n", + "Model has 6 linear objective coefficients\n", + "Model has 6 SOS constraints\n", + "Variable types: 21 continuous, 6 integer (6 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 2e+02]\n", + " Objective range [1e+00, 1e+01]\n", + " Bounds range [1e+00, 8e+01]\n", + " RHS range [1e+00, 9e+01]\n", + "\n", + "Presolve removed 15 rows and 22 columns\n", + "Presolve time: 0.00s\n", + "Presolved: 3 rows, 5 columns, 8 nonzeros\n", + "Variable types: 4 continuous, 1 integer (1 binary)\n", + "Found heuristic solution: objective 575.0000000\n", + "\n", + "Root relaxation: cutoff, 0 iterations, 0.00 seconds (0.00 work units)\n", + "\n", + "Explored 1 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n", + "Thread count was 8 (of 8 available processors)\n", + "\n", + "Solution count 1: 575 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 5.750000000000e+02, best bound 5.750000000000e+02, gap 0.0000%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Dual values of MILP couldn't be parsed\n" + ] + }, + { + "data": { + "text/plain": [ + "('ok', 'optimal')" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 15 }, { "cell_type": "code", @@ -485,15 +887,83 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.028095Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.935150Z", - "start_time": "2026-04-01T11:08:37.929245Z" + "end_time": "2026-04-01T17:27:06.533424Z", + "start_time": "2026-04-01T17:27:06.529179Z" } }, "source": [ "m3.solution[[\"power\", \"cost\", \"backup\"]].to_pandas()" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + " power cost backup\n", + "time \n", + "1 0.0 0.0 10.0\n", + "2 70.0 175.0 0.0\n", + "3 80.0 200.0 10.0" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
powercostbackup
time
10.00.010.0
270.0175.00.0
380.0200.010.0
\n", + "
" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 16 }, { "cell_type": "markdown", @@ -892,8 +1362,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.043484Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:37.974567Z", - "start_time": "2026-04-01T11:08:37.947618Z" + "end_time": "2026-04-01T17:27:06.558621Z", + "start_time": "2026-04-01T17:27:06.537791Z" } }, "source": [ @@ -916,7 +1386,7 @@ "m4.add_objective(-fuel.sum())" ], "outputs": [], - "execution_count": null + "execution_count": 17 }, { "cell_type": "code", @@ -929,15 +1399,59 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.113810Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.006772Z", - "start_time": "2026-04-01T11:08:37.980912Z" + "end_time": "2026-04-01T17:27:06.585861Z", + "start_time": "2026-04-01T17:27:06.561038Z" } }, "source": [ "m4.solve(reformulate_sos=\"auto\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2026-12-18\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-46j_zrn6.lp\n", + "Reading time = 0.00 seconds\n", + "obj: 12 rows, 6 columns, 21 nonzeros\n", + "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", + "\n", + "CPU model: Apple M3\n", + "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", + "\n", + "Optimize a model with 12 rows, 6 columns and 21 nonzeros (Min)\n", + "Model fingerprint: 0x0a213b23\n", + "Model has 3 linear objective coefficients\n", + "Coefficient statistics:\n", + " Matrix range [8e-01, 1e+00]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+02, 1e+02]\n", + " RHS range [1e+01, 1e+02]\n", + "\n", + "Presolve removed 12 rows and 6 columns\n", + "Presolve time: 0.00s\n", + "Presolve: All rows and columns removed\n", + "Iteration Objective Primal Inf. Dual Inf. Time\n", + " 0 -2.3250000e+02 0.000000e+00 0.000000e+00 0s\n", + "\n", + "Solved in 0 iterations and 0.00 seconds (0.00 work units)\n", + "Optimal objective -2.325000000e+02\n" + ] + }, + { + "data": { + "text/plain": [ + "('ok', 'optimal')" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 18 }, { "cell_type": "code", @@ -950,15 +1464,78 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.171993Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.016635Z", - "start_time": "2026-04-01T11:08:38.012572Z" + "end_time": "2026-04-01T17:27:06.600907Z", + "start_time": "2026-04-01T17:27:06.597269Z" } }, "source": [ "m4.solution[[\"power\", \"fuel\"]].to_pandas()" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + " power fuel\n", + "time \n", + "1 30.0 37.5\n", + "2 80.0 90.0\n", + "3 100.0 105.0" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
powerfuel
time
130.037.5
280.090.0
3100.0105.0
\n", + "
" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 19 }, { "cell_type": "code", @@ -971,16 +1548,30 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.192590Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.127204Z", - "start_time": "2026-04-01T11:08:38.036942Z" + "end_time": "2026-04-01T17:27:06.678383Z", + "start_time": "2026-04-01T17:27:06.605130Z" } }, "source": [ "bp4 = linopy.breakpoints({\"power\": x_pts4.values, \"fuel\": y_pts4.values}, dim=\"var\")\n", "plot_pwl_results(m4, bp4, demand4, color=\"C4\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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i18s3T1Duv0/BNxAGLKe7SJFiujhhx/Wjh079OCDD+qXX37R2rVrNW7cON19990qV47GOAAAQjbo3rt3r6666irlypXLpbmtWrVK//73v90Ngs/w4cP1yiuvaMyYMa51Pl++fGrRooUbmwbgLwe3Sx90ld5sLm1dKcUW9I7b7vqNVKkJlwkIU1999ZVr1Lbgu1mzZrr22mtdIzYAAAiT9PJhw4a5FLfx48cnH/NfT9R6uV966SU99dRTatu2rTs2adIkN9PqjBkzdMcdd2R2kYDgknhcWjxWWjBMOnbAe6xmB6n501L+EoEuHYAA27dvnwu8La3c6tw777xTF110kUsptwnW7Ot5550X6GICAICs6un+6KOPVKdOHd16660qUaKEatWq5dLdfDZs2KBt27a5lHKfQoUKqV69eoqPj8/s4gDB5Zd50uirpM+f9AbcpS+XHpgjtXuNgBuAY9lhLVu21PPPP++yxXbt2uUyyPLmzeu+2prdl156KVcLAIBQ7en+9ddfNXr0aPXq1Uv9+vXT0qVL1aNHD8XExOjee+91AbdJvYao7fseS+3YsWNu8zlw4K/ePyBU7N3oDbRXf+zdz1tcaj5QqnmXFJklUy8ACKEgvGjRom6zoVzR0dFavXp1oIsFAACyKuhOSkpyPd1Dhgxx+9bT/eOPP7rx2xZ0n42hQ4dq0KBBmVxSIAc4/qf0zcvS1y9KJ45KEVHSFZ2la/pKeQoHunQAciCrZ21yUksvt9nLv/nmGx0+fFjnn3++WzZs1KhR7isAAAjRoNsmc6lWrVqKY1WrVtW0adPc93Fxce7r9u3bU0z8Yvs1a9ZM8zX79u3res79e7pt3DgQtDweb6/2Z09K+3/3HqtwtdRqmFTykkCXDkAOVrhwYRdkW31qwfWLL77oxnJXqlQp0EUDAADZEXTbzOW2bIm/devWqXz58smTqtmNwpw5c5KDbAuibVxa165d03zN2NhYtwEhYedaaWZv6df53v2C50vXPSddcpMUERHo0gHI4V544QUXbNvkaQAAIAyD7scee0wNGjRw6eW33XablixZotdff91tJiIiQj179tRzzz2nypUruyC8f//+Kl26tNq1a5fZxQFyjqMHvDOSLx4jJZ2QomKkBj2kq3tJMfkCXToAQcIaqW07k7feeitbygMAALI56K5bt64++OADlxL+zDPP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" + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 20 }, { "cell_type": "markdown", @@ -1004,8 +1595,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.345513Z" }, "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.135897Z", - "start_time": "2026-04-01T11:08:38.133078Z" + "end_time": "2026-04-01T17:27:06.688859Z", + "start_time": "2026-04-01T17:27:06.686556Z" } }, "source": [ @@ -1014,8 +1605,16 @@ "y_pts5 = linopy.breakpoints(slopes=[1.1, 1.5, 1.9], x_points=[0, 50, 100, 150], y0=0)\n", "print(\"y breakpoints from slopes:\", y_pts5.values)" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "y breakpoints from slopes: [ 0. 55. 130. 225.]\n" + ] + } + ], + "execution_count": 21 }, { "cell_type": "markdown", @@ -1934,8 +2533,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.148433Z", - "start_time": "2026-04-01T11:08:38.145204Z" + "end_time": "2026-04-01T17:27:06.699522Z", + "start_time": "2026-04-01T17:27:06.697229Z" } }, "source": [ @@ -1949,88 +2548,245 @@ "print(\"Power breakpoints:\", x_pts6.values)\n", "print(\"Fuel breakpoints: \", y_pts6.values)" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Power breakpoints: [ 30. 60. 100.]\n", + "Fuel breakpoints: [ 40. 90. 170.]\n" + ] + } + ], + "execution_count": 22 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.256777Z", - "start_time": "2026-04-01T11:08:38.161249Z" + "end_time": "2026-04-01T17:27:06.775344Z", + "start_time": "2026-04-01T17:27:06.707055Z" } }, - "source": [ - "m6 = linopy.Model()\n", - "\n", - "power = m6.add_variables(name=\"power\", lower=0, upper=p_max, coords=[time])\n", - "fuel = m6.add_variables(name=\"fuel\", lower=0, coords=[time])\n", - "commit = m6.add_variables(name=\"commit\", binary=True, coords=[time])\n", - "\n", - "# The active parameter gates the PWL with the commitment binary:\n", - "# - commit=1: power in [30, 100], fuel = f(power)\n", - "# - commit=0: power = 0, fuel = 0\n", - "m6.add_piecewise_formulation(\n", - " (power, x_pts6),\n", - " (fuel, y_pts6),\n", - " active=commit,\n", - " name=\"pwl\",\n", - " method=\"incremental\",\n", - ")\n", - "\n", - "# Demand: low at t=1 (cheaper to stay off), high at t=2,3\n", - "demand6 = xr.DataArray([15, 70, 50], coords=[time])\n", - "backup = m6.add_variables(name=\"backup\", lower=0, coords=[time])\n", - "m6.add_constraints(power + backup >= demand6, name=\"demand\")\n", - "\n", - "# Objective: fuel + startup cost + backup at $5/MW\n", - "m6.add_objective((fuel + startup_cost * commit + 5 * backup).sum())" + "source": "m6 = linopy.Model()\n\npower = m6.add_variables(name=\"power\", lower=0, upper=p_max, coords=[time])\nfuel = m6.add_variables(name=\"fuel\", lower=0, coords=[time])\ncommit = m6.add_variables(name=\"commit\", binary=True, coords=[time])\n\n# Demand: low at t=1 (cheaper to stay off), high at t=2,3\ndemand6 = xr.DataArray([15, 70, 50], coords=[time])\nbackup = m6.add_variables(name=\"backup\", lower=0, coords=[time])\nm6.add_constraints(power + backup >= demand6, name=\"demand\")\n\n# Objective: fuel + startup cost + backup at /MW\nm6.add_objective((fuel + startup_cost * commit + 5 * backup).sum())\n\n# The active parameter gates the PWL with the commitment binary:\n# - commit=1: power in [30, 100], fuel = f(power)\n# - commit=0: power = 0, fuel = 0\nm6.add_piecewise_formulation(\n (power, x_pts6),\n (fuel, y_pts6),\n active=commit,\n name=\"pwl\",\n method=\"incremental\",\n)", + "outputs": [ + { + "data": { + "text/plain": [ + "PiecewiseFormulation 'pwl' (incremental)\n", + " Variables (2):\n", + " * pwl_delta\n", + " * pwl_inc_binary\n", + " Constraints (5):\n", + " * pwl_active_bound\n", + " * pwl_inc_link\n", + " * pwl_fill\n", + " * pwl_inc_order\n", + " * pwl_x_link" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } ], - "outputs": [], - "execution_count": null + "execution_count": 23 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.332350Z", - "start_time": "2026-04-01T11:08:38.263473Z" + "end_time": "2026-04-01T17:27:06.834804Z", + "start_time": "2026-04-01T17:27:06.783525Z" } }, "source": [ "m6.solve(reformulate_sos=\"auto\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2026-12-18\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-tcp1bwlk.lp\n", + "Reading time = 0.00 seconds\n", + "obj: 27 rows, 24 columns, 66 nonzeros\n", + "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", + "\n", + "CPU model: Apple M3\n", + "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", + "\n", + "Optimize a model with 27 rows, 24 columns and 66 nonzeros (Min)\n", + "Model fingerprint: 0x9cac1f29\n", + "Model has 9 linear objective coefficients\n", + "Variable types: 15 continuous, 9 integer (9 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 8e+01]\n", + " Objective range [1e+00, 5e+01]\n", + " Bounds range [1e+00, 1e+02]\n", + " RHS range [2e+01, 7e+01]\n", + "\n", + "Found heuristic solution: objective 675.0000000\n", + "Presolve removed 24 rows and 19 columns\n", + "Presolve time: 0.00s\n", + "Presolved: 3 rows, 5 columns, 10 nonzeros\n", + "Found heuristic solution: objective 485.0000000\n", + "Variable types: 3 continuous, 2 integer (2 binary)\n", + "\n", + "Root relaxation: objective 3.516667e+02, 2 iterations, 0.00 seconds (0.00 work units)\n", + "\n", + " Nodes | Current Node | Objective Bounds | Work\n", + " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", + "\n", + " 0 0 351.66667 0 1 485.00000 351.66667 27.5% - 0s\n", + "* 0 0 0 358.3333333 358.33333 0.00% - 0s\n", + "\n", + "Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n", + "Thread count was 8 (of 8 available processors)\n", + "\n", + "Solution count 3: 358.333 485 675 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 3.583333333333e+02, best bound 3.583333333333e+02, gap 0.0000%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Dual values of MILP couldn't be parsed\n" + ] + }, + { + "data": { + "text/plain": [ + "('ok', 'optimal')" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 24 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.341128Z", - "start_time": "2026-04-01T11:08:38.336172Z" + "end_time": "2026-04-01T17:27:06.843069Z", + "start_time": "2026-04-01T17:27:06.837926Z" } }, "source": [ "m6.solution[[\"commit\", \"power\", \"fuel\", \"backup\"]].to_pandas()" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + " commit power fuel backup\n", + "time \n", + "1 0.0 0.0 0.000000 15.0\n", + "2 1.0 70.0 110.000000 0.0\n", + "3 1.0 50.0 73.333333 0.0" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
commitpowerfuelbackup
time
10.00.00.00000015.0
21.070.0110.0000000.0
31.050.073.3333330.0
\n", + "
" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 25 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.440499Z", - "start_time": "2026-04-01T11:08:38.353813Z" + "end_time": "2026-04-01T17:27:06.924865Z", + "start_time": "2026-04-01T17:27:06.847612Z" } }, "source": [ "bp6 = linopy.breakpoints({\"power\": x_pts6.values, \"fuel\": y_pts6.values}, dim=\"var\")\n", "plot_pwl_results(m6, bp6, demand6, color=\"C2\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAFUCAYAAAA57l+/AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAYqZJREFUeJzt3Qd4VNXWxvE3ofcOoTepCqigCIJUBVSkXSsqIhcboGBDVEBQQdErKtUK+CmiKF0BESkqHURBioA06YL0HvI9aw8zTkICCWQyk8z/9zxjOGfOTE5Oxuyz9l577YiYmJgYAQAAAACAZBeZ/G8JAAAAAAAIugEAAAAACCBGugEAAAAACBCCbgAAAAAAAoSgGwAAAACAACHoBgAAAAAgQAi6AQAAAAAIEIJuAAAAAAAChKAbAAAAAIAAIegGAAAAguSll15SREREqr/+9jN07tw52KcBhCSCbiCFjRw50jVM3kfmzJlVvnx511Dt2rXLHbNo0SL33MCBA895fYsWLdxzI0aMOOe5G264QUWLFvVt169fX1dccUWAfyIAAHC+dr5IkSJq0qSJ3n33XR06dCgkL9a3337rOgAAJD+CbiBI+vbtq//7v//T4MGDVbt2bQ0bNky1atXS0aNHdfXVVytr1qz66aefznndvHnzlD59ev3888+x9p88eVKLFy/W9ddfn4I/BQAAOF87b+17ly5d3L6uXbuqSpUq+u2333zHvfjiizp27FhIBN19+vQJ9mkAaVL6YJ8AEK6aNWumGjVquH//97//Vb58+fTWW29p4sSJuvvuu1WzZs1zAuu1a9fq77//1j333HNOQL506VIdP35cderUUWpgnQvWsQAAQFpv502PHj30ww8/6NZbb9Vtt92m1atXK0uWLK4j3R4A0i5GuoEQ0bBhQ/d148aN7qsFz5Zuvn79et8xFoTnzJlTDz30kC8A93/O+7rksH//fnXr1k2lSpVSpkyZVKxYMd1///2+7+lNn9u0aVOs182ePdvtt69x09ytY8BS4C3Yfv75592NR5kyZeL9/jbq73+zYj799FNVr17d3aTkzZtXd911l7Zu3ZosPy8AACnR1vfs2VObN292bVpCc7pnzJjh2vPcuXMre/bsqlChgms347a1X3zxhdsfFRWlbNmyuWA+brv4448/6vbbb1eJEiVce168eHHXvvuPrj/wwAMaMmSI+7d/arzXmTNn9M4777hRekuXL1CggJo2baolS5ac8zNOmDDBtfn2vS6//HJNmzYtGa8gkDrRrQaEiA0bNrivNuLtHzzbiPZll13mC6yvu+46NwqeIUMGl2puDaz3uRw5cqhatWqXfC6HDx9W3bp1XS/8gw8+6NLdLdieNGmS/vrrL+XPnz/J77l3717X62+B8r333qtChQq5ANoCeUuLv+aaa3zH2s3IggUL9MYbb/j2vfrqq+5G5Y477nCZAXv27NGgQYNcEP/LL7+4GxMAAELdfffd5wLl7777Th07djzn+d9//911SletWtWlqFvwah3wcbPfvG2jBcfdu3fX7t279fbbb6tx48Zavny566A2Y8eOddlljz76qLvHsLox1n5ae27PmYcffljbt293wb6lxMfVoUMH19lu7bi1wadPn3bBvLXV/h3kds8ybtw4PfbYY+6exOawt2nTRlu2bPHd3wBhKQZAihoxYkSM/a/3/fffx+zZsydm69atMWPGjInJly9fTJYsWWL++usvd9zBgwdj0qVLF9OhQwffaytUqBDTp08f9+9rr7025plnnvE9V6BAgZgbb7wx1veqV69ezOWXX57kc+zVq5c7x3Hjxp3z3JkzZ2L9HBs3boz1/KxZs9x+++p/HrZv+PDhsY49cOBATKZMmWKeeuqpWPsHDBgQExEREbN582a3vWnTJnctXn311VjHrVixIiZ9+vTn7AcAIFi87ePixYsTPCZXrlwxV111lft379693fFeAwcOdNt2j5AQb1tbtGhRd7/g9eWXX7r977zzjm/f0aNHz3l9//79Y7WzplOnTrHOw+uHH35w+x9//PEE7wmMHZMxY8aY9evX+/b9+uuvbv+gQYMS/FmAcEB6ORAk1hNt6VmW5mWjv5Y+Nn78eF/1ceshtl5u79xtG2m2lHIrumasYJq31/uPP/5wI7/JlVr+9ddfuxHzVq1anfPcxS5rYj317du3j7XPUuWt1/zLL7+0Vt6339LlbETfUuGM9ZpbapuNctt18D4sna5cuXKaNWvWRZ0TAADBYG1+QlXMvZlbVuPF2r7zsWwxu1/w+s9//qPChQu7omhe3hFvc+TIEdd+2r2EtbuWKZaYewJr+3v37n3BewK7tylbtqxv2+5jrK3/888/L/h9gLSMoBsIEps7ZWlcFjCuWrXKNUi2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VBYoV255adeNgBsAACAsEHQDQFIc3SeNfUBaNeHirxsBNwAAQNhIH+wTAIBU44/vpEmdpcO7pIh0nhHvmBhpzmuJfw8CbgAAgLBC0A0AF3LikDT9BWnZKM92/gpSq+FS0as925HpEreMGAE3AABA2CHoBoDz2TxPGv+ItH+zZ/u6TlKjnlKGLP8e4y2Gdr7Am4AbAAAgLBF0A0B8Th2XZr0izRssKUbKVVxqOVQqfUP81+t8gTcBNwAAQNhKciG1uXPnqnnz5ipSpIgiIiI0YULsYkIxMTHq1auXChcurCxZsqhx48Zat25drGP27duntm3bKmfOnMqdO7c6dOigw4cPX/pPAwDJYcev0vv1pXmDPAH3lfdKj85LOOA+33JiBNwAAABhLclB95EjR1StWjUNGTIk3ucHDBigd999V8OHD9fChQuVLVs2NWnSRMePH/cdYwH377//rhkzZmjKlCkukH/ooYcu7ScBgEsVfVqa84b0QUNpz2opWwHprs+llkOkzDkT9x6+wDuCgBsAAABJD7qbNWumV155Ra1atTrnORvlfvvtt/Xiiy+qRYsWqlq1qj755BNt377dNyK+evVqTZs2TR9++KFq1qypOnXqaNCgQRozZow7DgCC4u910sdNPCnlZ05LlZpLjy2QKt6c9PeywPul/f+mnAOp1Guvveay2rp27erbZ53onTp1Ur58+ZQ9e3a1adNGu3btCup5AgAQNut0b9y4UTt37nQp5V65cuVywfX8+fPdtn21lPIaNWr4jrHjIyMj3ch4fE6cOKGDBw/GegBAsjhzRlr4vjS8rrRtiZQpl9TqfemO/5Oy5eciI2wtXrxY7733nutA99etWzdNnjxZY8eO1Zw5c1yHeevWrYN2ngAAhFXQbQG3KVSoUKz9tu19zr4WLFgw1vPp06dX3rx5fcfE1b9/fxe8ex/FixdPztMGEK4O/CV92kqa+ox0+phUpr702Dyp2p1SRESwzw4IGquzYlPBPvjgA+XJk8e3/8CBA/roo4/01ltvqWHDhqpevbpGjBihefPmacGCBfzGAAAIdNAdKD169HANvfexdevWYJ8SgNQsJkb6dYw0tLb052wpfRbp5jele8dLuYoF++yAoLP08VtuuSVW5ppZunSpTp06FWt/xYoVVaJECV9GW3zIWAMAhLNkXTIsKirKfbW5XVa93Mu2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s0s5f+yxx3T69Gn9/vvvyp49O78HAACChKAbwPkD7gsF3jt+9czb3vzzv/O2rSJ5lduZtw0EQWRkpCIiItwod3R0NL8DAADSWnp5qVKlXGMf99GpUyf3vK0dGve5Rx55JLlPA0ByBtxe/qnmNm97YifpvXqegDt9Zqled08qebU7CbiBFHTixAk3r/vGG290S4etWLFCgwcP1pYtWxjlBgAgrY10L168OFbP+sqVK91NwO233+7b17FjR/Xt29e3nTVr1uQ+DQDJHXB72XGb50l/LZFOHvLss1HtRr2l3MW57kAKszTyMWPGuLncDz74oAu+8+fPz+8BAIC0GnQXKFAg1vZrr72msmXLql69erGC7KioqOT+1gACHXB7/TnL87XI1VIzm7d9LdceCJLhw4erRIkSKlOmjObMmeMe8Rk3blyKnxsAAAjwnO6TJ0/q008/1ZNPPunSyL0+++wzt98C7+bNm6tnz57nHe22tDl7eB08eJDfHRCsgNtf+aYE3ECQ3X///bHaWAAAEEZB94QJE7R//3498MADvn333HOPSpYsqSJFiui3335T9+7dtXbt2vP2wPfv3199+vQJ5KkC4edSA24zu59kN/tJXccbQLKxSuXJadiwYe6xadMmt3355ZerV69eatasmds+fvy4nnrqKZfSbh3iTZo00dChQ1WoUKFkPQ8AANKKgAbdH330kWukLcD2euihh3z/rlKligoXLqxGjRppw4YNLg09Pj169HCj5f4j3TZ3DUAQA+7ELicGIFUpVqyYmxpWrlw5VwF91KhRatGihX755RcXgHfr1k3ffPONxo4dq1y5cqlz585q3bq1fv757AoGAAAgZYJuWyf0+++/v+Acspo1a7qv69evTzDotvVH7QEgmczql/zvR9ANpAk27cvfq6++6ka+FyxY4AJy61AfPXq0GjZs6J4fMWKEKlWq5J6/7rrrgnTWAACE0ZJhXtYIFyxYULfccst5j1u+fLn7aiPeAFJIg+dD+/0AhARbjcTSyI8cOaJatWpp6dKlOnXqlBo3buw7pmLFiq6Q2/z584N6rgAAhNVI95kzZ1zQ3a5dO6VP/++3sBRy6x2/+eablS9fPjen29LUbrjhBlWtWjUQpwIgPt5R6eRIMW/wAqPcQBpj63xbkG3zt7Nnz67x48ercuXKrqM8Y8aMyp07d6zjbT73zp07E3w/CqICAMJZQEa6La18y5Ytbr1Qf9ZQ23M33XST6xm3Qixt2rTR5MmTA3EaAM7n+iekMg0u7RoRcANpUoUKFVyAvXDhQj366KOuE33VqlUX/X5WENXmf3sf1GUBAISTgIx0W1BtxVfiskY2ofVDAaQQ+39zzRTpuxelfzzViS8KATeQZlkn+WWXXeb+Xb16dS1evFjvvPOO7rzzTrccqK1M4j/avWvXLrcMaEIoiAoACGcBm9MNIATtXCGNai59ca8n4M4eJbUcJtVP4pxsAm4grNi0MUsRtwA8Q4YMmjlzpu85W/bTstssHT0hVgw1Z86csR4AAISLgC4ZBiBEHN4j/fCytOwTG+qW0mWSaneR6nSTMmX3HGPrbSdmjjcBN5Cm2ai0LfdpxdEOHTrkarHMnj1b06dPd6nhHTp0cMt45s2b1wXPXbp0cQE3lcsBAIgfQTeQlp0+IS0cLs19Uzpx0LPv8lbSjX2l3CWSXlyNgBtI83bv3q37779fO3bscEG2FTq1gPvGG290zw8cOFCRkZGuJouNfjdp0kRDhw4N9mkDABCyCLqBNDtv+5uz87Y3evYVvlJq+ppUMuEU0PMG3gTcQFiwdbjPJ3PmzBoyZIh7AACACyPoBtKanSul6T2kjXM929kLSY16S9XuliITUcYhvsCbgBsAAAC4KATdQFqatz3rFc+87ZgzZ+dtd5bqPPnvvO3E8gXe/aQGz7MONwAAAHCRCLqB1O70SWnRe9KcAbHnbTfuI+UpefHva4G3N/gGAAAAcFEIuoHUPG977beeedv7/vTsK1zt7Lzt2sE+OwAAAAAE3UAqtet3aZrN257jN2+7l1TtnsTN2wYAAACQIhjpBlKTI397CpwtHfnvvO1anaS6Nm87R7DPDgAAAEAcBN1Aap23XbmFZ73tPKWCfXYAAAAAEkDQDYT8vO2p0ncv/DtvO6qqZ952qeuDfXYAAAAALoCgGwjledvTn5f+nO3ZzlbQM2/7Spu3nS7YZwcAAAAgEQi6gZCct91PWjri7LztjGfnbT/FvG0AAAAglSHoBkJq3vb7Z+dtH/Dsq3SbdNPLzNsGAAAAUimCbiAU5m3/MU2abvO2N3j2RVU5O2+7TrDPDgAAAMAlIOgGgmnXqrPztmd5trMVODtvuy3ztgEAAIA0gKAbCIYje8+ut+03b/u6xzzztjPn5HcCAAAApBEE3UBKz9te/IE0+3W/edvNpRtflvKW5ncBAAAApDEE3UCKzdue7llve+96z75CNm+7v1S6Lr8DAAAAII0i6AYCbfdqz7ztDT/8O2+7YU/pqnuZtw0AAACkcQTdQCDnbc/uJy2xedvRZ+dtPyrVfZp52wAAAECYIOgGklv0KWnxh9Ls/tJx/3nbfaW8ZbjeAAAAQBiJTO43fOmllxQRERHrUbFiRd/zx48fV6dOnZQvXz5lz55dbdq00a5du5L7NIDgzdseWkua9pwn4LZ52+0mS3d+SsANAAAAhKGAjHRffvnl+v777//9Jun//TbdunXTN998o7FjxypXrlzq3LmzWrdurZ9//jkQpwKkjN1rzs7bnunZzppfamTztu9j3jYAAAAQxgISdFuQHRUVdc7+AwcO6KOPPtLo0aPVsGFDt2/EiBGqVKmSFixYoOuuuy4QpwMEztF9njTyxR955m1HZvDM277B5m3n4soDAAAAYS4gQfe6detUpEgRZc6cWbVq1VL//v1VokQJLV26VKdOnVLjxo19x1rquT03f/78BIPuEydOuIfXwYMHA3HawKXN2654q2fedr6yXEkAAAAAgQm6a9asqZEjR6pChQrasWOH+vTpo7p162rlypXauXOnMmbMqNy5c8d6TaFChdxzCbGg3d4HCAl/fOdJJd+7zrNd6AqpST+pTL1gnxkAAACAtB50N2vWzPfvqlWruiC8ZMmS+vLLL5UlS5aLes8ePXroySefjDXSXbx48WQ5XyBJ87a/e0Fa//2/87YbvihdfT/ztgEAAAAEZ8kwG9UuX7681q9frxtvvFEnT57U/v37Y412W/Xy+OaAe2XKlMk9gODN237Nk07um7f9iHTDM8zbBgAAAJCyS4bFdfjwYW3YsEGFCxdW9erVlSFDBs2cebbCs6S1a9dqy5Ytbu43EHLzthcMl969Slr0nifgrnCL1GmhdNMrBNwA0iSb0nXNNdcoR44cKliwoFq2bOnaan8s/wkAQBCD7qefflpz5szRpk2bNG/ePLVq1Urp0qXT3Xff7ZYI69Chg0sVnzVrlius1r59exdwU7kcIWXdDGlYbWlad+n4fqng5dL9E6W7R1MoDUCaZm14p06d3KoiM2bMcAVQb7rpJh05ciTW8p+TJ092y3/a8du3b3fLfwIAgBRIL//rr79cgL13714VKFBAderUcQ23/dsMHDhQkZGRatOmjatI3qRJEw0dOjS5TwO4OHvWStNt3vYMz3bWfGfnbbdj3jaAsDBt2rRY21Yc1Ua8raP8hhtuYPlPAACCHXSPGTPmvM/bMmJDhgxxDyCk5m3PeV1a9MG/87ZrPuyZt50ldrV9AAgnBw54lkXMmzev+3oxy3+y9CcAIJwFvJAaEPLztpd8LM3q50kjNxVu9szZZr1tAGHuzJkz6tq1q66//npdccUVbt/FLP/J0p8AgHBG0I3wte57z3rbf58tEFSwsme97bINgn1mABASbG73ypUr9dNPP13S+7D0JwAgnBF0I+06Ey1tnicd3iVlLySVrO2Zl73nD8962+u++3fedoMXPPO20/G/BACYzp07a8qUKZo7d66KFSvmuyi2xGdSl/9k6U8AQDgjwkDatGqSp/L4we3/7ssRJUVVlTb8IJ05LUWml2qeXW+bedsA4MTExKhLly4aP368Zs+erdKlS8e6Mv7Lf1pRVMPynwAAJIygG2kz4P7yfrt1jL3/0E7Pw5Rv5pm3nf+yoJwiAIRySvno0aM1ceJEt1a3d562LfuZJUuWWMt/WnG1nDlzuiCd5T8BAIgfQTfSXkq5jXDHDbj9Zc0v3fUZS4ABQDyGDRvmvtavXz/W/hEjRuiBBx5w/2b5TwAAEo+gG2mLzeH2TymPz9G/PceVrptSZwUAqSq9/EJY/hMAgMSLTMKxQOizomnJeRwAAAAAXAKCbqQtVqU8OY8DAAAAgEtA0I20xZYFy1lEUkQCB0RIOYt6jgMAAACAACPoRtpi63A3ff3sRtzA++x209coogYAAAAgRRB0I+2pfJt0xydSzsKx99sIuO235wEAAAAgBVC9HGmTBdYVb/FUKbeiaTaH21LKbSQcAAAAAFIIQTfSLguwWRYMAAAAQBCRXg4AAAAAQIAQdAMAAAAAECAE3QAAAAAABAhzugEAQKpWo0YN7dy5M9ingRCxY8eOYJ8CAMRC0A0AAFI1C7i3bdsW7NNAiMmRI0ewTwEAHIJuAACQqkVFRV3U684cPpLs54LkF5k920UF3C+//DK/DgAhgaAbAACkakuWLLmo1+0ZNDjZzwXJr0CXzlxWAKkahdQAAAAAAAgQgm4AAAAAAFJL0N2/f39dc801bi5NwYIF1bJlS61duzbWMfXr11dERESsxyOPPJLcpwIAAAAAQNoKuufMmaNOnTppwYIFmjFjhk6dOqWbbrpJR47ELlbSsWNHt6SD9zFgwIDkPhUAAAAAANJWIbVp06bF2h45cqQb8V66dKluuOEG3/6sWbNedLVRAAAAAABSg4DP6T5w4ID7mjdv3lj7P/vsM+XPn19XXHGFevTooaNHjyb4HidOnNDBgwdjPQAAAAAACOslw86cOaOuXbvq+uuvd8G11z333KOSJUuqSJEi+u2339S9e3c373vcuHEJzhPv06dPIE8VAAAAAIDUFXTb3O6VK1fqp59+irX/oYce8v27SpUqKly4sBo1aqQNGzaobNmy57yPjYQ/+eSTvm0b6S5evHggTx0AAAAAgNANujt37qwpU6Zo7ty5Klas2HmPrVmzpvu6fv36eIPuTJkyuQcAAAAAAGEddMfExKhLly4aP368Zs+erdKlS1/wNcuXL3dfbcQbAAAAAIC0In0gUspHjx6tiRMnurW6d+7c6fbnypVLWbJkcSnk9vzNN9+sfPnyuTnd3bp1c5XNq1atmtynAwAAAABA2qlePmzYMFexvH79+m7k2vv44osv3PMZM2bU999/79burlixop566im1adNGkydPTu5TAQAASWTTwpo3b+6KnUZERGjChAnnZLT16tXLte3Wmd64cWOtW7eO6wwAQEqml5+PFUCbM2dOcn9bAACQDI4cOaJq1arpwQcfVOvWrc95fsCAAXr33Xc1atQoN4WsZ8+eatKkiVatWqXMmTPzOwAAICWrlwMAgNSlWbNm7pFQx/rbb7+tF198US1atHD7PvnkExUqVMiNiN91110pfLYAAIRhejkAAEibNm7c6Gq1WEq5l9VssVVI5s+fn+DrTpw44Zb79H8AABAuCLoBAECieIuj2si2P9v2Phef/v37u+Dc+7CpZgAAhAuCbgAAEFA9evRwRVa9j61bt3LFAQBhg6AbAAAkSlRUlPu6a9euWPtt2/tcfDJlyqScOXPGegAAEC4IugEAQKJYtXILrmfOnOnbZ/OzFy5cqFq1anEVAQCIB9XLAQCAz+HDh7V+/fpYxdOWL1+uvHnzqkSJEuratateeeUVlStXzrdkmK3p3bJlS64iAADxIOgGAAA+S5YsUYMGDXzbTz75pPvarl07jRw5Us8++6xby/uhhx7S/v37VadOHU2bNo01ugEASABBNwAA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GLv22mtjOnXq5NuOjo6OKVKkSEz//v2Del6hbvfu3TZUFjNnzhy3vX///pgMGTLEjB071nfM6tWr3THz588P4pmGjkOHDsWUK1cuZsaMGTH16tWLeeKJJ9x+rt35de/ePaZOnToJPn/mzJmYqKiomDfeeMO3z65ppkyZYj7//POYcHbLLbfEPPjgg7H2tW7dOqZt27bu31y7hNnfrvHjx/u2E3OtVq1a5V63ePFi3zFTp06NiYiIiNm2bVsy/maBpH1+gbj3bUCePHliPvzwQy5ECgrbke6TJ0+6Hh9LEfSKjIx02/Pnzw/quYW6AwcOuK958+Z1X+06Wi+q/7WsWLGiSpQowbU8y3qcb7nllljXiGt3YZMmTVKNGjV0++23uxS5q666Sh988IHv+Y0bN2rnzp2xrmuuXLncVJFw//+4du3amjlzpv744w+3/euvv+qnn35Ss2bN3DbXLvESc63sq6WU2+fVy463dsVGxgEgVO7bEN5Tz8aMGeOyHizNHCknvcLU33//7T54hQoVirXfttesWRO08wp1Z86ccfORLeX3iiuucPvsZjRjxozuhjPutbTnwp39cbPpC5ZeHhfX7vz+/PNPlyJt00Cef/55dw0ff/xx93lr166d7/MV3//H4f7Ze+6553Tw4EHXAZYuXTr39+7VV191KdCGa5d4iblW9tU6hvylT5/e3eSG+2cRQGjdtyH8rFixwgXZNiXKai+NHz9elStXDvZphZWwDbpx8SO2K1eudCNmuLCtW7fqiSeecHOqrFgfkn6zYCOH/fr1c9s20m2fP5tXa0E3Evbll1/qs88+0+jRo3X55Zdr+fLl7sbLCi1x7QAgPHDfBlOhQgV3H2BZD1999ZW7D7C5/wTeKSds08vz58/vRn/iVti27aioqKCdVyjr3LmzKw40a9YsV5TBy66Xpevv378/1vFcS0/qvRXmu/rqq92olz3sj5wVZLJ/20gZ1y5hVik6boNQqVIlbdmyxffZ837W+OzF9swzz7jR7rvuustVfL/vvvtc0T6rasu1S5rEfM7sa9winKdPn3YVzWlTAITSfRvCj2UIXnbZZapevbq7D7DCi++8806wTyusRIbzh88+eDbn0X9UzbaZ4xCb1WWxP9yWivLDDz+4JYj82XW06tL+19KWprDAKNyvZaNGjVxKj/Uueh82cmspvt5/c+0S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" + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 26 }, { "cell_type": "markdown", @@ -2734,8 +3490,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.453545Z", - "start_time": "2026-04-01T11:08:38.450339Z" + "end_time": "2026-04-01T17:27:06.936048Z", + "start_time": "2026-04-01T17:27:06.933369Z" } }, "source": [ @@ -2751,83 +3507,229 @@ "print(\"CHP breakpoints:\")\n", "print(bp_chp.to_pandas())" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CHP breakpoints:\n", + "_breakpoint 0 1 2 3\n", + "var \n", + "power 0.0 30.0 60.0 100.0\n", + "fuel 0.0 40.0 85.0 160.0\n", + "heat 0.0 25.0 55.0 95.0\n" + ] + } + ], + "execution_count": 27 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.518849Z", - "start_time": "2026-04-01T11:08:38.466354Z" + "end_time": "2026-04-01T17:27:06.977986Z", + "start_time": "2026-04-01T17:27:06.938485Z" } }, - "source": [ - "m7 = linopy.Model()\n", - "\n", - "power = m7.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\n", - "fuel = m7.add_variables(name=\"fuel\", lower=0, coords=[time])\n", - "heat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n", - "\n", - "# N-variable: all three linked through shared interpolation weights\n", - "m7.add_piecewise_formulation(\n", - " (power, bp_chp.sel(var=\"power\")),\n", - " (fuel, bp_chp.sel(var=\"fuel\")),\n", - " (heat, bp_chp.sel(var=\"heat\")),\n", - " name=\"chp\",\n", - " method=\"sos2\",\n", - ")\n", - "\n", - "# Fixed power dispatch determines the operating point — fuel and heat follow\n", - "power_dispatch = xr.DataArray([20, 60, 90], coords=[time])\n", - "m7.add_constraints(power == power_dispatch, name=\"power_dispatch\")\n", - "\n", - "m7.add_objective(fuel.sum())" + "source": "m7 = linopy.Model()\n\npower = m7.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m7.add_variables(name=\"fuel\", lower=0, coords=[time])\nheat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n\n# Fixed power dispatch determines the operating point — fuel and heat follow\npower_dispatch = xr.DataArray([20, 60, 90], coords=[time])\nm7.add_constraints(power == power_dispatch, name=\"power_dispatch\")\nm7.add_objective(fuel.sum())\n\n# N-variable: all three linked through shared interpolation weights\nm7.add_piecewise_formulation(\n (power, bp_chp.sel(var=\"power\")),\n (fuel, bp_chp.sel(var=\"fuel\")),\n (heat, bp_chp.sel(var=\"heat\")),\n name=\"chp\",\n method=\"sos2\",\n)", + "outputs": [ + { + "data": { + "text/plain": [ + "PiecewiseFormulation 'chp' (sos2)\n", + " Variables (1):\n", + " * chp_lambda\n", + " Constraints (2):\n", + " * chp_convex\n", + " * chp_x_link" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } ], - "outputs": [], - "execution_count": null + "execution_count": 28 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.581845Z", - "start_time": "2026-04-01T11:08:38.522785Z" + "end_time": "2026-04-01T17:27:07.007460Z", + "start_time": "2026-04-01T17:27:06.980545Z" } }, "source": [ "m7.solve(reformulate_sos=\"auto\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2026-12-18\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-_1vpbkgs.lp\n", + "Reading time = 0.00 seconds\n", + "obj: 15 rows, 21 columns, 51 nonzeros\n", + "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", + "\n", + "CPU model: Apple M3\n", + "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", + "\n", + "Optimize a model with 15 rows, 21 columns and 51 nonzeros (Min)\n", + "Model fingerprint: 0x8c65a8ab\n", + "Model has 3 linear objective coefficients\n", + "Model has 3 SOS constraints\n", + "Variable types: 21 continuous, 0 integer (0 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 2e+02]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+00, 1e+02]\n", + " RHS range [1e+00, 9e+01]\n", + "\n", + "Presolve removed 15 rows and 21 columns\n", + "Presolve time: 0.00s\n", + "Presolve: All rows and columns removed\n", + "\n", + "Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n", + "Thread count was 1 (of 8 available processors)\n", + "\n", + "Solution count 2: 252.917 252.917 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 2.529166651870e+02, best bound 2.529166651870e+02, gap 0.0000%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Dual values of MILP couldn't be parsed\n" + ] + }, + { + "data": { + "text/plain": [ + "('ok', 'optimal')" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 29 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.632933Z", - "start_time": "2026-04-01T11:08:38.620498Z" + "end_time": "2026-04-01T17:27:07.021084Z", + "start_time": "2026-04-01T17:27:07.016008Z" } }, "source": [ "m7.solution[[\"power\", \"fuel\", \"heat\"]].to_pandas().round(2)" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + " power fuel heat\n", + "time \n", + "1 20.0 26.67 16.67\n", + "2 60.0 85.00 55.00\n", + "3 90.0 141.25 85.00" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
powerfuelheat
time
120.026.6716.67
260.085.0055.00
390.0141.2585.00
\n", + "
" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 30 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.743684Z", - "start_time": "2026-04-01T11:08:38.645091Z" + "end_time": "2026-04-01T17:27:07.102824Z", + "start_time": "2026-04-01T17:27:07.025649Z" } }, "source": [ "plot_pwl_results(m7, bp_chp, power_dispatch, x_name=\"fuel\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAFUCAYAAAA57l+/AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAg9RJREFUeJzt3Qd4FNXbBfCTHkIKPYEk9NB7B1G6gIg0QRAVEUGpAv5pShERaUqVJirlkyYKSBGQjvTea+gtCS2FhPT9nvfGWTchCQnZTXaz5+ezhpmdzM7sJrlz5jYbnU6nAxEREREREREZna3xd0lEREREREREDN1EREREREREJsSabiIiIiIiIiITYegmIiIiIiIiMhGGbiIiIiIiIiITYegmIiIiIiIiMhGGbiIiIiIiIiITYegmIiIiIiIiMhGGbiIiIiIiIiITYegmIiIiIspiX331FWxsbGDp5Bz69euX1YdBZFYYuokyyaJFi1RBpD2cnZ1RqlQpVTAFBgaqbQ4fPqyemzZt2nPf36ZNG/XcwoULn3vutddeg7e3t365YcOGqFChgonPiIiIiNJT7hcqVAjNmzfHzJkzERYWZpZv3l9//aVuABCR8TB0E2Wyr7/+Gv/3f/+HH374AfXq1cPcuXNRt25dREREoFq1anBxccHevXuf+779+/fD3t4e+/btS7Q+OjoaR44cwSuvvJKJZ0FERETpKfelvO/fv79aN3DgQFSsWBGnT5/Wbzdy5Eg8e/bMLEL32LFjs/owiLIV+6w+ACJr07JlS9SoUUP9++OPP0bevHkxdepU/Pnnn+jSpQtq1679XLC+dOkSHj58iHffffe5QH7s2DFERkaifv36sARyc0FuLBAREVlbuS9GjBiBHTt24M0338Rbb72FCxcuIEeOHOrGujyIKPthTTdRFmvcuLH6ev36dfVVwrM0N/f399dvIyHc3d0dvXr10gdww+e07zOG4OBgDBo0CEWLFoWTkxN8fHzwwQcf6F9Tay5348aNRN+3a9cutV6+Jm3mLjcGpAm8hO0vvvhCXWgUL1482deXWn/DixPx66+/onr16uqiJE+ePOjcuTNu375tlPMlIiLKirJ/1KhRuHnzpirjUurTvXXrVlW+58qVC66urihdurQqR5OWvStXrlTrvby8kDNnThXmk5aT//zzDzp27IjChQur8t3X11eV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p05V/9ZG9k7L8bZo0UJXtWpV3aFDh3R79+5VI+h36dLFLM4hOjpa99Zbb+l8fHx0J0+eTPQ7HhUVZRHnkJyko5dbwjnI74OMTv7jjz+q3/FZs2bp7OzsdP/884/F/J0i65be31PKntJy3UjWYfjw4WrUernmk2skWZZZQ/7++++sPjSrYdWhW8jFlFw4OTo6qinEDh48qDNXUnAm91i4cKF+GwkYffr0UdMASBBs166d+gNrSaHbEs5h/fr1ugoVKqibNmXKlFEX54ZkCqtRo0bpPD091TZNmjTRXbp0SWcuQkND1XsuP/vOzs664sWL67788stE4c7czmHnzp3J/vzLDYS0Hu+jR49UuHN1ddW5u7vrunfvri5OzeEcpCBM6Xdcvs8SziGtodsSzuHnn3/WlSxZUv1+VK5cWbd27dpE+7CEv1NkvdL7e0rZU1quG8k6yDSxUh5L3smfP7+6RmLgzlw28r+srm0nIiIiIiIiyo6stk83ERERERERkakxdBMRERERERGZCEM3ERERERERkYkwdBMRERERERGZCEM3ERERERERkYkwdBMRERERERGZCEM3ERERERERkYkwdBMRERERERGZCEM3Eb20Xbt2wcbGBsHBwXwXiYiIssiHH36Itm3b8v0nMlMM3URWUBBLME768Pf3z+pDIyIiohdIrgw3fHz11VeYMWMGFi1axPeSyEzZZ/UBEJHptWjRAgsXLky0Ln/+/HzriYiIzNz9+/f1/165ciVGjx6NS5cu6de5urqqBxGZL9Z0E1kBJycneHl5JXr06NHjuaZoAwcORMOGDfXL8fHxmDBhAooVK4YcOXKgcuXK+P3337PgDIiIiKyTYdnt4eGharcN10ngTtq8XMry/v37q3I9d+7c8PT0xIIFCxAeHo7u3bvDzc0NJUuWxKZNmxK91tmzZ9GyZUu1T/me999/Hw8fPsyCsybKXhi6iShFEriXLFmCefPm4dy5cxg0aBDee+897N69m+8aERGRGVu8eDHy5cuHw4cPqwDeu3dvdOzYEfXq1cPx48fx+uuvq1AdERGhtpfxWRo3boyqVavi6NGj2Lx5MwIDA9GpU6esPhUii8fm5URWYMOGDYmansld7Jw5c6b6PVFRUfj222+xbds21K1bV60rXrw49u7di/nz56NBgwYmP24iIiJ6OdI6beTIkerfI0aMwMSJE1UI79mzp1onzdTnzp2L06dPo06dOvjhhx9U4JayX/PLL7/A19cXly9fRqlSpfhREL0khm4iK9CoUSNVsGokcEsBnBoZaE3ufjdr1izR+ujoaFUoExERkfmqVKmS/t92dnbImzcvKlasqF8nzcdFUFCQ+nrq1Cns3Lkz2f7hV69eZegmygCGbiIrICFb+m4ZsrW1hU6nS7QuJiZG/++nT5+qrxs3boS3t/dzfcSJiIjIfDk4OCRalr7ghutkWRu/RSv3W7dujUmTJj23r4IFC5r8eImyM4ZuIislo5fLgCmGTp48qS+Qy5Urp8L1rVu32JSciIgom6tWrRr++OMPFC1aFPb2jAhExsSB1IislAyWIgOlyEBpV65cwZgxYxKFcBnZ9H//+58aPE0GY5GmZTLwyqxZs9QyERERZR99+/bF48eP0aVLFxw5ckSV+1u2bFGjncfFxWX14RFZNIZuIivVvHlzjBo1CkOHDkXNmjURFhaGDz74INE248aNU9vIKOZly5ZV831Lc3OZQoyIiIiyj0KFCmHfvn0qYMvI5tL/W6Ycy5Url+qSRkQvz0aXtFMnERERERERERkFb1sRERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxERERERERFM4/8BZDGANiuN9OMAAAAASUVORK5CYII=" + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 31 }, { "cell_type": "markdown", @@ -2838,8 +3740,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.759346Z", - "start_time": "2026-04-01T11:08:38.752115Z" + "end_time": "2026-04-01T17:27:07.117343Z", + "start_time": "2026-04-01T17:27:07.113289Z" } }, "source": [ @@ -2855,71 +3757,241 @@ "print(\"Power breakpoints:\\n\", x_gen.to_pandas())\n", "print(\"Fuel breakpoints:\\n\", y_gen.to_pandas())" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Power breakpoints:\n", + " _breakpoint 0 1 2 3\n", + "gen \n", + "gas 0.0 30.0 60.0 100.0\n", + "coal 0.0 50.0 100.0 150.0\n", + "Fuel breakpoints:\n", + " _breakpoint 0 1 2 3\n", + "gen \n", + "gas 0.0 40.0 90.0 180.0\n", + "coal 0.0 55.0 130.0 225.0\n" + ] + } + ], + "execution_count": 32 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.852492Z", - "start_time": "2026-04-01T11:08:38.765098Z" + "end_time": "2026-04-01T17:27:07.183189Z", + "start_time": "2026-04-01T17:27:07.120111Z" } }, - "source": [ - "m8 = linopy.Model()\n", - "\n", - "power = m8.add_variables(name=\"power\", lower=0, upper=150, coords=[gens, time])\n", - "fuel = m8.add_variables(name=\"fuel\", lower=0, coords=[gens, time])\n", - "\n", - "# Per-entity breakpoints: each generator gets its own curve\n", - "m8.add_piecewise_formulation(\n", - " (power, x_gen),\n", - " (fuel, y_gen),\n", - " name=\"pwl\",\n", - ")\n", - "\n", - "demand8 = xr.DataArray([80, 120, 60], coords=[time])\n", - "m8.add_constraints(power.sum(\"gen\") >= demand8, name=\"demand\")\n", - "m8.add_objective(fuel.sum())" + "source": "m8 = linopy.Model()\n\npower = m8.add_variables(name=\"power\", lower=0, upper=150, coords=[gens, time])\nfuel = m8.add_variables(name=\"fuel\", lower=0, coords=[gens, time])\n\ndemand8 = xr.DataArray([80, 120, 60], coords=[time])\nm8.add_constraints(power.sum(\"gen\") >= demand8, name=\"demand\")\nm8.add_objective(fuel.sum())\n\n# Per-entity breakpoints: each generator gets its own curve\nm8.add_piecewise_formulation(\n (power, x_gen),\n (fuel, y_gen),\n name=\"pwl\",\n)", + "outputs": [ + { + "data": { + "text/plain": [ + "PiecewiseFormulation 'pwl' (incremental)\n", + " Variables (2):\n", + " * pwl_delta\n", + " * pwl_inc_binary\n", + " Constraints (4):\n", + " * pwl_inc_link\n", + " * pwl_fill\n", + " * pwl_inc_order\n", + " * pwl_x_link" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } ], - "outputs": [], - "execution_count": null + "execution_count": 33 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.923105Z", - "start_time": "2026-04-01T11:08:38.855310Z" + "end_time": "2026-04-01T17:27:07.232662Z", + "start_time": "2026-04-01T17:27:07.190995Z" } }, "source": [ "m8.solve(reformulate_sos=\"auto\")" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2026-12-18\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-rnwq0oox.lp\n", + "Reading time = 0.00 seconds\n", + "obj: 57 rows, 48 columns, 138 nonzeros\n", + "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", + "\n", + "CPU model: Apple M3\n", + "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", + "\n", + "Optimize a model with 57 rows, 48 columns and 138 nonzeros (Min)\n", + "Model fingerprint: 0x79e2e4b7\n", + "Model has 6 linear objective coefficients\n", + "Variable types: 30 continuous, 18 integer (18 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 1e+02]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+00, 2e+02]\n", + " RHS range [6e+01, 1e+02]\n", + "\n", + "Found heuristic solution: objective 392.0000000\n", + "Presolve removed 50 rows and 38 columns\n", + "Presolve time: 0.00s\n", + "Presolved: 7 rows, 10 columns, 23 nonzeros\n", + "Found heuristic solution: objective 340.0000000\n", + "Variable types: 6 continuous, 4 integer (4 binary)\n", + "\n", + "Root relaxation: objective 3.183333e+02, 1 iterations, 0.00 seconds (0.00 work units)\n", + "\n", + " Nodes | Current Node | Objective Bounds | Work\n", + " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", + "\n", + "* 0 0 0 318.3333333 318.33333 0.00% - 0s\n", + "\n", + "Explored 1 nodes (1 simplex iterations) in 0.00 seconds (0.00 work units)\n", + "Thread count was 8 (of 8 available processors)\n", + "\n", + "Solution count 3: 318.333 340 392 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 3.183333333333e+02, best bound 3.183333333333e+02, gap 0.0000%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Dual values of MILP couldn't be parsed\n" + ] + }, + { + "data": { + "text/plain": [ + "('ok', 'optimal')" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 34 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:38.943143Z", - "start_time": "2026-04-01T11:08:38.934884Z" + "end_time": "2026-04-01T17:27:07.247121Z", + "start_time": "2026-04-01T17:27:07.241878Z" } }, "source": [ "m8.solution[[\"power\", \"fuel\"]].to_dataframe().round(2)" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "data": { + "text/plain": [ + " power fuel\n", + "gen time \n", + "gas 1 30.0 40.00\n", + " 2 30.0 40.00\n", + " 3 10.0 13.33\n", + "coal 1 50.0 55.00\n", + " 2 90.0 115.00\n", + " 3 50.0 55.00" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
powerfuel
gentime
gas130.040.00
230.040.00
310.013.33
coal150.055.00
290.0115.00
350.055.00
\n", + "
" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 35 }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T11:08:39.047739Z", - "start_time": "2026-04-01T11:08:38.949442Z" + "end_time": "2026-04-01T17:27:07.332241Z", + "start_time": "2026-04-01T17:27:07.251731Z" } }, "source": "sol = m8.solution\nfig, axes = plt.subplots(1, 2, figsize=(10, 3.5))\n\nfor i, gen in enumerate(gens):\n ax = axes[i]\n fuel_bp = y_gen.sel(gen=gen).values\n power_bp = x_gen.sel(gen=gen).values\n ax.plot(fuel_bp, power_bp, \"o-\", color=f\"C{i}\", label=\"Breakpoints\")\n for t in time:\n ax.plot(\n float(sol[\"fuel\"].sel(gen=gen, time=t)),\n float(sol[\"power\"].sel(gen=gen, time=t)),\n \"D\",\n color=\"black\",\n ms=8,\n )\n ax.set(xlabel=\"Fuel\", ylabel=\"Power [MW]\", title=f\"{gen.title()} heat-rate curve\")\n ax.legend()\n\nplt.tight_layout()", @@ -2929,7 +4001,7 @@ "text/plain": [ "
" ], - "image/png": "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UDWnzN6XBPmM/s7k+8Thw4c1tWvXVgHO3d1dU65cOc1nn32W6oLAkt6TBF0JohI8ZcoQmUarf//+TyQulnaunvb7J+bNm6fx8PBQ06GkZYnniewrZpubrcbW7GSrcdCcbDFeWXp+YOjf++XLlzWtW7dWcVVu0MmNu4SEBI09cZB/zN3aTkRERERERGSLOKabiIiIiIiIyESYdBMRERERERGZCJNuIiIiIiIiIhNh0k1ERERERERkIky6iYiIiIiIiEyESTcRERERERGRiTDpJiIiIiIiIjIRJt1EREREREREJsKkm4jMYvv27XBwcEBERATPABERkYVivCZ6fky6iShDvXv3Volx2kdISAiPGhERkYVgvCaybM7m3gEismytWrXCwoULU63Lnz+/2faHiIiInsR4TWS52NJNRJlyc3ODv79/qke/fv3QoUOHVNsNGzYMTZo0SVlOTk7GlClTUKxYMXh4eKBy5cr47bffeLSJiIhMgPGayHKxpZuITEIS7sWLF2Pu3LkoVaoUdu7ciR49eqhW8saNG/OoExERWQDGayLTY9JNRJlat24dPD09U5Zbt26NnDlzZvo9cXFx+Oyzz7B582bUrVtXrStevDh2796NefPmMekmIiIyMsZrIsvFpJuIMtW0aVPMmTMnZVkS7rFjx2b6PVJoLSYmBi+88EKq9fHx8ahatSqPOBERkZExXhNZLibdRJQpSbJLliyZap2joyM0Gk2qdQkJCSn/f/Tokfq6fv16FCxY8IkxZ0RERGRcjNdElotJNxFlmYzLPnnyZKp1x44dg4uLi/p/UFCQSq6vXr3KruRERERmwnhNZBmYdBNRljVr1gxffPEFFi1apMZsS8E0ScJ1Xce9vLwwatQoDB8+XFUxb9CgASIjI7Fnzx7kypULvXr14lEnIiIyMcZrIsvApJuIsqxly5YYP3483nvvPcTGxqJv377o2bMnTpw4kbLNxx9/rO6wS1XUS5cuIXfu3KhWrRo++OADHnEiIqJswHhNZBkcNGkHZhIRERERERGRUTga52WIiIiIiIiIKC0m3UREREREREQmwqSbiIiIiIiIyESYdBMRERERERGZCJNuIiIiIiIiIhNh0k1ERERERERkIky6iYiIiIiIiEyESTcRERERERGRiTDpJiIiIiIiIjIRJt1EREREREREJsKkm4iIiIiIiMhEmHQTERERERERwTT+DyL9jcFaLIqHAAAAAElFTkSuQmCC" + "image/png": "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oKZkyZIad3d3jYeHh6Zs2bKat99+W01Bou/69etq+i6Z/kmmenr11Vc1N2/eVFNHyHQVIi4uTjN69GhN5cqV1dQXMp2H/P+777576r7opryQqcr0yfRVsl6ms9L3+++/axo0aKB+hjxkv2Uqj3PnzqVsc/r0aU2LFi00np6emnz58qnpqf75558npsVKTEzUDB06VJM/f341PcjTPi50U26tWLHiiedkyhWZJqVAgQLqeNavX18THBysady4sXro++OPPzRBQUFqqrO0+3T06FFNx44d1XRpMvWKTBPSpUsXzZYtW556LGXqk3HjxqkpxlxcXDT+/v6azp07ay5evJiyjRxnme5LponJkyePmjLm5MmT6U4ZJsc3M/Kz5Pvk9yizYybToMnvjvyulShRQtO7d2/NoUOHnvp+iIjslUyxJbGraNGiGldXVxVbJa7MnDkz1RRfCQkJmkmTJqV87gcGBmrGjh2bahshUz3VqVNHxaeAgADNe++9lzKNlP40klmZMqxt27ZPrE8v5skUkrJPEivkvUhcrlevnubLL79U04LpLFiwQE2dKbFPYrvEpPSmxTp79qyaakveizz3tOnDMotnxrpe+P777zXVq1dX+yTnqmLFiuoYy/XS00gM1l1nSZwsU6aMZvz48am2+fvvv9X0aXL85PnFixdnOGVYZtO3ylRk8jsi233yySfpbiPnZOrUqZry5curcyHXCvLe5PdMprUjyoiD/GPuxJ+IiIiIiIjIFnFMNxEREREREZGJMOkmIiIiIiIiMhEm3UREREREREQmwqSbiIiIiIiIyESYdBMRERERERGZCJNuIiIiIiIiIhNxNtULW5Pk5GTcvHkTXl5ecHBwMPfuEBGRnZPZPKOiohAQEABHR94f12G8JiIia4zXTLoBlXAHBgZm5/khIiJ6qmvXrqFQoUI8Uv9ivCYiImuM10y6AdXCrTtYuXLlyr6zQ0RElI6HDx+qm8G6+ERajNdERGSN8ZpJN5DSpVwSbibdRERkKTjkKf3jwXhNRETWFK85UIyIiIiIiIjIRJh0ExEREREREZkIk24iIiIiIiIiE+GY7ixMUxIfH2+q80BWwsXFBU5OTubeDSIiykRSUhISEhJ4jOwY4zURWRKzJt07d+7EF198gcOHD+PWrVtYtWoVOnTokGres4kTJ2L+/PmIiIhA/fr1MWfO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VFA1p8zelwT5jP7O5PvE4cOHNbVr11YBzt3dXVOuXDnNZ599luqCwJLekwRdCaISPGXKEJlGq3///k8kLpZ2rp72+yfmzZun8fDwUNOhpGWJ54nsK2abm63G1uxkq3HQnGwxXll6fmDo3/vly5c1rVu3VnFVbtDJjbuEhASNPXGQf8zd2k5ERERERERkizimm4iIiIiIiMhEmHQTERERERERmQiTbiIiIiIiIiITYdJNREREREREZCJMuomIiIiIiIhMhEk3ERERERERkYkw6SYiIiIiIiIyESbdRERERERERCbCpJuIzGL79u1wcHBAREQEzwAREZGFYrwmen5MuokoQ71791aJcdpHSEgIjxoREZGFYLwmsmzO5t4BIrJsrVq1wsKFC1Oty58/v9n2h4iIiJ7EeE1kudjSTUSZcnNzg7+/f6pHv3790KFDh1TbDRs2DE2aNElZTk5OxpQpU1CsWDF4eHigcuXK+O2333i0iYiITIDxmshysaWbiExCEu7Fixdj7ty5KFWqFHbu3IkePXqoVvLGjRvzqBMREVkAxmsi02PSTUSZWrduHTw9PVOWW7dujZw5c2b6PXFxcfjss8+wefNm1K1bV60rXrw4du/ejXnz5jHpJiIiMjLGayLLxaSbiDLVtGlTzJkzJ2VZEu6xY8dm+j1SaC0mJgYvvPBCqvXx8fGoWrUqjzgREZGRMV4TWS4m3USUKUmyS5YsmWqdo6MjNBpNqnUJCQkp/3/06JH6un79ehQsWPCJMWdERERkXIzXRJaLSTcRZZmMyz558mSqdceOHYOLi4v6f1BQkEqur169yq7kREREZsJ4TWQZmHQTUZY1a9YMX3zxBRYtWqTGbEvBNEnCdV3Hvby8MGrUKAwfPlxVMW/QoAEiIyOxZ88e5MqVC7169eJRJyIiMjHGayLLwKSbiLKsZcuWGD9+PN577z3Exsaib9++6NmzJ06cOJGyzccff6zusEtV1EuXLiF37tyoVq0aPvjgAx5xIiKibMB4TWQZHDRpB2YSERERERERkVE4GudliIiIiIiIiCgtJt1EREREREREJsKkm4iIiIiIiMhEmHQTERERERERmQiTbiIiIiIiIiITYdJNREREREREZCJMuomIiIiIiIhMhEk3ERERERERkYkw6SYiIiIiIiIyESbdRERERERERCbCpJuIiIiIiIjIRJh0ExEREREREcE0/g8i/Y3BWiyKhwAAAABJRU5ErkJggg==" }, "metadata": {}, "output_type": "display_data", @@ -2938,7 +4010,7 @@ } } ], - "execution_count": null + "execution_count": 36 } ], "metadata": { From 9b54a04d7ff817927ee9af8a8c290c41c7e947fb Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:30:31 +0200 Subject: [PATCH 03/16] docs: show tangent_lines repr in notebook Split tangent_lines cell so its LinearExpression repr is displayed. Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/piecewise-linear-constraints.ipynb | 214 +++++++++----------- 1 file changed, 101 insertions(+), 113 deletions(-) diff --git a/examples/piecewise-linear-constraints.ipynb b/examples/piecewise-linear-constraints.ipynb index be18e1c2..f5b94b58 100644 --- a/examples/piecewise-linear-constraints.ipynb +++ b/examples/piecewise-linear-constraints.ipynb @@ -16,8 +16,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.166974Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:05.899439Z", - "start_time": "2026-04-01T17:27:05.021330Z" + "end_time": "2026-04-01T17:28:22.053416Z", + "start_time": "2026-04-01T17:28:21.542852Z" } }, "source": [ @@ -111,7 +111,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 1. SOS2 formulation — Gas turbine\n", + "## 1. SOS2 formulation \u2014 Gas turbine\n", "\n", "The gas turbine has a **convex** heat rate: efficient at moderate load,\n", "increasingly fuel-hungry at high output. We use the **SOS2** formulation\n", @@ -129,8 +129,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.185683Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:05.948816Z", - "start_time": "2026-04-01T17:27:05.906263Z" + "end_time": "2026-04-01T17:28:22.089537Z", + "start_time": "2026-04-01T17:28:22.056020Z" } }, "source": [ @@ -162,8 +162,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.200161Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:05.986206Z", - "start_time": "2026-04-01T17:27:05.952679Z" + "end_time": "2026-04-01T17:28:22.128686Z", + "start_time": "2026-04-01T17:28:22.093357Z" } }, "source": "m1 = linopy.Model()\n\npower = m1.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m1.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand1 = xr.DataArray([50, 80, 30], coords=[time])\nm1.add_constraints(power >= demand1, name=\"demand\")\nm1.add_objective(fuel.sum())\n\n# breakpoints are auto-broadcast to match the time dimension\nm1.add_piecewise_formulation(\n (power, x_pts1),\n (fuel, y_pts1),\n name=\"pwl\",\n method=\"sos2\",\n)", @@ -190,8 +190,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:05.990643Z", - "start_time": "2026-04-01T17:27:05.988955Z" + "end_time": "2026-04-01T17:28:22.133481Z", + "start_time": "2026-04-01T17:28:22.131822Z" } }, "source": "print(m1)", @@ -235,8 +235,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.267514Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.053338Z", - "start_time": "2026-04-01T17:27:06.004296Z" + "end_time": "2026-04-01T17:28:22.184355Z", + "start_time": "2026-04-01T17:28:22.144895Z" } }, "source": [ @@ -249,7 +249,7 @@ "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-fywnqlto.lp\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-ov4ya6r1.lp\n", "Reading time = 0.00 seconds\n", "obj: 12 rows, 18 columns, 39 nonzeros\n", "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", @@ -258,7 +258,7 @@ "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", "\n", "Optimize a model with 12 rows, 18 columns and 39 nonzeros (Min)\n", - "Model fingerprint: 0x0c548251\n", + "Model fingerprint: 0x7b212967\n", "Model has 3 linear objective coefficients\n", "Model has 3 SOS constraints\n", "Variable types: 18 continuous, 0 integer (0 binary)\n", @@ -321,8 +321,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.327130Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.065261Z", - "start_time": "2026-04-01T17:27:06.058441Z" + "end_time": "2026-04-01T17:28:22.196765Z", + "start_time": "2026-04-01T17:28:22.190006Z" } }, "source": [ @@ -405,8 +405,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.339680Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.205889Z", - "start_time": "2026-04-01T17:27:06.068279Z" + "end_time": "2026-04-01T17:28:22.293275Z", + "start_time": "2026-04-01T17:28:22.201264Z" } }, "source": [ @@ -434,11 +434,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 2. Incremental formulation — Coal plant\n", + "## 2. Incremental formulation \u2014 Coal plant\n", "\n", "The coal plant has a **monotonically increasing** heat rate. Since all\n", "breakpoints are strictly monotonic, we can use the **incremental**\n", - "formulation — which uses fill-fraction variables with binary indicators." + "formulation \u2014 which uses fill-fraction variables with binary indicators." ] }, { @@ -452,8 +452,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.490084Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.210795Z", - "start_time": "2026-04-01T17:27:06.208665Z" + "end_time": "2026-04-01T17:28:22.305191Z", + "start_time": "2026-04-01T17:28:22.302343Z" } }, "source": [ @@ -485,8 +485,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.501307Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.269733Z", - "start_time": "2026-04-01T17:27:06.218536Z" + "end_time": "2026-04-01T17:28:22.363252Z", + "start_time": "2026-04-01T17:28:22.309089Z" } }, "source": "m2 = linopy.Model()\n\npower = m2.add_variables(name=\"power\", lower=0, upper=150, coords=[time])\nfuel = m2.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand2 = xr.DataArray([80, 120, 50], coords=[time])\nm2.add_constraints(power >= demand2, name=\"demand\")\nm2.add_objective(fuel.sum())\n\nm2.add_piecewise_formulation(\n (power, x_pts2),\n (fuel, y_pts2),\n name=\"pwl\",\n method=\"incremental\",\n)", @@ -523,8 +523,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.604427Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.317497Z", - "start_time": "2026-04-01T17:27:06.278796Z" + "end_time": "2026-04-01T17:28:22.416398Z", + "start_time": "2026-04-01T17:28:22.366896Z" } }, "source": [ @@ -537,7 +537,7 @@ "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-3b6ea5d8.lp\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-bmyktitw.lp\n", "Reading time = 0.00 seconds\n", "obj: 30 rows, 24 columns, 69 nonzeros\n", "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", @@ -589,8 +589,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.681822Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.331446Z", - "start_time": "2026-04-01T17:27:06.326994Z" + "end_time": "2026-04-01T17:28:22.429247Z", + "start_time": "2026-04-01T17:28:22.423565Z" } }, "source": [ @@ -673,8 +673,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.699334Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.406354Z", - "start_time": "2026-04-01T17:27:06.335595Z" + "end_time": "2026-04-01T17:28:22.515387Z", + "start_time": "2026-04-01T17:28:22.432596Z" } }, "source": [ @@ -702,10 +702,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 3. Disjunctive formulation — Diesel generator\n", + "## 3. Disjunctive formulation \u2014 Diesel generator\n", "\n", "The diesel generator has a **forbidden operating zone**: it must either\n", - "be off (0 MW) or run between 50–80 MW. Because of this gap, we use\n", + "be off (0 MW) or run between 50\u201380 MW. Because of this gap, we use\n", "**disjunctive** piecewise constraints via `linopy.segments()` and add a\n", "high-cost **backup** source to cover demand when the diesel is off or\n", "at its maximum.\n", @@ -725,8 +725,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.852387Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.418987Z", - "start_time": "2026-04-01T17:27:06.416214Z" + "end_time": "2026-04-01T17:28:22.522587Z", + "start_time": "2026-04-01T17:28:22.518566Z" } }, "source": [ @@ -768,8 +768,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.866931Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.470016Z", - "start_time": "2026-04-01T17:27:06.421487Z" + "end_time": "2026-04-01T17:28:22.577159Z", + "start_time": "2026-04-01T17:28:22.529026Z" } }, "source": "m3 = linopy.Model()\n\npower = m3.add_variables(name=\"power\", lower=0, upper=80, coords=[time])\ncost = m3.add_variables(name=\"cost\", lower=0, coords=[time])\nbackup = m3.add_variables(name=\"backup\", lower=0, coords=[time])\n\ndemand3 = xr.DataArray([10, 70, 90], coords=[time])\nm3.add_constraints(power + backup >= demand3, name=\"demand\")\nm3.add_objective((cost + 10 * backup).sum())\n\nm3.add_piecewise_formulation(\n (power, x_seg),\n (cost, y_seg),\n name=\"pwl\",\n)", @@ -806,8 +806,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.955741Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.522256Z", - "start_time": "2026-04-01T17:27:06.479790Z" + "end_time": "2026-04-01T17:28:22.633918Z", + "start_time": "2026-04-01T17:28:22.580144Z" } }, "source": [ @@ -820,7 +820,7 @@ "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-x2n7iuy8.lp\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-wlr9q50z.lp\n", "Reading time = 0.00 seconds\n", "obj: 18 rows, 27 columns, 48 nonzeros\n", "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", @@ -829,7 +829,7 @@ "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", "\n", "Optimize a model with 18 rows, 27 columns and 48 nonzeros (Min)\n", - "Model fingerprint: 0xf675751b\n", + "Model fingerprint: 0x4aeb7a1d\n", "Model has 6 linear objective coefficients\n", "Model has 6 SOS constraints\n", "Variable types: 21 continuous, 6 integer (6 binary)\n", @@ -847,7 +847,7 @@ "\n", "Root relaxation: cutoff, 0 iterations, 0.00 seconds (0.00 work units)\n", "\n", - "Explored 1 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n", + "Explored 1 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 1: 575 \n", @@ -887,8 +887,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.028095Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.533424Z", - "start_time": "2026-04-01T17:27:06.529179Z" + "end_time": "2026-04-01T17:28:22.640822Z", + "start_time": "2026-04-01T17:28:22.636837Z" } }, "source": [ @@ -989,7 +989,7 @@ "e", "s", " ", - "—", + "\u2014", " ", "C", "o", @@ -1214,7 +1214,7 @@ "t", "s", " ", - "—", + "\u2014", " ", "n", "o", @@ -1362,32 +1362,20 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.043484Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.558621Z", - "start_time": "2026-04-01T17:27:06.537791Z" + "end_time": "2026-04-01T17:28:22.668861Z", + "start_time": "2026-04-01T17:28:22.646927Z" } }, - "source": [ - "x_pts4 = linopy.breakpoints([0, 40, 80, 120])\n", - "# Concave curve: decreasing marginal fuel per MW\n", - "y_pts4 = linopy.breakpoints([0, 50, 90, 120])\n", - "\n", - "m4 = linopy.Model()\n", - "\n", - "power = m4.add_variables(name=\"power\", lower=0, upper=120, coords=[time])\n", - "fuel = m4.add_variables(name=\"fuel\", lower=0, coords=[time])\n", - "\n", - "# tangent_lines returns one LinearExpression per segment — pure LP, no aux variables\n", - "t = linopy.tangent_lines(power, x_pts4, y_pts4)\n", - "m4.add_constraints(fuel <= t, name=\"pwl\")\n", - "\n", - "demand4 = xr.DataArray([30, 80, 100], coords=[time])\n", - "m4.add_constraints(power == demand4, name=\"demand\")\n", - "# Maximize fuel (to push against the upper bound)\n", - "m4.add_objective(-fuel.sum())" - ], + "source": "x_pts4 = linopy.breakpoints([0, 40, 80, 120])\n# Concave curve: decreasing marginal fuel per MW\ny_pts4 = linopy.breakpoints([0, 50, 90, 120])\n\nm4 = linopy.Model()\n\npower = m4.add_variables(name=\"power\", lower=0, upper=120, coords=[time])\nfuel = m4.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand4 = xr.DataArray([30, 80, 100], coords=[time])\nm4.add_constraints(power == demand4, name=\"demand\")\n# Maximize fuel (to push against the upper bound)\nm4.add_objective(-fuel.sum())\n\n# tangent_lines returns one LinearExpression per segment \u2014 pure LP, no aux variables\nlinopy.tangent_lines(power, x_pts4, y_pts4)", "outputs": [], "execution_count": 17 }, + { + "cell_type": "code", + "metadata": {}, + "outputs": [], + "source": "t = linopy.tangent_lines(power, x_pts4, y_pts4)\nm4.add_constraints(fuel <= t, name=\"pwl\")" + }, { "cell_type": "code", "metadata": { @@ -1399,8 +1387,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.113810Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.585861Z", - "start_time": "2026-04-01T17:27:06.561038Z" + "end_time": "2026-04-01T17:28:22.696596Z", + "start_time": "2026-04-01T17:28:22.672774Z" } }, "source": [ @@ -1413,7 +1401,7 @@ "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-46j_zrn6.lp\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-truzuxpt.lp\n", "Reading time = 0.00 seconds\n", "obj: 12 rows, 6 columns, 21 nonzeros\n", "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", @@ -1464,8 +1452,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.171993Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.600907Z", - "start_time": "2026-04-01T17:27:06.597269Z" + "end_time": "2026-04-01T17:28:22.727938Z", + "start_time": "2026-04-01T17:28:22.721758Z" } }, "source": [ @@ -1548,8 +1536,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.192590Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.678383Z", - "start_time": "2026-04-01T17:27:06.605130Z" + "end_time": "2026-04-01T17:28:22.827955Z", + "start_time": "2026-04-01T17:28:22.748152Z" } }, "source": [ @@ -1577,7 +1565,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 5. Slopes mode — Building breakpoints from slopes\n", + "## 5. Slopes mode \u2014 Building breakpoints from slopes\n", "\n", "Sometimes you know the **slope** of each segment rather than the y-values\n", "at each breakpoint. The `breakpoints()` factory can compute y-values from\n", @@ -1595,8 +1583,8 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.345513Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.688859Z", - "start_time": "2026-04-01T17:27:06.686556Z" + "end_time": "2026-04-01T17:28:22.838752Z", + "start_time": "2026-04-01T17:28:22.836497Z" } }, "source": [ @@ -2533,8 +2521,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.699522Z", - "start_time": "2026-04-01T17:27:06.697229Z" + "end_time": "2026-04-01T17:28:22.843383Z", + "start_time": "2026-04-01T17:28:22.841319Z" } }, "source": [ @@ -2564,8 +2552,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.775344Z", - "start_time": "2026-04-01T17:27:06.707055Z" + "end_time": "2026-04-01T17:28:22.918581Z", + "start_time": "2026-04-01T17:28:22.850187Z" } }, "source": "m6 = linopy.Model()\n\npower = m6.add_variables(name=\"power\", lower=0, upper=p_max, coords=[time])\nfuel = m6.add_variables(name=\"fuel\", lower=0, coords=[time])\ncommit = m6.add_variables(name=\"commit\", binary=True, coords=[time])\n\n# Demand: low at t=1 (cheaper to stay off), high at t=2,3\ndemand6 = xr.DataArray([15, 70, 50], coords=[time])\nbackup = m6.add_variables(name=\"backup\", lower=0, coords=[time])\nm6.add_constraints(power + backup >= demand6, name=\"demand\")\n\n# Objective: fuel + startup cost + backup at /MW\nm6.add_objective((fuel + startup_cost * commit + 5 * backup).sum())\n\n# The active parameter gates the PWL with the commitment binary:\n# - commit=1: power in [30, 100], fuel = f(power)\n# - commit=0: power = 0, fuel = 0\nm6.add_piecewise_formulation(\n (power, x_pts6),\n (fuel, y_pts6),\n active=commit,\n name=\"pwl\",\n method=\"incremental\",\n)", @@ -2596,8 +2584,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.834804Z", - "start_time": "2026-04-01T17:27:06.783525Z" + "end_time": "2026-04-01T17:28:22.999635Z", + "start_time": "2026-04-01T17:28:22.943236Z" } }, "source": [ @@ -2610,7 +2598,7 @@ "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-tcp1bwlk.lp\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-prvz64c7.lp\n", "Reading time = 0.00 seconds\n", "obj: 27 rows, 24 columns, 66 nonzeros\n", "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", @@ -2676,8 +2664,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.843069Z", - "start_time": "2026-04-01T17:27:06.837926Z" + "end_time": "2026-04-01T17:28:23.007912Z", + "start_time": "2026-04-01T17:28:23.003644Z" } }, "source": [ @@ -2763,8 +2751,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.924865Z", - "start_time": "2026-04-01T17:27:06.847612Z" + "end_time": "2026-04-01T17:28:23.099707Z", + "start_time": "2026-04-01T17:28:23.018181Z" } }, "source": [ @@ -2924,7 +2912,7 @@ "0", "`", " ", - "—", + "\u2014", " ", "t", "h", @@ -3490,8 +3478,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.936048Z", - "start_time": "2026-04-01T17:27:06.933369Z" + "end_time": "2026-04-01T17:28:23.106128Z", + "start_time": "2026-04-01T17:28:23.102693Z" } }, "source": [ @@ -3527,11 +3515,11 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:06.977986Z", - "start_time": "2026-04-01T17:27:06.938485Z" + "end_time": "2026-04-01T17:28:23.156431Z", + "start_time": "2026-04-01T17:28:23.115330Z" } }, - "source": "m7 = linopy.Model()\n\npower = m7.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m7.add_variables(name=\"fuel\", lower=0, coords=[time])\nheat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n\n# Fixed power dispatch determines the operating point — fuel and heat follow\npower_dispatch = xr.DataArray([20, 60, 90], coords=[time])\nm7.add_constraints(power == power_dispatch, name=\"power_dispatch\")\nm7.add_objective(fuel.sum())\n\n# N-variable: all three linked through shared interpolation weights\nm7.add_piecewise_formulation(\n (power, bp_chp.sel(var=\"power\")),\n (fuel, bp_chp.sel(var=\"fuel\")),\n (heat, bp_chp.sel(var=\"heat\")),\n name=\"chp\",\n method=\"sos2\",\n)", + "source": "m7 = linopy.Model()\n\npower = m7.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m7.add_variables(name=\"fuel\", lower=0, coords=[time])\nheat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n\n# Fixed power dispatch determines the operating point \u2014 fuel and heat follow\npower_dispatch = xr.DataArray([20, 60, 90], coords=[time])\nm7.add_constraints(power == power_dispatch, name=\"power_dispatch\")\nm7.add_objective(fuel.sum())\n\n# N-variable: all three linked through shared interpolation weights\nm7.add_piecewise_formulation(\n (power, bp_chp.sel(var=\"power\")),\n (fuel, bp_chp.sel(var=\"fuel\")),\n (heat, bp_chp.sel(var=\"heat\")),\n name=\"chp\",\n method=\"sos2\",\n)", "outputs": [ { "data": { @@ -3555,8 +3543,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.007460Z", - "start_time": "2026-04-01T17:27:06.980545Z" + "end_time": "2026-04-01T17:28:23.195969Z", + "start_time": "2026-04-01T17:28:23.165043Z" } }, "source": [ @@ -3569,7 +3557,7 @@ "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-_1vpbkgs.lp\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-nakr2nzl.lp\n", "Reading time = 0.00 seconds\n", "obj: 15 rows, 21 columns, 51 nonzeros\n", "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", @@ -3625,8 +3613,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.021084Z", - "start_time": "2026-04-01T17:27:07.016008Z" + "end_time": "2026-04-01T17:28:23.208354Z", + "start_time": "2026-04-01T17:28:23.202782Z" } }, "source": [ @@ -3707,8 +3695,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.102824Z", - "start_time": "2026-04-01T17:27:07.025649Z" + "end_time": "2026-04-01T17:28:23.296918Z", + "start_time": "2026-04-01T17:28:23.217335Z" } }, "source": [ @@ -3734,14 +3722,14 @@ { "cell_type": "markdown", "metadata": {}, - "source": "## 8. Per-entity breakpoints — Fleet of generators\n\nWhen different generators have different efficiency curves, pass\nper-entity breakpoints using a dict with `breakpoints()`. The breakpoint\narrays are auto-broadcast over the remaining dimensions (here `time`)." + "source": "## 8. Per-entity breakpoints \u2014 Fleet of generators\n\nWhen different generators have different efficiency curves, pass\nper-entity breakpoints using a dict with `breakpoints()`. The breakpoint\narrays are auto-broadcast over the remaining dimensions (here `time`)." }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.117343Z", - "start_time": "2026-04-01T17:27:07.113289Z" + "end_time": "2026-04-01T17:28:23.308251Z", + "start_time": "2026-04-01T17:28:23.304773Z" } }, "source": [ @@ -3781,8 +3769,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.183189Z", - "start_time": "2026-04-01T17:27:07.120111Z" + "end_time": "2026-04-01T17:28:23.378677Z", + "start_time": "2026-04-01T17:28:23.316179Z" } }, "source": "m8 = linopy.Model()\n\npower = m8.add_variables(name=\"power\", lower=0, upper=150, coords=[gens, time])\nfuel = m8.add_variables(name=\"fuel\", lower=0, coords=[gens, time])\n\ndemand8 = xr.DataArray([80, 120, 60], coords=[time])\nm8.add_constraints(power.sum(\"gen\") >= demand8, name=\"demand\")\nm8.add_objective(fuel.sum())\n\n# Per-entity breakpoints: each generator gets its own curve\nm8.add_piecewise_formulation(\n (power, x_gen),\n (fuel, y_gen),\n name=\"pwl\",\n)", @@ -3812,8 +3800,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.232662Z", - "start_time": "2026-04-01T17:27:07.190995Z" + "end_time": "2026-04-01T17:28:23.433861Z", + "start_time": "2026-04-01T17:28:23.386142Z" } }, "source": [ @@ -3826,7 +3814,7 @@ "text": [ "Set parameter Username\n", "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-rnwq0oox.lp\n", + "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-5iggilc6.lp\n", "Reading time = 0.00 seconds\n", "obj: 57 rows, 48 columns, 138 nonzeros\n", "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", @@ -3891,8 +3879,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.247121Z", - "start_time": "2026-04-01T17:27:07.241878Z" + "end_time": "2026-04-01T17:28:23.441819Z", + "start_time": "2026-04-01T17:28:23.437057Z" } }, "source": [ @@ -3990,8 +3978,8 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:27:07.332241Z", - "start_time": "2026-04-01T17:27:07.251731Z" + "end_time": "2026-04-01T17:28:23.528662Z", + "start_time": "2026-04-01T17:28:23.444194Z" } }, "source": "sol = m8.solution\nfig, axes = plt.subplots(1, 2, figsize=(10, 3.5))\n\nfor i, gen in enumerate(gens):\n ax = axes[i]\n fuel_bp = y_gen.sel(gen=gen).values\n power_bp = x_gen.sel(gen=gen).values\n ax.plot(fuel_bp, power_bp, \"o-\", color=f\"C{i}\", label=\"Breakpoints\")\n for t in time:\n ax.plot(\n float(sol[\"fuel\"].sel(gen=gen, time=t)),\n float(sol[\"power\"].sel(gen=gen, time=t)),\n \"D\",\n color=\"black\",\n ms=8,\n )\n ax.set(xlabel=\"Fuel\", ylabel=\"Power [MW]\", title=f\"{gen.title()} heat-rate curve\")\n ax.legend()\n\nplt.tight_layout()", @@ -4034,4 +4022,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From b12683fa93400fe8df899f693769b91d23cdc55e Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:35:33 +0200 Subject: [PATCH 04/16] feat: show dims in PiecewiseFormulation repr and user dims in Model groups PiecewiseFormulation now shows full dims (including internal) for each variable and constraint. Model groups section shows "over (dim1, dim2)" for user-facing dims only. Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/model.py | 9 ++++++++- linopy/piecewise.py | 10 ++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/linopy/model.py b/linopy/model.py index 5c33f964..1edc5ac8 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -514,9 +514,16 @@ def __repr__(self) -> str: for group in self._groups.values(): n_vars = len(group.variables) n_cons = len(group.constraints) + # Collect user-facing dims (skip internal _ prefixed dims) + user_dims: list[str] = [] + for var in group.variables.data.values(): + for d in var.coords: + if not str(d).startswith("_") and str(d) not in user_dims: + user_dims.append(str(d)) + dims_str = f" over ({', '.join(user_dims)})" if user_dims else "" result += ( f" * {group.name} ({group.method}):" - f" {n_vars} variables, {n_cons} constraints\n" + f" {n_vars} variables, {n_cons} constraints{dims_str}\n" ) result += f"\nStatus:\n-------\n{self.status}" diff --git a/linopy/piecewise.py b/linopy/piecewise.py index 3d8e9e14..618c53c8 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -80,11 +80,13 @@ def __repr__(self) -> str: n_cons = len(self.constraints) r = f"PiecewiseFormulation '{self.name}' ({self.method})\n" r += f" Variables ({n_vars}):\n" - for vname in self.variables: - r += f" * {vname}\n" + for vname, var in self.variables.items(): + dims = ", ".join(str(d) for d in var.coords) if var.coords else "" + r += f" * {vname} ({dims})\n" if dims else f" * {vname}\n" r += f" Constraints ({n_cons}):\n" - for cname in self.constraints: - r += f" * {cname}\n" + for cname, con in self.constraints.items(): + dims = ", ".join(str(d) for d in con.coords) if con.coords else "" + r += f" * {cname} ({dims})\n" if dims else f" * {cname}\n" return r From 9cdd41e88a3bbd3594594628eb5afc2a303e5ff1 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:35:55 +0200 Subject: [PATCH 05/16] refac: remove counts from PiecewiseFormulation repr Match style of Variables/Constraints containers which don't show counts. Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/piecewise.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/linopy/piecewise.py b/linopy/piecewise.py index 618c53c8..736a976b 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -76,14 +76,12 @@ class PiecewiseFormulation: constraints: Constraints def __repr__(self) -> str: - n_vars = len(self.variables) - n_cons = len(self.constraints) r = f"PiecewiseFormulation '{self.name}' ({self.method})\n" - r += f" Variables ({n_vars}):\n" + r += " Variables:\n" for vname, var in self.variables.items(): dims = ", ".join(str(d) for d in var.coords) if var.coords else "" r += f" * {vname} ({dims})\n" if dims else f" * {vname}\n" - r += f" Constraints ({n_cons}):\n" + r += " Constraints:\n" for cname, con in self.constraints.items(): dims = ", ".join(str(d) for d in con.coords) if con.coords else "" r += f" * {cname} ({dims})\n" if dims else f" * {cname}\n" From 820798680f5b176e5fcf158a0eb183299260de37 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:39:29 +0200 Subject: [PATCH 06/16] refac: rename _groups to _piecewise_formulations, use direct section name Replace generic "Groups" with "Piecewise Formulations" in Model repr. Rename internal registry and helper to match. Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/model.py | 30 +++++++++++++++--------------- linopy/piecewise.py | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/linopy/model.py b/linopy/model.py index 1edc5ac8..b6ca74b2 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -231,7 +231,7 @@ class Model: "_auto_mask", "_solver_dir", "_relaxed_registry", - "_groups", + "_piecewise_formulations", "solver_model", "solver_name", "matrices", @@ -288,7 +288,7 @@ def __init__( self._chunk: T_Chunks = chunk self._force_dim_names: bool = bool(force_dim_names) self._auto_mask: bool = bool(auto_mask) - self._groups: dict[str, PiecewiseFormulation] = {} + self._piecewise_formulations: dict[str, PiecewiseFormulation] = {} self._relaxed_registry: dict[str, str] = {} self._solver_dir: Path = Path( gettempdir() if solver_dir is None else solver_dir @@ -498,7 +498,7 @@ def __repr__(self) -> str: """ Return a string representation of the linopy model. """ - grouped_names = self._grouped_names() + grouped_names = self._piecewise_names() var_string = self.variables._repr_filtered(grouped_names) con_string = self.constraints._repr_filtered(grouped_names) model_string = f"Linopy {self.type} model" @@ -509,32 +509,32 @@ def __repr__(self) -> str: f"Constraints:\n------------\n{con_string}" ) - if self._groups: - result += "\nGroups:\n-------\n" - for group in self._groups.values(): - n_vars = len(group.variables) - n_cons = len(group.constraints) + if self._piecewise_formulations: + result += "\nPiecewise Formulations:\n----------------------\n" + for pwl in self._piecewise_formulations.values(): + n_vars = len(pwl.variables) + n_cons = len(pwl.constraints) # Collect user-facing dims (skip internal _ prefixed dims) user_dims: list[str] = [] - for var in group.variables.data.values(): + for var in pwl.variables.data.values(): for d in var.coords: if not str(d).startswith("_") and str(d) not in user_dims: user_dims.append(str(d)) dims_str = f" over ({', '.join(user_dims)})" if user_dims else "" result += ( - f" * {group.name} ({group.method}):" + f" * {pwl.name} ({pwl.method}):" f" {n_vars} variables, {n_cons} constraints{dims_str}\n" ) result += f"\nStatus:\n-------\n{self.status}" return result - def _grouped_names(self) -> set[str]: - """Return all variable/constraint names that belong to a group.""" + def _piecewise_names(self) -> set[str]: + """Return all variable/constraint names belonging to piecewise formulations.""" names: set[str] = set() - for group in self._groups.values(): - names.update(group.variables) - names.update(group.constraints) + for pwl in self._piecewise_formulations.values(): + names.update(pwl.variables) + names.update(pwl.constraints) return names def __getitem__(self, key: str) -> Variable: diff --git a/linopy/piecewise.py b/linopy/piecewise.py index 736a976b..9580072c 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -756,7 +756,7 @@ def add_piecewise_formulation( variables=model.variables[new_vars], constraints=model.constraints[new_cons], ) - model._groups[name] = result + model._piecewise_formulations[name] = result return result From 757ede97cdc2da5c9bea1dc5857e027f8f708620 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:41:20 +0200 Subject: [PATCH 07/16] refac: move method after counts in repr to avoid looking like a dim Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/model.py | 5 +++-- linopy/piecewise.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/linopy/model.py b/linopy/model.py index b6ca74b2..a9a9399c 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -522,8 +522,9 @@ def __repr__(self) -> str: user_dims.append(str(d)) dims_str = f" over ({', '.join(user_dims)})" if user_dims else "" result += ( - f" * {pwl.name} ({pwl.method}):" - f" {n_vars} variables, {n_cons} constraints{dims_str}\n" + f" * {pwl.name}:" + f" {n_vars} variables, {n_cons} constraints{dims_str}" + f" — {pwl.method}\n" ) result += f"\nStatus:\n-------\n{self.status}" diff --git a/linopy/piecewise.py b/linopy/piecewise.py index 9580072c..e1745fb5 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -76,7 +76,7 @@ class PiecewiseFormulation: constraints: Constraints def __repr__(self) -> str: - r = f"PiecewiseFormulation '{self.name}' ({self.method})\n" + r = f"PiecewiseFormulation '{self.name}' — {self.method}\n" r += " Variables:\n" for vname, var in self.variables.items(): dims = ", ".join(str(d) for d in var.coords) if var.coords else "" From 534d59d1485781551f55783f65dd19d96da747f7 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:43:17 +0200 Subject: [PATCH 08/16] refac: show dims before name like regular variables/constraints Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linopy/model.py b/linopy/model.py index a9a9399c..fed73a7a 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -520,10 +520,10 @@ def __repr__(self) -> str: for d in var.coords: if not str(d).startswith("_") and str(d) not in user_dims: user_dims.append(str(d)) - dims_str = f" over ({', '.join(user_dims)})" if user_dims else "" + dims_str = f" ({', '.join(user_dims)})" if user_dims else "" result += ( - f" * {pwl.name}:" - f" {n_vars} variables, {n_cons} constraints{dims_str}" + f" * {pwl.name}{dims_str}:" + f" {n_vars} variables, {n_cons} constraints" f" — {pwl.method}\n" ) From f8c7f45fe76864de49f1b2bd9db78b18ef89bbac Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:44:46 +0200 Subject: [PATCH 09/16] refac: compact piecewise formulation line in model repr Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/model.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/linopy/model.py b/linopy/model.py index fed73a7a..dcb39cf3 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -522,9 +522,8 @@ def __repr__(self) -> str: user_dims.append(str(d)) dims_str = f" ({', '.join(user_dims)})" if user_dims else "" result += ( - f" * {pwl.name}{dims_str}:" - f" {n_vars} variables, {n_cons} constraints" - f" — {pwl.method}\n" + f" * {pwl.name}{dims_str}" + f" — {pwl.method}, {n_vars} vars, {n_cons} cons\n" ) result += f"\nStatus:\n-------\n{self.status}" From 290a20aa67e6ce79eb9f0dbc2a84dd018cc7cf17 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:49:18 +0200 Subject: [PATCH 10/16] refac: use backtick name style in PiecewiseFormulation repr Match Constraint repr pattern: `name` instead of 'name'. Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/piecewise.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linopy/piecewise.py b/linopy/piecewise.py index e1745fb5..721cbe6b 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -76,7 +76,7 @@ class PiecewiseFormulation: constraints: Constraints def __repr__(self) -> str: - r = f"PiecewiseFormulation '{self.name}' — {self.method}\n" + r = f"PiecewiseFormulation `{self.name}` — {self.method}\n" r += " Variables:\n" for vname, var in self.variables.items(): dims = ", ".join(str(d) for d in var.coords) if var.coords else "" From e1a5ddfa920ce58134ad6213791792840b5fe873 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:50:18 +0200 Subject: [PATCH 11/16] feat: show user dims with sizes in PiecewiseFormulation header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match Constraint repr style: `name` [dim: size, ...] — method Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/piecewise.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/linopy/piecewise.py b/linopy/piecewise.py index 721cbe6b..b67de05d 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -76,7 +76,18 @@ class PiecewiseFormulation: constraints: Constraints def __repr__(self) -> str: - r = f"PiecewiseFormulation `{self.name}` — {self.method}\n" + # Collect user-facing dims with sizes (skip internal _ prefixed dims) + user_dims: dict[str, int] = {} + for var in self.variables.data.values(): + for d in var.coords: + ds = str(d) + if not ds.startswith("_") and ds not in user_dims: + user_dims[ds] = var.data.sizes[d] + dims_str = ", ".join(f"{d}: {s}" for d, s in user_dims.items()) + header = f"PiecewiseFormulation `{self.name}`" + if dims_str: + header += f" [{dims_str}]" + r = f"{header} — {self.method}\n" r += " Variables:\n" for vname, var in self.variables.items(): dims = ", ".join(str(d) for d in var.coords) if var.coords else "" From 470495cd10386a5b6172cce14bdde799615549a8 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:08:16 +0200 Subject: [PATCH 12/16] fix: clear notebook outputs to fix nbformat validation Remove jetTransient metadata and normalize cell format. Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/piecewise-linear-constraints.ipynb | 1714 ++----------------- 1 file changed, 177 insertions(+), 1537 deletions(-) diff --git a/examples/piecewise-linear-constraints.ipynb b/examples/piecewise-linear-constraints.ipynb index f5b94b58..a34c63e5 100644 --- a/examples/piecewise-linear-constraints.ipynb +++ b/examples/piecewise-linear-constraints.ipynb @@ -16,96 +16,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.166974Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.053416Z", - "start_time": "2026-04-01T17:28:21.542852Z" + "end_time": "2026-04-01T17:50:20.809300Z", + "start_time": "2026-04-01T17:50:20.202138Z" } }, - "source": [ - "import matplotlib.pyplot as plt\n", - "import pandas as pd\n", - "import xarray as xr\n", - "\n", - "import linopy\n", - "\n", - "time = pd.Index([1, 2, 3], name=\"time\")\n", - "\n", - "\n", - "def plot_pwl_results(model, breakpoints, demand, *, x_name=\"power\", color=\"C0\"):\n", - " \"\"\"\n", - " Plot PWL curves with operating points and dispatch vs demand.\n", - "\n", - " Parameters\n", - " ----------\n", - " model : linopy.Model\n", - " Solved model.\n", - " breakpoints : DataArray\n", - " Breakpoints array. For 2-variable cases pass a DataArray with a\n", - " \"var\" dimension containing two coordinates (x and y variable names).\n", - " Alternatively pass two separate arrays and they will be stacked.\n", - " demand : DataArray\n", - " Demand time series (plotted as step line).\n", - " x_name : str\n", - " Name of the x-axis variable (used for the curve plot).\n", - " color : str\n", - " Base color for the plot.\n", - " \"\"\"\n", - " sol = model.solution\n", - " var_names = list(breakpoints.coords[\"var\"].values)\n", - " bp_x = breakpoints.sel(var=x_name).values\n", - "\n", - " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3.5))\n", - "\n", - " # Left: breakpoint curves with operating points\n", - " colors = [f\"C{i}\" for i in range(len(var_names))]\n", - " for var, c in zip(var_names, colors):\n", - " if var == x_name:\n", - " continue\n", - " bp_y = breakpoints.sel(var=var).values\n", - " ax1.plot(bp_x, bp_y, \"o-\", color=c, label=f\"{var} (breakpoints)\")\n", - " for t in time:\n", - " ax1.plot(\n", - " float(sol[x_name].sel(time=t)),\n", - " float(sol[var].sel(time=t)),\n", - " \"D\",\n", - " color=c,\n", - " ms=10,\n", - " )\n", - " ax1.set(xlabel=x_name.title(), title=\"PWL curve\")\n", - " ax1.legend()\n", - "\n", - " # Right: dispatch vs demand\n", - " x = list(range(len(time)))\n", - " power_vals = sol[x_name].values\n", - " ax2.bar(x, power_vals, color=color, label=x_name.title())\n", - " if \"backup\" in sol:\n", - " ax2.bar(\n", - " x,\n", - " sol[\"backup\"].values,\n", - " bottom=power_vals,\n", - " color=\"C3\",\n", - " alpha=0.5,\n", - " label=\"Backup\",\n", - " )\n", - " ax2.step(\n", - " [v - 0.5 for v in x] + [x[-1] + 0.5],\n", - " list(demand.values) + [demand.values[-1]],\n", - " where=\"post\",\n", - " color=\"black\",\n", - " lw=2,\n", - " label=\"Demand\",\n", - " )\n", - " ax2.set(\n", - " xlabel=\"Time\",\n", - " ylabel=\"MW\",\n", - " title=\"Dispatch\",\n", - " xticks=x,\n", - " xticklabels=time.values,\n", - " )\n", - " ax2.legend()\n", - " plt.tight_layout()" - ], + "source": "import matplotlib.pyplot as plt\nimport pandas as pd\nimport xarray as xr\n\nimport linopy\n\ntime = pd.Index([1, 2, 3], name=\"time\")\n\n\ndef plot_pwl_results(model, breakpoints, demand, *, x_name=\"power\", color=\"C0\"):\n \"\"\"\n Plot PWL curves with operating points and dispatch vs demand.\n\n Parameters\n ----------\n model : linopy.Model\n Solved model.\n breakpoints : DataArray\n Breakpoints array. For 2-variable cases pass a DataArray with a\n \"var\" dimension containing two coordinates (x and y variable names).\n Alternatively pass two separate arrays and they will be stacked.\n demand : DataArray\n Demand time series (plotted as step line).\n x_name : str\n Name of the x-axis variable (used for the curve plot).\n color : str\n Base color for the plot.\n \"\"\"\n sol = model.solution\n var_names = list(breakpoints.coords[\"var\"].values)\n bp_x = breakpoints.sel(var=x_name).values\n\n fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3.5))\n\n # Left: breakpoint curves with operating points\n colors = [f\"C{i}\" for i in range(len(var_names))]\n for var, c in zip(var_names, colors):\n if var == x_name:\n continue\n bp_y = breakpoints.sel(var=var).values\n ax1.plot(bp_x, bp_y, \"o-\", color=c, label=f\"{var} (breakpoints)\")\n for t in time:\n ax1.plot(\n float(sol[x_name].sel(time=t)),\n float(sol[var].sel(time=t)),\n \"D\",\n color=c,\n ms=10,\n )\n ax1.set(xlabel=x_name.title(), title=\"PWL curve\")\n ax1.legend()\n\n # Right: dispatch vs demand\n x = list(range(len(time)))\n power_vals = sol[x_name].values\n ax2.bar(x, power_vals, color=color, label=x_name.title())\n if \"backup\" in sol:\n ax2.bar(\n x,\n sol[\"backup\"].values,\n bottom=power_vals,\n color=\"C3\",\n alpha=0.5,\n label=\"Backup\",\n )\n ax2.step(\n [v - 0.5 for v in x] + [x[-1] + 0.5],\n list(demand.values) + [demand.values[-1]],\n where=\"post\",\n color=\"black\",\n lw=2,\n label=\"Demand\",\n )\n ax2.set(\n xlabel=\"Time\",\n ylabel=\"MW\",\n title=\"Dispatch\",\n xticks=x,\n xticklabels=time.values,\n )\n ax2.legend()\n plt.tight_layout()", "outputs": [], - "execution_count": 1 + "execution_count": null }, { "cell_type": "markdown", @@ -129,27 +46,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.185683Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.089537Z", - "start_time": "2026-04-01T17:28:22.056020Z" + "end_time": "2026-04-01T17:50:20.848260Z", + "start_time": "2026-04-01T17:50:20.813939Z" } }, - "source": [ - "x_pts1 = linopy.breakpoints([0, 30, 60, 100])\n", - "y_pts1 = linopy.breakpoints([0, 36, 84, 170])\n", - "print(\"x_pts:\", x_pts1.values)\n", - "print(\"y_pts:\", y_pts1.values)" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "x_pts: [ 0. 30. 60. 100.]\n", - "y_pts: [ 0. 36. 84. 170.]\n" - ] - } - ], - "execution_count": 2 + "source": "x_pts1 = linopy.breakpoints([0, 30, 60, 100])\ny_pts1 = linopy.breakpoints([0, 36, 84, 170])\nprint(\"x_pts:\", x_pts1.values)\nprint(\"y_pts:\", y_pts1.values)", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -162,67 +65,25 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.200161Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.128686Z", - "start_time": "2026-04-01T17:28:22.093357Z" + "end_time": "2026-04-01T17:50:20.884905Z", + "start_time": "2026-04-01T17:50:20.851433Z" } }, "source": "m1 = linopy.Model()\n\npower = m1.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m1.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand1 = xr.DataArray([50, 80, 30], coords=[time])\nm1.add_constraints(power >= demand1, name=\"demand\")\nm1.add_objective(fuel.sum())\n\n# breakpoints are auto-broadcast to match the time dimension\nm1.add_piecewise_formulation(\n (power, x_pts1),\n (fuel, y_pts1),\n name=\"pwl\",\n method=\"sos2\",\n)", - "outputs": [ - { - "data": { - "text/plain": [ - "PiecewiseFormulation 'pwl' (sos2)\n", - " Variables (1):\n", - " * pwl_lambda\n", - " Constraints (2):\n", - " * pwl_convex\n", - " * pwl_x_link" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 3 + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.133481Z", - "start_time": "2026-04-01T17:28:22.131822Z" + "end_time": "2026-04-01T17:50:20.889691Z", + "start_time": "2026-04-01T17:50:20.888003Z" } }, "source": "print(m1)", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Linopy LP model\n", - "===============\n", - "\n", - "Variables:\n", - "----------\n", - " * power (time)\n", - " * fuel (time)\n", - "\n", - "Constraints:\n", - "------------\n", - " * demand (time)\n", - "\n", - "Groups:\n", - "-------\n", - " * pwl (sos2): 1 variables, 2 constraints\n", - "\n", - "Status:\n", - "-------\n", - "initialized\n" - ] - } - ], - "execution_count": 4 + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -235,80 +96,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.267514Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.184355Z", - "start_time": "2026-04-01T17:28:22.144895Z" + "end_time": "2026-04-01T17:50:20.941957Z", + "start_time": "2026-04-01T17:50:20.900785Z" } }, - "source": [ - "m1.solve(reformulate_sos=\"auto\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-ov4ya6r1.lp\n", - "Reading time = 0.00 seconds\n", - "obj: 12 rows, 18 columns, 39 nonzeros\n", - "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", - "\n", - "CPU model: Apple M3\n", - "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 12 rows, 18 columns and 39 nonzeros (Min)\n", - "Model fingerprint: 0x7b212967\n", - "Model has 3 linear objective coefficients\n", - "Model has 3 SOS constraints\n", - "Variable types: 18 continuous, 0 integer (0 binary)\n", - "Coefficient statistics:\n", - " Matrix range [1e+00, 2e+02]\n", - " Objective range [1e+00, 1e+00]\n", - " Bounds range [1e+00, 1e+02]\n", - " RHS range [1e+00, 8e+01]\n", - "\n", - "Presolve removed 8 rows and 13 columns\n", - "Presolve time: 0.00s\n", - "Presolved: 4 rows, 5 columns, 10 nonzeros\n", - "Variable types: 4 continuous, 1 integer (1 binary)\n", - "Found heuristic solution: objective 231.0000000\n", - "\n", - "Root relaxation: cutoff, 2 iterations, 0.00 seconds (0.00 work units)\n", - "\n", - " Nodes | Current Node | Objective Bounds | Work\n", - " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", - "\n", - " 0 0 cutoff 0 231.00000 231.00000 0.00% - 0s\n", - "\n", - "Explored 1 nodes (2 simplex iterations) in 0.00 seconds (0.00 work units)\n", - "Thread count was 8 (of 8 available processors)\n", - "\n", - "Solution count 1: 231 \n", - "\n", - "Optimal solution found (tolerance 1.00e-04)\n", - "Best objective 2.310000000000e+02, best bound 2.310000000000e+02, gap 0.0000%\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Dual values of MILP couldn't be parsed\n" - ] - }, - { - "data": { - "text/plain": [ - "('ok', 'optimal')" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 5 + "source": "m1.solve(reformulate_sos=\"auto\")", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -321,78 +115,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.327130Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.196765Z", - "start_time": "2026-04-01T17:28:22.190006Z" + "end_time": "2026-04-01T17:50:20.957062Z", + "start_time": "2026-04-01T17:50:20.946704Z" } }, - "source": [ - "m1.solution[[\"power\", \"fuel\"]].to_pandas()" - ], - "outputs": [ - { - "data": { - "text/plain": [ - " power fuel\n", - "time \n", - "1 50.0 68.0\n", - "2 80.0 127.0\n", - "3 30.0 36.0" - ], - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
powerfuel
time
150.068.0
280.0127.0
330.036.0
\n", - "
" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 6 + "source": "m1.solution[[\"power\", \"fuel\"]].to_pandas()", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -405,30 +134,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.339680Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.293275Z", - "start_time": "2026-04-01T17:28:22.201264Z" + "end_time": "2026-04-01T17:50:21.068805Z", + "start_time": "2026-04-01T17:50:20.970458Z" } }, - "source": [ - "bp1 = linopy.breakpoints({\"power\": x_pts1.values, \"fuel\": y_pts1.values}, dim=\"var\")\n", - "plot_pwl_results(m1, bp1, demand1, color=\"C0\")" - ], - "outputs": [ - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "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XZdevnXrVlWsWPG0xy0QTyoYT47dR9izZ48OHDiQ6nYDoZA/f35X4yDSiikBGUr8KWnbV9LhvVLuolKZK6VobpgBAFKHWCXyrtODFnRPmDBBNWvWdJXOz2b16tVuMfEiRYqkyff2Bdz2ejlz5iSQQVj/0T169Kj27dvn9osXLx7qJgFIytoPpDkPSod2/XMsbwmp9TPSpddnupGXIUOG6I033nD9aYkSJdStWzc9+uij/v7U/nY9/vjjevXVV11/e9VVV2ncuHEqX758qJsPAGGPWCXyrtNTHXRbCvimTZv8+1u2bHFBs83PLl26tH+Yfdq0afrf//532tcvXbpUX3/9tatobvO9bX/AgAG67bbbdMEFFygtLhZ8AbcVagPCXY4cOdxH+w9t71tSzYEwDLjfvd2634THD+32Hr/p9UwVeD/zzDMugLa6LJdddplWrlyp7t27u/Q5q8linn32Wb3wwgvuOeXKldPgwYPVqlUrrV27VtmzZw/1jwAAYYtYJTKv01MddFvnawGzz8CBA93Hrl27avLkye7zt99+290Z6Ny582lfb2ni9rjdRbd52tZZW9Dte53z5ZvDbSPcQEbhe7/a+5egGwizlHIb4U4ccDt2LEqa85BU6dpMk2puBU7btWuna6+91u2XLVtWb731lpYvX+72rX8fNWqUG/m255nXX39dRYsW1axZs3TLLbeEtP0AEM6IVSLzOj3VQXfjxo1dh3smvXv3dltSrGr5smXLFGzMjUVGwvsVCFM2hzswpfw0HunQTu/zyl2tzODKK6/UK6+8og0bNqhChQr67rvv9MUXX/hXGLEMN0uNbN68uf9rbBTc6rNY9lpSQXdSBVGBYLFsy8cee0x//vknJxmOZdc+8cQT6tSpU9icEa79Mo60+F0FdckwAAAyNCualpbPywAeeughFxTbCiR2R99SIZ966il16dLFPW4Bt7GR7UC273ssMZb+RHqygPunn37ipCMBmwYTTkE3IgtBd5iw7AFbNm369On6448/9O2336p69ern/bqWxm/pfjbv/mx/iPbu3etGN3wZDfb9LYUwvS1atMhNYbDzYNUCgyU9fsbx48fr448/1ocffhi07wEgiLLnS9nzrJp5JvHuu+/qzTff1NSpU92cbus/+vfv7wqq2VSyczFo0KAE08h8S38CweAb4bYivakpfLTn4DF+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UhNwB7riX1KdXsFoEQAAQMShIg4AZEbnGnCblRNStpwYAAAAzoqgGwAym/MJuH3s6wm8AQAA0j/oXrJkidq2basSJUooKipKs2bN8j924sQJPfjgg6pSpYpy5crlnnP77bdr165dCV6jbNmy7msDtxEjRpz/TwMAkS4tAm4fAu+ItXPnTt12220qWLCgcuTI4fr1lStX+h/3eDx67LHHVLx4cfd48+bNtXHjxpC2GQCATBN0HzlyRNWqVdPYsWNPe+zo0aP65ptvNHjwYPdxxowZWr9+va6//vrTnjts2DDt3r3bv/Xr1+/cfwoAgNfCp8P79RD2/vjjD1111VXKli2bZs+erbVr1+p///ufLrjgnyr2zz77rF544QWNHz9eX3/9tbvR3qpVKx07diykbQcAIFMUUmvTpo3bkpIvXz7NnTs3wbEXX3xRderU0fbt21W6dGn/8Tx58qhYsWLn0mYAQHKaPJx2I92+10NEeeaZZ1SqVClNmjTJf6xcuXIJRrlHjRqlRx99VO3atXPHXn/9dRUtWtRlv91yyy0haTcAABE7p/vgwYMufTx//vwJjls6uaWtXXHFFXruued08uTJZF8jLi5Ohw4dSrABAJLQ6AGpySNpc2rsdez1EFE++OAD1apVSzfeeKOKFCni+ulXX33V//iWLVu0Z88el1IeeNO9bt26Wrp0aZKvST8OAIhkQQ26Lc3M5nh37txZefPm9R+/99579fbbb2vhwoW688479fTTT+uBB5K/sBs+fLjr0H2b3YEHAAQx8Cbgjlg///yzxo0bp/Lly+vTTz/V3Xff7frtKVOmuMct4DY2sh3I9n2PJUY/DgCIZEFbp9uKqt10000uDc0670ADBw70f161alXFxMS44Ns65djY2NNea9CgQQm+xka6CbwB4AzylZKis0nxJ1J/mgi4I1p8fLwb6bYb4sZGutesWePmb3ft2vWcXpN+HAAQyaKDGXBv27bNzfEOHOVOiqWkWXr51q1bk3zcAnF7jcANAJCEuMPSzLukWXd5A+78ZVJ3mgi4I55VJL/00ksTnIfKlSu72izGV49l7969CZ5j+8nVaqEfBwBEsuhgBdy2dMi8efPcvO2zWb16taKjo93cMQDAOdrzg/RKY+m7t6SoaG8Afe+3KU81J+CG5CqX28ojgTZs2KAyZcr4i6pZcD1//vwEGWhW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UvL+RWRJyXUbIkfJkiXdoM+qVavcoEXTpk3Vrl07118hHXkiWJ06dTx9+vTx7586dcpTokQJz/Dhw0ParnC3b98+GyrzLF682O0fOHDAky1bNs+0adP8z1m3bp17ztKlS0PY0vDx559/esqXL++ZO3eup1GjRp777rvPHefcndmDDz7oadCgQbKPx8fHe4oVK+Z57rnn/MfsnMbGxnreeustTyS79tprPT169EhwrEOHDp4uXbq4zzl3ybO/XTNnzvTvp+RcrV271n3dihUr/M+ZPXu2JyoqyrNz5840/M0CqXv/Aomv24ALLrjA89prr3Ei0lHEjnQfP37c3fGxFEGf6Ohot7906dKQti3cHTx40H0sUKCA+2jn0e6iBp7LSpUqqXTp0pzLv9kd52uvvTbBOeLcnd0HH3ygWrVq6cYbb3QpcldccYVeffVV/+NbtmzRnj17EpzXfPnyuakikf7/+Morr9T8+fO1YcMGt//dd9/piy++UJs2bdw+5y7lUnKu7KOllNv71ceeb/2KjYwDQLhctyGyp569/fbbLuvB0syRfrIqQv3666/ujVe0aNEEx23/p59+Clm7wl18fLybj2wpv5dffrk7ZhejMTEx7oIz8bm0xyKd/XGz6QuWXp4Y5+7Mfv75Z5cibdNAHn74YXcO7733Xvd+69q1q//9ldT/40h/7z300EM6dOiQuwGWJUsW9/fuqaeecinQhnOXcik5V/bRbgwFypo1q7vIjfT3IoDwum5D5Pnhhx9ckG1Toqz20syZM3XppZeGulkRJWKDbpz7iO2aNWvciBnObseOHbrvvvvcnCor1ofUXyzYyOHTTz/t9m2k295/Nq/Wgm4k791339Wbb76pqVOn6rLLLtPq1avdhZcVWuLcAUBk4LoNpmLFiu46wLIepk+f7q4DbO4/gXf6idj08kKFCrnRn8QVtm2/WLFiIWtXOOvbt68rDrRw4UJXlMHHzpel6x84cCDB8zmX3tR7K8xXo0YNN+plm/2Rs4JM9rmNlHHukmeVohN3CJUrV9b27dv97z3fe433XkL333+/G+2+5ZZbXMX3f/3rX65on1W15dylTkreZ/YxcRHOkydPuorm9CkAwum6DZHHMgQvueQS1axZ010HWOHF0aNHh7pZESU6kt989sazOY+Bo2q2zxyHhKwui/3htlSUBQsWuCWIAtl5tOrSgefSlqawwCjSz2WzZs1cSo/dXfRtNnJrKb6+zzl3ybN0uMTLnNgc5TJlyrjP7b1oAU3ge89Sqm0ObaS/944ePermEweyG432d85w7lIuJefKPtqNR7vR5mN/L+1829xvAAiX6zbA+qa4uDhORDqK6PRymydq6RUW+NSpU0ejRo1yhQW6d+8e6qaFXWqSpai+//77bs1H3/xEKyRk69XaR1uP1s6nzV+0NQD79evnLkLr1aunSGbnK/EcKltqyNac9h3n3CXPRmatIJill990001avny5XnnlFbcZ35rnTz75pMqXL+8uLGxtakuhtnVJI5mt2WtzuK2goaWXf/vtt3r++efVo0cP9zjnLiFbT3vTpk0JiqfZjTH7m2bn8GzvM8vAaN26tXr16uWmP1hxSbvotUwDex4QyvcvIsvZrtsQWQYNGuSKqNrfgj///NO9NxYtWqRPP/001E2LLJ4IN2bMGE/p0qU9MTExbgmxZcuWhbpJYcfeJkltkyZN8j/nr7/+8txzzz1uCYKcOXN6brjhBs/u3btD2u5wFbhkmOHcndmHH37oufzyy93yTJUqVfK88sorCR635ZwGDx7sKVq0qHtOs2bNPOvXrw/Sby/jOHTokHuf2d+37Nmzey666CLPI4884omLi/M/h3P3j4ULFyb5d65r164pPle//fabp3Pnzp7cuXN78ubN6+nevbtbLhAI9fsXkSUl122IHLZ8aJkyZVysU7hwYdd/ffbZZ6FuVsSJsn9CHfgDAAAAAJAZReycbgAAAAAAgo2gGwAAAACAICHoBgAAAAAgSAi6AQAAAAAIEoJuAAAAAACChKAbAAAAAIAgIegGAAAAACBICLoBAAAAAAgSgm4AAAAgA+rWrZvat28f6mYAOAuCbiCTdb5RUVFui4mJ0SWXXKJhw4bp5MmToW4aAABIBV9/ntw2ZMgQjR49WpMnT+a8AmEua6gbACBttW7dWpMmTVJcXJw++eQT9enTR9myZdOgQYNCeqqPHz/ubgQAAICz2717t//zd955R4899pjWr1/vP5Y7d263AQh/jHQDmUxsbKyKFSumMmXK6O6771bz5s31wQcf6I8//tDtt9+uCy64QDlz5lSbNm20ceNG9zUej0eFCxfW9OnT/a9TvXp1FS9e3L//xRdfuNc+evSo2z9w4IDuuOMO93V58+ZV06ZN9d133/mfb3fg7TVee+01lStXTtmzZ0/X8wAAQEZmfblvy5cvnxvdDjxmAXfi9PLGjRurX79+6t+/v+vvixYtqldffVVHjhxR9+7dlSdPHpcFN3v27ATfa82aNe66wF7TvuZf//qXfv311xD81EDmRNANZHI5cuRwo8zWMa9cudIF4EuXLnWB9jXXXKMTJ064jrxhw4ZatGiR+xoL0NetW6e//vpLP/30kzu2ePFi1a5d2wXs5sYbb9S+fftcx71q1SrVqFFDzZo10++//+7/3ps2bdJ7772nGTNmaPXq1SE6AwAARI4pU6aoUKFCWr58uQvA7Qa89dlXXnmlvvnmG7Vs2dIF1YE30e3G+RVXXOGuE+bMmaO9e/fqpptuCvWPAmQaBN1AJmVB9bx58/Tpp5+qdOnSLti2Ueerr75a1apV05tvvqmdO3dq1qxZ/rvjvqB7yZIlrvMNPGYfGzVq5B/1ts582rRpqlWrlsqXL6///ve/yp8/f4LRcgv2X3/9dfdaVatWDcl5AAAgklgf/+ijj7q+2aaWWaaZBeG9evVyxyxN/bffftP333/vnv/iiy+6fvrpp59WpUqV3OcTJ07UwoULtWHDhlD/OECmQNANZDIfffSRSw+zTtZSxW6++WY3yp01a1bVrVvX/7yCBQuqYsWKbkTbWEC9du1a7d+/341qW8DtC7ptNPyrr75y+8bSyA8fPuxewzenzLYtW7Zo8+bN/u9hKe6Wfg4AANJH4E3uLFmyuL66SpUq/mOWPm4sW83Xp1uAHdifW/BtAvt0AOeOQmpAJtOkSRONGzfOFS0rUaKEC7ZtlPtsrEMuUKCAC7hte+qpp9ycsWeeeUYrVqxwgbelphkLuG2+t28UPJCNdvvkypUrjX86AABwJlY8NZBNIQs8ZvsmPj7e36e3bdvW9feJBdZ2AXDuCLqBTMYCXSuSEqhy5cpu2bCvv/7aHzhbaplVQb300kv9nbClnr///vv68ccf1aBBAzd/26qgv/zyyy6N3BdE2/ztPXv2uIC+bNmyIfgpAQBAWrA+3eqvWH9u/TqAtEd6ORABbA5Xu3bt3Hwum49tqWS33XabLrzwQnfcx9LH33rrLVd13NLLoqOjXYE1m//tm89trCJ6/fr1XcXUzz77TFu3bnXp54888ogrwgIAADIGW1rUiqB27tzZZbZZSrnVg7Fq56dOnQp184BMgaAbiBC2dnfNmjV13XXXuYDZCq3ZOt6BKWcWWFsH65u7bezzxMdsVNy+1gJy65QrVKigW265Rdu2bfPPFQMAAOHPpqJ9+eWXrq+3yuY23cyWHLPpYnbzHcD5i/LYlTcAAAAAAEhz3L4CAAAAACBICLoBAAAAAAgSgm4AAAAAAIKEoBsAAAAAgCAh6AYAAAAAIEgIugEAAAAACBKCbgAAAAAAgoSgGwAAAACAICHoBgAAAAAgSAi6AQAAAAAIEoJuAAAAAACChKAbAAAAAAAFx/8Drszp20UZwFsAAAAASUVORK5CYII=" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 7 + "source": "bp1 = linopy.breakpoints({\"power\": x_pts1.values, \"fuel\": y_pts1.values}, dim=\"var\")\nplot_pwl_results(m1, bp1, demand1, color=\"C0\")", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -452,27 +164,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.490084Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.305191Z", - "start_time": "2026-04-01T17:28:22.302343Z" + "end_time": "2026-04-01T17:50:21.074995Z", + "start_time": "2026-04-01T17:50:21.072706Z" } }, - "source": [ - "x_pts2 = linopy.breakpoints([0, 50, 100, 150])\n", - "y_pts2 = linopy.breakpoints([0, 55, 130, 225])\n", - "print(\"x_pts:\", x_pts2.values)\n", - "print(\"y_pts:\", y_pts2.values)" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "x_pts: [ 0. 50. 100. 150.]\n", - "y_pts: [ 0. 55. 130. 225.]\n" - ] - } - ], - "execution_count": 8 + "source": "x_pts2 = linopy.breakpoints([0, 50, 100, 150])\ny_pts2 = linopy.breakpoints([0, 55, 130, 225])\nprint(\"x_pts:\", x_pts2.values)\nprint(\"y_pts:\", y_pts2.values)", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -485,32 +183,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.501307Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.363252Z", - "start_time": "2026-04-01T17:28:22.309089Z" + "end_time": "2026-04-01T17:50:21.135253Z", + "start_time": "2026-04-01T17:50:21.083396Z" } }, "source": "m2 = linopy.Model()\n\npower = m2.add_variables(name=\"power\", lower=0, upper=150, coords=[time])\nfuel = m2.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand2 = xr.DataArray([80, 120, 50], coords=[time])\nm2.add_constraints(power >= demand2, name=\"demand\")\nm2.add_objective(fuel.sum())\n\nm2.add_piecewise_formulation(\n (power, x_pts2),\n (fuel, y_pts2),\n name=\"pwl\",\n method=\"incremental\",\n)", - "outputs": [ - { - "data": { - "text/plain": [ - "PiecewiseFormulation 'pwl' (incremental)\n", - " Variables (2):\n", - " * pwl_delta\n", - " * pwl_inc_binary\n", - " Constraints (4):\n", - " * pwl_inc_link\n", - " * pwl_fill\n", - " * pwl_inc_order\n", - " * pwl_x_link" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 9 + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -523,60 +202,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.604427Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.416398Z", - "start_time": "2026-04-01T17:28:22.366896Z" + "end_time": "2026-04-01T17:50:21.185956Z", + "start_time": "2026-04-01T17:50:21.147474Z" } }, - "source": [ - "m2.solve(reformulate_sos=\"auto\");" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-bmyktitw.lp\n", - "Reading time = 0.00 seconds\n", - "obj: 30 rows, 24 columns, 69 nonzeros\n", - "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", - "\n", - "CPU model: Apple M3\n", - "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 30 rows, 24 columns and 69 nonzeros (Min)\n", - "Model fingerprint: 0x31378744\n", - "Model has 3 linear objective coefficients\n", - "Variable types: 15 continuous, 9 integer (9 binary)\n", - "Coefficient statistics:\n", - " Matrix range [1e+00, 1e+02]\n", - " Objective range [1e+00, 1e+00]\n", - " Bounds range [1e+00, 2e+02]\n", - " RHS range [5e+01, 1e+02]\n", - "\n", - "Presolve removed 30 rows and 24 columns\n", - "Presolve time: 0.00s\n", - "Presolve: All rows and columns removed\n", - "\n", - "Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n", - "Thread count was 1 (of 8 available processors)\n", - "\n", - "Solution count 1: 323 \n", - "\n", - "Optimal solution found (tolerance 1.00e-04)\n", - "Best objective 3.230000000000e+02, best bound 3.230000000000e+02, gap 0.0000%\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Dual values of MILP couldn't be parsed\n" - ] - } - ], - "execution_count": 10 + "source": "m2.solve(reformulate_sos=\"auto\");", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -589,78 +221,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.681822Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.429247Z", - "start_time": "2026-04-01T17:28:22.423565Z" + "end_time": "2026-04-01T17:50:21.205500Z", + "start_time": "2026-04-01T17:50:21.200814Z" } }, - "source": [ - "m2.solution[[\"power\", \"fuel\"]].to_pandas()" - ], - "outputs": [ - { - "data": { - "text/plain": [ - " power fuel\n", - "time \n", - "1 80.0 100.0\n", - "2 120.0 168.0\n", - "3 50.0 55.0" - ], - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
powerfuel
time
180.0100.0
2120.0168.0
350.055.0
\n", - "
" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 11 + "source": "m2.solution[[\"power\", \"fuel\"]].to_pandas()", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -673,30 +240,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.699334Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.515387Z", - "start_time": "2026-04-01T17:28:22.432596Z" + "end_time": "2026-04-01T17:50:21.289611Z", + "start_time": "2026-04-01T17:50:21.213993Z" } }, - "source": [ - "bp2 = linopy.breakpoints({\"power\": x_pts2.values, \"fuel\": y_pts2.values}, dim=\"var\")\n", - "plot_pwl_results(m2, bp2, demand2, color=\"C1\")" - ], - "outputs": [ - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAFUCAYAAAA57l+/AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAYedJREFUeJzt3Qd4FFXbxvE7Cb33XlWq0qSJotKkiAiC9UVFRFQUFfG1gIBgAVE/GyJYQX3FgoKVIlJF6QrSRECkN+k1gWS/6znrLkkIkECSbf/fdQ3LzM7unplsMvOc85xzojwej0cAAAAAACDdRaf/WwIAAAAAAIJuAAAAAAAyEC3dAAAAAABkEIJuAAAAAAAyCEE3AAAAAAAZhKAbAAAAAIAMQtANAAAAAEAGIegGAAAAACCDEHQDAAAAAJBBCLoBAACAABs4cKCioqIU6uwYevbsGehiAEGFoBvIJKNHj3YXIt+SI0cOVa5c2V2Ytm/f7vaZP3++e+6VV1456fXt27d3z40aNeqk56644gqVLl3av96kSRNddNFFGXxEAAAgLdf9UqVKqVWrVnr99dd14MCBoDx5EyZMcBUAANIPQTeQyZ5++ml99NFHeuONN3TppZdqxIgRatSokQ4fPqyLL75YuXLl0uzZs0963S+//KIsWbLo559/TrI9Li5OCxYs0GWXXZaJRwEAANJy3bfr/QMPPOC29erVSzVq1NDvv//u369fv346cuRIUATdgwYNCnQxgLCSJdAFACJNmzZtVK9ePff/u+66S4ULF9bLL7+sr7/+WrfccosaNmx4UmC9atUq/fPPP/rPf/5zUkC+aNEiHT16VI0bN1YosMoFq1gAACDSrvumT58+mjZtmq655hpde+21WrlypXLmzOkq1m0BEH5o6QYCrFmzZu5x3bp17tGCZ0s3X7NmjX8fC8Lz5cunu+++2x+AJ37O97r0sHfvXj388MOqUKGCsmfPrjJlyuj222/3f6YvXe7vv/9O8roZM2a47faYPM3dKgYsBd6C7b59+7objfPOOy/Fz7dW/8Q3J+Z///uf6tat625KChUqpJtvvlkbN25Ml+MFACAQ1/7+/ftr/fr17hp3qj7dU6ZMcdf3AgUKKE+ePKpSpYq7jia/9n722Wdue4kSJZQ7d24XzCe/Tv7000+64YYbVK5cOXd9L1u2rLveJ25dv+OOOzR8+HD3/8Sp8T4JCQl67bXXXCu9pcsXLVpUrVu31sKFC086xq+++srdA9hnXXjhhZo0aVI6nkEgtFCdBgTY2rVr3aO1eCcOnq1F+4ILLvAH1pdccolrBc+aNatLNbcLqu+5vHnzqlatWudcloMHD+ryyy93te533nmnS3e3YPubb77Rpk2bVKRIkTS/565du1wtvwXKt956q4oXL+4CaAvkLS2+fv36/n3t5mPu3Ll68cUX/duee+45d2Ny4403usyAnTt3atiwYS6I/+2339yNCAAAoea2225zgfIPP/yg7t27n/T88uXLXSV1zZo1XYq6Ba9WIZ88G853rbTg+PHHH9eOHTv06quvqkWLFlq8eLGrsDZjx4512WY9evRw9xw2joxdT+36bs+Ze+65R1u2bHHBvqXEJ9etWzdX+W7XdbsmHz9+3AXzdu1OXGFu9zDjxo3Tfffd5+5RrA97p06dtGHDBv/9DhBRPAAyxahRozz2K/fjjz96du7c6dm4caPn008/9RQuXNiTM2dOz6ZNm9x++/fv98TExHi6devmf22VKlU8gwYNcv9v0KCB59FHH/U/V7RoUc9VV12V5LOuvPJKz4UXXpjmMg4YMMCVcdy4cSc9l5CQkOQ41q1bl+T56dOnu+32mLgctm3kyJFJ9t23b58ne/bsnkceeSTJ9hdeeMETFRXlWb9+vVv/+++/3bl47rnnkuy3dOlST5YsWU7aDgBAsPBdLxcsWHDKffLnz++pU6eO+/9TTz3l9vd55ZVX3LrdM5yK79pbunRpd//g8/nnn7vtr732mn/b4cOHT3r9kCFDklx3zf3335+kHD7Tpk1z2x988MFT3iMY2ydbtmyeNWvW+LctWbLEbR82bNgpjwUIZ6SXA5nMap4tHcvSuqz119LFxo8f7x993GqErVbb13fbWpotpdwGXTM2YJqvlvvPP/90Lb/plVr+5Zdfuhbz66677qTnznYaE6uZ79q1a5JtlipvteSff/65XdX92y09zlr0LfXNWC25pbJZK7edB99i6XOVKlXS9OnTz6pMAAAEA7sHONUo5r5MLhvzxa6Fp2PZY3b/4HP99derZMmSblA0H1+Ltzl06JC7ntq9hV2HLXMsNfcIdi/w1FNPnfEewe51zj//fP+63dfYtf+vv/464+cA4YigG8hk1lfK0rYsYFyxYoW7ANn0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Umrxjj8mzX9bmvG8FLvfu612Z6nFQClPMX4KQCr16NFDn3zyiQt2u3bt6vpa28jlGeWvv/7SiBEj1Lt3b/Xt21cLFizQgw8+qGzZsqlLly4u4DbWsp2YrfueSy42NtYtPvv3//s3AQCAMERLN4D0DbhTavFeO10acZk0ua834C5VR+r2o9ThTQJuII1sdPKtW7fqscce07fffutSv2+88UZNnjzZpXpnxGjpF198sQYPHuxaue+++251795dI0eOPOv3HDJkiGsN9y12DAAAhCuCbgDpH3D72H5vNJA+6iD9s0rKVUS6dph01zSpbH3OPHCWsmfPrltuuUVTpkxxg5VdeOGFuu+++1ShQgUdPHgwXc+rjUhevXr1JNuqVavmRks3JUqUcI/bt29Pso+t+55Lrk+fPtq3b59/2bhxY7qWGQCAkA66Z82apXbt2qlUqVKKiopyg6QklpppQ3bv3q3OnTsrX758buqTbt26pftNAoAAB9w+FmwrSmp4r/TAIuni26Vo6vuA9BIdHe2ux3b9jY+PT/cTayOXr1plv8cn2BRlvmnJbFA1C66nTp2aJF3cBnuzqc1OVWlg9wCJFwAAwlWa73wPHTqkWrVqufS2lPimDbG0M7vg5s6d200bcvToUf8+FnAvX77c1dB/9913LpC3dDUAYRZw+3mkXIWlnAXSuVBAZLL+0Nav+6qrrnJThy1dulRvvPGGa33OkydPun7Www8/rLlz57r08jVr1mjMmDF6++23df/997vnLeDv1auXnn32WTfompXl9ttvd5XzHTp0SNeyAAAQEQOptWnTxi0pSc20IStXrtSkSZPcQCw2GqoZNmyYrr76ar300kvuIg0gnAJupX06MQCnZGnkn376qesHfeedd7rgu0iRIhl2xurXr6/x48e7lPCnn37atWzbtd4q0H2sf7lVylsFuo2q3rhxY3etZ45uAADSeZ7uM00bYkG3PVpKuS/gNra/pcdZy/h111130vsyyikQ4gG3D4E3cM4sk6xcuXI677zzNHPmTLekZNy4cel2tq+55hq3nIq1dltAbgsAAMjAoDs104bYo83zmaQQWbK46U5ONbWIjXI6aNCg9CwqgNSaPjj934/WbuCsWeq2BbkAACA0hMQ83ZbSZvODJh6ghelFgEzStG/6tXT73g/AWRs9ejRnDwCAEJKuQwinZtoQ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" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 12 + "source": "bp2 = linopy.breakpoints({\"power\": x_pts2.values, \"fuel\": y_pts2.values}, dim=\"var\")\nplot_pwl_results(m2, bp2, demand2, color=\"C1\")", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -725,37 +275,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.852387Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.522587Z", - "start_time": "2026-04-01T17:28:22.518566Z" + "end_time": "2026-04-01T17:50:21.296416Z", + "start_time": "2026-04-01T17:50:21.293422Z" } }, - "source": [ - "# x-breakpoints define where each segment lives on the power axis\n", - "# y-breakpoints define the corresponding cost values\n", - "x_seg = linopy.segments([(0, 0), (50, 80)])\n", - "y_seg = linopy.segments([(0, 0), (125, 200)])\n", - "print(\"x segments:\\n\", x_seg.to_pandas())\n", - "print(\"y segments:\\n\", y_seg.to_pandas())" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "x segments:\n", - " _breakpoint 0 1\n", - "_segment \n", - "0 0.0 0.0\n", - "1 50.0 80.0\n", - "y segments:\n", - " _breakpoint 0 1\n", - "_segment \n", - "0 0.0 0.0\n", - "1 125.0 200.0\n" - ] - } - ], - "execution_count": 13 + "source": "# x-breakpoints define where each segment lives on the power axis\n# y-breakpoints define the corresponding cost values\nx_seg = linopy.segments([(0, 0), (50, 80)])\ny_seg = linopy.segments([(0, 0), (125, 200)])\nprint(\"x segments:\\n\", x_seg.to_pandas())\nprint(\"y segments:\\n\", y_seg.to_pandas())", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -768,32 +294,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.866931Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.577159Z", - "start_time": "2026-04-01T17:28:22.529026Z" + "end_time": "2026-04-01T17:50:21.351922Z", + "start_time": "2026-04-01T17:50:21.304030Z" } }, "source": "m3 = linopy.Model()\n\npower = m3.add_variables(name=\"power\", lower=0, upper=80, coords=[time])\ncost = m3.add_variables(name=\"cost\", lower=0, coords=[time])\nbackup = m3.add_variables(name=\"backup\", lower=0, coords=[time])\n\ndemand3 = xr.DataArray([10, 70, 90], coords=[time])\nm3.add_constraints(power + backup >= demand3, name=\"demand\")\nm3.add_objective((cost + 10 * backup).sum())\n\nm3.add_piecewise_formulation(\n (power, x_seg),\n (cost, y_seg),\n name=\"pwl\",\n)", - "outputs": [ - { - "data": { - "text/plain": [ - "PiecewiseFormulation 'pwl' (sos2)\n", - " Variables (2):\n", - " * pwl_binary\n", - " * pwl_lambda\n", - " Constraints (4):\n", - " * pwl_select\n", - " * pwl_convex\n", - " * pwl_x_link\n", - " * pwl_y_link" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 14 + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -806,75 +313,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:29.955741Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.633918Z", - "start_time": "2026-04-01T17:28:22.580144Z" + "end_time": "2026-04-01T17:50:21.398282Z", + "start_time": "2026-04-01T17:50:21.355402Z" } }, - "source": [ - "m3.solve(reformulate_sos=\"auto\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-wlr9q50z.lp\n", - "Reading time = 0.00 seconds\n", - "obj: 18 rows, 27 columns, 48 nonzeros\n", - "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", - "\n", - "CPU model: Apple M3\n", - "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 18 rows, 27 columns and 48 nonzeros (Min)\n", - "Model fingerprint: 0x4aeb7a1d\n", - "Model has 6 linear objective coefficients\n", - "Model has 6 SOS constraints\n", - "Variable types: 21 continuous, 6 integer (6 binary)\n", - "Coefficient statistics:\n", - " Matrix range [1e+00, 2e+02]\n", - " Objective range [1e+00, 1e+01]\n", - " Bounds range [1e+00, 8e+01]\n", - " RHS range [1e+00, 9e+01]\n", - "\n", - "Presolve removed 15 rows and 22 columns\n", - "Presolve time: 0.00s\n", - "Presolved: 3 rows, 5 columns, 8 nonzeros\n", - "Variable types: 4 continuous, 1 integer (1 binary)\n", - "Found heuristic solution: objective 575.0000000\n", - "\n", - "Root relaxation: cutoff, 0 iterations, 0.00 seconds (0.00 work units)\n", - "\n", - "Explored 1 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)\n", - "Thread count was 8 (of 8 available processors)\n", - "\n", - "Solution count 1: 575 \n", - "\n", - "Optimal solution found (tolerance 1.00e-04)\n", - "Best objective 5.750000000000e+02, best bound 5.750000000000e+02, gap 0.0000%\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Dual values of MILP couldn't be parsed\n" - ] - }, - { - "data": { - "text/plain": [ - "('ok', 'optimal')" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 15 + "source": "m3.solve(reformulate_sos=\"auto\")", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -887,83 +332,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.028095Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.640822Z", - "start_time": "2026-04-01T17:28:22.636837Z" + "end_time": "2026-04-01T17:50:21.413359Z", + "start_time": "2026-04-01T17:50:21.408184Z" } }, - "source": [ - "m3.solution[[\"power\", \"cost\", \"backup\"]].to_pandas()" - ], - "outputs": [ - { - "data": { - "text/plain": [ - " power cost backup\n", - "time \n", - "1 0.0 0.0 10.0\n", - "2 70.0 175.0 0.0\n", - "3 80.0 200.0 10.0" - ], - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
powercostbackup
time
10.00.010.0
270.0175.00.0
380.0200.010.0
\n", - "
" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 16 + "source": "m3.solution[[\"power\", \"cost\", \"backup\"]].to_pandas()", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -1362,19 +737,25 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.043484Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.668861Z", - "start_time": "2026-04-01T17:28:22.646927Z" + "end_time": "2026-04-01T17:50:21.449956Z", + "start_time": "2026-04-01T17:50:21.433179Z" } }, "source": "x_pts4 = linopy.breakpoints([0, 40, 80, 120])\n# Concave curve: decreasing marginal fuel per MW\ny_pts4 = linopy.breakpoints([0, 50, 90, 120])\n\nm4 = linopy.Model()\n\npower = m4.add_variables(name=\"power\", lower=0, upper=120, coords=[time])\nfuel = m4.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand4 = xr.DataArray([30, 80, 100], coords=[time])\nm4.add_constraints(power == demand4, name=\"demand\")\n# Maximize fuel (to push against the upper bound)\nm4.add_objective(-fuel.sum())\n\n# tangent_lines returns one LinearExpression per segment \u2014 pure LP, no aux variables\nlinopy.tangent_lines(power, x_pts4, y_pts4)", "outputs": [], - "execution_count": 17 + "execution_count": null }, { "cell_type": "code", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.470263Z", + "start_time": "2026-04-01T17:50:21.454181Z" + } + }, + "source": "t = linopy.tangent_lines(power, x_pts4, y_pts4)\nm4.add_constraints(fuel <= t, name=\"pwl\")", "outputs": [], - "source": "t = linopy.tangent_lines(power, x_pts4, y_pts4)\nm4.add_constraints(fuel <= t, name=\"pwl\")" + "execution_count": null }, { "cell_type": "code", @@ -1387,59 +768,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.113810Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.696596Z", - "start_time": "2026-04-01T17:28:22.672774Z" + "end_time": "2026-04-01T17:50:21.498563Z", + "start_time": "2026-04-01T17:50:21.476327Z" } }, - "source": [ - "m4.solve(reformulate_sos=\"auto\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-truzuxpt.lp\n", - "Reading time = 0.00 seconds\n", - "obj: 12 rows, 6 columns, 21 nonzeros\n", - "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", - "\n", - "CPU model: Apple M3\n", - "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 12 rows, 6 columns and 21 nonzeros (Min)\n", - "Model fingerprint: 0x0a213b23\n", - "Model has 3 linear objective coefficients\n", - "Coefficient statistics:\n", - " Matrix range [8e-01, 1e+00]\n", - " Objective range [1e+00, 1e+00]\n", - " Bounds range [1e+02, 1e+02]\n", - " RHS range [1e+01, 1e+02]\n", - "\n", - "Presolve removed 12 rows and 6 columns\n", - "Presolve time: 0.00s\n", - "Presolve: All rows and columns removed\n", - "Iteration Objective Primal Inf. Dual Inf. Time\n", - " 0 -2.3250000e+02 0.000000e+00 0.000000e+00 0s\n", - "\n", - "Solved in 0 iterations and 0.00 seconds (0.00 work units)\n", - "Optimal objective -2.325000000e+02\n" - ] - }, - { - "data": { - "text/plain": [ - "('ok', 'optimal')" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 18 + "source": "m4.solve(reformulate_sos=\"auto\")", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -1452,78 +787,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.171993Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.727938Z", - "start_time": "2026-04-01T17:28:22.721758Z" + "end_time": "2026-04-01T17:50:21.512519Z", + "start_time": "2026-04-01T17:50:21.508408Z" } }, - "source": [ - "m4.solution[[\"power\", \"fuel\"]].to_pandas()" - ], - "outputs": [ - { - "data": { - "text/plain": [ - " power fuel\n", - "time \n", - "1 30.0 37.5\n", - "2 80.0 90.0\n", - "3 100.0 105.0" - ], - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
powerfuel
time
130.037.5
280.090.0
3100.0105.0
\n", - "
" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 19 + "source": "m4.solution[[\"power\", \"fuel\"]].to_pandas()", + "outputs": [], + "execution_count": null }, { "cell_type": "code", @@ -1536,30 +806,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.192590Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.827955Z", - "start_time": "2026-04-01T17:28:22.748152Z" + "end_time": "2026-04-01T17:50:21.608738Z", + "start_time": "2026-04-01T17:50:21.525541Z" } }, - "source": [ - "bp4 = linopy.breakpoints({\"power\": x_pts4.values, \"fuel\": y_pts4.values}, dim=\"var\")\n", - "plot_pwl_results(m4, bp4, demand4, color=\"C4\")" - ], - "outputs": [ - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "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i18s3T1Duv0/BNxAGLKe7SJFiujhhx/Wjh079OCDD+qXX37R2rVrNW7cON19990qV47GOAAAQjbo3rt3r6666irlypXLpbmtWrVK//73v90Ngs/w4cP1yiuvaMyYMa51Pl++fGrRooUbmwbgLwe3Sx90ld5sLm1dKcUW9I7b7vqNVKkJlwkIU1999ZVr1Lbgu1mzZrr22mtdIzYAAAiT9PJhw4a5FLfx48cnH/NfT9R6uV966SU99dRTatu2rTs2adIkN9PqjBkzdMcdd2R2kYDgknhcWjxWWjBMOnbAe6xmB6n501L+EoEuHYAA27dvnwu8La3c6tw777xTF110kUsptwnW7Ot5550X6GICAICs6un+6KOPVKdOHd16660qUaKEatWq5dLdfDZs2KBt27a5lHKfQoUKqV69eoqPj8/s4gDB5Zd50uirpM+f9AbcpS+XHpgjtXuNgBuAY9lhLVu21PPPP++yxXbt2uUyyPLmzeu+2prdl156KVcLAIBQ7en+9ddfNXr0aPXq1Uv9+vXT0qVL1aNHD8XExOjee+91AbdJvYao7fseS+3YsWNu8zlw4K/ePyBU7N3oDbRXf+zdz1tcaj5QqnmXFJklUy8ACKEgvGjRom6zoVzR0dFavXp1oIsFAACyKuhOSkpyPd1Dhgxx+9bT/eOPP7rx2xZ0n42hQ4dq0KBBmVxSIAc4/qf0zcvS1y9KJ45KEVHSFZ2la/pKeQoHunQAciCrZ21yUksvt9nLv/nmGx0+fFjnn3++WzZs1KhR7isAAAjRoNsmc6lWrVqKY1WrVtW0adPc93Fxce7r9u3bU0z8Yvs1a9ZM8zX79u3res79e7pt3DgQtDweb6/2Z09K+3/3HqtwtdRqmFTykkCXDkAOVrhwYRdkW31qwfWLL77oxnJXqlQp0EUDAADZEXTbzOW2bIm/devWqXz58smTqtmNwpw5c5KDbAuibVxa165d03zN2NhYtwEhYedaaWZv6df53v2C50vXPSddcpMUERHo0gHI4V544QUXbNvkaQAAIAyD7scee0wNGjRw6eW33XablixZotdff91tJiIiQj179tRzzz2nypUruyC8f//+Kl26tNq1a5fZxQFyjqMHvDOSLx4jJZ2QomKkBj2kq3tJMfkCXToAQcIaqW07k7feeitbygMAALI56K5bt64++OADlxL+zDPP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" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 20 + "source": "bp4 = linopy.breakpoints({\"power\": x_pts4.values, \"fuel\": y_pts4.values}, dim=\"var\")\nplot_pwl_results(m4, bp4, demand4, color=\"C4\")", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -1583,26 +836,13 @@ "shell.execute_reply.started": "2026-03-06T11:51:30.345513Z" }, "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.838752Z", - "start_time": "2026-04-01T17:28:22.836497Z" + "end_time": "2026-04-01T17:50:21.614899Z", + "start_time": "2026-04-01T17:50:21.612589Z" } }, - "source": [ - "# Marginal costs: $1.1/MW for 0-50, $1.5/MW for 50-100, $1.9/MW for 100-150\n", - "x_pts5 = linopy.breakpoints([0, 50, 100, 150])\n", - "y_pts5 = linopy.breakpoints(slopes=[1.1, 1.5, 1.9], x_points=[0, 50, 100, 150], y0=0)\n", - "print(\"y breakpoints from slopes:\", y_pts5.values)" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "y breakpoints from slopes: [ 0. 55. 130. 225.]\n" - ] - } - ], - "execution_count": 21 + "source": "# Marginal costs: $1.1/MW for 0-50, $1.5/MW for 50-100, $1.9/MW for 100-150\nx_pts5 = linopy.breakpoints([0, 50, 100, 150])\ny_pts5 = linopy.breakpoints(slopes=[1.1, 1.5, 1.9], x_points=[0, 50, 100, 150], y0=0)\nprint(\"y breakpoints from slopes:\", y_pts5.values)", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -2521,260 +1761,61 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.843383Z", - "start_time": "2026-04-01T17:28:22.841319Z" + "end_time": "2026-04-01T17:50:21.626940Z", + "start_time": "2026-04-01T17:50:21.624504Z" } }, - "source": [ - "# Unit parameters: operates between 30-100 MW when on\n", - "p_min, p_max = 30, 100\n", - "fuel_min, fuel_max = 40, 170\n", - "startup_cost = 50\n", - "\n", - "x_pts6 = linopy.breakpoints([p_min, 60, p_max])\n", - "y_pts6 = linopy.breakpoints([fuel_min, 90, fuel_max])\n", - "print(\"Power breakpoints:\", x_pts6.values)\n", - "print(\"Fuel breakpoints: \", y_pts6.values)" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Power breakpoints: [ 30. 60. 100.]\n", - "Fuel breakpoints: [ 40. 90. 170.]\n" - ] - } - ], - "execution_count": 22 + "source": "# Unit parameters: operates between 30-100 MW when on\np_min, p_max = 30, 100\nfuel_min, fuel_max = 40, 170\nstartup_cost = 50\n\nx_pts6 = linopy.breakpoints([p_min, 60, p_max])\ny_pts6 = linopy.breakpoints([fuel_min, 90, fuel_max])\nprint(\"Power breakpoints:\", x_pts6.values)\nprint(\"Fuel breakpoints: \", y_pts6.values)", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.918581Z", - "start_time": "2026-04-01T17:28:22.850187Z" + "end_time": "2026-04-01T17:50:21.707770Z", + "start_time": "2026-04-01T17:50:21.635963Z" } }, "source": "m6 = linopy.Model()\n\npower = m6.add_variables(name=\"power\", lower=0, upper=p_max, coords=[time])\nfuel = m6.add_variables(name=\"fuel\", lower=0, coords=[time])\ncommit = m6.add_variables(name=\"commit\", binary=True, coords=[time])\n\n# Demand: low at t=1 (cheaper to stay off), high at t=2,3\ndemand6 = xr.DataArray([15, 70, 50], coords=[time])\nbackup = m6.add_variables(name=\"backup\", lower=0, coords=[time])\nm6.add_constraints(power + backup >= demand6, name=\"demand\")\n\n# Objective: fuel + startup cost + backup at /MW\nm6.add_objective((fuel + startup_cost * commit + 5 * backup).sum())\n\n# The active parameter gates the PWL with the commitment binary:\n# - commit=1: power in [30, 100], fuel = f(power)\n# - commit=0: power = 0, fuel = 0\nm6.add_piecewise_formulation(\n (power, x_pts6),\n (fuel, y_pts6),\n active=commit,\n name=\"pwl\",\n method=\"incremental\",\n)", - "outputs": [ - { - "data": { - "text/plain": [ - "PiecewiseFormulation 'pwl' (incremental)\n", - " Variables (2):\n", - " * pwl_delta\n", - " * pwl_inc_binary\n", - " Constraints (5):\n", - " * pwl_active_bound\n", - " * pwl_inc_link\n", - " * pwl_fill\n", - " * pwl_inc_order\n", - " * pwl_x_link" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 23 + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:22.999635Z", - "start_time": "2026-04-01T17:28:22.943236Z" + "end_time": "2026-04-01T17:50:21.766060Z", + "start_time": "2026-04-01T17:50:21.710952Z" } }, - "source": [ - "m6.solve(reformulate_sos=\"auto\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-prvz64c7.lp\n", - "Reading time = 0.00 seconds\n", - "obj: 27 rows, 24 columns, 66 nonzeros\n", - "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", - "\n", - "CPU model: Apple M3\n", - "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 27 rows, 24 columns and 66 nonzeros (Min)\n", - "Model fingerprint: 0x9cac1f29\n", - "Model has 9 linear objective coefficients\n", - "Variable types: 15 continuous, 9 integer (9 binary)\n", - "Coefficient statistics:\n", - " Matrix range [1e+00, 8e+01]\n", - " Objective range [1e+00, 5e+01]\n", - " Bounds range [1e+00, 1e+02]\n", - " RHS range [2e+01, 7e+01]\n", - "\n", - "Found heuristic solution: objective 675.0000000\n", - "Presolve removed 24 rows and 19 columns\n", - "Presolve time: 0.00s\n", - "Presolved: 3 rows, 5 columns, 10 nonzeros\n", - "Found heuristic solution: objective 485.0000000\n", - "Variable types: 3 continuous, 2 integer (2 binary)\n", - "\n", - "Root relaxation: objective 3.516667e+02, 2 iterations, 0.00 seconds (0.00 work units)\n", - "\n", - " Nodes | Current Node | Objective Bounds | Work\n", - " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", - "\n", - " 0 0 351.66667 0 1 485.00000 351.66667 27.5% - 0s\n", - "* 0 0 0 358.3333333 358.33333 0.00% - 0s\n", - "\n", - "Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n", - "Thread count was 8 (of 8 available processors)\n", - "\n", - "Solution count 3: 358.333 485 675 \n", - "\n", - "Optimal solution found (tolerance 1.00e-04)\n", - "Best objective 3.583333333333e+02, best bound 3.583333333333e+02, gap 0.0000%\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Dual values of MILP couldn't be parsed\n" - ] - }, - { - "data": { - "text/plain": [ - "('ok', 'optimal')" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 24 + "source": "m6.solve(reformulate_sos=\"auto\")", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.007912Z", - "start_time": "2026-04-01T17:28:23.003644Z" + "end_time": "2026-04-01T17:50:21.775881Z", + "start_time": "2026-04-01T17:50:21.770500Z" } }, - "source": [ - "m6.solution[[\"commit\", \"power\", \"fuel\", \"backup\"]].to_pandas()" - ], - "outputs": [ - { - "data": { - "text/plain": [ - " commit power fuel backup\n", - "time \n", - "1 0.0 0.0 0.000000 15.0\n", - "2 1.0 70.0 110.000000 0.0\n", - "3 1.0 50.0 73.333333 0.0" - ], - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
commitpowerfuelbackup
time
10.00.00.00000015.0
21.070.0110.0000000.0
31.050.073.3333330.0
\n", - "
" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 25 + "source": "m6.solution[[\"commit\", \"power\", \"fuel\", \"backup\"]].to_pandas()", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.099707Z", - "start_time": "2026-04-01T17:28:23.018181Z" + "end_time": "2026-04-01T17:50:21.866232Z", + "start_time": "2026-04-01T17:50:21.784879Z" } }, - "source": [ - "bp6 = linopy.breakpoints({\"power\": x_pts6.values, \"fuel\": y_pts6.values}, dim=\"var\")\n", - "plot_pwl_results(m6, bp6, demand6, color=\"C2\")" - ], - "outputs": [ - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAFUCAYAAAA57l+/AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAYqZJREFUeJzt3Qd4VNXWxvE3ofcOoTepCqigCIJUBVSkXSsqIhcboGBDVEBQQdErKtUK+CmiKF0BESkqHURBioA06YL0HvI9aw8zTkICCWQyk8z/9zxjOGfOTE5Oxuyz9l577YiYmJgYAQAAAACAZBeZ/G8JAAAAAAAIugEAAAAACCBGugEAAAAACBCCbgAAAAAAAoSgGwAAAACAACHoBgAAAAAgQAi6AQAAAAAIEIJuAAAAAAAChKAbAAAAAIAAIegGAAAAguSll15SREREqr/+9jN07tw52KcBhCSCbiCFjRw50jVM3kfmzJlVvnx511Dt2rXLHbNo0SL33MCBA895fYsWLdxzI0aMOOe5G264QUWLFvVt169fX1dccUWAfyIAAHC+dr5IkSJq0qSJ3n33XR06dCgkL9a3337rOgAAJD+CbiBI+vbtq//7v//T4MGDVbt2bQ0bNky1atXS0aNHdfXVVytr1qz66aefznndvHnzlD59ev3888+x9p88eVKLFy/W9ddfn4I/BQAAOF87b+17ly5d3L6uXbuqSpUq+u2333zHvfjiizp27FhIBN19+vQJ9mkAaVL6YJ8AEK6aNWumGjVquH//97//Vb58+fTWW29p4sSJuvvuu1WzZs1zAuu1a9fq77//1j333HNOQL506VIdP35cderUUWpgnQvWsQAAQFpv502PHj30ww8/6NZbb9Vtt92m1atXK0uWLK4j3R4A0i5GuoEQ0bBhQ/d148aN7qsFz5Zuvn79et8xFoTnzJlTDz30kC8A93/O+7rksH//fnXr1k2lSpVSpkyZVKxYMd1///2+7+lNn9u0aVOs182ePdvtt69x09ytY8BS4C3Yfv75592NR5kyZeL9/jbq73+zYj799FNVr17d3aTkzZtXd911l7Zu3ZosPy8AACnR1vfs2VObN292bVpCc7pnzJjh2vPcuXMre/bsqlChgms347a1X3zxhdsfFRWlbNmyuWA+brv4448/6vbbb1eJEiVce168eHHXvvuPrj/wwAMaMmSI+7d/arzXmTNn9M4777hRekuXL1CggJo2baolS5ac8zNOmDDBtfn2vS6//HJNmzYtGa8gkDrRrQaEiA0bNrivNuLtHzzbiPZll13mC6yvu+46NwqeIUMGl2puDaz3uRw5cqhatWqXfC6HDx9W3bp1XS/8gw8+6NLdLdieNGmS/vrrL+XPnz/J77l3717X62+B8r333qtChQq5ANoCeUuLv+aaa3zH2s3IggUL9MYbb/j2vfrqq+5G5Y477nCZAXv27NGgQYNcEP/LL7+4GxMAAELdfffd5wLl7777Th07djzn+d9//911SletWtWlqFvwah3wcbPfvG2jBcfdu3fX7t279fbbb6tx48Zavny566A2Y8eOddlljz76qLvHsLox1n5ae27PmYcffljbt293wb6lxMfVoUMH19lu7bi1wadPn3bBvLXV/h3kds8ybtw4PfbYY+6exOawt2nTRlu2bPHd3wBhKQZAihoxYkSM/a/3/fffx+zZsydm69atMWPGjInJly9fTJYsWWL++usvd9zBgwdj0qVLF9OhQwffaytUqBDTp08f9+9rr7025plnnvE9V6BAgZgbb7wx1veqV69ezOWXX57kc+zVq5c7x3Hjxp3z3JkzZ2L9HBs3boz1/KxZs9x+++p/HrZv+PDhsY49cOBATKZMmWKeeuqpWPsHDBgQExEREbN582a3vWnTJnctXn311VjHrVixIiZ9+vTn7AcAIFi87ePixYsTPCZXrlwxV111lft379693fFeAwcOdNt2j5AQb1tbtGhRd7/g9eWXX7r977zzjm/f0aNHz3l9//79Y7WzplOnTrHOw+uHH35w+x9//PEE7wmMHZMxY8aY9evX+/b9+uuvbv+gQYMS/FmAcEB6ORAk1hNt6VmW5mWjv5Y+Nn78eF/1ceshtl5u79xtG2m2lHIrumasYJq31/uPP/5wI7/JlVr+9ddfuxHzVq1anfPcxS5rYj317du3j7XPUuWt1/zLL7+0Vt6339LlbETfUuGM9ZpbapuNctt18D4sna5cuXKaNWvWRZ0TAADBYG1+QlXMvZlbVuPF2r7zsWwxu1/w+s9//qPChQu7omhe3hFvc+TIEdd+2r2EtbuWKZaYewJr+3v37n3BewK7tylbtqxv2+5jrK3/888/L/h9gLSMoBsIEps7ZWlcFjCuWrXKNUi2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VBYoV255adeNgBsAACAsEHQDQFIc3SeNfUBaNeHirxsBNwAAQNhIH+wTAIBU44/vpEmdpcO7pIh0nhHvmBhpzmuJfw8CbgAAgLBC0A0AF3LikDT9BWnZKM92/gpSq+FS0as925HpEreMGAE3AABA2CHoBoDz2TxPGv+ItH+zZ/u6TlKjnlKGLP8e4y2Gdr7Am4AbAAAgLBF0A0B8Th2XZr0izRssKUbKVVxqOVQqfUP81+t8gTcBNwAAQNhKciG1uXPnqnnz5ipSpIgiIiI0YULsYkIxMTHq1auXChcurCxZsqhx48Zat25drGP27duntm3bKmfOnMqdO7c6dOigw4cPX/pPAwDJYcev0vv1pXmDPAH3lfdKj85LOOA+33JiBNwAAABhLclB95EjR1StWjUNGTIk3ucHDBigd999V8OHD9fChQuVLVs2NWnSRMePH/cdYwH377//rhkzZmjKlCkukH/ooYcu7ScBgEsVfVqa84b0QUNpz2opWwHprs+llkOkzDkT9x6+wDuCgBsAAABJD7qbNWumV155Ra1atTrnORvlfvvtt/Xiiy+qRYsWqlq1qj755BNt377dNyK+evVqTZs2TR9++KFq1qypOnXqaNCgQRozZow7DgCC4u910sdNPCnlZ05LlZpLjy2QKt6c9PeywPul/f+mnAOp1Guvveay2rp27erbZ53onTp1Ur58+ZQ9e3a1adNGu3btCup5AgAQNut0b9y4UTt37nQp5V65cuVywfX8+fPdtn21lPIaNWr4jrHjIyMj3ch4fE6cOKGDBw/GegBAsjhzRlr4vjS8rrRtiZQpl9TqfemO/5Oy5eciI2wtXrxY7733nutA99etWzdNnjxZY8eO1Zw5c1yHeevWrYN2ngAAhFXQbQG3KVSoUKz9tu19zr4WLFgw1vPp06dX3rx5fcfE1b9/fxe8ex/FixdPztMGEK4O/CV92kqa+ox0+phUpr702Dyp2p1SRESwzw4IGquzYlPBPvjgA+XJk8e3/8CBA/roo4/01ltvqWHDhqpevbpGjBihefPmacGCBfzGAAAIdNAdKD169HANvfexdevWYJ8SgNQsJkb6dYw0tLb052wpfRbp5jele8dLuYoF++yAoLP08VtuuSVW5ppZunSpTp06FWt/xYoVVaJECV9GW3zIWAMAhLNkXTIsKirKfbW5XVa93Mu2r7zySt8xu3fvjvW606dPu4rm3tfHlSlTJvcAgEt25G9pSldp9WTPdtEaUqv3pPyXcXEBydVYWbZsmUsvj8sy0jJmzOimiSWU0ZZQxlqfPn24vgCAsJSsI92lS5d2gfPMmTN9+2z+tc3VrlWrltu2r/v373e95V4//PCDzpw54+Z+A0DArPlWGnqdJ+COTC81fFF6cDoBN3CWZZI98cQT+uyzz5Q5c+Zkuy5krAEAwln6i5nntX79+ljF05YvX+7mZFt6mVU4term5cqVc0F4z5493ZreLVu2dMdXqlRJTZs2VceOHd2yYpam1rlzZ911113uOABIdscPStN6SMs/9WwXrCy1Gi4VrsbFBvxYh7hlo1199dW+fdHR0W5pz8GDB2v69Ok6efKk6zz3H+22jLaEstUMGWsAgHCW5KB7yZIlatCggW/7ySefdF/btWunkSNH6tlnn3Vredu629Yo25JgtkSYf4+59aBboN2oUSNXtdyWG7G1vQEg2W38UZrwmHRgi2ft7NpdPOtnZ0i+UTwgrbB2ecWKFbH2tW/f3s3b7t69uytkmiFDBpfRZm23Wbt2rbZs2eLLaAMAAJcYdNevX9+tx50QW8+zb9++7pEQGxUfPXp0Ur81ACTeqWPSzL7SgqGe7dwlPaPbJWtzFYEE5MiRQ1dccUWsfdmyZXNrcnv3d+jQwXW4W1ueM2dOdenSxQXc1113HdcVAIBAF1IDgJCwbZk0/mHp7z8829UfkG56RcqUI9hnBqR6AwcO9GWpWVXyJk2aaOjQs51bAADgHATdANKO6FPS3DeluW9IMdFS9ijptkFS+ZuCfWZAqjV79uxY2zZdbMiQIe4BAAAujKAbQOpzJlraPE86vEvKXsiTMr53vTTuIWnHcs8xl7eWbvmflDVvsM8WAAAAYYygG0DqsmqSNK27dHD7v/sy5ZROHZXOnJYy5/YE21X+E8yzBFKMrSJiq4UAAIDQRNANIHUF3F/eLylOMccTBz1fC1WR2n4p5WT5QYSPsmXLqmTJkm5lEe+jWLFiwT4tAABwFkE3gNSTUm4j3HEDbn/H9nnSzYEw8sMPP7h51/b4/PPP3TraZcqUUcOGDX1BeKFC/H8BAECwEHQDSB1sDrd/Snl8Dm7zHFe6bkqdFRB0tpSnPczx48c1b948XxA+atQonTp1yq2z/fvvvwf7VAEACEsE3QBShz1rEnecFVcDwpRVFrcR7jp16rgR7qlTp+q9997TmjWJ/P8HAAAkO4JuAKHt1DFp3mDPMmCJQXo5wpCllC9YsECzZs1yI9wLFy5U8eLFdcMNN2jw4MGqV69esE8RAICwRdANIDTFxEi/j5Nm9JYObPXsS5dRij6ZwAsiPAXUbPkwIIzYyLYF2VbB3ILrhx9+WKNHj1bhwoWDfWoAAICgG0BI2rZMmtZD2rrAs52zmHRjHyldBunLdmcP8i+oFuH50vQ1KTJdip8uEEw//vijC7At+La53RZ458uXj18KAAAhIjLYJwAAPgd3SBMekz5o4Am4M2SVGrwgdV7sWXe7cgvpjk+knHFG8GyE2/ZXvo2LibCzf/9+vf/++8qaNatef/11FSlSRFWqVFHnzp311Vdfac+ePcE+RQAAwhrp5QBCY972/MHSjwOlU0c8+6reJTXqJeUqGvtYC6wr3uKpUm5F02wOt6WUM8KNMJUtWzY1bdrUPcyhQ4f0008/ufndAwYMUNu2bVWuXDmtXLky2KcKAEBYIugGEOR52+PPztve4tlX7BpPmnixGgm/zgJslgUDEgzC8+bN6x558uRR+vTptXr1aq4WAABBQtANIDi2/+KZt71lvmc7Z1GpcR9PGnnE2TnaAC7ozJkzWrJkiatabqPbP//8s44cOaKiRYu6ZcOGDBnivgIAgOAg6AaQsg7tlGa+LC3/zFMMLX0WqU5XqfbjUsas/DaAJMqdO7cLsqOiolxwPXDgQFdQrWzZslxLAABCAEE3gJRx6vjZedtv/Ttvu8odUuOXzp23DSDR3njjDRdsly9fnqsGAEAIIugGEPh526smSN/1+nfedtEannnbxa/h6gOXyNbotseFfPzxx1xrAACCgKAbQOBsX3523vY8z3aOIp71tq/4jxTJioVAchg5cqRKliypq666SjHWyQUAAEIKQTeA+M0ZIM3qJzV4Xqr3bNKu0qFd0sy+sedtX/+EdL3N287GFQeS0aOPPqrPP/9cGzduVPv27XXvvfe6yuUAACA0MNQEIIGA+1VPwGxfbTux87Z//J806Gpp+aee19u87S5LpAY9CLiBALDq5Dt27NCzzz6ryZMnq3jx4rrjjjs0ffp0Rr4BAAgBjHQDSCDg9uPdTmjE283bnijN6Cnt987bri41fZ1520AKyJQpk+6++2732Lx5s0s5f+yxx3T69Gn9/vvvyp49O78HAACChKAbwPkD7gsF3jt+9czb3vzzv/O2rSJ5lduZtw0EQWRkpCIiItwod3R0NL8DAADSWnp5qVKlXGMf99GpUyf3vK0dGve5Rx55JLlPA0ByBtxe/qnmNm97YifpvXqegDt9Zqled08qebU7CbiBFHTixAk3r/vGG290S4etWLFCgwcP1pYtWxjlBgAgrY10L168OFbP+sqVK91NwO233+7b17FjR/Xt29e3nTVr1uQ+DQDJHXB72XGb50l/LZFOHvLss1HtRr2l3MW57kAKszTyMWPGuLncDz74oAu+8+fPz+8BAIC0GnQXKFAg1vZrr72msmXLql69erGC7KioqOT+1gACHXB7/TnL87XI1VIzm7d9LdceCJLhw4erRIkSKlOmjObMmeMe8Rk3blyKnxsAAAjwnO6TJ0/q008/1ZNPPunSyL0+++wzt98C7+bNm6tnz57nHe22tDl7eB08eJDfHRCsgNtf+aYE3ECQ3X///bHaWAAAEEZB94QJE7R//3498MADvn333HOPSpYsqSJFiui3335T9+7dtXbt2vP2wPfv3199+vQJ5KkC4edSA24zu59kN/tJXccbQLKxSuXJadiwYe6xadMmt3355ZerV69eatasmds+fvy4nnrqKZfSbh3iTZo00dChQ1WoUKFkPQ8AANKKgAbdH330kWukLcD2euihh3z/rlKligoXLqxGjRppw4YNLg09Pj169HCj5f4j3TZ3DUAQA+7ELicGIFUpVqyYmxpWrlw5VwF91KhRatGihX755RcXgHfr1k3ffPONxo4dq1y5cqlz585q3bq1fv757AoGAAAgZYJuWyf0+++/v+Acspo1a7qv69evTzDotvVH7QEgmczql/zvR9ANpAk27cvfq6++6ka+FyxY4AJy61AfPXq0GjZs6J4fMWKEKlWq5J6/7rrrgnTWAACE0ZJhXtYIFyxYULfccst5j1u+fLn7aiPeAFJIg+dD+/0AhARbjcTSyI8cOaJatWpp6dKlOnXqlBo3buw7pmLFiq6Q2/z584N6rgAAhNVI95kzZ1zQ3a5dO6VP/++3sBRy6x2/+eablS9fPjen29LUbrjhBlWtWjUQpwIgPt5R6eRIMW/wAqPcQBpj63xbkG3zt7Nnz67x48ercuXKrqM8Y8aMyp07d6zjbT73zp07E3w/CqICAMJZQEa6La18y5Ytbr1Qf9ZQ23M33XST6xm3Qixt2rTR5MmTA3EaAM7n+iekMg0u7RoRcANpUoUKFVyAvXDhQj366KOuE33VqlUX/X5WENXmf3sf1GUBAISTgIx0W1BtxVfiskY2ofVDAaQQ+39zzRTpuxelfzzViS8KATeQZlkn+WWXXeb+Xb16dS1evFjvvPOO7rzzTrccqK1M4j/avWvXLrcMaEIoiAoACGcBm9MNIATtXCGNai59ca8n4M4eJbUcJtVP4pxsAm4grNi0MUsRtwA8Q4YMmjlzpu85W/bTstssHT0hVgw1Z86csR4AAISLgC4ZBiBEHN4j/fCytOwTG+qW0mWSaneR6nSTMmX3HGPrbSdmjjcBN5Cm2ai0LfdpxdEOHTrkarHMnj1b06dPd6nhHTp0cMt45s2b1wXPXbp0cQE3lcsBAIgfQTeQlp0+IS0cLs19Uzpx0LPv8lbSjX2l3CWSXlyNgBtI83bv3q37779fO3bscEG2FTq1gPvGG290zw8cOFCRkZGuJouNfjdp0kRDhw4N9mkDABCyCLqBNDtv+5uz87Y3evYVvlJq+ppUMuEU0PMG3gTcQFiwdbjPJ3PmzBoyZIh7AACACyPoBtKanSul6T2kjXM929kLSY16S9XuliITUcYhvsCbgBsAAAC4KATdQFqatz3rFc+87ZgzZ+dtd5bqPPnvvO3E8gXe/aQGz7MONwAAAHCRCLqB1O70SWnRe9KcAbHnbTfuI+UpefHva4G3N/gGAAAAcFEIuoHUPG977beeedv7/vTsK1zt7Lzt2sE+OwAAAAAE3UAqtet3aZrN257jN2+7l1TtnsTN2wYAAACQIhjpBlKTI397CpwtHfnvvO1anaS6Nm87R7DPDgAAAEAcBN1Aap23XbmFZ73tPKWCfXYAAAAAEkDQDYT8vO2p0ncv/DtvO6qqZ952qeuDfXYAAAAALoCgGwjledvTn5f+nO3ZzlbQM2/7Spu3nS7YZwcAAAAgEQi6gZCct91PWjri7LztjGfnbT/FvG0AAAAglSHoBkJq3vb7Z+dtH/Dsq3SbdNPLzNsGAAAAUimCbiAU5m3/MU2abvO2N3j2RVU5O2+7TrDPDgAAAMAlIOgGgmnXqrPztmd5trMVODtvuy3ztgEAAIA0gKAbCIYje8+ut+03b/u6xzzztjPn5HcCAAAApBEE3UBKz9te/IE0+3W/edvNpRtflvKW5ncBAAAApDEE3UCKzdue7llve+96z75CNm+7v1S6Lr8DAAAAII0i6AYCbfdqz7ztDT/8O2+7YU/pqnuZtw0AAACkcQTdQCDnbc/uJy2xedvRZ+dtPyrVfZp52wAAAECYIOgGklv0KWnxh9Ls/tJx/3nbfaW8ZbjeAAAAQBiJTO43fOmllxQRERHrUbFiRd/zx48fV6dOnZQvXz5lz55dbdq00a5du5L7NIDgzdseWkua9pwn4LZ52+0mS3d+SsANAAAAhKGAjHRffvnl+v777//9Jun//TbdunXTN998o7FjxypXrlzq3LmzWrdurZ9//jkQpwKkjN1rzs7bnunZzppfamTztu9j3jYAAAAQxgISdFuQHRUVdc7+AwcO6KOPPtLo0aPVsGFDt2/EiBGqVKmSFixYoOuuuy4QpwMEztF9njTyxR955m1HZvDM277B5m3n4soDAAAAYS4gQfe6detUpEgRZc6cWbVq1VL//v1VokQJLV26VKdOnVLjxo19x1rquT03f/78BIPuEydOuIfXwYMHA3HawKXN2654q2fedr6yXEkAAAAAgQm6a9asqZEjR6pChQrasWOH+vTpo7p162rlypXauXOnMmbMqNy5c8d6TaFChdxzCbGg3d4HCAl/fOdJJd+7zrNd6AqpST+pTL1gnxkAAACAtB50N2vWzPfvqlWruiC8ZMmS+vLLL5UlS5aLes8ePXroySefjDXSXbx48WQ5XyBJ87a/e0Fa//2/87YbvihdfT/ztgEAAAAEZ8kwG9UuX7681q9frxtvvFEnT57U/v37Y412W/Xy+OaAe2XKlMk9gODN237Nk07um7f9iHTDM8zbBgAAAJCyS4bFdfjwYW3YsEGFCxdW9erVlSFDBs2cebbCs6S1a9dqy5Ytbu43EHLzthcMl969Slr0nifgrnCL1GmhdNMrBNwA0iSb0nXNNdcoR44cKliwoFq2bOnaan8s/wkAQBCD7qefflpz5szRpk2bNG/ePLVq1Urp0qXT3Xff7ZYI69Chg0sVnzVrlius1r59exdwU7kcIWXdDGlYbWlad+n4fqng5dL9E6W7R1MoDUCaZm14p06d3KoiM2bMcAVQb7rpJh05ciTW8p+TJ092y3/a8du3b3fLfwIAgBRIL//rr79cgL13714VKFBAderUcQ23/dsMHDhQkZGRatOmjatI3qRJEw0dOjS5TwO4OHvWStNt3vYMz3bWfGfnbbdj3jaAsDBt2rRY21Yc1Ua8raP8hhtuYPlPAACCHXSPGTPmvM/bMmJDhgxxDyCk5m3PeV1a9MG/87ZrPuyZt50ldrV9AAgnBw54lkXMmzev+3oxy3+y9CcAIJwFvJAaEPLztpd8LM3q50kjNxVu9szZZr1tAGHuzJkz6tq1q66//npdccUVbt/FLP/J0p8AgHBG0I3wte57z3rbf58tEFSwsme97bINgn1mABASbG73ypUr9dNPP13S+7D0JwAgnBF0I+06Ey1tnicd3iVlLySVrO2Zl73nD8962+u++3fedoMXPPO20/G/BACYzp07a8qUKZo7d66KFSvmuyi2xGdSl/9k6U8AQDgjwkDatGqSp/L4we3/7ssRJUVVlTb8IJ05LUWml2qeXW+bedsA4MTExKhLly4aP368Zs+erdKlS8e6Mv7Lf1pRVMPynwAAJIygG2kz4P7yfrt1jL3/0E7Pw5Rv5pm3nf+yoJwiAIRySvno0aM1ceJEt1a3d562LfuZJUuWWMt/WnG1nDlzuiCd5T8BAIgfQTfSXkq5jXDHDbj9Zc0v3fUZS4ABQDyGDRvmvtavXz/W/hEjRuiBBx5w/2b5TwAAEo+gG2mLzeH2TymPz9G/PceVrptSZwUAqSq9/EJY/hMAgMSLTMKxQOizomnJeRwAAAAAXAKCbqQtVqU8OY8DAAAAgEtA0I20xZYFy1lEUkQCB0RIOYt6jgMAAACAACPoRtpi63A3ff3sRtzA++x209coogYAAAAgRRB0I+2pfJt0xydSzsKx99sIuO235wEAAAAgBVC9HGmTBdYVb/FUKbeiaTaH21LKbSQcAAAAAFIIQTfSLguwWRYMAAAAQBCRXg4AAAAAQIAQdAMAAAAAECAE3QAAAAAABAhzugEAQKpWo0YN7dy5M9ingRCxY8eOYJ8CAMRC0A0AAFI1C7i3bdsW7NNAiMmRI0ewTwEAHIJuAACQqkVFRV3U684cPpLs54LkF5k920UF3C+//DK/DgAhgaAbAACkakuWLLmo1+0ZNDjZzwXJr0CXzlxWAKkahdQAAAAAAAgQgm4AAAAAAFJL0N2/f39dc801bi5NwYIF1bJlS61duzbWMfXr11dERESsxyOPPJLcpwIAAAAAQNoKuufMmaNOnTppwYIFmjFjhk6dOqWbbrpJR47ELlbSsWNHt6SD9zFgwIDkPhUAAAAAANJWIbVp06bF2h45cqQb8V66dKluuOEG3/6sWbNedLVRAAAAAABSg4DP6T5w4ID7mjdv3lj7P/vsM+XPn19XXHGFevTooaNHjyb4HidOnNDBgwdjPQAAAAAACOslw86cOaOuXbvq+uuvd8G11z333KOSJUuqSJEi+u2339S9e3c373vcuHEJzhPv06dPIE8VAAAAAIDUFXTb3O6VK1fqp59+irX/oYce8v27SpUqKly4sBo1aqQNGzaobNmy57yPjYQ/+eSTvm0b6S5evHggTx0AAAAAgNANujt37qwpU6Zo7ty5Klas2HmPrVmzpvu6fv36eIPuTJkyuQcAAAAAAGEddMfExKhLly4aP368Zs+erdKlS1/wNcuXL3dfbcQbAAAAAIC0In0gUspHjx6tiRMnurW6d+7c6fbnypVLWbJkcSnk9vzNN9+sfPnyuTnd3bp1c5XNq1atmtynAwAAAABA2qlePmzYMFexvH79+m7k2vv44osv3PMZM2bU999/79burlixop566im1adNGkydPTu5TAQAASWTTwpo3b+6KnUZERGjChAnnZLT16tXLte3Wmd64cWOtW7eO6wwAQEqml5+PFUCbM2dOcn9bAACQDI4cOaJq1arpwQcfVOvWrc95fsCAAXr33Xc1atQoN4WsZ8+eatKkiVatWqXMmTPzOwAAICWrlwMAgNSlWbNm7pFQx/rbb7+tF198US1atHD7PvnkExUqVMiNiN91110pfLYAAIRhejkAAEibNm7c6Gq1WEq5l9VssVVI5s+fn+DrTpw44Zb79H8AABAuCLoBAECieIuj2si2P9v2Phef/v37u+Dc+7CpZgAAhAuCbgAAEFA9evRwRVa9j61bt3LFAQBhg6AbAAAkSlRUlPu6a9euWPtt2/tcfDJlyqScOXPGegAAEC4IugEAQKJYtXILrmfOnOnbZ/OzFy5cqFq1anEVAQCIB9XLAQCAz+HDh7V+/fpYxdOWL1+uvHnzqkSJEuratateeeUVlStXzrdkmK3p3bJlS64iAADxIOgGAAA+S5YsUYMGDXzbTz75pPvarl07jRw5Us8++6xby/uhhx7S/v37VadOHU2bNo01ugEASABBNwAA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GLv22mtjOnXq5NuOjo6OKVKkSEz//v2Del6hbvfu3TZUFjNnzhy3vX///pgMGTLEjB071nfM6tWr3THz588P4pmGjkOHDsWUK1cuZsaMGTH16tWLeeKJJ9x+rt35de/ePaZOnToJPn/mzJmYqKiomDfeeMO3z65ppkyZYj7//POYcHbLLbfEPPjgg7H2tW7dOqZt27bu31y7hNnfrvHjx/u2E3OtVq1a5V63ePFi3zFTp06NiYiIiNm2bVsy/maBpH1+gbj3bUCePHliPvzwQy5ECgrbke6TJ0+6Hh9LEfSKjIx02/Pnzw/quYW6AwcOuK958+Z1X+06Wi+q/7WsWLGiSpQowbU8y3qcb7nllljXiGt3YZMmTVKNGjV0++23uxS5q666Sh988IHv+Y0bN2rnzp2xrmuuXLncVJFw//+4du3amjlzpv744w+3/euvv+qnn35Ss2bN3DbXLvESc63sq6WU2+fVy463dsVGxgEgVO7bEN5Tz8aMGeOyHizNHCknvcLU33//7T54hQoVirXfttesWRO08wp1Z86ccfORLeX3iiuucPvsZjRjxozuhjPutbTnwp39cbPpC5ZeHhfX7vz+/PNPlyJt00Cef/55dw0ff/xx93lr166d7/MV3//H4f7Ze+6553Tw4EHXAZYuXTr39+7VV191KdCGa5d4iblW9tU6hvylT5/e3eSG+2cRQGjdtyH8rFixwgXZNiXKai+NHz9elStXDvZphZWwDbpx8SO2K1eudCNmuLCtW7fqiSeecHOqrFgfkn6zYCOH/fr1c9s20m2fP5tXa0E3Evbll1/qs88+0+jRo3X55Zdr+fLl7sbLCi1x7QAgPHDfBlOhQgV3H2BZD1999ZW7D7C5/wTeKSds08vz58/vRn/iVti27aioqKCdVyjr3LmzKw40a9YsV5TBy66Xpevv378/1vFcS0/qvRXmu/rqq92olz3sj5wVZLJ/20gZ1y5hVik6boNQqVIlbdmyxffZ837W+OzF9swzz7jR7rvuustVfL/vvvtc0T6rasu1S5rEfM7sa9winKdPn3YVzWlTAITSfRvCj2UIXnbZZapevbq7D7DCi++8806wTyusRIbzh88+eDbn0X9UzbaZ4xCb1WWxP9yWivLDDz+4JYj82XW06tL+19KWprDAKNyvZaNGjVxKj/Uueh82cmspvt5/c+0S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" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 26 + "source": "bp6 = linopy.breakpoints({\"power\": x_pts6.values, \"fuel\": y_pts6.values}, dim=\"var\")\nplot_pwl_results(m6, bp6, demand6, color=\"C2\")", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -3478,246 +2519,61 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.106128Z", - "start_time": "2026-04-01T17:28:23.102693Z" + "end_time": "2026-04-01T17:50:21.872549Z", + "start_time": "2026-04-01T17:50:21.869653Z" } }, - "source": [ - "# CHP operating points: as load increases, power, fuel, and heat all change\n", - "bp_chp = linopy.breakpoints(\n", - " {\n", - " \"power\": [0, 30, 60, 100],\n", - " \"fuel\": [0, 40, 85, 160],\n", - " \"heat\": [0, 25, 55, 95],\n", - " },\n", - " dim=\"var\",\n", - ")\n", - "print(\"CHP breakpoints:\")\n", - "print(bp_chp.to_pandas())" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CHP breakpoints:\n", - "_breakpoint 0 1 2 3\n", - "var \n", - "power 0.0 30.0 60.0 100.0\n", - "fuel 0.0 40.0 85.0 160.0\n", - "heat 0.0 25.0 55.0 95.0\n" - ] - } - ], - "execution_count": 27 + "source": "# CHP operating points: as load increases, power, fuel, and heat all change\nbp_chp = linopy.breakpoints(\n {\n \"power\": [0, 30, 60, 100],\n \"fuel\": [0, 40, 85, 160],\n \"heat\": [0, 25, 55, 95],\n },\n dim=\"var\",\n)\nprint(\"CHP breakpoints:\")\nprint(bp_chp.to_pandas())", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.156431Z", - "start_time": "2026-04-01T17:28:23.115330Z" + "end_time": "2026-04-01T17:50:21.920666Z", + "start_time": "2026-04-01T17:50:21.879829Z" } }, "source": "m7 = linopy.Model()\n\npower = m7.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m7.add_variables(name=\"fuel\", lower=0, coords=[time])\nheat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n\n# Fixed power dispatch determines the operating point \u2014 fuel and heat follow\npower_dispatch = xr.DataArray([20, 60, 90], coords=[time])\nm7.add_constraints(power == power_dispatch, name=\"power_dispatch\")\nm7.add_objective(fuel.sum())\n\n# N-variable: all three linked through shared interpolation weights\nm7.add_piecewise_formulation(\n (power, bp_chp.sel(var=\"power\")),\n (fuel, bp_chp.sel(var=\"fuel\")),\n (heat, bp_chp.sel(var=\"heat\")),\n name=\"chp\",\n method=\"sos2\",\n)", - "outputs": [ - { - "data": { - "text/plain": [ - "PiecewiseFormulation 'chp' (sos2)\n", - " Variables (1):\n", - " * chp_lambda\n", - " Constraints (2):\n", - " * chp_convex\n", - " * chp_x_link" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 28 + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.195969Z", - "start_time": "2026-04-01T17:28:23.165043Z" + "end_time": "2026-04-01T17:50:21.964861Z", + "start_time": "2026-04-01T17:50:21.926856Z" } }, - "source": [ - "m7.solve(reformulate_sos=\"auto\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-nakr2nzl.lp\n", - "Reading time = 0.00 seconds\n", - "obj: 15 rows, 21 columns, 51 nonzeros\n", - "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", - "\n", - "CPU model: Apple M3\n", - "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 15 rows, 21 columns and 51 nonzeros (Min)\n", - "Model fingerprint: 0x8c65a8ab\n", - "Model has 3 linear objective coefficients\n", - "Model has 3 SOS constraints\n", - "Variable types: 21 continuous, 0 integer (0 binary)\n", - "Coefficient statistics:\n", - " Matrix range [1e+00, 2e+02]\n", - " Objective range [1e+00, 1e+00]\n", - " Bounds range [1e+00, 1e+02]\n", - " RHS range [1e+00, 9e+01]\n", - "\n", - "Presolve removed 15 rows and 21 columns\n", - "Presolve time: 0.00s\n", - "Presolve: All rows and columns removed\n", - "\n", - "Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n", - "Thread count was 1 (of 8 available processors)\n", - "\n", - "Solution count 2: 252.917 252.917 \n", - "\n", - "Optimal solution found (tolerance 1.00e-04)\n", - "Best objective 2.529166651870e+02, best bound 2.529166651870e+02, gap 0.0000%\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Dual values of MILP couldn't be parsed\n" - ] - }, - { - "data": { - "text/plain": [ - "('ok', 'optimal')" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 29 + "source": "m7.solve(reformulate_sos=\"auto\")", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.208354Z", - "start_time": "2026-04-01T17:28:23.202782Z" + "end_time": "2026-04-01T17:50:21.981116Z", + "start_time": "2026-04-01T17:50:21.976461Z" } }, - "source": [ - "m7.solution[[\"power\", \"fuel\", \"heat\"]].to_pandas().round(2)" - ], - "outputs": [ - { - "data": { - "text/plain": [ - " power fuel heat\n", - "time \n", - "1 20.0 26.67 16.67\n", - "2 60.0 85.00 55.00\n", - "3 90.0 141.25 85.00" - ], - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
powerfuelheat
time
120.026.6716.67
260.085.0055.00
390.0141.2585.00
\n", - "
" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 30 + "source": "m7.solution[[\"power\", \"fuel\", \"heat\"]].to_pandas().round(2)", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.296918Z", - "start_time": "2026-04-01T17:28:23.217335Z" + "end_time": "2026-04-01T17:50:22.088132Z", + "start_time": "2026-04-01T17:50:22.003877Z" } }, - "source": [ - "plot_pwl_results(m7, bp_chp, power_dispatch, x_name=\"fuel\")" - ], - "outputs": [ - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAFUCAYAAAA57l+/AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAg9RJREFUeJzt3Qd4FNXbBfCTHkIKPYEk9NB7B1G6gIg0QRAVEUGpAv5pShERaUqVJirlkyYKSBGQjvTea+gtCS2FhPT9nvfGWTchCQnZTXaz5+ezhpmdzM7sJrlz5jYbnU6nAxEREREREREZna3xd0lEREREREREDN1EREREREREJsSabiIiIiIiIiITYegmIiIiIiIiMhGGbiIiIiIiIiITYegmIiIiIiIiMhGGbiIiIiIiIiITYegmIiIiIiIiMhGGbiIiIiIiIiITYegmIiIiIspiX331FWxsbGDp5Bz69euX1YdBZFYYuokyyaJFi1RBpD2cnZ1RqlQpVTAFBgaqbQ4fPqyemzZt2nPf36ZNG/XcwoULn3vutddeg7e3t365YcOGqFChgonPiIiIiNJT7hcqVAjNmzfHzJkzERYWZpZv3l9//aVuABCR8TB0E2Wyr7/+Gv/3f/+HH374AfXq1cPcuXNRt25dREREoFq1anBxccHevXuf+779+/fD3t4e+/btS7Q+OjoaR44cwSuvvJKJZ0FERETpKfelvO/fv79aN3DgQFSsWBGnT5/Wbzdy5Eg8e/bMLEL32LFjs/owiLIV+6w+ACJr07JlS9SoUUP9++OPP0bevHkxdepU/Pnnn+jSpQtq1679XLC+dOkSHj58iHffffe5QH7s2DFERkaifv36sARyc0FuLBAREVlbuS9GjBiBHTt24M0338Rbb72FCxcuIEeOHOrGujyIKPthTTdRFmvcuLH6ev36dfVVwrM0N/f399dvIyHc3d0dvXr10gdww+e07zOG4OBgDBo0CEWLFoWTkxN8fHzwwQcf6F9Tay5348aNRN+3a9cutV6+Jm3mLjcGpAm8hO0vvvhCXWgUL1482deXWn/DixPx66+/onr16uqiJE+ePOjcuTNu375tlPMlIiLKirJ/1KhRuHnzpirjUurTvXXrVlW+58qVC66urihdurQqR5OWvStXrlTrvby8kDNnThXmk5aT//zzDzp27IjChQur8t3X11eV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p05V/9ZG9k7L8bZo0UJXtWpV3aFDh3R79+5VI+h36dLFLM4hOjpa99Zbb+l8fHx0J0+eTPQ7HhUVZRHnkJyko5dbwjnI74OMTv7jjz+q3/FZs2bp7OzsdP/884/F/J0i65be31PKntJy3UjWYfjw4WrUernmk2skWZZZQ/7++++sPjSrYdWhW8jFlFw4OTo6qinEDh48qDNXUnAm91i4cKF+GwkYffr0UdMASBBs166d+gNrSaHbEs5h/fr1ugoVKqibNmXKlFEX54ZkCqtRo0bpPD091TZNmjTRXbp0SWcuQkND1XsuP/vOzs664sWL67788stE4c7czmHnzp3J/vzLDYS0Hu+jR49UuHN1ddW5u7vrunfvri5OzeEcpCBM6Xdcvs8SziGtodsSzuHnn3/WlSxZUv1+VK5cWbd27dpE+7CEv1NkvdL7e0rZU1quG8k6yDSxUh5L3smfP7+6RmLgzlw28r+srm0nIiIiIiIiyo6stk83ERERERERkakxdBMRERERERGZCEM3ERERERERkYkwdBMRERERERGZCEM3ERERERERkYkwdBMRERERERGZCEM3ERERERERkYkwdBMRERERERGZCEM3Eb20Xbt2wcbGBsHBwXwXiYiIssiHH36Itm3b8v0nMlMM3URWUBBLME768Pf3z+pDIyIiohdIrgw3fHz11VeYMWMGFi1axPeSyEzZZ/UBEJHptWjRAgsXLky0Ln/+/HzriYiIzNz9+/f1/165ciVGjx6NS5cu6de5urqqBxGZL9Z0E1kBJycneHl5JXr06NHjuaZoAwcORMOGDfXL8fHxmDBhAooVK4YcOXKgcuXK+P3337PgDIiIiKyTYdnt4eGharcN10ngTtq8XMry/v37q3I9d+7c8PT0xIIFCxAeHo7u3bvDzc0NJUuWxKZNmxK91tmzZ9GyZUu1T/me999/Hw8fPsyCsybKXhi6iShFEriXLFmCefPm4dy5cxg0aBDee+897N69m+8aERGRGVu8eDHy5cuHw4cPqwDeu3dvdOzYEfXq1cPx48fx+uuvq1AdERGhtpfxWRo3boyqVavi6NGj2Lx5MwIDA9GpU6esPhUii8fm5URWYMOGDYmansld7Jw5c6b6PVFRUfj222+xbds21K1bV60rXrw49u7di/nz56NBgwYmP24iIiJ6OdI6beTIkerfI0aMwMSJE1UI79mzp1onzdTnzp2L06dPo06dOvjhhx9U4JayX/PLL7/A19cXly9fRqlSpfhREL0khm4iK9CoUSNVsGokcEsBnBoZaE3ufjdr1izR+ujoaFUoExERkfmqVKmS/t92dnbImzcvKlasqF8nzcdFUFCQ+nrq1Cns3Lkz2f7hV69eZegmygCGbiIrICFb+m4ZsrW1hU6nS7QuJiZG/++nT5+qrxs3boS3t/dzfcSJiIjIfDk4OCRalr7ghutkWRu/RSv3W7dujUmTJj23r4IFC5r8eImyM4ZuIislo5fLgCmGTp48qS+Qy5Urp8L1rVu32JSciIgom6tWrRr++OMPFC1aFPb2jAhExsSB1IislAyWIgOlyEBpV65cwZgxYxKFcBnZ9H//+58aPE0GY5GmZTLwyqxZs9QyERERZR99+/bF48eP0aVLFxw5ckSV+1u2bFGjncfFxWX14RFZNIZuIivVvHlzjBo1CkOHDkXNmjURFhaGDz74INE248aNU9vIKOZly5ZV831Lc3OZQoyIiIiyj0KFCmHfvn0qYMvI5tL/W6Ycy5Url+qSRkQvz0aXtFMnERERERERERkFb1sRERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxEREREREZGJMHQTERERERERmQhDNxERERERERFM4/8BZDGANiuN9OMAAAAASUVORK5CYII=" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 31 + "source": "plot_pwl_results(m7, bp_chp, power_dispatch, x_name=\"fuel\")", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -3728,277 +2584,61 @@ "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.308251Z", - "start_time": "2026-04-01T17:28:23.304773Z" + "end_time": "2026-04-01T17:50:22.097775Z", + "start_time": "2026-04-01T17:50:22.094150Z" } }, - "source": [ - "gens = pd.Index([\"gas\", \"coal\"], name=\"gen\")\n", - "\n", - "# Each generator has its own heat-rate curve\n", - "x_gen = linopy.breakpoints(\n", - " {\"gas\": [0, 30, 60, 100], \"coal\": [0, 50, 100, 150]}, dim=\"gen\"\n", - ")\n", - "y_gen = linopy.breakpoints(\n", - " {\"gas\": [0, 40, 90, 180], \"coal\": [0, 55, 130, 225]}, dim=\"gen\"\n", - ")\n", - "print(\"Power breakpoints:\\n\", x_gen.to_pandas())\n", - "print(\"Fuel breakpoints:\\n\", y_gen.to_pandas())" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Power breakpoints:\n", - " _breakpoint 0 1 2 3\n", - "gen \n", - "gas 0.0 30.0 60.0 100.0\n", - "coal 0.0 50.0 100.0 150.0\n", - "Fuel breakpoints:\n", - " _breakpoint 0 1 2 3\n", - "gen \n", - "gas 0.0 40.0 90.0 180.0\n", - "coal 0.0 55.0 130.0 225.0\n" - ] - } - ], - "execution_count": 32 + "source": "gens = pd.Index([\"gas\", \"coal\"], name=\"gen\")\n\n# Each generator has its own heat-rate curve\nx_gen = linopy.breakpoints(\n {\"gas\": [0, 30, 60, 100], \"coal\": [0, 50, 100, 150]}, dim=\"gen\"\n)\ny_gen = linopy.breakpoints(\n {\"gas\": [0, 40, 90, 180], \"coal\": [0, 55, 130, 225]}, dim=\"gen\"\n)\nprint(\"Power breakpoints:\\n\", x_gen.to_pandas())\nprint(\"Fuel breakpoints:\\n\", y_gen.to_pandas())", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.378677Z", - "start_time": "2026-04-01T17:28:23.316179Z" + "end_time": "2026-04-01T17:50:22.177554Z", + "start_time": "2026-04-01T17:50:22.111112Z" } }, "source": "m8 = linopy.Model()\n\npower = m8.add_variables(name=\"power\", lower=0, upper=150, coords=[gens, time])\nfuel = m8.add_variables(name=\"fuel\", lower=0, coords=[gens, time])\n\ndemand8 = xr.DataArray([80, 120, 60], coords=[time])\nm8.add_constraints(power.sum(\"gen\") >= demand8, name=\"demand\")\nm8.add_objective(fuel.sum())\n\n# Per-entity breakpoints: each generator gets its own curve\nm8.add_piecewise_formulation(\n (power, x_gen),\n (fuel, y_gen),\n name=\"pwl\",\n)", - "outputs": [ - { - "data": { - "text/plain": [ - "PiecewiseFormulation 'pwl' (incremental)\n", - " Variables (2):\n", - " * pwl_delta\n", - " * pwl_inc_binary\n", - " Constraints (4):\n", - " * pwl_inc_link\n", - " * pwl_fill\n", - " * pwl_inc_order\n", - " * pwl_x_link" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 33 + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.433861Z", - "start_time": "2026-04-01T17:28:23.386142Z" + "end_time": "2026-04-01T17:50:22.234795Z", + "start_time": "2026-04-01T17:50:22.185178Z" } }, - "source": [ - "m8.solve(reformulate_sos=\"auto\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2026-12-18\n", - "Read LP format model from file /private/var/folders/7j/18_93__x4wl2px44pq3f570m0000gn/T/linopy-problem-5iggilc6.lp\n", - "Reading time = 0.00 seconds\n", - "obj: 57 rows, 48 columns, 138 nonzeros\n", - "Gurobi Optimizer version 13.0.1 build v13.0.1rc0 (mac64[arm] - Darwin 25.2.0 25C56)\n", - "\n", - "CPU model: Apple M3\n", - "Thread count: 8 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 57 rows, 48 columns and 138 nonzeros (Min)\n", - "Model fingerprint: 0x79e2e4b7\n", - "Model has 6 linear objective coefficients\n", - "Variable types: 30 continuous, 18 integer (18 binary)\n", - "Coefficient statistics:\n", - " Matrix range [1e+00, 1e+02]\n", - " Objective range [1e+00, 1e+00]\n", - " Bounds range [1e+00, 2e+02]\n", - " RHS range [6e+01, 1e+02]\n", - "\n", - "Found heuristic solution: objective 392.0000000\n", - "Presolve removed 50 rows and 38 columns\n", - "Presolve time: 0.00s\n", - "Presolved: 7 rows, 10 columns, 23 nonzeros\n", - "Found heuristic solution: objective 340.0000000\n", - "Variable types: 6 continuous, 4 integer (4 binary)\n", - "\n", - "Root relaxation: objective 3.183333e+02, 1 iterations, 0.00 seconds (0.00 work units)\n", - "\n", - " Nodes | Current Node | Objective Bounds | Work\n", - " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", - "\n", - "* 0 0 0 318.3333333 318.33333 0.00% - 0s\n", - "\n", - "Explored 1 nodes (1 simplex iterations) in 0.00 seconds (0.00 work units)\n", - "Thread count was 8 (of 8 available processors)\n", - "\n", - "Solution count 3: 318.333 340 392 \n", - "\n", - "Optimal solution found (tolerance 1.00e-04)\n", - "Best objective 3.183333333333e+02, best bound 3.183333333333e+02, gap 0.0000%\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Dual values of MILP couldn't be parsed\n" - ] - }, - { - "data": { - "text/plain": [ - "('ok', 'optimal')" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 34 + "source": "m8.solve(reformulate_sos=\"auto\")", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.441819Z", - "start_time": "2026-04-01T17:28:23.437057Z" + "end_time": "2026-04-01T17:50:22.245727Z", + "start_time": "2026-04-01T17:50:22.242646Z" } }, - "source": [ - "m8.solution[[\"power\", \"fuel\"]].to_dataframe().round(2)" - ], - "outputs": [ - { - "data": { - "text/plain": [ - " power fuel\n", - "gen time \n", - "gas 1 30.0 40.00\n", - " 2 30.0 40.00\n", - " 3 10.0 13.33\n", - "coal 1 50.0 55.00\n", - " 2 90.0 115.00\n", - " 3 50.0 55.00" - ], - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
powerfuel
gentime
gas130.040.00
230.040.00
310.013.33
coal150.055.00
290.0115.00
350.055.00
\n", - "
" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 35 + "source": "m8.constraints['demand']", + "outputs": [], + "execution_count": null }, { "cell_type": "code", "metadata": { "ExecuteTime": { - "end_time": "2026-04-01T17:28:23.528662Z", - "start_time": "2026-04-01T17:28:23.444194Z" + "end_time": "2026-04-01T17:50:22.346404Z", + "start_time": "2026-04-01T17:50:22.260902Z" } }, "source": "sol = m8.solution\nfig, axes = plt.subplots(1, 2, figsize=(10, 3.5))\n\nfor i, gen in enumerate(gens):\n ax = axes[i]\n fuel_bp = y_gen.sel(gen=gen).values\n power_bp = x_gen.sel(gen=gen).values\n ax.plot(fuel_bp, power_bp, \"o-\", color=f\"C{i}\", label=\"Breakpoints\")\n for t in time:\n ax.plot(\n float(sol[\"fuel\"].sel(gen=gen, time=t)),\n float(sol[\"power\"].sel(gen=gen, time=t)),\n \"D\",\n color=\"black\",\n ms=8,\n )\n ax.set(xlabel=\"Fuel\", ylabel=\"Power [MW]\", title=f\"{gen.title()} heat-rate curve\")\n ax.legend()\n\nplt.tight_layout()", - "outputs": [ - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "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oKZkyZIad3d3jYeHh6Zs2bKat99+W01Bou/69etq+i6Z/kmmenr11Vc1N2/eVFNHyHQVIi4uTjN69GhN5cqV1dQXMp2H/P+777576r7opryQqcr0yfRVsl6ms9L3+++/axo0aKB+hjxkv2Uqj3PnzqVsc/r0aU2LFi00np6emnz58qnpqf75558npsVKTEzUDB06VJM/f341PcjTPi50U26tWLHiiedkyhWZJqVAgQLqeNavX18THBysady4sXro++OPPzRBQUFqqrO0+3T06FFNx44d1XRpMvWKTBPSpUsXzZYtW556LGXqk3HjxqkpxlxcXDT+/v6azp07ay5evJiyjRxnme5LponJkyePmjLm5MmT6U4ZJsc3M/Kz5Pvk9yizYybToMnvjvyulShRQtO7d2/NoUOHnvp+iIjslUyxJbGraNGiGldXVxVbJa7MnDkz1RRfCQkJmkmTJqV87gcGBmrGjh2bahshUz3VqVNHxaeAgADNe++9lzKNlP40klmZMqxt27ZPrE8v5skUkrJPEivkvUhcrlevnubLL79U04LpLFiwQE2dKbFPYrvEpPSmxTp79qyaakveizz3tOnDMotnxrpe+P777zXVq1dX+yTnqmLFiuoYy/XS00gM1l1nSZwsU6aMZvz48am2+fvvv9X0aXL85PnFixdnOGVYZtO3ylRk8jsi233yySfpbiPnZOrUqZry5curcyHXCvLe5PdMprUjyoiD/GPuxJ+IiIiIiIjIFnFMNxEREREREZGJMOkmIiIiIiIiMhEm3UREREREREQmwqSbiIiIiIiIyESYdBMRERERERGZCJNuIiIiIiIiIhNxNtULW5Pk5GTcvHkTXl5ecHBwMPfuEBGRnZPZPKOiohAQEABHR94f12G8JiIia4zXTLoBlXAHBgZm5/khIiJ6qmvXrqFQoUI8Uv9ivCYiImuM10y6AdXCrTtYuXLlyr6zQ0RElI6HDx+qm8G6+ERajNdERGSN8ZpJN5DSpVwSbibdRERkKTjkKf3jwXhNRETWFK85UIyIiIiIiIjIRJh0ExEREREREZkIk24iIiIiIiIiE+GY7ixMUxIfH2+q80BWwsXFBU5OTubeDSIiykRSUhISEhJ4jOwY4zURWRKzJt07d+7EF198gcOHD+PWrVtYtWoVOnTokGres4kTJ2L+/PmIiIhA/fr1MWfO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VFA1p8zelwT5jP7O5PvE4cOHNbVr11YBzt3dXVOuXDnNZ599luqCwJLekwRdCaISPGXKEJlGq3///k8kLpZ2rp72+yfmzZun8fDwUNOhpGWJ54nsK2abm63G1uxkq3HQnGwxXll6fmDo3/vly5c1rVu3VnFVbtDJjbuEhASNPXGQf8zd2k5ERERERERkizimm4iIiIiIiMhEmHQTERERERERmQiTbiIiIiIiIiITYdJNREREREREZCJMuomIiIiIiIhMhEk3ERERERERkYkw6SYiIiIiIiIyESbdRERERERERCbCpJuIzGL79u1wcHBAREQEzwAREZGFYrwmen5MuokoQ71791aJcdpHSEgIjxoREZGFYLwmsmzO5t4BIrJsrVq1wsKFC1Oty58/v9n2h4iIiJ7EeE1kudjSTUSZcnNzg7+/f6pHv3790KFDh1TbDRs2DE2aNElZTk5OxpQpU1CsWDF4eHigcuXK+O2333i0iYiITIDxmshysaWbiExCEu7Fixdj7ty5KFWqFHbu3IkePXqoVvLGjRvzqBMREVkAxmsi02PSTUSZWrduHTw9PVOWW7dujZw5c2b6PXFxcfjss8+wefNm1K1bV60rXrw4du/ejXnz5jHpJiIiMjLGayLLxaSbiDLVtGlTzJkzJ2VZEu6xY8dm+j1SaC0mJgYvvPBCqvXx8fGoWrUqjzgREZGRMV4TWS4m3USUKUmyS5YsmWqdo6MjNBpNqnUJCQkp/3/06JH6un79ehQsWPCJMWdERERkXIzXRJaLSTcRZZmMyz558mSqdceOHYOLi4v6f1BQkEqur169yq7kREREZsJ4TWQZmHQTUZY1a9YMX3zxBRYtWqTGbEvBNEnCdV3Hvby8MGrUKAwfPlxVMW/QoAEiIyOxZ88e5MqVC7169eJRJyIiMjHGayLLwKSbiLKsZcuWGD9+PN577z3Exsaib9++6NmzJ06cOJGyzccff6zusEtV1EuXLiF37tyoVq0aPvjgAx5xIiKibMB4TWQZHDRpB2YSERERERERkVE4GudliIiIiIiIiCgtJt1EREREREREJsKkm4iIiIiIiMhEmHQTERERERERmQiTbiIiIiIiIiITYdJNREREREREZCJMuomIiIiIiIhMhEk3ERERERERkYkw6SYiIiIiIiIyESbdRERERERERCbCpJuIiIiIiIjIRJh0ExEREREREcE0/g8i/Y3BWiyKhwAAAABJRU5ErkJggg==" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 36 + "outputs": [], + "execution_count": null } ], "metadata": { From 522fa6e638785aae08e2f4461fd3b79130662a97 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:14:45 +0200 Subject: [PATCH 13/16] refac: store names in PiecewiseFormulation, add IO persistence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PiecewiseFormulation now stores variable/constraint names as strings with a model reference. Properties return live Views on access. This makes serialization trivial — persist as JSON in netcdf attrs, reconstruct on load. Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/io.py | 17 +++++++++++++++++ linopy/model.py | 4 ++-- linopy/piecewise.py | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/linopy/io.py b/linopy/io.py index f2929398..9eaa964d 100644 --- a/linopy/io.py +++ b/linopy/io.py @@ -1147,6 +1147,11 @@ def with_prefix(ds: xr.Dataset, prefix: str) -> xr.Dataset: ds = ds.assign_attrs(scalars) if m._relaxed_registry: ds.attrs["_relaxed_registry"] = json.dumps(m._relaxed_registry) + if m._piecewise_formulations: + ds.attrs["_piecewise_formulations"] = json.dumps( + {name: {"method": pwl.method, "variables": pwl.variable_names, "constraints": pwl.constraint_names} + for name, pwl in m._piecewise_formulations.items()} + ) ds.attrs = non_bool_dict(ds.attrs) for k in ds: @@ -1244,6 +1249,18 @@ def get_prefix(ds: xr.Dataset, prefix: str) -> xr.Dataset: if "_relaxed_registry" in ds.attrs: m._relaxed_registry = json.loads(ds.attrs["_relaxed_registry"]) + if "_piecewise_formulations" in ds.attrs: + from linopy.piecewise import PiecewiseFormulation + + for name, d in json.loads(ds.attrs["_piecewise_formulations"]).items(): + m._piecewise_formulations[name] = PiecewiseFormulation( + name=name, + method=d["method"], + variable_names=d["variables"], + constraint_names=d["constraints"], + model=m, + ) + return m diff --git a/linopy/model.py b/linopy/model.py index dcb39cf3..366b75a4 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -533,8 +533,8 @@ def _piecewise_names(self) -> set[str]: """Return all variable/constraint names belonging to piecewise formulations.""" names: set[str] = set() for pwl in self._piecewise_formulations.values(): - names.update(pwl.variables) - names.update(pwl.constraints) + names.update(pwl.variable_names) + names.update(pwl.constraint_names) return names def __getitem__(self, key: str) -> Variable: diff --git a/linopy/piecewise.py b/linopy/piecewise.py index b67de05d..1ba28f78 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -8,7 +8,6 @@ from __future__ import annotations from collections.abc import Sequence -from dataclasses import dataclass from numbers import Real from typing import TYPE_CHECKING, Literal, TypeAlias @@ -61,19 +60,40 @@ # --------------------------------------------------------------------------- -@dataclass(repr=False) class PiecewiseFormulation: """ Result of ``add_piecewise_formulation``. Groups all auxiliary variables and constraints created by a single - piecewise formulation. + piecewise formulation. Stores only names internally; ``variables`` + and ``constraints`` properties return live views from the model. """ - name: str - method: str - variables: Variables - constraints: Constraints + __slots__ = ("name", "method", "variable_names", "constraint_names", "_model") + + def __init__( + self, + name: str, + method: str, + variable_names: list[str], + constraint_names: list[str], + model: Model, + ) -> None: + self.name = name + self.method = method + self.variable_names = variable_names + self.constraint_names = constraint_names + self._model = model + + @property + def variables(self) -> Variables: + """View of the auxiliary variables in this formulation.""" + return self._model.variables[self.variable_names] + + @property + def constraints(self) -> Constraints: + """View of the auxiliary constraints in this formulation.""" + return self._model.constraints[self.constraint_names] def __repr__(self) -> str: # Collect user-facing dims with sizes (skip internal _ prefixed dims) @@ -764,8 +784,9 @@ def add_piecewise_formulation( result = PiecewiseFormulation( name=name, method=resolved_method, - variables=model.variables[new_vars], - constraints=model.constraints[new_cons], + variable_names=new_vars, + constraint_names=new_cons, + model=model, ) model._piecewise_formulations[name] = result return result From 0b482eef0d6ede9ba1f08a04bea4743709133955 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:26:19 +0200 Subject: [PATCH 14/16] fix: rename remaining add_piecewise_constraints reference after rebase Co-Authored-By: Claude Opus 4.6 (1M context) --- test/test_piecewise_constraints.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_piecewise_constraints.py b/test/test_piecewise_constraints.py index 5d4175bc..ebfd3c6e 100644 --- a/test/test_piecewise_constraints.py +++ b/test/test_piecewise_constraints.py @@ -585,7 +585,7 @@ def test_three_variables(self) -> None: x = m.add_variables(name="x") y = m.add_variables(name="y") z = m.add_variables(name="z") - m.add_piecewise_constraints( + m.add_piecewise_formulation( (x, segments([[0, 10], [50, 100]])), (y, segments([[0, 5], [20, 80]])), (z, segments([[0, 3], [15, 60]])), From 18af4d7768cd05bb32d6c4cd84df10db761f91cb Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:35:41 +0200 Subject: [PATCH 15/16] refac: rename PWL suffix constants for clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PWL_X_LINK_SUFFIX/_Y_LINK_SUFFIX → PWL_LINK_SUFFIX (N-var, single link) - PWL_BINARY_SUFFIX → PWL_SEGMENT_BINARY_SUFFIX (disjunctive segment selection) - PWL_INC_BINARY_SUFFIX → PWL_ORDER_BINARY_SUFFIX (incremental ordering) - PWL_INC_LINK_SUFFIX → PWL_DELTA_BOUND_SUFFIX (δ ≤ binary) - PWL_INC_ORDER_SUFFIX → PWL_BINARY_ORDER_SUFFIX (binary_{i+1} ≤ δ_i) - PWL_FILL_SUFFIX → PWL_FILL_ORDER_SUFFIX (δ_{i+1} ≤ δ_i) Co-Authored-By: Claude Opus 4.6 (1M context) --- linopy/constants.py | 13 ++++--- linopy/piecewise.py | 36 ++++++++++---------- test/test_piecewise_constraints.py | 54 +++++++++++++++--------------- 3 files changed, 51 insertions(+), 52 deletions(-) diff --git a/linopy/constants.py b/linopy/constants.py index 0d8d4adc..268a7ac1 100644 --- a/linopy/constants.py +++ b/linopy/constants.py @@ -40,15 +40,14 @@ PWL_LAMBDA_SUFFIX = "_lambda" PWL_CONVEX_SUFFIX = "_convex" -PWL_X_LINK_SUFFIX = "_x_link" -PWL_Y_LINK_SUFFIX = "_y_link" +PWL_LINK_SUFFIX = "_link" PWL_DELTA_SUFFIX = "_delta" -PWL_FILL_SUFFIX = "_fill" -PWL_BINARY_SUFFIX = "_binary" +PWL_FILL_ORDER_SUFFIX = "_fill_order" +PWL_SEGMENT_BINARY_SUFFIX = "_segment_binary" PWL_SELECT_SUFFIX = "_select" -PWL_INC_BINARY_SUFFIX = "_inc_binary" -PWL_INC_LINK_SUFFIX = "_inc_link" -PWL_INC_ORDER_SUFFIX = "_inc_order" +PWL_ORDER_BINARY_SUFFIX = "_order_binary" +PWL_DELTA_BOUND_SUFFIX = "_delta_bound" +PWL_BINARY_ORDER_SUFFIX = "_binary_order" PWL_ACTIVE_BOUND_SUFFIX = "_active_bound" BREAKPOINT_DIM = "_breakpoint" SEGMENT_DIM = "_segment" diff --git a/linopy/piecewise.py b/linopy/piecewise.py index 1ba28f78..d3078fff 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -21,16 +21,16 @@ HELPER_DIMS, LP_SEG_DIM, PWL_ACTIVE_BOUND_SUFFIX, - PWL_BINARY_SUFFIX, + PWL_BINARY_ORDER_SUFFIX, PWL_CONVEX_SUFFIX, + PWL_DELTA_BOUND_SUFFIX, PWL_DELTA_SUFFIX, - PWL_FILL_SUFFIX, - PWL_INC_BINARY_SUFFIX, - PWL_INC_LINK_SUFFIX, - PWL_INC_ORDER_SUFFIX, + PWL_FILL_ORDER_SUFFIX, PWL_LAMBDA_SUFFIX, + PWL_LINK_SUFFIX, + PWL_ORDER_BINARY_SUFFIX, + PWL_SEGMENT_BINARY_SUFFIX, PWL_SELECT_SUFFIX, - PWL_X_LINK_SUFFIX, SEGMENT_DIM, ) @@ -903,7 +903,7 @@ def _add_sos2( lambda_name = f"{name}{PWL_LAMBDA_SUFFIX}" convex_name = f"{name}{PWL_CONVEX_SUFFIX}" - link_name = f"{name}{PWL_X_LINK_SUFFIX}" + link_name = f"{name}{PWL_LINK_SUFFIX}" lambda_var = model.add_variables( lower=0, upper=1, coords=lambda_coords, name=lambda_name, mask=lambda_mask @@ -930,11 +930,11 @@ def _add_incremental( extra = _var_coords_from(stacked_bp, exclude={dim, link_dim}) delta_name = f"{name}{PWL_DELTA_SUFFIX}" - fill_name = f"{name}{PWL_FILL_SUFFIX}" - link_name = f"{name}{PWL_X_LINK_SUFFIX}" - inc_binary_name = f"{name}{PWL_INC_BINARY_SUFFIX}" - inc_link_name = f"{name}{PWL_INC_LINK_SUFFIX}" - inc_order_name = f"{name}{PWL_INC_ORDER_SUFFIX}" + fill_order_name = f"{name}{PWL_FILL_ORDER_SUFFIX}" + link_name = f"{name}{PWL_LINK_SUFFIX}" + order_binary_name = f"{name}{PWL_ORDER_BINARY_SUFFIX}" + delta_bound_name = f"{name}{PWL_DELTA_BOUND_SUFFIX}" + binary_order_name = f"{name}{PWL_BINARY_ORDER_SUFFIX}" n_segments = stacked_bp.sizes[dim] - 1 seg_dim = f"{dim}_seg" @@ -963,17 +963,17 @@ def _add_incremental( model.add_constraints(delta_var <= active, name=active_bound_name) binary_var = model.add_variables( - binary=True, coords=delta_coords, name=inc_binary_name, mask=delta_mask + binary=True, coords=delta_coords, name=order_binary_name, mask=delta_mask ) - model.add_constraints(delta_var <= binary_var, name=inc_link_name) + model.add_constraints(delta_var <= binary_var, name=delta_bound_name) if n_segments >= 2: delta_lo = delta_var.isel({seg_dim: slice(None, -1)}, drop=True) delta_hi = delta_var.isel({seg_dim: slice(1, None)}, drop=True) - model.add_constraints(delta_hi <= delta_lo, name=fill_name) + model.add_constraints(delta_hi <= delta_lo, name=fill_order_name) binary_hi = binary_var.isel({seg_dim: slice(1, None)}, drop=True) - model.add_constraints(binary_hi <= delta_lo, name=inc_order_name) + model.add_constraints(binary_hi <= delta_lo, name=binary_order_name) bp0 = stacked_bp.isel({dim: 0}) bp0_term: DataArray | LinearExpression = bp0 @@ -1037,11 +1037,11 @@ def _add_disjunctive( lambda_mask = agg_mask binary_mask = agg_mask.any(dim=dim) - binary_name = f"{name}{PWL_BINARY_SUFFIX}" + binary_name = f"{name}{PWL_SEGMENT_BINARY_SUFFIX}" select_name = f"{name}{PWL_SELECT_SUFFIX}" lambda_name = f"{name}{PWL_LAMBDA_SUFFIX}" convex_name = f"{name}{PWL_CONVEX_SUFFIX}" - link_name = f"{name}{PWL_X_LINK_SUFFIX}" + link_name = f"{name}{PWL_LINK_SUFFIX}" binary_var = model.add_variables( binary=True, coords=binary_coords, name=binary_name, mask=binary_mask diff --git a/test/test_piecewise_constraints.py b/test/test_piecewise_constraints.py index ebfd3c6e..b837d1a5 100644 --- a/test/test_piecewise_constraints.py +++ b/test/test_piecewise_constraints.py @@ -21,16 +21,16 @@ BREAKPOINT_DIM, LP_SEG_DIM, PWL_ACTIVE_BOUND_SUFFIX, - PWL_BINARY_SUFFIX, + PWL_BINARY_ORDER_SUFFIX, PWL_CONVEX_SUFFIX, + PWL_DELTA_BOUND_SUFFIX, PWL_DELTA_SUFFIX, - PWL_FILL_SUFFIX, - PWL_INC_BINARY_SUFFIX, - PWL_INC_LINK_SUFFIX, - PWL_INC_ORDER_SUFFIX, + PWL_FILL_ORDER_SUFFIX, PWL_LAMBDA_SUFFIX, + PWL_LINK_SUFFIX, + PWL_ORDER_BINARY_SUFFIX, + PWL_SEGMENT_BINARY_SUFFIX, PWL_SELECT_SUFFIX, - PWL_X_LINK_SUFFIX, SEGMENT_DIM, ) from linopy.solver_capabilities import SolverFeature, get_available_solvers_with_feature @@ -289,7 +289,7 @@ def test_sos2(self) -> None: ) assert f"pwl0{PWL_LAMBDA_SUFFIX}" in m.variables assert f"pwl0{PWL_CONVEX_SUFFIX}" in m.constraints - assert f"pwl0{PWL_X_LINK_SUFFIX}" in m.constraints + assert f"pwl0{PWL_LINK_SUFFIX}" in m.constraints # N-var path uses a single stacked link constraint (no separate y_link) lam = m.variables[f"pwl0{PWL_LAMBDA_SUFFIX}"] assert lam.attrs.get("sos_type") == 2 @@ -430,7 +430,7 @@ def test_creates_delta_vars(self) -> None: assert f"pwl0{PWL_DELTA_SUFFIX}" in m.variables delta = m.variables[f"pwl0{PWL_DELTA_SUFFIX}"] assert delta.labels.sizes[LP_SEG_DIM] == 3 - assert f"pwl0{PWL_FILL_SUFFIX}" in m.constraints + assert f"pwl0{PWL_FILL_ORDER_SUFFIX}" in m.constraints assert f"pwl0{PWL_LAMBDA_SUFFIX}" not in m.variables def test_nonmonotonic_raises(self) -> None: @@ -467,7 +467,7 @@ def test_two_breakpoints_no_fill(self) -> None: ) delta = m.variables[f"pwl0{PWL_DELTA_SUFFIX}"] assert delta.labels.sizes[LP_SEG_DIM] == 1 - assert f"pwl0{PWL_X_LINK_SUFFIX}" in m.constraints + assert f"pwl0{PWL_LINK_SUFFIX}" in m.constraints # N-var path uses a single stacked link constraint (no separate y_link) def test_creates_binary_indicator_vars(self) -> None: @@ -479,10 +479,10 @@ def test_creates_binary_indicator_vars(self) -> None: (y, [5, 10, 20, 80]), method="incremental", ) - assert f"pwl0{PWL_INC_BINARY_SUFFIX}" in m.variables - binary = m.variables[f"pwl0{PWL_INC_BINARY_SUFFIX}"] + assert f"pwl0{PWL_ORDER_BINARY_SUFFIX}" in m.variables + binary = m.variables[f"pwl0{PWL_ORDER_BINARY_SUFFIX}"] assert binary.labels.sizes[LP_SEG_DIM] == 3 - assert f"pwl0{PWL_INC_LINK_SUFFIX}" in m.constraints + assert f"pwl0{PWL_DELTA_BOUND_SUFFIX}" in m.constraints def test_creates_order_constraints(self) -> None: m = Model() @@ -493,7 +493,7 @@ def test_creates_order_constraints(self) -> None: (y, [5, 10, 20, 80]), method="incremental", ) - assert f"pwl0{PWL_INC_ORDER_SUFFIX}" in m.constraints + assert f"pwl0{PWL_BINARY_ORDER_SUFFIX}" in m.constraints def test_two_breakpoints_no_order_constraint(self) -> None: """With only one segment, there's no order constraint needed.""" @@ -505,9 +505,9 @@ def test_two_breakpoints_no_order_constraint(self) -> None: (y, [5, 80]), method="incremental", ) - assert f"pwl0{PWL_INC_BINARY_SUFFIX}" in m.variables - assert f"pwl0{PWL_INC_LINK_SUFFIX}" in m.constraints - assert f"pwl0{PWL_INC_ORDER_SUFFIX}" not in m.constraints + assert f"pwl0{PWL_ORDER_BINARY_SUFFIX}" in m.variables + assert f"pwl0{PWL_DELTA_BOUND_SUFFIX}" in m.constraints + assert f"pwl0{PWL_BINARY_ORDER_SUFFIX}" not in m.constraints def test_decreasing_monotonic(self) -> None: m = Model() @@ -535,7 +535,7 @@ def test_equality_creates_binary(self) -> None: (x, segments([[0, 10], [50, 100]])), (y, segments([[0, 5], [20, 80]])), ) - assert f"pwl0{PWL_BINARY_SUFFIX}" in m.variables + assert f"pwl0{PWL_SEGMENT_BINARY_SUFFIX}" in m.variables assert f"pwl0{PWL_SELECT_SUFFIX}" in m.constraints assert f"pwl0{PWL_LAMBDA_SUFFIX}" in m.variables assert f"pwl0{PWL_CONVEX_SUFFIX}" in m.constraints @@ -574,7 +574,7 @@ def test_multi_dimensional(self) -> None: ), ), ) - binary = m.variables[f"pwl0{PWL_BINARY_SUFFIX}"] + binary = m.variables[f"pwl0{PWL_SEGMENT_BINARY_SUFFIX}"] lam = m.variables[f"pwl0{PWL_LAMBDA_SUFFIX}"] assert "generator" in binary.dims assert "generator" in lam.dims @@ -590,10 +590,10 @@ def test_three_variables(self) -> None: (y, segments([[0, 5], [20, 80]])), (z, segments([[0, 3], [15, 60]])), ) - assert f"pwl0{PWL_BINARY_SUFFIX}" in m.variables + assert f"pwl0{PWL_SEGMENT_BINARY_SUFFIX}" in m.variables assert f"pwl0{PWL_LAMBDA_SUFFIX}" in m.variables # Single link constraint with _pwl_var dimension - link = m.constraints[f"pwl0{PWL_X_LINK_SUFFIX}"] + link = m.constraints[f"pwl0{PWL_LINK_SUFFIX}"] assert "_pwl_var" in [str(d) for d in link.dims] @@ -663,7 +663,7 @@ def test_custom_name(self) -> None: name="my_pwl", ) assert f"my_pwl{PWL_DELTA_SUFFIX}" in m.variables - assert f"my_pwl{PWL_X_LINK_SUFFIX}" in m.constraints + assert f"my_pwl{PWL_LINK_SUFFIX}" in m.constraints # N-var path uses a single stacked link constraint (no separate y_link) @@ -1148,7 +1148,7 @@ def test_sos2_creates_lambda_and_link(self) -> None: ) assert f"pwl0{PWL_LAMBDA_SUFFIX}" in m.variables assert f"pwl0{PWL_CONVEX_SUFFIX}" in m.constraints - assert f"pwl0{PWL_X_LINK_SUFFIX}" in m.constraints + assert f"pwl0{PWL_LINK_SUFFIX}" in m.constraints def test_incremental_creates_delta(self) -> None: m = Model() @@ -1160,7 +1160,7 @@ def test_incremental_creates_delta(self) -> None: method="incremental", ) assert f"pwl0{PWL_DELTA_SUFFIX}" in m.variables - assert f"pwl0{PWL_X_LINK_SUFFIX}" in m.constraints + assert f"pwl0{PWL_LINK_SUFFIX}" in m.constraints def test_auto_selects_method(self) -> None: m = Model() @@ -1193,9 +1193,9 @@ def test_three_variables(self) -> None: method="sos2", ) assert f"pwl0{PWL_LAMBDA_SUFFIX}" in m.variables - assert f"pwl0{PWL_X_LINK_SUFFIX}" in m.constraints + assert f"pwl0{PWL_LINK_SUFFIX}" in m.constraints # link constraint should have _pwl_var dimension - link = m.constraints[f"pwl0{PWL_X_LINK_SUFFIX}"] + link = m.constraints[f"pwl0{PWL_LINK_SUFFIX}"] assert "_pwl_var" in link.labels.dims def test_custom_name(self) -> None: @@ -1307,9 +1307,9 @@ def test_disjunctive_three_pairs(self) -> None: (y, seg), (z, seg), ) - assert f"pwl0{PWL_BINARY_SUFFIX}" in m.variables + assert f"pwl0{PWL_SEGMENT_BINARY_SUFFIX}" in m.variables assert f"pwl0{PWL_LAMBDA_SUFFIX}" in m.variables - assert f"pwl0{PWL_X_LINK_SUFFIX}" in m.constraints + assert f"pwl0{PWL_LINK_SUFFIX}" in m.constraints def test_disjunctive_interior_nan_raises(self) -> None: """Disjunctive with interior NaN raises ValueError.""" From d4fdef25c5df0ac34ffce90b029751badaea12ef Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:46:25 +0000 Subject: [PATCH 16/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/piecewise-linear-constraints.ipynb | 664 +++++++++++++++----- linopy/io.py | 10 +- 2 files changed, 507 insertions(+), 167 deletions(-) diff --git a/examples/piecewise-linear-constraints.ipynb b/examples/piecewise-linear-constraints.ipynb index a34c63e5..71d10a11 100644 --- a/examples/piecewise-linear-constraints.ipynb +++ b/examples/piecewise-linear-constraints.ipynb @@ -7,28 +7,111 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:20.809300Z", + "start_time": "2026-04-01T17:50:20.202138Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.167007Z", "iopub.status.busy": "2026-03-06T11:51:29.166576Z", "iopub.status.idle": "2026-03-06T11:51:29.185103Z", "shell.execute_reply": "2026-03-06T11:51:29.184712Z", "shell.execute_reply.started": "2026-03-06T11:51:29.166974Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:20.809300Z", - "start_time": "2026-04-01T17:50:20.202138Z" } }, - "source": "import matplotlib.pyplot as plt\nimport pandas as pd\nimport xarray as xr\n\nimport linopy\n\ntime = pd.Index([1, 2, 3], name=\"time\")\n\n\ndef plot_pwl_results(model, breakpoints, demand, *, x_name=\"power\", color=\"C0\"):\n \"\"\"\n Plot PWL curves with operating points and dispatch vs demand.\n\n Parameters\n ----------\n model : linopy.Model\n Solved model.\n breakpoints : DataArray\n Breakpoints array. For 2-variable cases pass a DataArray with a\n \"var\" dimension containing two coordinates (x and y variable names).\n Alternatively pass two separate arrays and they will be stacked.\n demand : DataArray\n Demand time series (plotted as step line).\n x_name : str\n Name of the x-axis variable (used for the curve plot).\n color : str\n Base color for the plot.\n \"\"\"\n sol = model.solution\n var_names = list(breakpoints.coords[\"var\"].values)\n bp_x = breakpoints.sel(var=x_name).values\n\n fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3.5))\n\n # Left: breakpoint curves with operating points\n colors = [f\"C{i}\" for i in range(len(var_names))]\n for var, c in zip(var_names, colors):\n if var == x_name:\n continue\n bp_y = breakpoints.sel(var=var).values\n ax1.plot(bp_x, bp_y, \"o-\", color=c, label=f\"{var} (breakpoints)\")\n for t in time:\n ax1.plot(\n float(sol[x_name].sel(time=t)),\n float(sol[var].sel(time=t)),\n \"D\",\n color=c,\n ms=10,\n )\n ax1.set(xlabel=x_name.title(), title=\"PWL curve\")\n ax1.legend()\n\n # Right: dispatch vs demand\n x = list(range(len(time)))\n power_vals = sol[x_name].values\n ax2.bar(x, power_vals, color=color, label=x_name.title())\n if \"backup\" in sol:\n ax2.bar(\n x,\n sol[\"backup\"].values,\n bottom=power_vals,\n color=\"C3\",\n alpha=0.5,\n label=\"Backup\",\n )\n ax2.step(\n [v - 0.5 for v in x] + [x[-1] + 0.5],\n list(demand.values) + [demand.values[-1]],\n where=\"post\",\n color=\"black\",\n lw=2,\n label=\"Demand\",\n )\n ax2.set(\n xlabel=\"Time\",\n ylabel=\"MW\",\n title=\"Dispatch\",\n xticks=x,\n xticklabels=time.values,\n )\n ax2.legend()\n plt.tight_layout()", "outputs": [], - "execution_count": null + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import xarray as xr\n", + "\n", + "import linopy\n", + "\n", + "time = pd.Index([1, 2, 3], name=\"time\")\n", + "\n", + "\n", + "def plot_pwl_results(model, breakpoints, demand, *, x_name=\"power\", color=\"C0\"):\n", + " \"\"\"\n", + " Plot PWL curves with operating points and dispatch vs demand.\n", + "\n", + " Parameters\n", + " ----------\n", + " model : linopy.Model\n", + " Solved model.\n", + " breakpoints : DataArray\n", + " Breakpoints array. For 2-variable cases pass a DataArray with a\n", + " \"var\" dimension containing two coordinates (x and y variable names).\n", + " Alternatively pass two separate arrays and they will be stacked.\n", + " demand : DataArray\n", + " Demand time series (plotted as step line).\n", + " x_name : str\n", + " Name of the x-axis variable (used for the curve plot).\n", + " color : str\n", + " Base color for the plot.\n", + " \"\"\"\n", + " sol = model.solution\n", + " var_names = list(breakpoints.coords[\"var\"].values)\n", + " bp_x = breakpoints.sel(var=x_name).values\n", + "\n", + " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3.5))\n", + "\n", + " # Left: breakpoint curves with operating points\n", + " colors = [f\"C{i}\" for i in range(len(var_names))]\n", + " for var, c in zip(var_names, colors):\n", + " if var == x_name:\n", + " continue\n", + " bp_y = breakpoints.sel(var=var).values\n", + " ax1.plot(bp_x, bp_y, \"o-\", color=c, label=f\"{var} (breakpoints)\")\n", + " for t in time:\n", + " ax1.plot(\n", + " float(sol[x_name].sel(time=t)),\n", + " float(sol[var].sel(time=t)),\n", + " \"D\",\n", + " color=c,\n", + " ms=10,\n", + " )\n", + " ax1.set(xlabel=x_name.title(), title=\"PWL curve\")\n", + " ax1.legend()\n", + "\n", + " # Right: dispatch vs demand\n", + " x = list(range(len(time)))\n", + " power_vals = sol[x_name].values\n", + " ax2.bar(x, power_vals, color=color, label=x_name.title())\n", + " if \"backup\" in sol:\n", + " ax2.bar(\n", + " x,\n", + " sol[\"backup\"].values,\n", + " bottom=power_vals,\n", + " color=\"C3\",\n", + " alpha=0.5,\n", + " label=\"Backup\",\n", + " )\n", + " ax2.step(\n", + " [v - 0.5 for v in x] + [x[-1] + 0.5],\n", + " list(demand.values) + [demand.values[-1]],\n", + " where=\"post\",\n", + " color=\"black\",\n", + " lw=2,\n", + " label=\"Demand\",\n", + " )\n", + " ax2.set(\n", + " xlabel=\"Time\",\n", + " ylabel=\"MW\",\n", + " title=\"Dispatch\",\n", + " xticks=x,\n", + " xticklabels=time.values,\n", + " )\n", + " ax2.legend()\n", + " plt.tight_layout()" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 1. SOS2 formulation \u2014 Gas turbine\n", + "## 1. SOS2 formulation — Gas turbine\n", "\n", "The gas turbine has a **convex** heat rate: efficient at moderate load,\n", "increasingly fuel-hungry at high output. We use the **SOS2** formulation\n", @@ -37,225 +120,284 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:20.848260Z", + "start_time": "2026-04-01T17:50:20.813939Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.185693Z", "iopub.status.busy": "2026-03-06T11:51:29.185601Z", "iopub.status.idle": "2026-03-06T11:51:29.199760Z", "shell.execute_reply": "2026-03-06T11:51:29.199416Z", "shell.execute_reply.started": "2026-03-06T11:51:29.185683Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:20.848260Z", - "start_time": "2026-04-01T17:50:20.813939Z" } }, - "source": "x_pts1 = linopy.breakpoints([0, 30, 60, 100])\ny_pts1 = linopy.breakpoints([0, 36, 84, 170])\nprint(\"x_pts:\", x_pts1.values)\nprint(\"y_pts:\", y_pts1.values)", "outputs": [], - "execution_count": null + "source": [ + "x_pts1 = linopy.breakpoints([0, 30, 60, 100])\n", + "y_pts1 = linopy.breakpoints([0, 36, 84, 170])\n", + "print(\"x_pts:\", x_pts1.values)\n", + "print(\"y_pts:\", y_pts1.values)" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:20.884905Z", + "start_time": "2026-04-01T17:50:20.851433Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.200170Z", "iopub.status.busy": "2026-03-06T11:51:29.200087Z", "iopub.status.idle": "2026-03-06T11:51:29.266847Z", "shell.execute_reply": "2026-03-06T11:51:29.266379Z", "shell.execute_reply.started": "2026-03-06T11:51:29.200161Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:20.884905Z", - "start_time": "2026-04-01T17:50:20.851433Z" } }, - "source": "m1 = linopy.Model()\n\npower = m1.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m1.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand1 = xr.DataArray([50, 80, 30], coords=[time])\nm1.add_constraints(power >= demand1, name=\"demand\")\nm1.add_objective(fuel.sum())\n\n# breakpoints are auto-broadcast to match the time dimension\nm1.add_piecewise_formulation(\n (power, x_pts1),\n (fuel, y_pts1),\n name=\"pwl\",\n method=\"sos2\",\n)", "outputs": [], - "execution_count": null + "source": [ + "m1 = linopy.Model()\n", + "\n", + "power = m1.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\n", + "fuel = m1.add_variables(name=\"fuel\", lower=0, coords=[time])\n", + "\n", + "demand1 = xr.DataArray([50, 80, 30], coords=[time])\n", + "m1.add_constraints(power >= demand1, name=\"demand\")\n", + "m1.add_objective(fuel.sum())\n", + "\n", + "# breakpoints are auto-broadcast to match the time dimension\n", + "m1.add_piecewise_formulation(\n", + " (power, x_pts1),\n", + " (fuel, y_pts1),\n", + " name=\"pwl\",\n", + " method=\"sos2\",\n", + ")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:20.889691Z", "start_time": "2026-04-01T17:50:20.888003Z" } }, - "source": "print(m1)", "outputs": [], - "execution_count": null + "source": [ + "print(m1)" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:20.941957Z", + "start_time": "2026-04-01T17:50:20.900785Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.267522Z", "iopub.status.busy": "2026-03-06T11:51:29.267433Z", "iopub.status.idle": "2026-03-06T11:51:29.326758Z", "shell.execute_reply": "2026-03-06T11:51:29.326518Z", "shell.execute_reply.started": "2026-03-06T11:51:29.267514Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:20.941957Z", - "start_time": "2026-04-01T17:50:20.900785Z" } }, - "source": "m1.solve(reformulate_sos=\"auto\")", "outputs": [], - "execution_count": null + "source": [ + "m1.solve(reformulate_sos=\"auto\")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:20.957062Z", + "start_time": "2026-04-01T17:50:20.946704Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.327139Z", "iopub.status.busy": "2026-03-06T11:51:29.327044Z", "iopub.status.idle": "2026-03-06T11:51:29.339334Z", "shell.execute_reply": "2026-03-06T11:51:29.338974Z", "shell.execute_reply.started": "2026-03-06T11:51:29.327130Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:20.957062Z", - "start_time": "2026-04-01T17:50:20.946704Z" } }, - "source": "m1.solution[[\"power\", \"fuel\"]].to_pandas()", "outputs": [], - "execution_count": null + "source": [ + "m1.solution[[\"power\", \"fuel\"]].to_pandas()" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.068805Z", + "start_time": "2026-04-01T17:50:20.970458Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.339689Z", "iopub.status.busy": "2026-03-06T11:51:29.339608Z", "iopub.status.idle": "2026-03-06T11:51:29.489677Z", "shell.execute_reply": "2026-03-06T11:51:29.489280Z", "shell.execute_reply.started": "2026-03-06T11:51:29.339680Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.068805Z", - "start_time": "2026-04-01T17:50:20.970458Z" } }, - "source": "bp1 = linopy.breakpoints({\"power\": x_pts1.values, \"fuel\": y_pts1.values}, dim=\"var\")\nplot_pwl_results(m1, bp1, demand1, color=\"C0\")", "outputs": [], - "execution_count": null + "source": [ + "bp1 = linopy.breakpoints({\"power\": x_pts1.values, \"fuel\": y_pts1.values}, dim=\"var\")\n", + "plot_pwl_results(m1, bp1, demand1, color=\"C0\")" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 2. Incremental formulation \u2014 Coal plant\n", + "## 2. Incremental formulation — Coal plant\n", "\n", "The coal plant has a **monotonically increasing** heat rate. Since all\n", "breakpoints are strictly monotonic, we can use the **incremental**\n", - "formulation \u2014 which uses fill-fraction variables with binary indicators." + "formulation — which uses fill-fraction variables with binary indicators." ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.074995Z", + "start_time": "2026-04-01T17:50:21.072706Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.490092Z", "iopub.status.busy": "2026-03-06T11:51:29.490011Z", "iopub.status.idle": "2026-03-06T11:51:29.500894Z", "shell.execute_reply": "2026-03-06T11:51:29.500558Z", "shell.execute_reply.started": "2026-03-06T11:51:29.490084Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.074995Z", - "start_time": "2026-04-01T17:50:21.072706Z" } }, - "source": "x_pts2 = linopy.breakpoints([0, 50, 100, 150])\ny_pts2 = linopy.breakpoints([0, 55, 130, 225])\nprint(\"x_pts:\", x_pts2.values)\nprint(\"y_pts:\", y_pts2.values)", "outputs": [], - "execution_count": null + "source": [ + "x_pts2 = linopy.breakpoints([0, 50, 100, 150])\n", + "y_pts2 = linopy.breakpoints([0, 55, 130, 225])\n", + "print(\"x_pts:\", x_pts2.values)\n", + "print(\"y_pts:\", y_pts2.values)" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.135253Z", + "start_time": "2026-04-01T17:50:21.083396Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.501317Z", "iopub.status.busy": "2026-03-06T11:51:29.501216Z", "iopub.status.idle": "2026-03-06T11:51:29.604024Z", "shell.execute_reply": "2026-03-06T11:51:29.603543Z", "shell.execute_reply.started": "2026-03-06T11:51:29.501307Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.135253Z", - "start_time": "2026-04-01T17:50:21.083396Z" } }, - "source": "m2 = linopy.Model()\n\npower = m2.add_variables(name=\"power\", lower=0, upper=150, coords=[time])\nfuel = m2.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand2 = xr.DataArray([80, 120, 50], coords=[time])\nm2.add_constraints(power >= demand2, name=\"demand\")\nm2.add_objective(fuel.sum())\n\nm2.add_piecewise_formulation(\n (power, x_pts2),\n (fuel, y_pts2),\n name=\"pwl\",\n method=\"incremental\",\n)", "outputs": [], - "execution_count": null + "source": [ + "m2 = linopy.Model()\n", + "\n", + "power = m2.add_variables(name=\"power\", lower=0, upper=150, coords=[time])\n", + "fuel = m2.add_variables(name=\"fuel\", lower=0, coords=[time])\n", + "\n", + "demand2 = xr.DataArray([80, 120, 50], coords=[time])\n", + "m2.add_constraints(power >= demand2, name=\"demand\")\n", + "m2.add_objective(fuel.sum())\n", + "\n", + "m2.add_piecewise_formulation(\n", + " (power, x_pts2),\n", + " (fuel, y_pts2),\n", + " name=\"pwl\",\n", + " method=\"incremental\",\n", + ")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.185956Z", + "start_time": "2026-04-01T17:50:21.147474Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.604434Z", "iopub.status.busy": "2026-03-06T11:51:29.604359Z", "iopub.status.idle": "2026-03-06T11:51:29.680947Z", "shell.execute_reply": "2026-03-06T11:51:29.680667Z", "shell.execute_reply.started": "2026-03-06T11:51:29.604427Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.185956Z", - "start_time": "2026-04-01T17:50:21.147474Z" } }, - "source": "m2.solve(reformulate_sos=\"auto\");", "outputs": [], - "execution_count": null + "source": [ + "m2.solve(reformulate_sos=\"auto\");" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.205500Z", + "start_time": "2026-04-01T17:50:21.200814Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.681833Z", "iopub.status.busy": "2026-03-06T11:51:29.681725Z", "iopub.status.idle": "2026-03-06T11:51:29.698558Z", "shell.execute_reply": "2026-03-06T11:51:29.698011Z", "shell.execute_reply.started": "2026-03-06T11:51:29.681822Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.205500Z", - "start_time": "2026-04-01T17:50:21.200814Z" } }, - "source": "m2.solution[[\"power\", \"fuel\"]].to_pandas()", "outputs": [], - "execution_count": null + "source": [ + "m2.solution[[\"power\", \"fuel\"]].to_pandas()" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.289611Z", + "start_time": "2026-04-01T17:50:21.213993Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.699350Z", "iopub.status.busy": "2026-03-06T11:51:29.699116Z", "iopub.status.idle": "2026-03-06T11:51:29.852000Z", "shell.execute_reply": "2026-03-06T11:51:29.851741Z", "shell.execute_reply.started": "2026-03-06T11:51:29.699334Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.289611Z", - "start_time": "2026-04-01T17:50:21.213993Z" } }, - "source": "bp2 = linopy.breakpoints({\"power\": x_pts2.values, \"fuel\": y_pts2.values}, dim=\"var\")\nplot_pwl_results(m2, bp2, demand2, color=\"C1\")", "outputs": [], - "execution_count": null + "source": [ + "bp2 = linopy.breakpoints({\"power\": x_pts2.values, \"fuel\": y_pts2.values}, dim=\"var\")\n", + "plot_pwl_results(m2, bp2, demand2, color=\"C1\")" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 3. Disjunctive formulation \u2014 Diesel generator\n", + "## 3. Disjunctive formulation — Diesel generator\n", "\n", "The diesel generator has a **forbidden operating zone**: it must either\n", - "be off (0 MW) or run between 50\u201380 MW. Because of this gap, we use\n", + "be off (0 MW) or run between 50–80 MW. Because of this gap, we use\n", "**disjunctive** piecewise constraints via `linopy.segments()` and add a\n", "high-cost **backup** source to cover demand when the diesel is off or\n", "at its maximum.\n", @@ -266,79 +408,106 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.296416Z", + "start_time": "2026-04-01T17:50:21.293422Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.852397Z", "iopub.status.busy": "2026-03-06T11:51:29.852305Z", "iopub.status.idle": "2026-03-06T11:51:29.866500Z", "shell.execute_reply": "2026-03-06T11:51:29.866141Z", "shell.execute_reply.started": "2026-03-06T11:51:29.852387Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.296416Z", - "start_time": "2026-04-01T17:50:21.293422Z" } }, - "source": "# x-breakpoints define where each segment lives on the power axis\n# y-breakpoints define the corresponding cost values\nx_seg = linopy.segments([(0, 0), (50, 80)])\ny_seg = linopy.segments([(0, 0), (125, 200)])\nprint(\"x segments:\\n\", x_seg.to_pandas())\nprint(\"y segments:\\n\", y_seg.to_pandas())", "outputs": [], - "execution_count": null + "source": [ + "# x-breakpoints define where each segment lives on the power axis\n", + "# y-breakpoints define the corresponding cost values\n", + "x_seg = linopy.segments([(0, 0), (50, 80)])\n", + "y_seg = linopy.segments([(0, 0), (125, 200)])\n", + "print(\"x segments:\\n\", x_seg.to_pandas())\n", + "print(\"y segments:\\n\", y_seg.to_pandas())" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.351922Z", + "start_time": "2026-04-01T17:50:21.304030Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.866940Z", "iopub.status.busy": "2026-03-06T11:51:29.866839Z", "iopub.status.idle": "2026-03-06T11:51:29.955272Z", "shell.execute_reply": "2026-03-06T11:51:29.954810Z", "shell.execute_reply.started": "2026-03-06T11:51:29.866931Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.351922Z", - "start_time": "2026-04-01T17:50:21.304030Z" } }, - "source": "m3 = linopy.Model()\n\npower = m3.add_variables(name=\"power\", lower=0, upper=80, coords=[time])\ncost = m3.add_variables(name=\"cost\", lower=0, coords=[time])\nbackup = m3.add_variables(name=\"backup\", lower=0, coords=[time])\n\ndemand3 = xr.DataArray([10, 70, 90], coords=[time])\nm3.add_constraints(power + backup >= demand3, name=\"demand\")\nm3.add_objective((cost + 10 * backup).sum())\n\nm3.add_piecewise_formulation(\n (power, x_seg),\n (cost, y_seg),\n name=\"pwl\",\n)", "outputs": [], - "execution_count": null + "source": [ + "m3 = linopy.Model()\n", + "\n", + "power = m3.add_variables(name=\"power\", lower=0, upper=80, coords=[time])\n", + "cost = m3.add_variables(name=\"cost\", lower=0, coords=[time])\n", + "backup = m3.add_variables(name=\"backup\", lower=0, coords=[time])\n", + "\n", + "demand3 = xr.DataArray([10, 70, 90], coords=[time])\n", + "m3.add_constraints(power + backup >= demand3, name=\"demand\")\n", + "m3.add_objective((cost + 10 * backup).sum())\n", + "\n", + "m3.add_piecewise_formulation(\n", + " (power, x_seg),\n", + " (cost, y_seg),\n", + " name=\"pwl\",\n", + ")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.398282Z", + "start_time": "2026-04-01T17:50:21.355402Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:29.955750Z", "iopub.status.busy": "2026-03-06T11:51:29.955667Z", "iopub.status.idle": "2026-03-06T11:51:30.027311Z", "shell.execute_reply": "2026-03-06T11:51:30.026945Z", "shell.execute_reply.started": "2026-03-06T11:51:29.955741Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.398282Z", - "start_time": "2026-04-01T17:50:21.355402Z" } }, - "source": "m3.solve(reformulate_sos=\"auto\")", "outputs": [], - "execution_count": null + "source": [ + "m3.solve(reformulate_sos=\"auto\")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.413359Z", + "start_time": "2026-04-01T17:50:21.408184Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:30.028114Z", "iopub.status.busy": "2026-03-06T11:51:30.027864Z", "iopub.status.idle": "2026-03-06T11:51:30.043138Z", "shell.execute_reply": "2026-03-06T11:51:30.042813Z", "shell.execute_reply.started": "2026-03-06T11:51:30.028095Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.413359Z", - "start_time": "2026-04-01T17:50:21.408184Z" } }, - "source": "m3.solution[[\"power\", \"cost\", \"backup\"]].to_pandas()", "outputs": [], - "execution_count": null + "source": [ + "m3.solution[[\"power\", \"cost\", \"backup\"]].to_pandas()" + ] }, { "cell_type": "markdown", @@ -364,7 +533,7 @@ "e", "s", " ", - "\u2014", + "—", " ", "C", "o", @@ -589,7 +758,7 @@ "t", "s", " ", - "\u2014", + "—", " ", "n", "o", @@ -728,97 +897,124 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.449956Z", + "start_time": "2026-04-01T17:50:21.433179Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:30.043492Z", "iopub.status.busy": "2026-03-06T11:51:30.043410Z", "iopub.status.idle": "2026-03-06T11:51:30.113382Z", "shell.execute_reply": "2026-03-06T11:51:30.112320Z", "shell.execute_reply.started": "2026-03-06T11:51:30.043484Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.449956Z", - "start_time": "2026-04-01T17:50:21.433179Z" } }, - "source": "x_pts4 = linopy.breakpoints([0, 40, 80, 120])\n# Concave curve: decreasing marginal fuel per MW\ny_pts4 = linopy.breakpoints([0, 50, 90, 120])\n\nm4 = linopy.Model()\n\npower = m4.add_variables(name=\"power\", lower=0, upper=120, coords=[time])\nfuel = m4.add_variables(name=\"fuel\", lower=0, coords=[time])\n\ndemand4 = xr.DataArray([30, 80, 100], coords=[time])\nm4.add_constraints(power == demand4, name=\"demand\")\n# Maximize fuel (to push against the upper bound)\nm4.add_objective(-fuel.sum())\n\n# tangent_lines returns one LinearExpression per segment \u2014 pure LP, no aux variables\nlinopy.tangent_lines(power, x_pts4, y_pts4)", "outputs": [], - "execution_count": null + "source": [ + "x_pts4 = linopy.breakpoints([0, 40, 80, 120])\n", + "# Concave curve: decreasing marginal fuel per MW\n", + "y_pts4 = linopy.breakpoints([0, 50, 90, 120])\n", + "\n", + "m4 = linopy.Model()\n", + "\n", + "power = m4.add_variables(name=\"power\", lower=0, upper=120, coords=[time])\n", + "fuel = m4.add_variables(name=\"fuel\", lower=0, coords=[time])\n", + "\n", + "demand4 = xr.DataArray([30, 80, 100], coords=[time])\n", + "m4.add_constraints(power == demand4, name=\"demand\")\n", + "# Maximize fuel (to push against the upper bound)\n", + "m4.add_objective(-fuel.sum())\n", + "\n", + "# tangent_lines returns one LinearExpression per segment — pure LP, no aux variables\n", + "linopy.tangent_lines(power, x_pts4, y_pts4)" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.470263Z", "start_time": "2026-04-01T17:50:21.454181Z" } }, - "source": "t = linopy.tangent_lines(power, x_pts4, y_pts4)\nm4.add_constraints(fuel <= t, name=\"pwl\")", "outputs": [], - "execution_count": null + "source": [ + "t = linopy.tangent_lines(power, x_pts4, y_pts4)\n", + "m4.add_constraints(fuel <= t, name=\"pwl\")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.498563Z", + "start_time": "2026-04-01T17:50:21.476327Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:30.113818Z", "iopub.status.busy": "2026-03-06T11:51:30.113727Z", "iopub.status.idle": "2026-03-06T11:51:30.171329Z", "shell.execute_reply": "2026-03-06T11:51:30.170942Z", "shell.execute_reply.started": "2026-03-06T11:51:30.113810Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.498563Z", - "start_time": "2026-04-01T17:50:21.476327Z" } }, - "source": "m4.solve(reformulate_sos=\"auto\")", "outputs": [], - "execution_count": null + "source": [ + "m4.solve(reformulate_sos=\"auto\")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.512519Z", + "start_time": "2026-04-01T17:50:21.508408Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:30.172009Z", "iopub.status.busy": "2026-03-06T11:51:30.171791Z", "iopub.status.idle": "2026-03-06T11:51:30.191956Z", "shell.execute_reply": "2026-03-06T11:51:30.191556Z", "shell.execute_reply.started": "2026-03-06T11:51:30.171993Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.512519Z", - "start_time": "2026-04-01T17:50:21.508408Z" } }, - "source": "m4.solution[[\"power\", \"fuel\"]].to_pandas()", "outputs": [], - "execution_count": null + "source": [ + "m4.solution[[\"power\", \"fuel\"]].to_pandas()" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.608738Z", + "start_time": "2026-04-01T17:50:21.525541Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:30.192604Z", "iopub.status.busy": "2026-03-06T11:51:30.192376Z", "iopub.status.idle": "2026-03-06T11:51:30.345074Z", "shell.execute_reply": "2026-03-06T11:51:30.344642Z", "shell.execute_reply.started": "2026-03-06T11:51:30.192590Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.608738Z", - "start_time": "2026-04-01T17:50:21.525541Z" } }, - "source": "bp4 = linopy.breakpoints({\"power\": x_pts4.values, \"fuel\": y_pts4.values}, dim=\"var\")\nplot_pwl_results(m4, bp4, demand4, color=\"C4\")", "outputs": [], - "execution_count": null + "source": [ + "bp4 = linopy.breakpoints({\"power\": x_pts4.values, \"fuel\": y_pts4.values}, dim=\"var\")\n", + "plot_pwl_results(m4, bp4, demand4, color=\"C4\")" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 5. Slopes mode \u2014 Building breakpoints from slopes\n", + "## 5. Slopes mode — Building breakpoints from slopes\n", "\n", "Sometimes you know the **slope** of each segment rather than the y-values\n", "at each breakpoint. The `breakpoints()` factory can compute y-values from\n", @@ -827,22 +1023,27 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2026-04-01T17:50:21.614899Z", + "start_time": "2026-04-01T17:50:21.612589Z" + }, "execution": { "iopub.execute_input": "2026-03-06T11:51:30.345523Z", "iopub.status.busy": "2026-03-06T11:51:30.345404Z", "iopub.status.idle": "2026-03-06T11:51:30.357312Z", "shell.execute_reply": "2026-03-06T11:51:30.356954Z", "shell.execute_reply.started": "2026-03-06T11:51:30.345513Z" - }, - "ExecuteTime": { - "end_time": "2026-04-01T17:50:21.614899Z", - "start_time": "2026-04-01T17:50:21.612589Z" } }, - "source": "# Marginal costs: $1.1/MW for 0-50, $1.5/MW for 50-100, $1.9/MW for 100-150\nx_pts5 = linopy.breakpoints([0, 50, 100, 150])\ny_pts5 = linopy.breakpoints(slopes=[1.1, 1.5, 1.9], x_points=[0, 50, 100, 150], y0=0)\nprint(\"y breakpoints from slopes:\", y_pts5.values)", "outputs": [], - "execution_count": null + "source": [ + "# Marginal costs: $1.1/MW for 0-50, $1.5/MW for 50-100, $1.9/MW for 100-150\n", + "x_pts5 = linopy.breakpoints([0, 50, 100, 150])\n", + "y_pts5 = linopy.breakpoints(slopes=[1.1, 1.5, 1.9], x_points=[0, 50, 100, 150], y0=0)\n", + "print(\"y breakpoints from slopes:\", y_pts5.values)" + ] }, { "cell_type": "markdown", @@ -1759,63 +1960,105 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.626940Z", "start_time": "2026-04-01T17:50:21.624504Z" } }, - "source": "# Unit parameters: operates between 30-100 MW when on\np_min, p_max = 30, 100\nfuel_min, fuel_max = 40, 170\nstartup_cost = 50\n\nx_pts6 = linopy.breakpoints([p_min, 60, p_max])\ny_pts6 = linopy.breakpoints([fuel_min, 90, fuel_max])\nprint(\"Power breakpoints:\", x_pts6.values)\nprint(\"Fuel breakpoints: \", y_pts6.values)", "outputs": [], - "execution_count": null + "source": [ + "# Unit parameters: operates between 30-100 MW when on\n", + "p_min, p_max = 30, 100\n", + "fuel_min, fuel_max = 40, 170\n", + "startup_cost = 50\n", + "\n", + "x_pts6 = linopy.breakpoints([p_min, 60, p_max])\n", + "y_pts6 = linopy.breakpoints([fuel_min, 90, fuel_max])\n", + "print(\"Power breakpoints:\", x_pts6.values)\n", + "print(\"Fuel breakpoints: \", y_pts6.values)" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.707770Z", "start_time": "2026-04-01T17:50:21.635963Z" } }, - "source": "m6 = linopy.Model()\n\npower = m6.add_variables(name=\"power\", lower=0, upper=p_max, coords=[time])\nfuel = m6.add_variables(name=\"fuel\", lower=0, coords=[time])\ncommit = m6.add_variables(name=\"commit\", binary=True, coords=[time])\n\n# Demand: low at t=1 (cheaper to stay off), high at t=2,3\ndemand6 = xr.DataArray([15, 70, 50], coords=[time])\nbackup = m6.add_variables(name=\"backup\", lower=0, coords=[time])\nm6.add_constraints(power + backup >= demand6, name=\"demand\")\n\n# Objective: fuel + startup cost + backup at /MW\nm6.add_objective((fuel + startup_cost * commit + 5 * backup).sum())\n\n# The active parameter gates the PWL with the commitment binary:\n# - commit=1: power in [30, 100], fuel = f(power)\n# - commit=0: power = 0, fuel = 0\nm6.add_piecewise_formulation(\n (power, x_pts6),\n (fuel, y_pts6),\n active=commit,\n name=\"pwl\",\n method=\"incremental\",\n)", "outputs": [], - "execution_count": null + "source": [ + "m6 = linopy.Model()\n", + "\n", + "power = m6.add_variables(name=\"power\", lower=0, upper=p_max, coords=[time])\n", + "fuel = m6.add_variables(name=\"fuel\", lower=0, coords=[time])\n", + "commit = m6.add_variables(name=\"commit\", binary=True, coords=[time])\n", + "\n", + "# Demand: low at t=1 (cheaper to stay off), high at t=2,3\n", + "demand6 = xr.DataArray([15, 70, 50], coords=[time])\n", + "backup = m6.add_variables(name=\"backup\", lower=0, coords=[time])\n", + "m6.add_constraints(power + backup >= demand6, name=\"demand\")\n", + "\n", + "# Objective: fuel + startup cost + backup at /MW\n", + "m6.add_objective((fuel + startup_cost * commit + 5 * backup).sum())\n", + "\n", + "# The active parameter gates the PWL with the commitment binary:\n", + "# - commit=1: power in [30, 100], fuel = f(power)\n", + "# - commit=0: power = 0, fuel = 0\n", + "m6.add_piecewise_formulation(\n", + " (power, x_pts6),\n", + " (fuel, y_pts6),\n", + " active=commit,\n", + " name=\"pwl\",\n", + " method=\"incremental\",\n", + ")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.766060Z", "start_time": "2026-04-01T17:50:21.710952Z" } }, - "source": "m6.solve(reformulate_sos=\"auto\")", "outputs": [], - "execution_count": null + "source": [ + "m6.solve(reformulate_sos=\"auto\")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.775881Z", "start_time": "2026-04-01T17:50:21.770500Z" } }, - "source": "m6.solution[[\"commit\", \"power\", \"fuel\", \"backup\"]].to_pandas()", "outputs": [], - "execution_count": null + "source": [ + "m6.solution[[\"commit\", \"power\", \"fuel\", \"backup\"]].to_pandas()" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.866232Z", "start_time": "2026-04-01T17:50:21.784879Z" } }, - "source": "bp6 = linopy.breakpoints({\"power\": x_pts6.values, \"fuel\": y_pts6.values}, dim=\"var\")\nplot_pwl_results(m6, bp6, demand6, color=\"C2\")", "outputs": [], - "execution_count": null + "source": [ + "bp6 = linopy.breakpoints({\"power\": x_pts6.values, \"fuel\": y_pts6.values}, dim=\"var\")\n", + "plot_pwl_results(m6, bp6, demand6, color=\"C2\")" + ] }, { "cell_type": "markdown", @@ -1953,7 +2196,7 @@ "0", "`", " ", - "\u2014", + "—", " ", "t", "h", @@ -2517,128 +2760,219 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.872549Z", "start_time": "2026-04-01T17:50:21.869653Z" } }, - "source": "# CHP operating points: as load increases, power, fuel, and heat all change\nbp_chp = linopy.breakpoints(\n {\n \"power\": [0, 30, 60, 100],\n \"fuel\": [0, 40, 85, 160],\n \"heat\": [0, 25, 55, 95],\n },\n dim=\"var\",\n)\nprint(\"CHP breakpoints:\")\nprint(bp_chp.to_pandas())", "outputs": [], - "execution_count": null + "source": [ + "# CHP operating points: as load increases, power, fuel, and heat all change\n", + "bp_chp = linopy.breakpoints(\n", + " {\n", + " \"power\": [0, 30, 60, 100],\n", + " \"fuel\": [0, 40, 85, 160],\n", + " \"heat\": [0, 25, 55, 95],\n", + " },\n", + " dim=\"var\",\n", + ")\n", + "print(\"CHP breakpoints:\")\n", + "print(bp_chp.to_pandas())" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.920666Z", "start_time": "2026-04-01T17:50:21.879829Z" } }, - "source": "m7 = linopy.Model()\n\npower = m7.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\nfuel = m7.add_variables(name=\"fuel\", lower=0, coords=[time])\nheat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n\n# Fixed power dispatch determines the operating point \u2014 fuel and heat follow\npower_dispatch = xr.DataArray([20, 60, 90], coords=[time])\nm7.add_constraints(power == power_dispatch, name=\"power_dispatch\")\nm7.add_objective(fuel.sum())\n\n# N-variable: all three linked through shared interpolation weights\nm7.add_piecewise_formulation(\n (power, bp_chp.sel(var=\"power\")),\n (fuel, bp_chp.sel(var=\"fuel\")),\n (heat, bp_chp.sel(var=\"heat\")),\n name=\"chp\",\n method=\"sos2\",\n)", "outputs": [], - "execution_count": null + "source": [ + "m7 = linopy.Model()\n", + "\n", + "power = m7.add_variables(name=\"power\", lower=0, upper=100, coords=[time])\n", + "fuel = m7.add_variables(name=\"fuel\", lower=0, coords=[time])\n", + "heat = m7.add_variables(name=\"heat\", lower=0, coords=[time])\n", + "\n", + "# Fixed power dispatch determines the operating point — fuel and heat follow\n", + "power_dispatch = xr.DataArray([20, 60, 90], coords=[time])\n", + "m7.add_constraints(power == power_dispatch, name=\"power_dispatch\")\n", + "m7.add_objective(fuel.sum())\n", + "\n", + "# N-variable: all three linked through shared interpolation weights\n", + "m7.add_piecewise_formulation(\n", + " (power, bp_chp.sel(var=\"power\")),\n", + " (fuel, bp_chp.sel(var=\"fuel\")),\n", + " (heat, bp_chp.sel(var=\"heat\")),\n", + " name=\"chp\",\n", + " method=\"sos2\",\n", + ")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.964861Z", "start_time": "2026-04-01T17:50:21.926856Z" } }, - "source": "m7.solve(reformulate_sos=\"auto\")", "outputs": [], - "execution_count": null + "source": [ + "m7.solve(reformulate_sos=\"auto\")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:21.981116Z", "start_time": "2026-04-01T17:50:21.976461Z" } }, - "source": "m7.solution[[\"power\", \"fuel\", \"heat\"]].to_pandas().round(2)", "outputs": [], - "execution_count": null + "source": [ + "m7.solution[[\"power\", \"fuel\", \"heat\"]].to_pandas().round(2)" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:22.088132Z", "start_time": "2026-04-01T17:50:22.003877Z" } }, - "source": "plot_pwl_results(m7, bp_chp, power_dispatch, x_name=\"fuel\")", "outputs": [], - "execution_count": null + "source": [ + "plot_pwl_results(m7, bp_chp, power_dispatch, x_name=\"fuel\")" + ] }, { "cell_type": "markdown", "metadata": {}, - "source": "## 8. Per-entity breakpoints \u2014 Fleet of generators\n\nWhen different generators have different efficiency curves, pass\nper-entity breakpoints using a dict with `breakpoints()`. The breakpoint\narrays are auto-broadcast over the remaining dimensions (here `time`)." + "source": "## 8. Per-entity breakpoints — Fleet of generators\n\nWhen different generators have different efficiency curves, pass\nper-entity breakpoints using a dict with `breakpoints()`. The breakpoint\narrays are auto-broadcast over the remaining dimensions (here `time`)." }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:22.097775Z", "start_time": "2026-04-01T17:50:22.094150Z" } }, - "source": "gens = pd.Index([\"gas\", \"coal\"], name=\"gen\")\n\n# Each generator has its own heat-rate curve\nx_gen = linopy.breakpoints(\n {\"gas\": [0, 30, 60, 100], \"coal\": [0, 50, 100, 150]}, dim=\"gen\"\n)\ny_gen = linopy.breakpoints(\n {\"gas\": [0, 40, 90, 180], \"coal\": [0, 55, 130, 225]}, dim=\"gen\"\n)\nprint(\"Power breakpoints:\\n\", x_gen.to_pandas())\nprint(\"Fuel breakpoints:\\n\", y_gen.to_pandas())", "outputs": [], - "execution_count": null + "source": [ + "gens = pd.Index([\"gas\", \"coal\"], name=\"gen\")\n", + "\n", + "# Each generator has its own heat-rate curve\n", + "x_gen = linopy.breakpoints(\n", + " {\"gas\": [0, 30, 60, 100], \"coal\": [0, 50, 100, 150]}, dim=\"gen\"\n", + ")\n", + "y_gen = linopy.breakpoints(\n", + " {\"gas\": [0, 40, 90, 180], \"coal\": [0, 55, 130, 225]}, dim=\"gen\"\n", + ")\n", + "print(\"Power breakpoints:\\n\", x_gen.to_pandas())\n", + "print(\"Fuel breakpoints:\\n\", y_gen.to_pandas())" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:22.177554Z", "start_time": "2026-04-01T17:50:22.111112Z" } }, - "source": "m8 = linopy.Model()\n\npower = m8.add_variables(name=\"power\", lower=0, upper=150, coords=[gens, time])\nfuel = m8.add_variables(name=\"fuel\", lower=0, coords=[gens, time])\n\ndemand8 = xr.DataArray([80, 120, 60], coords=[time])\nm8.add_constraints(power.sum(\"gen\") >= demand8, name=\"demand\")\nm8.add_objective(fuel.sum())\n\n# Per-entity breakpoints: each generator gets its own curve\nm8.add_piecewise_formulation(\n (power, x_gen),\n (fuel, y_gen),\n name=\"pwl\",\n)", "outputs": [], - "execution_count": null + "source": [ + "m8 = linopy.Model()\n", + "\n", + "power = m8.add_variables(name=\"power\", lower=0, upper=150, coords=[gens, time])\n", + "fuel = m8.add_variables(name=\"fuel\", lower=0, coords=[gens, time])\n", + "\n", + "demand8 = xr.DataArray([80, 120, 60], coords=[time])\n", + "m8.add_constraints(power.sum(\"gen\") >= demand8, name=\"demand\")\n", + "m8.add_objective(fuel.sum())\n", + "\n", + "# Per-entity breakpoints: each generator gets its own curve\n", + "m8.add_piecewise_formulation(\n", + " (power, x_gen),\n", + " (fuel, y_gen),\n", + " name=\"pwl\",\n", + ")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:22.234795Z", "start_time": "2026-04-01T17:50:22.185178Z" } }, - "source": "m8.solve(reformulate_sos=\"auto\")", "outputs": [], - "execution_count": null + "source": [ + "m8.solve(reformulate_sos=\"auto\")" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:22.245727Z", "start_time": "2026-04-01T17:50:22.242646Z" } }, - "source": "m8.constraints['demand']", "outputs": [], - "execution_count": null + "source": [ + "m8.constraints[\"demand\"]" + ] }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2026-04-01T17:50:22.346404Z", "start_time": "2026-04-01T17:50:22.260902Z" } }, - "source": "sol = m8.solution\nfig, axes = plt.subplots(1, 2, figsize=(10, 3.5))\n\nfor i, gen in enumerate(gens):\n ax = axes[i]\n fuel_bp = y_gen.sel(gen=gen).values\n power_bp = x_gen.sel(gen=gen).values\n ax.plot(fuel_bp, power_bp, \"o-\", color=f\"C{i}\", label=\"Breakpoints\")\n for t in time:\n ax.plot(\n float(sol[\"fuel\"].sel(gen=gen, time=t)),\n float(sol[\"power\"].sel(gen=gen, time=t)),\n \"D\",\n color=\"black\",\n ms=8,\n )\n ax.set(xlabel=\"Fuel\", ylabel=\"Power [MW]\", title=f\"{gen.title()} heat-rate curve\")\n ax.legend()\n\nplt.tight_layout()", "outputs": [], - "execution_count": null + "source": [ + "sol = m8.solution\n", + "fig, axes = plt.subplots(1, 2, figsize=(10, 3.5))\n", + "\n", + "for i, gen in enumerate(gens):\n", + " ax = axes[i]\n", + " fuel_bp = y_gen.sel(gen=gen).values\n", + " power_bp = x_gen.sel(gen=gen).values\n", + " ax.plot(fuel_bp, power_bp, \"o-\", color=f\"C{i}\", label=\"Breakpoints\")\n", + " for t in time:\n", + " ax.plot(\n", + " float(sol[\"fuel\"].sel(gen=gen, time=t)),\n", + " float(sol[\"power\"].sel(gen=gen, time=t)),\n", + " \"D\",\n", + " color=\"black\",\n", + " ms=8,\n", + " )\n", + " ax.set(xlabel=\"Fuel\", ylabel=\"Power [MW]\", title=f\"{gen.title()} heat-rate curve\")\n", + " ax.legend()\n", + "\n", + "plt.tight_layout()" + ] } ], "metadata": { @@ -2662,4 +2996,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/linopy/io.py b/linopy/io.py index 9eaa964d..a753b828 100644 --- a/linopy/io.py +++ b/linopy/io.py @@ -1149,8 +1149,14 @@ def with_prefix(ds: xr.Dataset, prefix: str) -> xr.Dataset: ds.attrs["_relaxed_registry"] = json.dumps(m._relaxed_registry) if m._piecewise_formulations: ds.attrs["_piecewise_formulations"] = json.dumps( - {name: {"method": pwl.method, "variables": pwl.variable_names, "constraints": pwl.constraint_names} - for name, pwl in m._piecewise_formulations.items()} + { + name: { + "method": pwl.method, + "variables": pwl.variable_names, + "constraints": pwl.constraint_names, + } + for name, pwl in m._piecewise_formulations.items() + } ) ds.attrs = non_bool_dict(ds.attrs)