【问题标题】:Python igraph: get all possible paths in a directed graphPython igraph:在有向图中获取所有可能的路径
【发布时间】:2020-07-09 18:31:17
【问题描述】:

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

更新:

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

【问题讨论】:

  • 你需要所有路径,还是所有路径的数量?
  • 所有路径,但为了更准确(对于我的具体实现),我想获取这些路径中的所有节点。但是,这两种解决方案都适合我。

标签: python graph path igraph


【解决方案1】:

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

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)

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

【讨论】:

  • 这是一个非常好的解决方案。谢谢
  • 我想知道这是否有助于提高my solution的性能来解决问题
【解决方案2】:

In this postTamás,igraph 的作者之一提出了一个简单的递归解决方案。此函数返回不重复的路径,因为它从可能的后续步骤集(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

【讨论】:

  • 我试图运行这段代码,但它需要很长时间才能完成。因此,我无法评估此代码
  • 确实很慢,我没有意识到我只是用它来查找约 2,000 对节点之间的路径。我将使用有序集对其进行修改,这会提高很多倍的速度。
【解决方案3】:

我不能确定,但​​是在 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)

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

【讨论】:

  • 谢谢,我无法让它工作。但是关于即使我们没有 DAG 也能获取所有路径,Networkx 有一个我曾经使用过的函数,称为 all_simple_paths。它检索两个节点之间的所有简单路径。术语简单,没有重复的术语。我不能使用 Networkx,因为它在处理大图时很糟糕(与 igraph 不同)。我只想拥有与 all_simple_paths 函数类似的功能。
  • 来自 Networkx 的 all_simple_paths 参考:link
【解决方案4】:

对于这个图表:

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 ?

【讨论】:

    【解决方案5】:

    我成功地将以下函数与 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
    

    【讨论】:

      【解决方案6】:

      有一个函数叫做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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-03
        • 1970-01-01
        • 1970-01-01
        • 2011-04-27
        相关资源
        最近更新 更多