pythonigraph:获取有向图中所有可能的路径
我正在使用igraph(Python)并希望获得有向图中两个节点之间的所有可能路径。我知道函数pythonigraph:获取有向图中所有可能的路径,python,graph,path,igraph,Python,Graph,Path,Igraph,我正在使用igraph(Python)并希望获得有向图中两个节点之间的所有可能路径。我知道函数get_all_shortest_path,用于最短路径,但找不到通用路径 更新: 我的主要目标是获取这些路径中的所有节点,这样我就可以得到这些节点的子图。我不能确定,但在python igraph文档中查找几分钟后,似乎不存在这样的函数。我停止寻找,因为在我看来,这些信息并不是真正有用的,至少如果我是一名开发人员,我不会创建它。回到问题上来: 首先,您需要了解,对于任意图,此类路径的数量是无限的。您只
get_all_shortest_path
,用于最短路径,但找不到通用路径
更新:
我的主要目标是获取这些路径中的所有节点,这样我就可以得到这些节点的子图。我不能确定,但在python igraph文档中查找几分钟后,似乎不存在这样的函数。我停止寻找,因为在我看来,这些信息并不是真正有用的,至少如果我是一名开发人员,我不会创建它。回到问题上来: 首先,您需要了解,对于任意图,此类路径的数量是无限的。您只需要一个循环,就可以创建无限多的路径。所以为了使这个数是有限的,它应该是有限的 因此,如果您有一个DAG,您可以使用并递归计算所有路径(请注意,您将以指数图结束,并且很可能无法在合理的时间内找到一个答案,即使对于一个合理的大型图)。我不是自己写代码的,只是在谷歌上搜索了一下,看起来(基本上他是在做DFS)
我没有检查它是否产生正确的结果。因为您在问题中提到,您的最终目标是只获取这些路径中的节点,而不是路径本身,所以我认为您甚至不必计算路径 igraph中的
图形
对象有一个名为子组件
的方法。默认情况下,它为您提供与给定输入节点位于同一(弱连接)组件中的所有节点。但是,它也有一个模式
参数。当您将模式设置为“out”
时,它将为您提供从某个节点可以访问的所有节点。当您在“
”中将模式设置为”时,它将为您提供可以到达某个节点的所有节点。因此,您可能需要源顶点的可到达节点集与可到达目标顶点的节点集的交点:
s=set(graph.subcomponent(source, mode="out"))
t=set(graph.subcomponent(target, mode="in"))
s.intersection(t)
无论如何,这可能比计算所有路径快得多。igraph的作者之一Tamás提出了一个简单的递归解决方案。此函数返回不重复的路径,因为它从可能的后续步骤集(adjlist[start]
,其中start是最新添加的节点)中减去set(path)
(路径中已存在的节点)。
我修改了这个解决方案,使其具有一个函数,用于在两组节点之间搜索最大长度为maxlen
的所有简单路径。它返回路径列表:
def find_all_paths(graph, start, end, mode = 'OUT', maxlen = None):
def find_all_paths_aux(adjlist, start, end, path, maxlen = None):
path = path + [start]
if start == end:
return [path]
paths = []
if maxlen is None or len(path) <= maxlen:
for node in adjlist[start] - set(path):
paths.extend(find_all_paths_aux(adjlist, node, end, path, maxlen))
return paths
adjlist = [set(graph.neighbors(node, mode = mode)) \
for node in xrange(graph.vcount())]
all_paths = []
start = start if type(start) is list else [start]
end = end if type(end) is list else [end]
for s in start:
for e in end:
all_paths.extend(find_all_paths_aux(adjlist, s, e, [], maxlen))
return all_paths
def find_all_路径(图形、开始、结束、模式='OUT',maxlen=None):
def find_all_path_aux(调整列表、开始、结束、路径、最大值=无):
路径=路径+[开始]
如果开始=结束:
返回[路径]
路径=[]
如果此图的maxlen为None或len(path):
import igraph
G = ig.Graph()
#ring
G.add_vertices(4)
G.add_edges([(0,1), (1,2),(2,3),(3,0)])
G = G.as_directed()
print G.is_directed()
print G
如果我应用上面的函数
像
我只有
因此,应该有第二条路径[0,1,2,3,0]
imho
如果图中有这样的环,我如何找到所有的路径
在networkx中,可以通过所有简单路径获得所需结果:
import networkx as nx
G = nx.MultiDiGraph()
G.add_path(['a','b','c','d','a'])
G.add_path(['a','e','f','g'])
G.add_path(['a','a'])
for p in nx.all_simple_paths(G,'a','a'):
print p
结果:
['a', 'a']
['a', 'b', 'c', 'd', 'a']
如上所述,all_simple_paths函数仅存在于networkx中,由于性能问题,它不适合处理大型图形。有没有办法将所有简单路径从networkx带到igraph?我成功地将下面的函数用于python igraph。
由于这是我的应用程序的性能瓶颈,我想知道是否有人知道如何进一步优化it性能
def find_all_paths2(G, start, end, vn = []):
""" Finds all paths between nodes start and end in graph.
If any node on such a path is within vn, the path is not returned.
!! start and end node can't be in the vn list !!
Params:
--------
G : igraph graph
start: start node index
end : end node index
vn : list of via- or stop-nodes indices
Returns:
--------
A list of paths (node index lists) between start and end node
"""
vn = vn if type(vn) is list else [vn]
#vn = list(set(vn)-set([start,end]))
path = []
paths = []
queue = [(start, end, path)]
while queue:
start, end, path = queue.pop()
path = path + [start]
if start not in vn:
for node in set(G.neighbors(start,mode='OUT')).difference(path):
queue.append((node, end, path))
if start == end and len(path) > 0:
paths.append(path)
else:
pass
else:
pass
return paths
有一个函数叫做get\u all\u simple\u path(v,to=None,mode=OUT)
。
也许当被问到这个问题时,这并不是一个特性,但它完全符合你的要求
你说:
希望获得有向图中两个节点之间的所有可能路径
因此,如果图形对象是g
,则开始节点是源顶点
,结束节点是目标顶点
,您可以通过以下方式获得所有可能的路径:
g.get_all_simple_paths(source_vertex, target_vertex)
您需要所有路径,或者所有路径的数量?所有路径,但更准确地说(对于我的具体实现),我希望获得这些路径中的所有节点。不过,这两种解决方案对我都很好。谢谢,我无法让它工作。但是,关于获取所有路径,即使我们没有DAG,Networkx有一个函数,我以前使用它称为all_simple_paths。它检索两个节点之间的所有简单路径。术语简单,没有重复的术语。我不能使用Networkx,因为它在处理大型图形时很糟糕(与igraph不同)。我只想拥有一个类似于所有简单路径函数的功能。Networkx中所有简单路径的参考:我尝试运行此代码,但完成此代码需要很长时间。因此,我无法评估此代码。实际上,它很慢,我没有意识到这一点,因为我只使用它查找~2000对节点之间的路径。我将使用有序集来修改它,这将使它加速很多倍。这是一个非常好的解决方案。谢谢,我想知道这是否有助于提高解决此问题的性能
def find_all_paths2(G, start, end, vn = []):
""" Finds all paths between nodes start and end in graph.
If any node on such a path is within vn, the path is not returned.
!! start and end node can't be in the vn list !!
Params:
--------
G : igraph graph
start: start node index
end : end node index
vn : list of via- or stop-nodes indices
Returns:
--------
A list of paths (node index lists) between start and end node
"""
vn = vn if type(vn) is list else [vn]
#vn = list(set(vn)-set([start,end]))
path = []
paths = []
queue = [(start, end, path)]
while queue:
start, end, path = queue.pop()
path = path + [start]
if start not in vn:
for node in set(G.neighbors(start,mode='OUT')).difference(path):
queue.append((node, end, path))
if start == end and len(path) > 0:
paths.append(path)
else:
pass
else:
pass
return paths
g.get_all_simple_paths(source_vertex, target_vertex)