You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Following strategies about persistent solving and decomposition, using equality constraints via Variable.fix() is sub-optimal and should be exchanged to use fix lower and upper bounds instead (like JuMP and Pyomo do).
Note
AI assisted writing
Describe the feature you'd like to see
Variable.fix() (added in #625, released in v0.7.0) fixes a variable by adding a __fix__{name} equality constraint. It should instead collapse the bounds:
importlinopym=linopy.Model()
x=m.add_variables(lower=0, upper=10, name="x")
x.fix(5.0)
# today: adds equality constraint "__fix__x" (new row, new labels)# proposed: sets x.lower = x.upper = 5.0 (pure value change, no new row)
Ecosystem convention. JuMP fix(x, v), Pyomo var.fix(v), gurobipy lb=ub — "fix" means bound/domain collapse everywhere else. linopy's equality-constraint version is the outlier.
Cheaper and cleaner model. No extra rows, no __fix__ constraint-namespace pollution, no cleanup hooks in Model.remove_variables; presolve removes fixed columns.
fix(value) stashes original lower/upper in a registry and sets both to value — unify with the existing _relaxed_registry pattern into one fix-registry holding bounds + integrality.
unfix() restores stashed bounds (and integrality, as today).
fixed checks the registry instead of the constraint namespace.
FIX_CONSTRAINT_PREFIX, the __fix__ handling in model.py, and the remove_variables cleanup go away.
The value=None (use solution), decimals rounding, bounds-validation, and relax=True behavior carry over unchanged.
Behavioral differences
The fix's marginal value appears as the variable's reduced cost instead of a constraint dual — equivalent information for the dual-extraction workflow, but a documented change.
m.constraints no longer lists __fix__* entries.
No deprecation shim: the API is ~10 weeks old with no downstream usage (PyPSA does not use it), and an in-place semantics swap behind a warning helps nobody. Clean break with a release note.
Following strategies about persistent solving and decomposition, using equality constraints via
Variable.fix()is sub-optimal and should be exchanged to use fix lower and upper bounds instead (like JuMP and Pyomo do).Note
AI assisted writing
Describe the feature you'd like to see
Variable.fix()(added in #625, released in v0.7.0) fixes a variable by adding a__fix__{name}equality constraint. It should instead collapse the bounds:Why
STRUCTURAL_LABELS→ full solver rebuild. Bound collapse is a pure value change and stays on the in-place update path — so fix/re-solve loops (including feat: Add fix(), unfix(), and fixed to Variable and Variables #625's stated MILP dual-extraction use case: fix binaries, relax, re-solve as LP) get warm starts instead of rebuilds.fix(x, v), Pyomovar.fix(v), gurobipylb=ub— "fix" means bound/domain collapse everywhere else. linopy's equality-constraint version is the outlier.__fix__constraint-namespace pollution, no cleanup hooks inModel.remove_variables; presolve removes fixed columns.fix=kwarg inModel.restrict/advance(Design: Model.restrict / advance — slice a model along a coordinate and condition on boundary values (rolling horizon) #768): with consistent semantics, "fix" means hold a variable at a value everywhere — bound collapse in a live model, fold-out (elimination) inrestrict.Implementation sketch
fix(value)stashes originallower/upperin a registry and sets both tovalue— unify with the existing_relaxed_registrypattern into one fix-registry holding bounds + integrality.unfix()restores stashed bounds (and integrality, as today).fixedchecks the registry instead of the constraint namespace.FIX_CONSTRAINT_PREFIX, the__fix__handling inmodel.py, and theremove_variablescleanup go away.value=None(use solution),decimalsrounding, bounds-validation, andrelax=Truebehavior carry over unchanged.Behavioral differences
m.constraintsno longer lists__fix__*entries.No deprecation shim: the API is ~10 weeks old with no downstream usage (PyPSA does not use it), and an in-place semantics swap behind a warning helps nobody. Clean break with a release note.