当前位置: 首页 > 知识库问答 >
问题:

有向无环图中从源到目标的所有路径*长度*

夏青青
2023-03-14

我有一个带有邻接矩阵形状的图(adj_mat.shape=(40004000))。我当前的问题是找到从源(row=0)到目标(col=trans\u mat.shape[0]-1)的路径长度列表(节点顺序并不重要)。

我对寻找路径序列不感兴趣;我只对传播路径长度感兴趣。因此,这不同于找到所有简单的路径——这太慢了(即。找到从源到目标的所有路径;然后给每条路径打分)。有没有一种表演方法可以快速做到这一点?

建议将DFS作为一种可能的策略(此处注明)。我当前的实施(如下)根本不是最优的:

# create graph
G = nx.from_numpy_matrix(adj_mat, create_using=nx.DiGraph())

# initialize nodes
for node in G.nodes:
    G.nodes[node]['cprob'] = []

# set starting node value
G.nodes[0]['cprob'] = [0]

def propagate_prob(G, node):

    # find incoming edges to node
    predecessors = list(G.predecessors(node))
    curr_node_arr = []        

    for prev_node in predecessors:
        # get incoming edge weight
        edge_weight = G.get_edge_data(prev_node, node)['weight']

        # get predecessor node value
        if len(G.nodes[prev_node]['cprob']) == 0:                
            G.nodes[prev_node]['cprob'] = propagate_prob(G, prev_node)            
        prev_node_arr = G.nodes[prev_node]['cprob']   

        # add incoming edge weight to prev_node arr
        curr_node_arr = np.concatenate([curr_node_arr, np.array(edge_weight) + np.array(prev_node_arr)])

    # update current node array
    G.nodes[node]['cprob'] = curr_node_arr
    return G.nodes[node]['cprob']

# calculate all path lengths from source to sink 
part_func = propagate_prob(G, 4000)

共有2个答案

姚浩歌
2023-03-14

使用igraph,我可以在~1秒内计算多达300个节点。我还发现访问相邻矩阵本身(而不是调用igraph的函数来检索边/顶点)也节省了时间。两个关键的瓶颈是1)以有效的方式追加一个长列表(同时保持内存)2)找到并行化的方法。这个时间指数增长超过~300个节点,我很想看看是否有人有更快的解决方案(同时也适合内存)。

import igraph

# create graph from adjacency matrix
G = igraph.Graph.Adjacency((trans_mat_pad > 0).tolist())

# add edge weights
G.es['weight'] = trans_mat_pad[trans_mat_pad.nonzero()]

# initialize nodes
for node in range(trans_mat_pad.shape[0]):
    G.vs[node]['cprob'] = []

# set starting node value
G.vs[0]['cprob'] = [0]

def propagate_prob(G, node, trans_mat_pad):

    # find incoming edges to node
    predecessors = trans_mat_pad[:, node].nonzero()[0] # G.get_adjlist(mode='IN')[node]
    curr_node_arr = []        

    for prev_node in predecessors:
        # get incoming edge weight
        edge_weight = trans_mat_pad[prev_node, node] # G.es[prev_node]['weight']

        # get predecessor node value
        if len(G.vs[prev_node]['cprob']) == 0:
            curr_node_arr = np.concatenate([curr_node_arr, np.array(edge_weight) + propagate_prob(G, prev_node, trans_mat_pad)])
        else: 
            curr_node_arr = np.concatenate([curr_node_arr, np.array(edge_weight) + np.array(G.vs[prev_node]['cprob'])])
    ## NB: If memory constraint, uncomment below
    # set max size
    # if len(curr_node_arr) > 100:
    #     curr_node_arr = np.sort(curr_node_arr)[:100]
    
    # update current node array
    G.vs[node]['cprob'] = curr_node_arr
    return G.vs[node]['cprob']

# calculate path lengths
path_len = propagate_prob(G, trans_mat_pad.shape[0]-1, trans_mat_pad)
段超
2023-03-14

我手头没有一个大的例子(例如:。

import networkx as nx

g = nx.DiGraph()

nx.add_path(g, range(7))

g.add_edge(0, 3)
g.add_edge(0, 5)
g.add_edge(1, 4)
g.add_edge(3, 6)

# first step retrieve topological sorting
sorted_nodes = nx.algorithms.topological_sort(g)

start = 0
target = 6

path_lengths = {start: [0]}

for node in sorted_nodes:
    if node == target:
        print(path_lengths[node])
        break

    if node not in path_lengths or g.out_degree(node) == 0:
        continue
    new_path_length = path_lengths[node]
    new_path_length = [i + 1 for i in new_path_length]
    for successor in g.successors(node):
        if successor in path_lengths:
            path_lengths[successor].extend(new_path_length)
        else:
            path_lengths[successor] = new_path_length.copy()

    if node != target:
        del path_lengths[node]

输出:[2,4,2,4,4,6]

如果您只对不同长度的路径数感兴趣,例如上面的例子中的{2:2,4:3,6:1},您甚至可以将列表减少为dicts。

一些解释我在做什么(我希望对更大的例子也有效)。第一步是检索拓扑排序。为什么啊?然后我知道边在哪个“方向”流动,我可以简单地按照这个顺序处理节点,而不会像递归变体中的“丢失任何边”或任何“回溯”。之后,我用包含当前路径长度的列表初始化开始节点([0])。这个列表被复制到所有的后继者,同时更新路径长度(所有元素1)。目标是在每次迭代中计算从起始节点到所有处理节点的路径长度,并将其存储在path_lengths。循环在到达目标-节点后停止。

 类似资料:
  • 是否有任何标准算法可以在有向无环图中找到所有可能的路径。如果没有,我如何在BFS / Dijkstra /任何其他算法中进行更改以枚举DAG中的所有路径

  • 我想在有向(无环)图中找到最长的路径。假设我知道起始节点-汇。路径应该从这一点开始。我在想我可以将边的权重设置为-1。有很多方法可以找到所有最短的路径,但你必须通过终点。有没有可能得到最短的路径(无论最终节点如何)? 假设我想为节点 nr 1(汇)找到最长路径。所以这个算法给了我1-2-3-4-5-6。

  • 我试图将这个问题概念化,然后为它编写Java代码。我知道这里有一些讨论,但我没有看到很多回答者,所以我想通过写下我的想法来重申这个问题,我希望从你们那里得到一些反馈。谢谢 我的想法:对于每个叶节点,找到从根节点到它的最长路径。对于所有路径,找到最大路径长度 然而,这不就是蛮力吗,对此还有更优雅的解决方案吗? 我听说过使用Djikstra的负权重算法,但在某些地方它说这只适用于特定情况?我也看到了关

  • 我需要为一组有向无环图找到从节点 0 开始的最长路径。我正在使用维基百科中的最长路径问题算法。我已经让算法适用于大多数图形,但对于其他图形,它没有给出正确的结果。算法为: 图形实现使用邻接列表来存储图形。如果我传递一个图,例如: 我得到的答案5,这是正确的。但是,如果我通过图表: 然后我得到2,而正确答案应该是3。 我使用的TopSort2算法是: DFS 算法包括:

  • 我有一个有向图。我想找到从源到目标的所有可能路径,覆盖所有转换。这与“覆盖所有顶点的所有可能路径”不同。该图将正好有一个起始顶点,并且可能有多个结束顶点。如果没有传出转换,则节点是结束节点。集合中的路径可能具有重复的变换,但不能具有重复的顶点。附有一个示例有向图。顶点a(黑色)是起始顶点,顶点e和f是结束节点(黄色)。此图的解决方案如下所示。 您可以看到最后一条路径有两次b。这是有效的。i、 例如