Search code examples
pythonpyomo

Define conditional bounds to Pyomo Var


Given the following trivial model:

model.WEEKS = Set(initialize = [1,2,3])
model.PRODS = Set(initialize = ['Q24','J24','F24'])

model.volume = Var(model.WEEKS,model.PRODS, within = NonNegativeIntegers)

I'd like to set varying bounds for each permutation in model.volume depending on the initial character of the second index. Currently, I have achieved this by applying the following constraints to specified subsets:

# create subsets
Q_PRODS = Set(within = model.WEEKS * model.PRODS, initialize = [x for x in model.volume if x[1][0]=='Q'])
M_PRODS = Set(within = model.WEEKS * model.PRODS, initialize = [x for x in model.volume if x[1][0]!='Q'])

#define functions
def c1(model, i,j):
    return (25, model.volume[i,j], 60)
model.c1 = Constraint(Q_PRODS, rule = c1)

def c2(model, i,j):
    return (40, model.volume[i,j], 75)
model.c2 = Constraint(M_PRODS, rule = c2)

Which correctly outputs the following:

2 Constraint Declarations
    c1 : Size=3, Index=c1_index, Active=True
        Key        : Lower : Body          : Upper : Active
        (1, 'Q24') :  25.0 : volume[1,Q24] :  60.0 :   True
        (2, 'Q24') :  25.0 : volume[2,Q24] :  60.0 :   True
        (3, 'Q24') :  25.0 : volume[3,Q24] :  60.0 :   True
    c2 : Size=6, Index=c2_index, Active=True
        Key        : Lower : Body          : Upper : Active
        (1, 'F24') :  40.0 : volume[1,F24] :  75.0 :   True
        (1, 'J24') :  40.0 : volume[1,J24] :  75.0 :   True
        (2, 'F24') :  40.0 : volume[2,F24] :  75.0 :   True
        (2, 'J24') :  40.0 : volume[2,J24] :  75.0 :   True
        (3, 'F24') :  40.0 : volume[3,F24] :  75.0 :   True
        (3, 'J24') :  40.0 : volume[3,J24] :  75.0 :   True

However, this seems a little clumsy and I wondered if there is more efficient method that would achieve the same ends? For example, by defining a rule to pass during the creation of model.volume?


Solution

  • You can use a callable to provide limits, if desired. For most Pyomo constructs, it must catch the indexing variables and also have a self-reference to the model. There are other examples in the dox.

    import pyomo.environ as pyo
    
    m = pyo.ConcreteModel()
    
    m.I = pyo.Set(initialize=[1, 2, 3, 4])
    
    def v_limits(m, i):
        if i%2==0: 
            return (10, 20)
        return (8, 9)
    
    m.X = pyo.Var(m.I, bounds=v_limits)
    
    m.pprint()