Search code examples
pythonoptimizationpyomo

Pyomo initializing and constraining 2xN variables


I have the following code, where I am trying to create a 2xN variable called x and initialize all columns in the first row to x0_init, and all columns in the second row to x1_init. After that I want to add initial and final boundary constraints to each row:

model = pyo.ConcreteModel()

N = 100

num_rows = range(2)
num_cols = range(N)

x0_init = 0.0
x1_init = 0.0

x0_final = 1.0
x1_final = 0.0

# Declaring and initializing 2xN state variable
model.x = pyo.Var(num_rows, num_cols, domain=pyo.Reals, initialize=[x0_init, x1_init])

# Declaring initial boundary constraints
model.initial_boundary_constraint_x0 = pyo.Constraint(expr=model.x[0,0] == x0_init)
model.initial_boundary_constraint_x1 = pyo.Constraint(expr=model.x[1,0] == x1_init)

# Declaring final boundary constraints
model.final_boundary_constraint_x0 = pyo.Constraint(expr=model.x[0,N-1] == x0_final)
model.final_boundary_constraint_x1 = pyo.Constraint(expr=model.x[1,N-1] == x1_final)

The above code of course does not work. However, I was hoping someone would be able to help me achieve the abovementioned goals. Looking through the pyomo documentation, I have unfortunately been unable to find a solution to this problem.


Solution

  • Here's a fix for you....

    A couple notes:

    • you generally do NOT need/want to initialize variables without some specific reason.
    • if you want to initialize, you have 2 choices: a dictionary that provides a value for every valid index. {(0,0): 0, (1, 0): 1, ...} or an initializer function as shown that returns a value for each call.
    • I put your row/column values into Sets within the model. It is usually good practice and better for QA, although it is not required as long as you are consistent with set members. So in your model, if you are referencing previous columns or such, you can do that if you are consistent with the numbering, or use some of the built in pyomo set operators.
    • Realize that if you have a variable and you are making a constraint to make that variable a set value..... then it isn't a variable, it's just a parameter, so your model, technically, could be simplified down by 1 column, but that is just nit-picky, it likely won't matter and if this expression makes sense to you, just stick with it.

    Code:

    import pyomo.environ as pyo
    
    model = pyo.ConcreteModel()
    
    num_rows = 2
    num_cols = 10
    
    x0_init = 0.0
    x1_init = 2.0
    
    x0_final = 4.0
    x1_final = 5.0
    
    # SETS
    model.R = pyo.Set(initialize=range(num_rows), doc='row')
    model.C = pyo.Set(initialize=range(num_cols), doc='col')
    
    # VARIABLES
    
    # NOTE:  INITIALIZING VARIABLES IS ALMOST NEVER NECESSARY.  Just
    #        showing how to do it as it is the same for parameters
    #        and was requested...
    def x_initializer(model, r, c):
        if r==0: 
            return x0_init
        return x1_init
    
    # Declaring and initializing 2xN state variable
    model.x = pyo.Var(model.R, model.C, domain=pyo.Reals, initialize=x_initializer)
    
    # CONSTRAINTS
    
    # Declaring initial boundary constraints
    model.initial_boundary_constraint_x0 = pyo.Constraint(expr=model.x[0, 0] == x0_init)
    model.initial_boundary_constraint_x1 = pyo.Constraint(expr=model.x[1, 0] == x1_init)
    
    # Declaring final boundary constraints
    model.final_boundary_constraint_x0 = pyo.Constraint(expr=model.x[0, model.C.last()] == x0_final)
    model.final_boundary_constraint_x1 = pyo.Constraint(expr=model.x[1, model.C.last()] == x1_final)
    
    model.pprint()