Search code examples
linear-programmingpyomo

Dynamic variables and constraints in Pyomo


I need to solve an LP problem in Pyomo. The number of variables and constraints changes depending on the purpose it will be used and can be freely changed by the user (input 'N' in the code below). I did a code for a fixed number of variables and constraints (N=9). It is working well but I don't know how to make it dynamically create the variables and constraints as the input N changes. The code below is a simplified version of my code for better understanding.

!pip install -q pyomo
!apt-get install -y -qq glpk-utils

import pyomo.environ as pyo
from pyomo.environ import *
from pyomo.opt import SolverFactory

alpha = 0.8
N = 9 # this is the input that can be changed and will impact on the number of variables and constraints

model = pyo.ConcreteModel()

model.a = pyo.Var(domain=NonNegativeReals)

# the number of the variables below must follow the input 'N' that in this case is 9
model.b1 = pyo.Var(domain=NonNegativeReals)
model.b2 = pyo.Var(domain=NonNegativeReals)
model.b3 = pyo.Var(domain=NonNegativeReals)
model.b4 = pyo.Var(domain=NonNegativeReals)
model.b5 = pyo.Var(domain=NonNegativeReals)
model.b6 = pyo.Var(domain=NonNegativeReals)
model.b7 = pyo.Var(domain=NonNegativeReals)
model.b8 = pyo.Var(domain=NonNegativeReals)
model.b9 = pyo.Var(domain=NonNegativeReals)

# below is a calculation during the building of obj function that also needs to change based on input 'N'. Necessary to sum all variables 'b' created
TTL = model.a + (1/(1-alpha)) * (model.b1 + model.b2 + model.b3 + model.b4 + model.b5 + model.b6 + model.b7 + model.b8 + model.b9)

# below are the constraints that should change based on the input 'N' as well
model.c1 = Constraint(expr = model.b1 + model.a >= 0)
model.c2 = Constraint(expr = model.b2 + model.a >= 0)
model.c3 = Constraint(expr = model.b3 + model.a >= 0)
model.c4 = Constraint(expr = model.b4 + model.a >= 0)
model.c5 = Constraint(expr = model.b5 + model.a >= 0)
model.c6 = Constraint(expr = model.b6 + model.a >= 0)
model.c7 = Constraint(expr = model.b7 + model.a >= 0)
model.c8 = Constraint(expr = model.b8 + model.a >= 0)
model.c9 = Constraint(expr = model.b9 + model.a >= 0)

model.obj = pyo.Objective(expr= TTL, sense=minimize)

For the creation of the variables, I am using the code below, which I understand may work. But once I cannot run the entire code with this variable declaration, I even don't know if it really works.

Using this

model.b = pyo.Var(range(N), domain=NonNegativeReals)

Instead of this

model.b1 = pyo.Var(domain=NonNegativeReals)
model.b2 = pyo.Var(domain=NonNegativeReals)
model.b3 = pyo.Var(domain=NonNegativeReals)
model.b4 = pyo.Var(domain=NonNegativeReals)
model.b5 = pyo.Var(domain=NonNegativeReals)
model.b6 = pyo.Var(domain=NonNegativeReals)
model.b7 = pyo.Var(domain=NonNegativeReals)
model.b8 = pyo.Var(domain=NonNegativeReals)
model.b9 = pyo.Var(domain=NonNegativeReals)

How can I adjust the code above to meet the application requirements?

Many thanks in advance!


Solution

  • Instead of making the variables 1-by-1, which is difficult to build and almost impossible to manage, just make an index set from whatever "dynamic" stuff happens in your model and use that. It is much more robust and succinct. A simple example... Main point, dynamically make the sets and then just use them to index your variables.

    Code:

    import pyomo.environ as pyo
    
    var_count = int(input("how many vars: "))
    
    m = pyo.ConcreteModel()
    
    m.N = pyo.Set(initialize=range(var_count))
    
    m.x = pyo.Var(m.N)
    
    m.pprint()
    

    Sample run...

    how many vars: 4
    1 Set Declarations
        N : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    4 : {0, 1, 2, 3}
    
    1 Var Declarations
        x : Size=4, Index=N
            Key : Lower : Value : Upper : Fixed : Stale : Domain
              0 :  None :  None :  None : False :  True :  Reals
              1 :  None :  None :  None : False :  True :  Reals
              2 :  None :  None :  None : False :  True :  Reals
              3 :  None :  None :  None : False :  True :  Reals