简体   繁体   中英

Pyomo create a constraint based on an indexed set

I have a set of constraint that is given as follows:

for all n in N, for all i in l(n): ...

N is a set of nodes, in a concrete model in Pyomo:

model.Nodes = pyo.Set(initialize = range(len(nodes)))

Each node has a different length. I need a RangeSet for each node running from 0 to its respective range. This, I solved as follows:

longest_node = max(map(len, nodes))
model.Lengths = pyo.Set(initialize = list(range(longest_node)))
model.NodeRangeSet = pyo.Set(model.nodes, within = model.Lengths, initialize = lambda model, node: list(range(len(nodes[node]))))

Which gives for eg 3 nodes of length 1, 3 and 2:

NodeRangeSet : Size=3, Index=Nodes, Ordered=Insertion
    Key : Dimen : Domain   : Size : Members
     0  :     1 : Lengths  :    1 : {0}
     1  :     1 : Lengths  :    3 : {0, 1, 2}
     2  :     1 : Lengths  :    2 : {0, 1}

But what I am seemingly not able to is to create a constraint as desired eg

model.Constr = model.Constraint(model.Nodes, model.NodeRangeSet[model.Nodes]
    rule = lambda model, node, offset: some_condition)

How do I replace this placeholder model.NodeRangeSet[model.Nodes] correctly? The number of nodes, as well as their lengths depends solely on the given input parameter. So each node in the constraint has its own RangeSet. Is there a completely different approach I can/have to take?

Here is an example that I think covers the topic well along with a few variants. The basic answer to your question is that if you want to use your indexed set within the constraint, then just put it in the constraint body (or rule) and pass in the index ( node ) to get what you want. If you want to "flatten it" and produce a constraint for all combinations (which would be weird because the values in the indexed set are tied to the value of the main set), you could make a product of the 2 sets with a set comprehension or some such.

Anyhow, the below shows how I would set up the key sets for a similar problem, one with nodes , another that is indexed by node , which is the connections, and perhaps, if needed, a flat set of all the legal combinations.

Also shown are 3 styles of constraints using these, depending on what "the math" is for the summations and what the "for each" statement is.

Code

import pyomo.environ as pyo

# some data for nodes & connections for a directed graph
graph = {   1: [2, 3, 4],
            2: [3,],
            3: [1, 4],
            4: [2, 3]
        }
connections = [(s, t) for s in graph.keys() for t in graph[s]]

m = pyo.ConcreteModel('graph')

# SETS
m.N = pyo.Set(initialize=graph.keys())                      # the set of all nodes
m.C = pyo.Set(m.N, within=m.N, initialize=graph)            # set of all connections, indexed by node
m.NN = pyo.Set(within=m.N * m.N, initialize=connections)    # a flat set of all "legal", directed arcs

# VARS
# initializing with only the legal connections keeps this small (it is only 8 members vs. 16)
m.traffic = pyo.Var(m.NN, domain=pyo.NonNegativeReals)

# CONSTRAINTS

# an outbound "traffic" constraint *for each node*
def traffic(m, node):
    return sum(m.traffic[node, other] for other in m.C[node]) <= 4
m.C1 = pyo.Constraint(m.N, rule=traffic)

# a traffic restriction *for each arc*
def arc_traffic(m, node, other):
    return m.traffic[node, other] <= 3
m.C2 = pyo.Constraint(m.NN, rule=arc_traffic)

# flow balance at each node *for each node* using an internally generated set/list
def flow_balance(m, node):
    # we can make an "on the fly" list from model parts, as needed...
    inbound_arcs = [s for (s, other) in m.NN if other==node]
    return sum(m.traffic[s, node] for s in inbound_arcs) == sum(m.traffic[node, t] for t in m.C[node])
m.C3 = pyo.Constraint(m.N, rule=flow_balance)

m.pprint()

Yields:

4 Set Declarations
    C : Size=4, Index=N, Ordered=Insertion
        Key : Dimen : Domain : Size : Members
          1 :     1 :      N :    3 : {2, 3, 4}
          2 :     1 :      N :    1 : {3,}
          3 :     1 :      N :    2 : {1, 4}
          4 :     1 :      N :    2 : {2, 3}
    N : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    4 : {1, 2, 3, 4}
    NN : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain    : Size : Members
        None :     2 : NN_domain :    8 : {(1, 2), (1, 3), (1, 4), (2, 3), (3, 1), (3, 4), (4, 2), (4, 3)}
    NN_domain : Size=1, Index=None, Ordered=True
        Key  : Dimen : Domain : Size : Members
        None :     2 :    N*N :   16 : {(1, 1), (1, 2), (1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4), (3, 1), (3, 2), (3, 3), (3, 4), (4, 1), (4, 2), (4, 3), (4, 4)}

1 Var Declarations
    traffic : Size=8, Index=NN
        Key    : Lower : Value : Upper : Fixed : Stale : Domain
        (1, 2) :     0 :  None :  None : False :  True : NonNegativeReals
        (1, 3) :     0 :  None :  None : False :  True : NonNegativeReals
        (1, 4) :     0 :  None :  None : False :  True : NonNegativeReals
        (2, 3) :     0 :  None :  None : False :  True : NonNegativeReals
        (3, 1) :     0 :  None :  None : False :  True : NonNegativeReals
        (3, 4) :     0 :  None :  None : False :  True : NonNegativeReals
        (4, 2) :     0 :  None :  None : False :  True : NonNegativeReals
        (4, 3) :     0 :  None :  None : False :  True : NonNegativeReals

3 Constraint Declarations
    C1 : Size=4, Index=N, Active=True
        Key : Lower : Body                                       : Upper : Active
          1 :  -Inf : traffic[1,2] + traffic[1,3] + traffic[1,4] :   4.0 :   True
          2 :  -Inf :                               traffic[2,3] :   4.0 :   True
          3 :  -Inf :                traffic[3,1] + traffic[3,4] :   4.0 :   True
          4 :  -Inf :                traffic[4,2] + traffic[4,3] :   4.0 :   True
    C2 : Size=8, Index=NN, Active=True
        Key    : Lower : Body         : Upper : Active
        (1, 2) :  -Inf : traffic[1,2] :   3.0 :   True
        (1, 3) :  -Inf : traffic[1,3] :   3.0 :   True
        (1, 4) :  -Inf : traffic[1,4] :   3.0 :   True
        (2, 3) :  -Inf : traffic[2,3] :   3.0 :   True
        (3, 1) :  -Inf : traffic[3,1] :   3.0 :   True
        (3, 4) :  -Inf : traffic[3,4] :   3.0 :   True
        (4, 2) :  -Inf : traffic[4,2] :   3.0 :   True
        (4, 3) :  -Inf : traffic[4,3] :   3.0 :   True
    C3 : Size=4, Index=N, Active=True
        Key : Lower : Body                                                                       : Upper : Active
          1 :   0.0 :                traffic[3,1] - (traffic[1,2] + traffic[1,3] + traffic[1,4]) :   0.0 :   True
          2 :   0.0 :                                 traffic[1,2] + traffic[4,2] - traffic[2,3] :   0.0 :   True
          3 :   0.0 : traffic[1,3] + traffic[2,3] + traffic[4,3] - (traffic[3,1] + traffic[3,4]) :   0.0 :   True
          4 :   0.0 :                traffic[1,4] + traffic[3,4] - (traffic[4,2] + traffic[4,3]) :   0.0 :   True

8 Declarations: N C NN_domain NN traffic C1 C2 C3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM