unhelpful Pyomo error ERROR: Initializer for Set objective_index returned non-iterable object of type SumExpression

Viewed 23

Here is the offending code, abstracted from the source to protect your sanity . . .

def objective_rule(model):
    return sum(model.ccv[c] * model.SELECT[c] for c in model.c)

nc=40
model.c = Set(initialize=[c for c in range(1, nc+1)], ordered=True)
model.SELECT=Var(model.c, initialize=0, domain=NonNegativeReals)
model.ccv= Param(model.c, initialize=ccd, domain=NonNegativeReals) 

ccd is a dictionary with the same integer keys as as model.c.

Here are the error allegations made by pyomo.

ERROR: Initializer for Set objective_index returned non-iterable object of
    type SumExpression.
ERROR: Constructing component 'objective_index' from data=None failed:
    TypeError: 'SumExpression' object is not iterable
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [44], line 1
----> 1 model.objective = Objective(objective_rule, sense = minimize)
      3 print("Done setting up the problem.")
...

TypeError: 'SumExpression' object is not iterable

You'll notice that I don't use SumExpression in my code, so an error message that SumExpression is not iterable is not actionable.

The objection function follows the form of many, many other pyomo objective functions that do work fine.

The problem I'm working on is easy to solve in cvxpy, but I'm tasked with getting pyomo to be useful. So far, not so good.

Is there a (nonobvious) error here? Do the error messages contain actionable information? Do I have a broken pyomo installation?

1 Answers

The error is in the construction of your Objective().

pyomo is making the (false) assumption that the first parameter in the function call is an iterable. Most pyomo commands like making variables or constraints with a "rule" assume the first thing(s) in the call are the indexing set(s).

You should identify it by a keyword. Or just put the expression in the function. Either of these should work. (Note the use of 'rule' in the first and 'expr' in the second)

model.objective = Objective(rule=objective_rule)  #minimize is default and not needed

or you can ditch the function as it is just a simple expression and put:

model.objective = Objective(expr=sum(model.ccv[c] * model.SELECT[c] for c in model.c))
Related