我有一个问题,因为问题不是优化,我正在尝试使用二进制变量 x 来确定是否使用了边,因为应该最小化使用的边数。问题是当边的 Q 大于零时,我无法将正确的值分配给 x=1。目标函数或约束 7 中肯定存在问题。这是我正在运行的代码:
import matplotlib.pyplot as plt
import networkx as nx
import pyomo.environ as pe
import pyomo.opt as po
import pandas as pd
import numpy as np
d = pd.read_excel("Grafo9Nodi_Bil.xlsx",header=0, index_col=0) #importo le posizioni dal file Excel
#impongo una lunghezza massima del singolo arco
LunMax=8
nodes = range(0,len((d["X"])))
distance = {}
pos={}
edges={}
for i in sorted(nodes):
pos[i]=(d["X"][i],d["Y"][i])
for j in sorted(nodes):
if i!=j and np.round(pe.sqrt((d["X"][i]-d["X"][j])**2+(d["Y"][i]-d["Y"][j])**2),2)<=LunMax:
distance [i,j]=np.round(pe.sqrt((d["X"][i]-d["X"][j])**2+(d["Y"][i]-d["Y"][j])**2),2)
edges={(i,j) for i in sorted(nodes) for j in sorted(nodes) if i!=j and np.round(pe.sqrt((d["X"][i]-d["X"][j])**2+(d["Y"][i]-d["Y"][j])**2),2)<=LunMax}
model = pe.ConcreteModel()
path_edges = []
model.nodes = pe.Set(initialize=nodes)
model.edges = pe.Set(within=model.nodes*model.nodes, initialize=edges)
model.IN = pe.Var(model.nodes, domain=pe.NonNegativeReals,initialize=0)
IN=model.IN
model.x = pe.Var(model.nodes*model.nodes, domain=pe.Binary,initialize=0)
x=model.x
model.Q = pe.Var(model.nodes*model.nodes, domain=pe.NonNegativeReals)
Q=model.Q
model.OUT = pe.Var(model.nodes, domain=pe.NonNegativeReals,initialize=0)
OUT=model.OUT
#funzione obiettivo
def obj_rule(model):
TCC=sum(d["OpexC"][i]*IN[i] for i in model.nodes)
TTC=sum(Q[i,j]*1*distance[i,j] if Q[i,j] is not None and Q[i,j].value != 0 else 0 for [i,j] in model.edges)+sum(distance [i,j]*4*x[i,j] for [i,j] in model.edges if x[i,j].value != None and x[i,j].value != 0)
TSC=sum(d["OpexS"][i]*OUT[i] for i in model.nodes)
return TCC+TTC+TSC
model.Objf= pe.Objective (rule=obj_rule, sense = pe.minimize)
#vincoli
def constraint1(model,nodes):
return IN[nodes] <= d["IN"][nodes]
model.Const1=pe.Constraint(model.nodes, rule=constraint1)
def constraint2(model,nodes):
return sum(IN[nodes] for nodes in model.nodes) >= 1*sum(d["IN"][nodes] for nodes in model.nodes)
model.Const2=pe.Constraint(model.nodes, rule=constraint2)
def constraint4(model,nodes):
return IN[nodes]+sum(Q[i,nodes] for i in model.nodes if [i,nodes] in model.edges) == sum(Q[nodes,i] for i in model.nodes if [i,nodes] in model.edges) +OUT[nodes]
model.Const4=pe.Constraint(model.nodes, rule=constraint4)
def constraint5(model,nodes):
return OUT[nodes] <= d["OUT"][nodes]
model.Const5=pe.Constraint(model.nodes, rule=constraint5)
def constraint6(model,nodes):
return sum(IN[nodes] for nodes in model.nodes) == sum(OUT[nodes] for nodes in model.nodes)
model.Const6=pe.Constraint(model.nodes, rule=constraint6)
def constraint7(model, i, j):
if Q[i,j].value != 0:
return x[i,j] == 1
else:
return x[i,j] == 0
model.Const7 = pe.Constraint(model.edges, rule=constraint7)
Solver = po.SolverFactory ('gurobi', tee=True)
results = Solver.solve(model)
结果没有优化,因为 x[i,j] 都等于 1 而 Q[i,j] 有不同的值。在此先感谢您的帮助
这里有几件事可以帮助你。这看起来确实像是一个家庭作业项目,所以我不愿意为你写下整个事情。
pyomo
错误/提示:您不能在构建模型时使用条件(
if
)语句或.value
。编写模型时,变量的值是 unknown。那是求解器的工作。您将需要重新制定一些约束和目标陈述。对于这种类型的模型可以这样做。
您的约束在变量中存在“名称冲突”。您正在覆盖从函数参数中获取的变量。例如在你的约束下:
def constraint2(model,nodes):
return sum(IN[nodes] for nodes in model.nodes) >= 1*sum(d["IN"][nodes] for nodes in model.nodes)
model.Const2=pe.Constraint(model.nodes, rule=constraint2)
……
nodes
指的是什么?您正在捕获它,但是您在求和中使用了相同的变量名称。如果你想为每个节点写一个约束,如果你要使用一个总和,你需要不要覆盖。
model.pprint()
您的边缘设置看起来不错,那么为什么不将其用于流和使用变量以将它们限制在您制作的边缘上?我希望:
model.q = pe.Var(model.edges, domain=pe.NonNegativeReals, doc='flow')
为了处理流量约束的平衡,您将需要组织您的边缘,以便您可以找到流入或流出每个节点的边缘。有几种方法可以做到这一点,但也许最简单的就是制作一些字典……这里有几个想法:
from collections import defaultdict
import pyomo.environ as pe
nodes = [1, 2, 3, 4, 5]
edges = [(1, 3), (1, 4), (5, 2)]
edges_out_of_node_dict = defaultdict(list)
for edge in edges:
edges_out_of_node_dict[edge[0]].append(edge)
print(edges_out_of_node_dict)
m = pe.ConcreteModel('flow')
m.N = pe.Set(initialize=nodes)
m.E = pe.Set(within=m.N*m.N, initialize=edges)
m.q = pe.Var(m.E, domain=pe.NonNegativeReals, doc='flow')
# example constraint: the total flow out of each connected node is less than 5
def outflow_limit(m, node):
return sum(m.q[edge] for edge in edges_out_of_node_dict[node]) <= 5
# we only want to apply this to nodes that have outbound arcs or we will get a key error, so...
nodes_with_connections = edges_out_of_node_dict.keys()
m.constraint1 = pe.Constraint(nodes_with_connections, rule=outflow_limit, doc='outflow limit')
m.pprint()
defaultdict(<class 'list'>, {1: [(1, 3), (1, 4)], 5: [(5, 2)]})
4 Set Declarations
E : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : E_domain : 3 : {(1, 3), (1, 4), (5, 2)}
E_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
None : 2 : N*N : 25 : {(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}
N : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 5 : {1, 2, 3, 4, 5}
constraint1_index : Size=1, Index=None, Ordered=False
Key : Dimen : Domain : Size : Members
None : 1 : Any : 2 : {1, 5}
1 Var Declarations
q : flow
Size=3, Index=E
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 3) : 0 : None : None : False : True : NonNegativeReals
(1, 4) : 0 : None : None : False : True : NonNegativeReals
(5, 2) : 0 : None : None : False : True : NonNegativeReals
1 Constraint Declarations
constraint1 : outflow limit
Size=2, Index=constraint1_index, Active=True
Key : Lower : Body : Upper : Active
1 : -Inf : q[1,3] + q[1,4] : 5.0 : True
5 : -Inf : q[5,2] : 5.0 : True
6 Declarations: N E_domain E q constraint1_index constraint1