Python igraph:获取有向图中的所有可能路径

时间:2015-03-28 07:32:36

标签: python graph path igraph

我正在使用igraph(Python),并希望获得有向图中两个节点之间的所有可能路径。我知道函数get_all_shortest_paths,这是最短的路径,但找不到一般的。

更新

我的主要目标是获取这些路径中的所有节点,以便我可以获得这些节点的子图。

6 个答案:

答案 0 :(得分:7)

由于您在问题中提到您的最终目标是仅获取这些路径中的节点而不是路径本身,我认为您甚至不必计算路径。

igraph中的Graph对象有一个名为subcomponent的方法。默认情况下,它为您提供与给定输入节点位于同一(弱连接)组件中的所有节点。但是,它也有一个mode参数。将mode设置为"out"时,它将为您提供可从某个节点访问的所有节点。将mode设置为"in"后,它会为您提供可以到达某个节点的所有节点。因此,您可能需要来自源顶点的可达节点集和可以到达目标顶点的节点集的交集:

s=set(graph.subcomponent(source, mode="out"))
t=set(graph.subcomponent(target, mode="in"))
s.intersection(t)

这可能比计算所有路径更快。

答案 1 :(得分:1)

我无法确定,但在python igraph文档中查找几分钟看起来这样的功能不存在。我停止了寻找,因为在我看来这些信息并不真正有用,至少如果我是开发人员,我就不会创建它。回到问题:

首先,您需要了解对于任意图形,此类路径的数量将是无限的。您所需要的只是一个循环,您可以创建无限量的路径。因此,为了使这个数字有限,它应该是directed acyclic graph

因此,如果你有一个DAG,你可以使用DFS并递归计算所有路径(注意你最终会得到指数图,并且很可能无法在合理的时间内找到答案)即使是一张相当大的图表)。我不是自己编写代码,只是用Google搜索了一下它看起来像this guy have done what you want(基本上他在做DFS)。

from igraph import *

def adjlist_find_paths(a, n, m, path=[]):
  "Find paths from node index n to m using adjacency list a."
  path = path + [n]

  if n == m:
    return [path]
  paths = []

  for child in a[n]:
    if child not in path:
      child_paths = adjlist_find_paths(a, child, m, path)
      for child_path in child_paths:
        paths.append(child_path)
  return paths

def paths_from_to(graph, source, dest):
  "Find paths in graph from vertex source to vertex dest."
  a = graph.get_adjlist()
  n = source.index
  m = dest.index
  return adjlist_find_paths(a, n, m)

我没有检查它是否产生了正确的结果。

答案 2 :(得分:1)

In this postTamás,igraph的作者之一提出了一个简单的递归解决方案。此函数返回路径而不重复,因为它从可能的后续步骤集set(path)中减去adjlist[start](路径中已有的节点),其中start是最新添加的节点。 我修改了这个解决方案,以便在两组节点之间搜索最长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

答案 3 :(得分:0)

此图表:

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

如果我应用上面https://stackoverflow.com/a/29324009/2772305

中的功能

喜欢

for p in find_all_paths(G,0,0):
    print p

我只得到

结果是

[0],而应该有第二条路径[0,1,2,3,0] imho

如果图表中有这样的环,我如何找到所有路径?

在networkx中,可以使用all_simple_paths获得所需的结果:

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']

如上面comments所述,all_simple_paths函数仅存在于networkx中,由于性能问题,它不适合处理大图。有没有办法将all_simple_paths从networkx带到igraph?

答案 4 :(得分:0)

我使用python-igraph成功使用以下功能。 由于这是我的应用程序中的性能瓶颈,我想知道是否有人知道如何进一步优化性能。

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

答案 5 :(得分:0)

有一个名为get_all_simple_paths(v, to=None, mode=OUT)的函数。 也许当问这个问题时,这不是功能,但它确实符合您的要求。

您说:

想获取有向图中两个节点之间的所有可能路径

因此,如果图形对象是g,起始节点是source_vertex,结束节点是target_vertex,则可以使用以下方法获得所有可能的路径:

g.get_all_simple_paths(source_vertex, target_vertex)

Function documentation in python