是否有一个可靠且文档齐全的Python库,其中 fast 实现了一种算法,可以在有向图中找到最大流量和最小割数?
来自pygraph.algorithms.minmax.maximum_flow的python-graph解决了这个问题,但速度非常缓慢:在一个有4000个节点和11000个边缘的有向图中找到最大流量和最小割数> 1分钟。我正在寻找至少快一个数量级的东西。
Bounty :我在这个问题上提供了一笔赏金,看看自从问到这个问题以来情况是否发生了变化。如果您对自己推荐的图书馆有个人经验,可以获得奖励积分!
答案 0 :(得分:21)
我使用graph-tool来执行类似的任务。
Graph-tool是一个高效的python模块,用于图形(a.k.a. networks)的操作和统计分析。他们甚至拥有关于max-flow algorithms的精湛文档。
目前图表工具支持给定的算法:
从文档中获取的示例:find maxflow using Boykov-Kolmogorov:
>>> g = gt.load_graph("flow-example.xml.gz") #producing example is in doc
>>> cap = g.edge_properties["cap"]
>>> src, tgt = g.vertex(0), g.vertex(1)
>>> res = gt.boykov_kolmogorov_max_flow(g, src, tgt, cap)
>>> res.a = cap.a - res.a # the actual flow
>>> max_flow = sum(res[e] for e in tgt.in_edges())
>>> print max_flow
6.92759897841
>>> pos = g.vertex_properties["pos"]
>>> gt.graph_draw(g, pos=pos, pin=True, penwidth=res, output="example-kolmogorov.png")
我用随机有向图(nodes = 4000,vertices = 23964)执行了这个例子,所有过程只需 11秒。
替代图书馆:
答案 1 :(得分:6)
我不知道它是否更快,你需要检查一下,但你试过networkx吗? 似乎它提供了您正在寻找的functionality,根据我的经验,它是一个非常易于使用的库来处理图形。
答案 2 :(得分:2)
SciPy(自1.4.0版开始)在scipy.sparse.csgraph.maximum_flow
中也有一个实现,可能易于用作构建链的一部分(因为可通过pip / conda获得该软件包)。
它通过处理表示图的邻接矩阵的稀疏矩阵(因此scipy.sparse
)来工作,因此,底层数据结构与金属接近,并且算法本身在Cython中实现,性能应该与例如图形工具。
在性能方面,不同实现的比较方式始终取决于您感兴趣的最大流量图的结构,但是作为一个简单的基准,我尝试通过NetworkX,图工具运行具有不同稀疏性的随机图和SciPy。它们都可以很好地与NumPy数组一起使用,因此,为了确保有一个公平的竞争环境,让我们创建一些方法,使每个方法都将NumPy数组作为形状(密度* 1000 * 1000,3)的输入,其行是边,其列是入射到给定边的两个顶点以及边的容量。
import numpy as np
from scipy.sparse import rand
def make_data(density):
m = (rand(1000, 1000, density=density, format='coo', random_state=42)*100).astype(np.int32)
return np.vstack([m.row, m.col, m.data]).T
data01 = make_data(0.1)
data03 = make_data(0.3)
data05 = make_data(0.5)
有了这个,各种框架可以如下计算最大流量的值:
import graph_tool.all as gt
from scipy.sparse import coo_matrix, csr_matrix
from scipy.sparse.csgraph import maximum_flow
import networkx as nx
def networkx_max_flow(data, primitive):
m = coo_matrix((data[:, 2], (data[:, 0], data[:, 1])))
G = nx.from_numpy_array(m.toarray(), create_using=nx.DiGraph())
return nx.maximum_flow_value(G, 0, 999, capacity='weight', flow_func=primitive)
def graph_tool_max_flow(data, primitive):
g = gt.Graph()
cap = g.new_edge_property('int')
eprops = [cap]
g.add_edge_list(data, eprops=eprops)
src, tgt = g.vertex(0), g.vertex(999)
res = primitive(g, src, tgt, cap)
res.a = cap.a - res.a
return sum(res[e] for e in tgt.in_edges())
def scipy_max_flow(data):
m = csr_matrix((data[:, 2], (data[:, 0], data[:, 1])))
return maximum_flow(m, 0, 999).flow_value
有了这个,IPython基准测试的例子就变成了
%timeit networkx_max_flow(data01, nx.algorithms.flow.shortest_augmenting_path)
%timeit graph_tool_max_flow(data03, gt.push_relabel_max_flow)
%timeit scipy_max_flow(data05)
然后我看到以下结果:
+----------------------------------------------+----------------+----------------+---------------+
| Algorithm | Density: 0.1 | Density: 0.3 | Density: 0.5 |
+----------------------------------------------+----------------+----------------+---------------+
| nx.algorithms.flow.edmonds_karp | 1.07s | 3.2s | 6.39s |
| nx.algorithms.flow.preflow_push | 1.07s | 3.27s | 6.18s |
| nx.algorithms.flow.shortest_augmenting_path | 1.08s | 3.25s | 6.23s |
| gt.edmonds_karp_max_flow | 274ms | 2.84s | 10s |
| gt.push_relabel_max_flow | 71ms | 466ms | 1.42s |
| gt.boykov_kolmogorov_max_flow | 79ms | 463ms | 895ms |
| scipy.sparse.csgraph.maximum_flow | 64ms | 234ms | 580ms |
+----------------------------------------------+----------------+----------------+---------------+
同样,结果将取决于图形结构,但这至少表明SciPy应该为您提供与图形工具同等的性能。
答案 3 :(得分:1)
为了获得非常好的性能,您可以尝试将问题重新设计为整数线性程序,任何标准ILP工具都应该为您提供足够的性能。
维基百科包含一个很好的商业和开源tools列表,其中许多似乎都有python绑定。其中最着名的是CPLEX和lp_solve。
我个人在过去几年中合理地使用了lp_solve,发现只需将输入写入lp_solve作为plain text files并使用shell调用lp_solve就足够了。回想一下,我可能应该投入更多精力来获得与lp_solve正式工作的官方python绑定。