Search code examples
variablesconstraintsmodelingpyomo

Possibility of indexing decision variables with 2 indices using a set of tuples in Pyomo


I am currently attempting to solve a network problem that is not fully connected.Thus,I have attempted to do some preprocessing of data so as to form a set of tuples, e.g. {(a,b , (c,e)}..., i.e. from a to b, from c to e.

I am able to declare binary decision variables with keys such as (a,b), (c,e), via using the set of tuples for indexing.

However, when I tried to use rules to declare constraints, with decision variables such as x[i][j], errors are thrown stating that (a,b) is an invalid index.

Hence, I would like to ask if tuples can be used as indices for decision variables.

If not, is there a way to only declare the only decision variables that are needed, rather than declaring all, and then setting those unneeded to 0.

Thank you!


Solution

  • Welcome to the site.

    You certainly CAN index variables with tuples of arbitrary dimensionality. The code I have below shows an example of indexing bad_X with a tuple of nodes. This makes sense when you have a variable that has a logical representation for all combinations of your indices or you control the indices somehow with smart set notation or you risk a whole bunch of nonsense variables as you can see in my example below with bad_X in the printout.

    For your network, I would suggest just making a set of ARCS that are the valid combination of the NODES. This set would just contain the tuples of the valid connections. Note in my example below, the set of NODES could be blown away as it is not needed. You could just create ARCS directly. Sometimes it is handy to have both if you have some node-based data like supply/demand.

    import pyomo.environ as pyo
    
    mdl = pyo.ConcreteModel()
    
    arc_data = {    ('a', 'b'): 10,
                    ('c', 'd'): 5,
                    ('e', 'j'): 44,
                    ('a', 'j'): 2,
                    ('j', 'e'): 12}
    
    # collapse the nodes into a set from the keys of the arc data
    node_set = set()
    for k in arc_data.keys():
        node_set.update(*k)
    
    
    # Sets
    mdl.NODES = pyo.Set(initialize=node_set)
    mdl.ARCS = pyo.Set(within=mdl.NODES * mdl.NODES, initialize=arc_data.keys())
    
    # Params
    mdl.cost = pyo.Param(mdl.NODES, mdl.NODES, initialize=arc_data)
    
    # Selection Variable:  poor choice...
    mdl.bad_X = pyo.Var(mdl.NODES, mdl.NODES, domain=pyo.Binary)
    
    # some examples of using this "bad X"
    print('printing just to show how to access...this will produce a None')
    print(mdl.bad_X['a', 'e'].value)
    print(mdl.bad_X[('c', 'd')].value)    # also valid
    
    # Better selection variable
    mdl.X = pyo.Var(mdl.ARCS, domain=pyo.Binary)
    
    # toy constraint...ensure at least 3 are selected
    mdl.c1 = pyo.Constraint(expr=sum(mdl.X[arc] for arc in mdl.ARCS) >= 3)
    
    # Objective:  Minimize cost of 3 selected arcs
    mdl.OBJ = pyo.Objective(expr=sum(mdl.X[arc] * mdl.cost[arc] for arc in mdl.ARCS))
    
    # to show the difference between the choices of variables
    mdl.pprint()
    
    # solve and show results
    solver = pyo.SolverFactory('cbc')
    results = solver.solve(mdl)
    for arc in mdl.ARCS:
        print(arc, mdl.X[arc].value)
    

    Output:

    printing just to show how to access...this will produce a None
    None
    None
    5 Set Declarations
        ARCS : Dim=0, Dimen=2, Size=5, Domain=ARCS_domain, Ordered=False, Bounds=None
            [('a', 'b'), ('a', 'j'), ('c', 'd'), ('e', 'j'), ('j', 'e')]
        ARCS_domain : Dim=0, Dimen=2, Size=36, Domain=None, Ordered=False, Bounds=None
            Virtual
        NODES : Dim=0, Dimen=1, Size=6, Domain=None, Ordered=False, Bounds=None
            ['a', 'b', 'c', 'd', 'e', 'j']
        bad_X_index : Dim=0, Dimen=2, Size=36, Domain=None, Ordered=False, Bounds=None
            Virtual
        cost_index : Dim=0, Dimen=2, Size=36, Domain=None, Ordered=False, Bounds=None
            Virtual
    
    1 Param Declarations
        cost : Size=5, Index=cost_index, Domain=Any, Default=None, Mutable=False
            Key        : Value
            ('a', 'b') :    10
            ('a', 'j') :     2
            ('c', 'd') :     5
            ('e', 'j') :    44
            ('j', 'e') :    12
    
    2 Var Declarations
        X : Size=5, Index=ARCS
            Key        : Lower : Value : Upper : Fixed : Stale : Domain
            ('a', 'b') :     0 :  None :     1 : False :  True : Binary
            ('a', 'j') :     0 :  None :     1 : False :  True : Binary
            ('c', 'd') :     0 :  None :     1 : False :  True : Binary
            ('e', 'j') :     0 :  None :     1 : False :  True : Binary
            ('j', 'e') :     0 :  None :     1 : False :  True : Binary
        bad_X : Size=36, Index=bad_X_index
            Key        : Lower : Value : Upper : Fixed : Stale : Domain
            ('a', 'a') :     0 :  None :     1 : False :  True : Binary
            ('a', 'b') :     0 :  None :     1 : False :  True : Binary
            ('a', 'c') :     0 :  None :     1 : False :  True : Binary
            ('a', 'd') :     0 :  None :     1 : False :  True : Binary
            ('a', 'e') :     0 :  None :     1 : False :  True : Binary
            ('a', 'j') :     0 :  None :     1 : False :  True : Binary
            ('b', 'a') :     0 :  None :     1 : False :  True : Binary
            ('b', 'b') :     0 :  None :     1 : False :  True : Binary
            ('b', 'c') :     0 :  None :     1 : False :  True : Binary
            ('b', 'd') :     0 :  None :     1 : False :  True : Binary
            ('b', 'e') :     0 :  None :     1 : False :  True : Binary
            ('b', 'j') :     0 :  None :     1 : False :  True : Binary
            ('c', 'a') :     0 :  None :     1 : False :  True : Binary
            ('c', 'b') :     0 :  None :     1 : False :  True : Binary
            ('c', 'c') :     0 :  None :     1 : False :  True : Binary
            ('c', 'd') :     0 :  None :     1 : False :  True : Binary
            ('c', 'e') :     0 :  None :     1 : False :  True : Binary
            ('c', 'j') :     0 :  None :     1 : False :  True : Binary
            ('d', 'a') :     0 :  None :     1 : False :  True : Binary
            ('d', 'b') :     0 :  None :     1 : False :  True : Binary
            ('d', 'c') :     0 :  None :     1 : False :  True : Binary
            ('d', 'd') :     0 :  None :     1 : False :  True : Binary
            ('d', 'e') :     0 :  None :     1 : False :  True : Binary
            ('d', 'j') :     0 :  None :     1 : False :  True : Binary
            ('e', 'a') :     0 :  None :     1 : False :  True : Binary
            ('e', 'b') :     0 :  None :     1 : False :  True : Binary
            ('e', 'c') :     0 :  None :     1 : False :  True : Binary
            ('e', 'd') :     0 :  None :     1 : False :  True : Binary
            ('e', 'e') :     0 :  None :     1 : False :  True : Binary
            ('e', 'j') :     0 :  None :     1 : False :  True : Binary
            ('j', 'a') :     0 :  None :     1 : False :  True : Binary
            ('j', 'b') :     0 :  None :     1 : False :  True : Binary
            ('j', 'c') :     0 :  None :     1 : False :  True : Binary
            ('j', 'd') :     0 :  None :     1 : False :  True : Binary
            ('j', 'e') :     0 :  None :     1 : False :  True : Binary
            ('j', 'j') :     0 :  None :     1 : False :  True : Binary
    
    1 Objective Declarations
        OBJ : Size=1, Index=None, Active=True
            Key  : Active : Sense    : Expression
            None :   True : minimize : 10*X[a,b] + 5*X[c,d] + 44*X[e,j] + 2*X[a,j] + 12*X[j,e]
    
    1 Constraint Declarations
        c1 : Size=1, Index=None, Active=True
            Key  : Lower : Body                                       : Upper : Active
            None :   3.0 : X[a,b] + X[c,d] + X[e,j] + X[a,j] + X[j,e] :  +Inf :   True
    
    10 Declarations: NODES ARCS_domain ARCS cost_index cost bad_X_index bad_X X c1 OBJ
    ('a', 'b') 1.0
    ('c', 'd') 1.0
    ('e', 'j') 0.0
    ('a', 'j') 1.0
    ('j', 'e') 0.0
    [Finished in 4.3s]