eli.m93
eli.m93

Reputation: 27

The outcome of defining a set of constraints in pyomo is wrong

I create an optimization model in pyomo, and I have a list of tuples as a parameter “par”.

import pyomo.environ as pe
model = pe.ConcreteModel()
p_set = [(1,2), (2,3), (4,5)]
model.par = pe.Param(initialize=p_set, mutable= True)
def var_fix(model, i, j ):
    if (i,j) in model.par:
        constraint = (model.v[i,j] == 1)      # v is a binary variable
    else:
        constraint = (model.v[i,j] == 0) 
    return constraint
model.var_fix = pe.Constraint(model.edges, rule=var_fix)  

But, after printing “var_fix” constraint, all of them are equall to zero:

Key       : Lower : Body     : Upper : Active
(1, 2)   :   0.0     :   v[1,2] :   0.0     :   True
(2, 3)   :   0.0     :   v[2,3] :   0.0     :   True
(4, 5)   :   0.0     :   v[4,5] :   0.0     :   True

I define the parameter and constraint in this way since I want to iteratively change this parameter “par” with a new one which may have different number of tuples, then solve the problem. In each iteration I will do :

# generating par_new based on some random processes 
par_new = [(5,10), (2,3), (4,5), (11,8), (10,6)]
model.par = par_new
# solve the problem again

Upvotes: 1

Views: 528

Answers (1)

jsiirola
jsiirola

Reputation: 2589

The crux of your problem is that you are defining a single ScalarParam that holds a list of tuples. Scalar objects in Pyomo are special cases of their Indexed counderparts that use an implicit index of None. This is done so that code working with Pyomo models can treat all components as if they were indexed (which prevents code from being littered with if comp.is_indexed(): tests). The __contains__ test that you are doing (if (i,j) in model.par) is testing if the tuple is in the Param's indexing set, and not in the Param's value.

The simplest change is to change the test to check the Param's value:

>>> from pyomo.environ import *
>>> m = ConcreteModel()
>>> m.p = Param(initialize=[(1,2),(3,4)], mutable=True, domain=Any)
>>> (1,2) in m.p
False
>>> (1,2) in m.p.value
True

However, if you intend on updating the model iteratively (without rebuilding it), I would recommend making the param hold the RHS of the constraint. That is, something more like:

model = pe.ConcreteModel()

p_set = [(1,2), (2,3), (4,5)]
def par(m, i, j):
    return 1 if (i,j) in p_set else 0
model.par = pe.Param(model.edges, initialize=par, mutable=True)

def var_fix(model, i, j ):
    return model.v[i,j] == model.par[i,j]
model.var_fix = pe.Constraint(model.edges, rule=var_fix)  

This is because construction rules are not callbacks: they are called only when initially constructing the component and not during the solve. Updating the Params would then look more like:

model.par.set_values(0)
for i,j in par_new:
    model.par[i,j] = 1

Upvotes: 3

Related Questions