I am building an Abstract optimization model with Pyomo in Python. I have a model variable (model.x) which is indexed with 4 sets. To build my objective function, i build 5 different terms with Python, then add them up, and return them. I use functions to return some values for the objective function. These functions use SumExpressions. I then want to check if the calculated expression is > 0 mod 2, but this is not working.
I already tried to replace my if-clause with an assert, but its not doing what i inially wanted it to do. I also tried to somehow retrieve the value of the expression with value(), but this will raise an error since the varaibles don't have values yet.
This is the function i call from the objective rule:
def sportGleichzeitig(model,k,z):
sport = sum(model.x[k,l,"SportM",z] for l in model.Lehrer) +
sum(model.x[k,l,"SportW",z] for l in model.Lehrer)
if sport % 2 > 0 :
return 0
else:
return 1
This is the part of the objective rule referring to the function
sport = model.sportweight * sum(sportGleichzeitig(model,k,z) for k in model.Klassen for z in model.Zeitslots)
So i want to weigh in sport whenever "SportW" and "SportM" is at the same time. This code raises the following exception:
TypeError at /optimierung/
unsupported operand type(s) for %: 'SumExpression' and 'int'
Is there a way of doing this with Pyomo?
In most optimization frameworks / formulations, you're not allowed to use the kind of functions you are trying to use (mod / if). Particularly in LP programs. An if statement can be expressed through a binary variable in MILP / MINLP formulation, mod is harder (it is periodically non-differentiable). I'm not sure if Pyomo supports the mod operator at all, but my guess it that it doesn't. Even if it does, you first need to make sure the solver you are going to use can solve this kind of problem (mixed integer non-linear with non-differentiable points).
If sportGleichzeitig
is associated to a cost, and therefore you expect the solver to minimize it, one way to express this in a MILP formulation is the following:
a
: non-negative integer variable (auxiliary)sportGleichzeitig
: binary variablesport >= a * 2
sport <= a * 2 + sportGleichzeitig * 2
This way:
mod(sport,2) == 0
, a
will be sport/2
and sportGleichzeitig
will be 0mod(sport,2) != 0
, a
will be sport // 2
and sportGleichzeitig
will be 1The risk is that sportGleichzeitig
is 1 even though mod(sport,2) == 0
.
This is why as mentioned above this only works if sportGleichzeitig
is part of your objective function and is associated to a cost, that why the model will always try to minimize it if it's possible.