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 c5de3563..0315d0c4 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, ) @@ -813,7 +813,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 @@ -840,11 +840,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" @@ -873,17 +873,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 @@ -947,11 +947,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 dbc038fd..4df05ad0 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."""