Search code examples
pythonmatrixoptimizationsetpyomo

Pyomo: how to work with 2D arrays or Sets


I have a matrix that carries different integer status per cell. I simply want to constrain each cell by a specific rule but pyomo doesn't comprehend the datatype.

Here's what I have

import pyomo.environ as pe

def assign_server_locations(model, i, j):
    return model[i, j] >= 0 


server_map = [[-1,1],[2,-2],[-3,3]]
model = pe.ConcreteModel()

model.server_x = range(2)
model.server_y = range(3)
model.server_map = pe.Set(dimen = 2, initialize = server_map)
model.c1 = pe.Constraint(model.server_map, model.server_y, model.server_x, rule=assign_server_locations)

the error around the Constraint creation is

TypeError: assign_server_locations() takes 3 positional arguments but 5 were given

How can:

  • a 2D-Matrix be correctly created
  • the indices correctly passed to the rule function (I was expecting in total 3 parameters: model and single x-y index per call)

Thanks in advance!


Solution

  • Welcome to the site...

    You've got a handful of problems there... Briefly:

    • the constraint construction is puking because you are handing it 5 values (the model, 2 for server.map, and x, and y.) and you are only catching 3

    • in your constraint, you have no variable! model[i, j] is going to cause an error. You need to create a properly indexed variable.

    • you are creating some model elements (like model.x and model.y as non-pyomo elements. I'd recommend you keep them as pyomo elements, it helps with troubleshooting.

    Here is an example that I think does a bunch of stuff similar to what you are looking for.

    import pyomo.environ as pe
    
    
    matrix_dims = (4, 2)  # row, col
    limit_positions = { (2, 1): 2,
                        (1, 0): 1,
                        (3, 1): 2}
    
    model = pe.ConcreteModel()
    
    # SETS
    model.server_x = pe.Set(initialize=range(matrix_dims[0]))  # may come in handy to total by rows or such.  Also, make it a pyomo Set
    model.server_y = pe.Set(initialize=range(matrix_dims[1]))
    model.matrix = pe.Set(initialize=model.server_x*model.server_y)
    model.low_positions = pe.Set(within=model.matrix, initialize=limit_positions.keys())   # use of "within" will error-check
    
    # PARAMS
    model.limit_positions = pe.Param(model.low_positions, initialize=limit_positions)
    
    # VARS
    model.X = pe.Var(model.matrix, domain=pe.NonNegativeReals)
    
    # CONSTRAINTS
    # limit all positions to max of 5
    def limit_all(model, i, j):
        return model.X[i, j] <= 5
    model.C1 = pe.Constraint(model.matrix, rule=limit_all)
    
    # limit the low-positions to their limit...
    def limit_lows(model, i, j):
        return model.X[i, j] <= model.limit_positions[i, j]
    model.C2 = pe.Constraint(model.low_positions, rule=limit_lows)
    
    model.pprint()
    

    Yields:

    4 Set Declarations
        low_positions : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     2 : matrix :    3 : {(2, 1), (1, 0), (3, 1)}
        matrix : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     2 :    Any :    8 : {(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)}
        server_x : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    4 : {0, 1, 2, 3}
        server_y : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    2 : {0, 1}
    
    1 Param Declarations
        limit_positions : Size=3, Index=low_positions, Domain=Any, Default=None, Mutable=False
            Key    : Value
            (1, 0) :     1
            (2, 1) :     2
            (3, 1) :     2
    
    1 Var Declarations
        X : Size=8, Index=matrix
            Key    : Lower : Value : Upper : Fixed : Stale : Domain
            (0, 0) :     0 :  None :  None : False :  True : NonNegativeReals
            (0, 1) :     0 :  None :  None : False :  True : NonNegativeReals
            (1, 0) :     0 :  None :  None : False :  True : NonNegativeReals
            (1, 1) :     0 :  None :  None : False :  True : NonNegativeReals
            (2, 0) :     0 :  None :  None : False :  True : NonNegativeReals
            (2, 1) :     0 :  None :  None : False :  True : NonNegativeReals
            (3, 0) :     0 :  None :  None : False :  True : NonNegativeReals
            (3, 1) :     0 :  None :  None : False :  True : NonNegativeReals
    
    2 Constraint Declarations
        C1 : Size=8, Index=matrix, Active=True
            Key    : Lower : Body   : Upper : Active
            (0, 0) :  -Inf : X[0,0] :   5.0 :   True
            (0, 1) :  -Inf : X[0,1] :   5.0 :   True
            (1, 0) :  -Inf : X[1,0] :   5.0 :   True
            (1, 1) :  -Inf : X[1,1] :   5.0 :   True
            (2, 0) :  -Inf : X[2,0] :   5.0 :   True
            (2, 1) :  -Inf : X[2,1] :   5.0 :   True
            (3, 0) :  -Inf : X[3,0] :   5.0 :   True
            (3, 1) :  -Inf : X[3,1] :   5.0 :   True
        C2 : Size=3, Index=low_positions, Active=True
            Key    : Lower : Body   : Upper : Active
            (1, 0) :  -Inf : X[1,0] :   1.0 :   True
            (2, 1) :  -Inf : X[2,1] :   2.0 :   True
            (3, 1) :  -Inf : X[3,1] :   2.0 :   True
    
    8 Declarations: server_x server_y matrix low_positions limit_positions X C1 C2