How to use if conditions which contain variables in Pyomo constraint - if-statement

I am trying to add a simple constraint to my Pyomo model:
maximum{x[1]-a,b}+maximum{x[2]-a,b} >= c
where a,b,c are given predefined parameters and x is the decision variable indexed by set model.I which is initialize to [1,2].
In order to achieve this, I tried the following method with no success:
from pyomo.environ import *
from pyomo.opt import SolverFactory
from pyomo.environ import *
model = AbstractModel()
model.I = Set()
model.a = Param()
model.b = Param()
model.c = Param()
model.x = Var(model.I)
def my_rule(model):
total = 0
for i in model.I:
val = model.x[i] - model.a
if val < model.b:
val = model.b
total = total + val
return total >= model.c
model.my_constraint = Constraint(rule=my_rule)
data = {None:{
'I': {None: [1,2]},
'a': {None: 3},
'b': {None: 5},
'c': {None: 4}}
}
real_model = model.create_instance(data)
The error given is:
WARNING: DEPRECATED: Chained inequalities are deprecated. Use the inequality()
function to express ranged inequality expressions.
ERROR: Rule failed when generating expression for constraint my_constraint:
TypeError: Attempting to form a compound inequality with two lower bounds
The inequality expression:
x[1] - 3 < 5.0
contains non-constant terms (variables) that were evaluated in an
unexpected Boolean context at
File '<ipython-input-11-e3a6c44c5b8e>', line 14:
if val < model.b:
Evaluating Pyomo variables in a Boolean context, e.g.
if expression <= 5:
is generally invalid. If you want to obtain the Boolean value of
the expression based on the current variable values, explicitly
evaluate the expression using the value() function:
if value(expression) <= 5:
or
if value(expression <= 5):
Could any one help me with this? Thanks a lot.

Couple problems...
You can't bury an "if" statement inside of the constraint construction where the condition depends on the evaluation of variables.
max and min functions can't be directly represented in a LP/IP if that is what you are trying to do. There may be ways to reformulate...however...
Your constraint is somewhat nonsensical. If b and c are fixed values then the constraint you presented is ALWAYS true because b>c as stated, so:
max(anything, b) + max(anything else, b) > c is always true.
Time to re-examine your problem formulation. :)

Related

Pyomo Cannot iterate over abstract Set before it has been constructed

I constructed an abstract model in Pyomo and it worked well.
However, when I try to use a dictionary to instantiate the abstract model, I got the following errors "ERROR: Rule failed when generating expression for objective value:
RuntimeError: Cannot iterate over abstract Set 'I' before it has been
constructed (initialized)."
To be specific, here's the issue:
from pyomo.environ import *
model = AbstractModel()
model.D = Set()
model.I = Set()
model.w = Param(model.D)
model.S_0 = Param(model.D)
model.x = Var(real_model.I, model.D)
def sum_cubic(m):
return sum(w[j]*(m.x[i][j]-m.S_0[j])**3 for i in model.I for j in model.D)
model.value = Objective(rule = sum_cubic, sense = maximize)
model.pprint()
The above code runs just fine. But errors are given when I add the following codes right after it where names and S_0 are predefined dictionaries:
data = {None:{
'D':{None: names},
'I':{None: list(range(1,4))},
'w':[0.3,0.3,0.4],
'S_0':S_0,
}
}
real_model = model.create_instance(data)
ERROR: Rule failed when generating expression for objective value:
RuntimeError: Cannot iterate over abstract Set 'I' before it has been
constructed (initialized).
ERROR: Constructing component 'value' from data=None failed:
RuntimeError: Cannot iterate over abstract Set 'I' before it has been
constructed (initialized).
Could anyone help me with that? Thanks.
You have a couple things biting you here...
you are mixing m. and model. in your function, where you should be using m. because that is the self-referencing parameter of your function signature
you are indexing m.x incorrectly. It should be tuple-indexed (see mine)
your data dictionary is not set up right for the parameters. (see mine)
Good luck!
from pyomo.environ import *
model = AbstractModel()
model.D = Set()
model.I = Set()
model.w = Param(model.D)
model.S_0 = Param(model.D)
model.x = Var(model.I, model.D)
def sum_cubic(m):
return sum(m.w[j]*(m.x[i, j]-m.S_0[j])**3 for i in m.I for j in m.D)
model.value = Objective(rule = sum_cubic, sense = maximize)
model.pprint()
names=['a', 'b', 'c']
data = { None:{
'D': {None: names},
'I': {None: [1, 2, 3]},
'w': {'a': 0.4, 'b': 0.3, 'c': 0.2},
'S_0': {'a': 1.0, 'b': 2.0, 'c': 3.0} }
}
real_model = model.create_instance(data)

Lambdifying a function with conditon statements using sympy

Im trying to lambdify this function
def f(x):
if ceil(x)%2 == 0:
return -1
else :
return +1
a = sympy.lambdify(x,f(x))
Im getting an error when i try to do that.
I also tried piecewise , but it is not giving me the desired outcome
y = lambdify(x,(Piecewise((1, ceil(x)%2 == 0), (-1,True))))
Please help
Thanks in advance
You need to pass a symbolic expression to lambdify so a Python function is no good. Also you need to use symbolic sympy functions and sympy's ceil function is actually called ceiling. Finally == compares if two expressions are the same which is not the same as constructing a symbolic Boolean. For that you need Eq:
That gives
In [19]: p = Piecewise((1, Eq(ceiling(x)%2, 0)), (-1,True))
In [20]: p
Out[20]:
⎧1 for ⌈x⌉ mod 2 = 0
⎨
⎩-1 otherwise
In [21]: y = lambdify(x, p)
In [22]: y([1, 2, 3])
Out[22]: array([-1., 1., -1.])
References:
https://docs.sympy.org/latest/modules/functions/elementary.html#ceiling
https://docs.sympy.org/latest/tutorial/gotchas.html#equals-signs

Working example of multi-stage model in Pyomo

This paper describes Pyomo's Differential and Algebraic Equations framework. It also mentions multi-stage problems; however, it does not show a complete example of such a problem. Does such an example exist somewhere?
The following demonstrates a complete minimum working example of a multi-stage optimization problem using Pyomo's DAE system:
#!/usr/bin/env python3
#http://www.gpops2.com/Examples/OrbitRaising.html
from pyomo.environ import *
from pyomo.dae import *
from pyomo.opt import SolverStatus, TerminationCondition
import random
import matplotlib.pyplot as plt
T = 10 #Maximum time for each stage of the model
STAGES = 3 #Number of stages
m = ConcreteModel() #Model
m.t = ContinuousSet(bounds=(0,T)) #Time variable
m.stages = RangeSet(0, STAGES) #Stages in the range [0,STAGES]. Can be thought of as an integer-valued set
m.a = Var(m.stages, m.t) #State variable defined for all stages and times
m.da = DerivativeVar(m.a, wrt=m.t) #First derivative of state variable with respect to time
m.u = Var(m.stages, m.t, bounds=(0,1)) #Control variable defined for all stages and times. Bounded to range [0,1]
#Setting the value of the derivative.
def eq_da(m,stage,t): #m argument supplied when function is called. `stage` and `t` are given values from m.stages and m.t (see below)
return m.da[stage,t] == m.u[stage,t] #Derivative is proportional to the control variable
m.eq_da = Constraint(m.stages, m.t, rule=eq_da) #Call constraint function eq_da for each unique value of m.stages and m.t
#We need to connect the different stages together...
def eq_stage_continuity(m,stage):
if stage==m.stages.last(): #The last stage doesn't connect to anything
return Constraint.Skip #So skip this constraint
else:
return m.a[stage,T]==m.a[stage+1,0] #Final time of each stage connects with the initial time of the following stage
m.eq_stage_continuity = Constraint(m.stages, rule=eq_stage_continuity)
#Boundary conditions
def _init(m):
yield m.a[0,0] == 0 #Initial value (at zeroth stage and zeroth time) of `a` is 0
yield ConstraintList.End
m.con_boundary = ConstraintList(rule=_init) #Repeatedly call `_init` until `ConstraintList.End` is returned
#Objective function: maximize `a` at the end of the final stage
m.obj = Objective(expr=m.a[STAGES,T], sense=maximize)
#Get a discretizer
discretizer = TransformationFactory('dae.collocation')
#Disrectize the model
#nfe (number of finite elements)
#ncp (number of collocation points within finite element)
discretizer.apply_to(m,nfe=30,ncp=6,scheme='LAGRANGE-RADAU')
#Get a solver
solver = SolverFactory('ipopt', keepfiles=True, log_file='/z/log', soln_file='/z/sol')
solver.options['max_iter'] = 100000
solver.options['print_level'] = 1
solver.options['linear_solver'] = 'ma27'
solver.options['halt_on_ampl_error'] = 'yes'
#Solve the model
results = solver.solve(m, tee=True)
print(results.solver.status)
print(results.solver.termination_condition)
#Retrieve the results in a pleasant format
r_t = [t for s in sorted(m.stages) for t in sorted(m.t)]
r_a = [value(m.a[s,t]) for s in sorted(m.stages) for t in sorted(m.t)]
r_u = [value(m.u[s,t]) for s in sorted(m.stages) for t in sorted(m.t)]
plt.plot(r_t, r_a, label="r_a")
plt.plot(r_t, r_u, label="r_u")
plt.legend()
plt.show()

Change constraints based on variable value in Pyomo

Is there a way of changing the values of a constraint as the solver is running?
Basically, I have a constraint that depends on the value of a variable. The problem is that the constraint is evaluated based on the initial value of the variable, but isn't updated as the variable changes.
Here's a simple example:
from pyomo.environ import *
from pyomo.opt import SolverFactory
import numpy as np
# Setup
model = ConcreteModel()
model.A = Set(initialize = [0,1,2])
model.B = Set(initialize = [0,1,2])
model.x = Var(model.A, model.B, initialize=0)
# A constraint that I'd like to keep updating, based on the value of x
def changing_constraint_rule(model, a):
x_values = list((model.x[a, b].value for b in model.B))
if np.max(x_values) == 0:
return Constraint.Skip
else:
# Not really important what goes here, just as long as it updates the constraint list
if a == 1 : return sum(model.x[a,b] for b in model.B) == 0
else: return sum(model.x[a,b] for b in model.B) == 1
model.changing_constraint = Constraint(model.A, rule = changing_constraint_rule)
# Another constraint that changes the value of x
def bounding_constraint_rule(model, a):
return sum(model.x[a, b] for b in model.B) == 1
model.bounding_constraint = Constraint(
model.A,
rule = bounding_constraint_rule)
# Some objective function
def obj_rule(model):
return(sum(model.x[a,b] for a in model.A for b in model.B))
model.objective = Objective(rule=obj_rule)
# Results
opt = SolverFactory("glpk")
results = opt.solve(model)
results.write()
model.x.display()
If I run model.changing_constraint.pprint() I can see that no constraints have been made, since the initial value of the variable model.x was set to 0.
If it's not possible to change the constraint values while solving, how could I formulate this problem differently to achieve what I'm looking for? I've read this other post but couldn't figure it out from the instructions.
I am giving you the same answer in the other question by #Gabe:
Any if-logic you use inside of rules should not involve the values of
variables (unless it is based on the initial value of a variable, in
which case you would wrap the variable in value() wherever you use it
outside of the main expression that is returned).
for example:
model.x[a, b].value should be model.x[a, b].value()
But still this might not give you the solution what you are looking for.

Convert a concrete model in an abstract one

I am just starting with Pyomo and I have a big problem.
I want to run an Abstract Model without using the terminal. I can do it with a concrete model but I have serious problems to do it in with the abstract one.
I just want to use F5 and run the code.
This ismy program:
import pyomo
from pyomo.environ import *
#
# Model
#
model = AbstractModel()
#Set: Indices
model.Unit = Set()
model.Block = Set()
model.DemBlock = Set()
#Parameters
model.EnergyBid = Param(model.Unit, model.Block)
model.PriceBid = Param(model.Unit, model.Block)
model.EnergyDem = Param(model.DemBlock)
model.PriceDem = Param(model.DemBlock)
model.Pmin = Param(model.Unit)
model.Pmax = Param(model.Unit)
#Variables definition
model.PD = Var(model.DemBlock, within=NonNegativeReals)
model.PG = Var(model.Unit,model.Block, within=NonNegativeReals)
#Binary variable
model.U = Var(model.Unit, within = Binary)
#Objective
def SocialWellfare(model):
SocialWellfare = sum([model.PriceDem[i]*model.PD[i] for i in model.DemBlock]) - sum([model.PriceBid[j,k]*model.PG[j,k] for j in model.Unit for k in model.Block ])
return SocialWellfare
model.SocialWellfare = Objective(rule=SocialWellfare, sense=maximize)
#Constraints
#Max and min Power generated
def PDmax_constraint(model,p):
return ((model.PD[p] - model.EnergyDem[p])) <= 0
model.PDmax = Constraint(model.DemBlock, rule=PDmax_constraint)
def PGmax_constraint(model,n,m):
return ((model.PG[n,m] - model.EnergyBid[n,m])) <= 0
model.PGmax = Constraint(model.Unit, model.Block,rule = PGmax_constraint)
def Power_constraintDW(model,i):
return ((sum(model.PG[i,k] for k in model.Block))-(model.Pmin[i] * model.U[i]) ) >= 0
model.LimDemandDw = Constraint(model.Unit, rule=Power_constraintDW)
def Power_constraintUP(model,i):
return ((sum(model.PG[i,k] for k in model.Block) - (model.Pmax[i])*model.U[i])) <= 0
model.LimDemandaUp = Constraint(model.Unit, rule=Power_constraintUP)
def PowerBalance_constraint(model):
return (sum(model.PD[i] for i in model.DemBlock) - sum(model.PG[j,k] for j in model.Unit for k in model.Block)) == 0
model.PowBalance = Constraint(rule = PowerBalance_constraint)
model.pprint()
instance = model.create('datos_transporte.dat')
## Create the ipopt solver plugin using the ASL interface
solver = 'ipopt'
solver_io = 'nl'
opt = SolverFactory(solver,solver_io=solver_io)
results = opt.solve(instance)
results.write()
Any help with the last part??
Thanks anyway,
I think your example is actually working. Starting in Pyomo 4.1, the solution returned from the solver is stored directly into the instance that was solved, and is not returned in the solver results object. This change was made because generating the representation of the solution in the results object was rather expensive and was not easily parsed by people. Working with the model instance directly is more natural.
It is unfortunate that the results object reports the number of solutions: 0, although this is technically correct: the results object holds no solutions ... but the Solver section should indicate that a solution was returned and stored into the model instance.
If you want to see the result returned by the solver, you can print out the current status of the model using:
instance.display()
after the call to solve(). That will report the current Var values that were returned from the solver. You will want to pay attention to the stale column:
False indicates the value is not "stale" ... that is, it was either set by the user (before the call to solve()), or it was returned from the solver (after the call to solve()).
True indicates the solver did not return a value for that variable. This is usually because the variable was not referenced by the objective or any enabled constraints, so Pyomo never sent the variable to the solver.
[Note: display() serves a slightly different role than pprint(): pprint() outputs the model structure, whereas display() outputs the model state. So, for example, where pprint() will output the constraint expressions, display() will output the numerical value of the expression (using the current variable/param values).]
Edited to expand the discussion of display() & pprint()