I want to solve an optimization problem using Pyomo and ensure that the decision variables are either between specified limits or equal to zero.
As a minimal example, I would like to show the following optimization problem:
Specifically, I want to keep the decision variable(s) x(t)
always at either zero or between ten and 30.
I can already restrict x(t) to a range using the bounds alone when declaring the variables. However, this gives me a result where x(2) = 5 and is therefore less than ten.
import pyomo.environ as pyo
model = pyo.ConcreteModel()
model.time = pyo.Set(initialize=range(5))
model.price = pyo.Param(model.time, initialize=[40, 20, 10, 30, 50])
model.out = pyo.Param(model.time, initialize=[0, 0, 0, 40, 20])
initial_state = 50
min_state = 25
model.x = pyo.Var(model.time, bounds=[0, 30])
def expression_state(m, t):
if t == m.time.first():
return initial_state + model.x[t] - model.out[t]
else:
return m.state[m.time.prev(t)] + model.x[t] - model.out[t]
model.state = pyo.Expression(model.time, rule=expression_state)
def constraint_min_state(m, t):
return m.state[t] >= min_state
model.state_constraint = pyo.Constraint(model.time, rule=constraint_min_state)
def objective(m):
return sum(m.x[t] * m.price[t] for t in m.time)
model.objective = pyo.Objective(rule=objective, sense=pyo.minimize)
pyo.SolverFactory("glpk").solve(model)
model.x.display()
I have now tried various ways of inserting a constraint that gives me the desired behavior (either equal to zero or between ten and 30), but I usually always get the same error. Here is an example of the error mentioned:
def constraint_x(m, t):
return (m.x[t] == 0) or (10, m.x[t], 30)
model.x_constraint = pyo.Constraint(model.time, rule=constraint_x)
Such a constraint (or similar ones) gives me the following error message:
pyomo.common.errors.PyomoException: Cannot convert non-constant Pyomo expression (x[0] == 0) to bool.
This error is usually caused by using a Var, unit, or mutable Param in a
Boolean context such as an "if" statement, or when checking container
membership or equality. For example,
>>> m.x = Var()
>>> if m.x >= 1:
... pass
and
>>> m.y = Var()
>>> if m.y in [m.x, m.y]:
... pass
would both cause this exception.
What options do I have to include such either/or constraints?
x[t] is zero or between L and U
. This means that x[t]
is a semi-continuous variable with bounds L
and U
. Some solvers and modeling tools have direct support for this.
If not, you can simulate semi-continuous variables with an additional binary variable δ ∈ {0,1}:
L⋅δ[t] ≤ x[t] ≤ U⋅δ[t]
This is a linear constraint.