Search code examples
pyomo

Adding variables by a cross-product in Pyomo


I am trying to create a ConcreteModel using Pyomo. I have a list including the indices of the variable x_ij.

Xindex = [(619, 0), (620, 0), (621, 0), (622, 0), (623, 0), (624, 0), (625, 0), (626, 0), (627, 0), (628, 0), (619, 1), (620, 1), (621, 1), (622, 1), (623, 1), (624, 1), (625, 1), (626, 1), (627, 1), (628, 1), (1098, 2), (1099, 2), (1100, 2), (1101, 2), (1102, 2), (1103, 2), (1104, 2), (1105, 2), (1106, 2), (1107, 2), (1098, 3), (1099, 3), (1100, 3), (1101, 3), (1102, 3), (1103, 3), (1104, 3), (1105, 3), (1106, 3), (1107, 3), (619, 4), (620, 4), (621, 4), (622, 4), (623, 4), (624, 4), (625, 4), (626, 4), (627, 4), (628, 4), (1098, 5), (1099, 5), (1100, 5), (1101, 5), (1102, 5), (1103, 5), (1104, 5), (1105, 5), (1106, 5), (1107, 5), (1098, 6), (1099, 6), (1100, 6), (1101, 6), (1102, 6), (1103, 6), (1104, 6), (1105, 6), (1106, 6), (1107, 6), (1098, 7), (1099, 7), (1100, 7), (1101, 7), (1102, 7), (1103, 7), (1104, 7), (1105, 7), (1106, 7), (1107, 7), (1098, 8), (1099, 8), (1100, 8), (1101, 8), (1102, 8), (1103, 8), (1104, 8), (1105, 8), (1106, 8), (1107, 8), (1098, 9), (1099, 9), (1100, 9), (1101, 9), (1102, 9), (1103, 9), (1104, 9), (1105, 9), (1106, 9), (1107, 9), (1098, 10), (1099, 10), (1100, 10), (1101, 10), (1102, 10), (1103, 10), (1104, 10), (1105, 10), (1106, 10), (1107, 10), (1098, 11), (1099, 11), (1100, 11), (1101, 11), (1102, 11), (1103, 11), (1104, 11), (1105, 11), (1106, 11), (1107, 11), (1098, 12), (1099, 12), (1100, 12), (1101, 12), (1102, 12), (1103, 12), (1104, 12), (1105, 12), (1106, 12), (1107, 12)]

The first element of each tuple corresponds to an i and second one to a j. Using this list, I would like to add my variables to the model m. But, I do not see a straightforward method in the Pyomo User Manual. I tried the following and did not work.

m.Xindexi = Set(initialize=[i[0] for i in Xindex])
m.Xindexj = Set(initialize=[j[1] for j in Xindex])
m.Xindex = Set(within = m.Xindexi*m.Xindexj)
m.x = Var(m.Xindexi, m.Xindexj,domain=NonNegativeReals)

Isn't there a way to do this like a dictionary creation (similar to the one Gurobi's Python uses)? For example:

m.x = {}
for i in Xindex:
    m.x[i[0],i[1]] = Var(domain=NonNegativeReals)

Based on the accepted answer, this is what I have done to resolve the issue. Adding it here for future reference...

m.Xindexi = Set(initialize=set([i[0] for i in Xindex]))
m.Xindexj = Set(initialize=set([j[1] for j in Xindex]))
m.Xindex = Set(within = m.Xindexi*m.Xindexj,
                  initialize=Xindex)
m.x = Var(m.Xindex,domain=NonNegativeReals)

Solution

  • There are a bunch of ways to do this. The basic idea here is to make a sparse set of combinations of (i, j). You can either strictly enumerate that sparse set or if for other parts of your model, you need a fuller set of (i, j) and you only need this sparse set for some of the variables/parameters, you can construct it on-the-fly from data or from any set rules you gin up.

    Here are some examples:

    # pyomo set patterns
    from pyomo.environ import *
    
    m = ConcreteModel()
    
    # initialize two sets from data
    I_vals = {1, 5, 9}
    m.I = Set(initialize=I_vals)
    m.J = Set(initialize={2, 4, 88})  # either way works
    
    # crossed set from list of known combinations
    my_sparse_indices = {(1, 4), (1, 88), (5, 4)}
    m.IJ = Set(within=m.I * m.J, initialize=my_sparse_indices)
    
    # make a variable X, indexed by this sparse set
    m.X = Var(m.IJ, domain=NonNegativeReals)
    
    # make a parameter from the same sparse indices
    limit_dict = {(1, 4): 10, (1, 88): 20, (5,4): 30}
    m.lim = Param(m.IJ, initialize=limit_dict)
    
    m.pprint()
    
    #############
    
    m2 = ConcreteModel()
    
    m2.I = Set(initialize=range(4))
    m2.J = Set(initialize=range(3))
    
    # make full x-product
    m2.IJ = Set(within=m2.I * m2.J, 
                initialize=[(i, j) for i in m2.I for j in m2.J])
    
    # make a sparse set from selected values
    selected_vals = [(2,1), (1,1)]
    m2.IJ_selected = Set(within=m2.IJ, initialize=selected_vals)
    
    # make a sparse set by excluding prohibited values
    prohibited={(2,2), (3,1), (0,0)}
    IJ_without_prohibited = {(i, j) for i in m2.I
                                    for j in m2.J
                                    if (i, j) not in prohibited}
    m2.IJ_without_prohibited = Set(within=m2.IJ, initialize=IJ_without_prohibited)
    
    m2.pprint()
    

    The output for these is:

    4 Set Declarations
        I : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(1, 9)
            [1, 5, 9]
        IJ : Dim=0, Dimen=2, Size=3, Domain=IJ_domain, Ordered=False, Bounds=None
            [(1, 4), (1, 88), (5, 4)]
        IJ_domain : Dim=0, Dimen=2, Size=9, Domain=None, Ordered=False, Bounds=None
            Virtual
        J : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(2, 88)
            [2, 4, 88]
    
    1 Param Declarations
        lim : Size=3, Index=IJ, Domain=Any, Default=None, Mutable=False
            Key     : Value
             (1, 4) :    10
            (1, 88) :    20
             (5, 4) :    30
    
    1 Var Declarations
        X : Size=3, Index=IJ
            Key     : Lower : Value : Upper : Fixed : Stale : Domain
             (1, 4) :     0 :  None :  None : False :  True : NonNegativeReals
            (1, 88) :     0 :  None :  None : False :  True : NonNegativeReals
             (5, 4) :     0 :  None :  None : False :  True : NonNegativeReals
    
    6 Declarations: I J IJ_domain IJ X lim
    

    Second model:

    6 Set Declarations
        I : Dim=0, Dimen=1, Size=4, Domain=None, Ordered=False, Bounds=(0, 3)
            [0, 1, 2, 3]
        IJ : Dim=0, Dimen=2, Size=12, Domain=IJ_domain, Ordered=False, Bounds=None
            [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (3, 0), (3, 1), (3, 2)]
        IJ_domain : Dim=0, Dimen=2, Size=12, Domain=None, Ordered=False, Bounds=None
            Virtual
        IJ_selected : Dim=0, Dimen=2, Size=2, Domain=IJ, Ordered=False, Bounds=None
            [(1, 1), (2, 1)]
        IJ_without_prohibited : Dim=0, Dimen=2, Size=9, Domain=IJ, Ordered=False, Bounds=None
            [(0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (3, 0), (3, 2)]
        J : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(0, 2)
            [0, 1, 2]
    
    6 Declarations: I J IJ_domain IJ IJ_selected IJ_without_prohibited
    [Finished in 2.6s]