简体   繁体   English

Pyomo 基于索引集创建约束

[英]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: N 是一组节点,在 Pyomo 的具体 model 中:

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.对于从 0 到其各自范围的每个节点,我需要一个 RangeSet。 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:例如,它给出了长度为 1、3 和 2 的 3 个节点:

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?如何正确替换此占位符model.NodeRangeSet[model.Nodes] 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.所以约束中的每个节点都有自己的 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.你的问题的基本答案是,如果你想在约束中使用你的索引集,那么只需将它放在约束体(或规则)中并传入索引( node )以获得你想要的。 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.如果你想“展平它”并为所有组合产生一个约束(这会很奇怪,因为索引集中的值与主集的值相关联),你可以用一个集合制作 2 个集合的乘积理解之类的。

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.无论如何,下面显示了我将如何为类似问题设置密钥集,一个带有nodes ,另一个由node索引,这是连接,如果需要,可能还有所有合法组合的平面集。

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.还显示了使用这些约束的 3 styles,具体取决于求和的“数学”以及“每个”语句的含义。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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