最短路径LP公式:反向链接取值为1

时间:2018-02-11 16:26:32

标签: python-3.x shortest-path linear-programming pulp

我正在尝试使用python中的PuLP包实现最短路径问题的ILP公式。输入是使用NetworkX包生成的图形。

import networkx as nx
import pulp
import random
import matplotlib.pyplot as plt

g = nx.to_directed(nx.barabasi_albert_graph(20, 2))
# nx.draw(g, with_labels=True)
# plt.show()
source = 0
target = 13

dict_d = {}
for i, j in g.edges:
    dict_d[i, j] = dict_d[j, i] = round(random.uniform(1.0, 20.0), 2)

nx.set_edge_attributes(g, dict_d, 'delay')

# instantiate
prob = pulp.LpProblem("Shortest Path Problem", pulp.LpMinimize)
cost = nx.get_edge_attributes(g, 'delay')

# binary variable to state a link is chosen or not
var_dict = {}
for (i, j) in g.edges:
    x = pulp.LpVariable("x_(%s_%s)" % (i,j), cat=pulp.LpBinary)
    var_dict[i, j] = x

# objective function
prob += pulp.lpSum([cost[i, j] * var_dict[i, j] for i, j in g.edges]), "Total Hop Count"

# constraints
for node in g.nodes:
    if node == source:
        prob += pulp.lpSum([var_dict[i, k] for i, k in g.edges if k == node]) - \
                pulp.lpSum([var_dict[k, j] for k, j in g.edges if k == node]) == 1
    elif node == target:
        prob += pulp.lpSum([var_dict[i, k] for i, k in g.edges if k == node]) - \
                pulp.lpSum([var_dict[k, j] for k, j in g.edges if k == node]) == -1
    else:
        prob += pulp.lpSum([var_dict[i, k] for i, k in g.edges if k == node]) - \
                pulp.lpSum([var_dict[k, j] for k, j in g.edges if k == node]) == 0

# solve
prob.solve(pulp.GUROBI_CMD(msg=0))

print(pulp.LpStatus[prob.status])
print(pulp.value(prob.objective))
print("The shortest path is ")
for link in g.edges:
    if var_dict[link].value() == 1.0:
        print(link, end=" ")

如果我使用无向图,则流量约束守恒不起作用,因为图中不存在反向边缘。

prob += pulp.lpSum([var_dict[i, k] for i, k in g.edges if k == node]) - \
                pulp.lpSum([var_dict[k, j] for k, j in g.edges if k == node]) == 1 

另一方面,在使用有向图时,反向边的指标变量取值,导致输出

The shortest path is (1, 2) (2, 0) (13, 1) 

当输出应为(0,2)(2,1)(1,13)

所以我的问题是双管齐下的:

  1. 对于最短路径问题,是否有更好的LP配方表示,完全避免了这个问题?
  2. 如果失败了,如何获得有意义的路径作为输出?阻止反向弧线取值?从我现在得到的输出中以某种方式获取路径?

1 个答案:

答案 0 :(得分:2)

  

如果我使用无向图,则流量约束的守恒确实如此   由于图中没有反向边缘,因此无法正常工作。

事实并非如此:我使用prob.writeLP('eyes.lp')检查余额约束,似乎存在反向边缘。

  

另一方面,在使用有向图时,指标   反向边的变量取值,导致输出

The shortest path is (1, 2) (2, 0) (13, 1)
     

当输出应为(0,2)(2,1)(1,13)

这里的问题是源和目标约束的符号被翻转:注意你的解决方案从目标到源而不是从源到目标。如果您更改了标志,它将正常工作:

# constraints
for node in g.nodes:
    rhs = 0
    if node == source:
        rhs = -1
    elif node == target:
        rhs = 1
    prob += pulp.lpSum([var_dict[i, k] for i, k in g.edges if k == node]) - \
            pulp.lpSum([var_dict[k, j] for k, j in g.edges if k == node]) == rhs
  

是否有更好的代表性的LP配方   完全避免这个问题的最短路径问题?

LP配方是正确的。

  

如果失败了,如何获得有意义的路径作为输出?停止反向   弧度取决于价值?从我的输出中以某种方式获取路径   现在开始?

修复标志应使其有效。