How do I dynamically add variables to list in Pyomo?

Question:

As part of a BuildAction rule that gets triggered on creation of a concrete model, I am dynamically creating additional "internal" decision variables (dependent on data supplied at construction time).

As well as creating these variables (which get used in constraint expressions), I know that I also need to add them to the model to avoid the "Variable ‘XXX’ is not part of the model being written out, but appears in an expression used on this model." error.

The VarList class seems designed for this (by analogy to the ConstraintList class which I am already successfully using for dynamically created constraints). However, I cannot find documentation for how to populate a VarList from pre-created variables. I can create a VarList and add variables to it, but this does not give me the control I need over how the variables are created…

import pyomo.environ as pyo

self.vl = pyo.VarList()
newVar = self.vl.add() # this does not give me control over the variable creation
# and I can't set all required properties of newVar, once created

It seems that I should be able to create a VarList by passing a dictionary of variables, but I cannot find documentation or examples that show how this works.

Asked By: Plug1

||

Answers:

VarList works pretty similar to an IndexedVar in Pyomo. You need to understand a couple of things:

  1. The variable index is constantly changing. This means that you need to check the actual length to avoid adding variables that you won’t use, or to use variable that have not been added.

  2. The VarList().add() method adds variables of the same type as in VarList(). For example, if VarList() was created as an Integer or NonNegativeReal variable, all variables you will add will be Integer or NonNegativeReal, respectively.

Here’s example to show you how it works:

import pyomo.environ as pyo

# Create the model
model = pyo.ConcreteModel()
# Add variables in a loop
model.x = pyo.VarList(domain=pyo.Integers)
for i in range(2):
    model.x.add()    # Add a new index to defined variable x
# Adding constraints
# Indexed variable starts at 1 and not in 0
model.myCons1 = pyo.Constraint(expr=2*model.x[1] + 0.5*model.x[2] <=20)
model.myCons2 = pyo.Constraint(expr=2+model.x[1] + 3*model.x[2] <=25)
# Add an objective
model.Obj = pyo.Objective(expr=model.x[1] + model.x[2], sense=pyo.maximize)

# Solve using Gurobi
solver = pyo.SolverFactory('gurobi')
solver.solve(model, tee=True)
# Display the x variable results
model.x.display()

This leads to the following output (showing only the relevant part):

Optimal solution found (tolerance 1.00e-04)
Best objective 1.300000000000e+01, best bound 1.300000000000e+01, gap 0.0000%
x : Size=2, Index=x_index
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      1 :  None :   8.0 :  None : False : False : Integers
      2 :  None :   5.0 :  None : False : False : Integers

If you start using the kernel modeling layer you can also use the pyomo.kernel.variable_list class, which works pretty similar to this approach. You can check it in the Pyomo documentation with the difference that you can assign different types of variables to the same list.

I don’t fully understand what you are modeling, but you can always use an AbstractModel() class and then populate it with some external data (from a .dat file or a dict, etc.) using model.create_instance(data=data). In this way, your model is always parameterized by some defined sets.

Answered By: pybegginer
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.