I am new to Python and I cannot seem to solve the problem I am having, even after going through similar problems posted on the forum.
My problem is that I get the ''SumExpression' object is not iterable' error on my objective function.
My code:
import pyomo.environ as pyo
from pyomo.opt import SolverFactory
model=pyo.ConcreteModel()
#C = contract capacity
D = [5048,5144,4616,4296,3696,3392,5048,5144,4616,4296,3696,3392]
R = [166.9,166.9,166.9,166.9,166.9,166.9,166.9,166.9,223.6,223.6,223.6,223.6]
PF=[0.027 for i in range (12)]
E=[1319.25,1319.25,1319.25,1319.25,1319.25,1319.25,1319.25,1319.25,1759,1759,1759,1759]
model.M=pyo.RangeSet(0,11)
model.X = pyo.Var(model.M, domain=pyo.NonNegativeReals)
model.C = pyo.Var(model.M, domain=pyo.NonNegativeReals)
model.Y = pyo.Var(model.M, domain=pyo.NonNegativeReals)
def constraint_1(model,M):
return model.X[M]+model.C[M] >= D[M]
model.constraint_1 = pyo.Constraint(model.M, rule=constraint_1)
def constraint_2(model,M):
return model.Y[M]+1.1*model.C[M] >= D[M]
model.constraint_2 = pyo.Constraint(model.M, rule=constraint_2)
def constraint_3(model,M):
if M == 11:
return model.C[0] >= model.C[M]
else:
return model.C[M+1] >= model.C[M]
model.constraint_3 = pyo.Constraint(model.M, rule=constraint_3)
def mod_obj(model,M):
if M==11:
return sum((1-PF[M])*R[M]*model.C[M]+2*R[M]*model.X[M]+R[M]*model.Y[M]+E[M]*(model.C[0]-model.C[M]))
else:
return sum((1-PF[M])*R[M]*model.C[M]+2*R[M]*model.X[M]+R[M]*model.Y[M]+E[M]*(model.C[M+1]-model.C[M]))
model.mod_obj = pyo.Constraint(model.M, rule=mod_obj)
model.obj=pyo.Objective(rule=mod_obj, sense=pyo.minimize)
opt = SolverFactory('glpk')
opt.solve(model)
model.pprint()
The error I get is from the second line in the objective function:
return sum((1-PF[M])*R[M]*model.C[M]+2*R[M]*model.X[M]+R[M]*model.Y[M]+E[M]*(model.C[M+1]-model.C[M]))
I think it has to do something with the M+1, as the first line does not give out an error but I cannot seem to get through this error and appreciate your help/input.
Thanks in advance!
You have a couple things hanging you up here...
First, when you use the sum()
expression the thing that is inside needs to be iterable. You are just passing in a fixed value for M
. Example:
In [32]: A = [5,6,7]
In [33]: sum(A[0] + A[1])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-143c09ad32d9> in <module>
----> 1 sum(A[0] + A[1])
TypeError: 'int' object is not iterable
In [34]: sum(A[idx] for idx in range(3))
Out[34]: 18
So you need to set up your sum()
function to have that type of structure, which leads to the second thing hanging you up, the construction of the proper index for model.C, which appears to wrap around. You can mathematically construct the "wrap around" you are looking for with modulo. Consider:
In [39]: import pyomo.environ as pyo
In [40]: M = pyo.RangeSet(0,11) # 0->11 inclusive
In [41]: M_prime = [(t+1)%12 for t in M]
In [42]: M_prime
Out[42]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0]
So we can stitch this together into one expression and NOT pass in the index M
in your model, which is improper structure for the objective function as passing in M
would produce M expressions in your model, right? So, I think you are looking for something like this:
def mod_obj(model):
return sum((1-PF[m])*R[m]*model.C[m]+2*R[m]*model.X[m]+R[m]*model.Y[m]+E[m]*(model.C[(m+1)%12]-model.C[m]) for m in model.M)
#model.mod_obj = pyo.Constraint(model.M, rule=mod_obj)
model.obj=pyo.Objective(rule=mod_obj, sense=pyo.minimize)
Also side note: You are setting yourself up for confusion/disaster by using capital M
to represent members of the set model.M
. I think it is much clearer to use lower-case letters to represent set members which reads more clearly.