Python networkx-遍历从节点A到节点A的所有路径,执行操作并查找最大值

Python networkx-遍历从节点A到节点A的所有路径,执行操作并查找最大值,python,pandas,networkx,Python,Pandas,Networkx,假设我有一个有向图,由下面的代码生成: G = nx.DiGraph() G.add_edges_from([('A', 'B'),('B', 'A'), ('C','D'),('G','D')], weight=1) G.add_edges_from([('D','A'),('D','E'),('B','D'),('D','E')], weight=2) G.add_edges_from([('B','C'),('E','F')], weight=3) G.add_edges_from([(

假设我有一个有向图,由下面的代码生成:

G = nx.DiGraph()

G.add_edges_from([('A', 'B'),('B', 'A'), ('C','D'),('G','D')], weight=1)
G.add_edges_from([('D','A'),('D','E'),('B','D'),('D','E')], weight=2)
G.add_edges_from([('B','C'),('E','F')], weight=3)
G.add_edges_from([('C','F')], weight=4)


edge_labels=dict([((u,v,),d['weight'])
                 for u,v,d in G.edges(data=True)])

pos=nx.spring_layout(G)
nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)
nx.draw(G,pos, node_size=1500,edge_cmap=plt.cm.Reds)
pylab.show()

对于初始值n和起始节点A,假设所有节点都有入边和出边,我希望遍历网络中的每条路径,并不断地将起始n除以方向边的值,然后找到使n最大化的路径,从而再次到达节点A

例如,如果n=100,这是另一个图形的示例路径,其中我遍历一些路径并返回最终值:

n/2=50,50/5=10,10/2=5,5/0.01=500

特别是我的用例有一个更大的网络,其中迭代解决方案是不可行的。是否有一种算法可以在最小化计算时间的同时近似精确解?

初始答案-基于nx.simple\u循环 有很多方法可以实现你想要的,但这里有一个建议:

首先,让我用一个具有更多循环和另一个布局的图替换原始图

G = nx.DiGraph()

G.add_edges_from([('A', 'B'),('B', 'A'), ('C','D'),('G','D')], weight=50)
G.add_edges_from([('D','B')], weight=1)
G.add_edges_from([('B','C'),('F','E'),('E','A')], weight=2)
G.add_edges_from([('C','F'),('B','G'),('A','G')], weight=3)

edge_labels=dict([((u,v,),d['weight'])
                 for u,v,d in G.edges(data=True)])

# improve layout and draw node labels

pos=nx.drawing.layout.circular_layout(G,scale=10)
nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)
nx.draw_networkx_labels(G,pos,font_color='white')
nx.draw(G,pos, node_size=1500,edge_cmap=plt.cm.Reds)

现在,我们在
G
中找到所有在给定感兴趣节点开始和结束的简单循环,并计算每个循环的
n

# node of interest
inode  = 'A'


acycs  = [ cyc for cyc in nx.simple_cycles(G) if inode in cyc ]

# for ease of computation we append the first node to the end of each cycle
acycs = [cyc+[cyc[0]] for cyc in acycs]

mcyc = []
maxn = 0

# for each cycle involving node of interest
for cyc in acycs:
    n = 100
    
    # group the nodes in the cycle by pairs
    for u, v in zip(cyc[:-1], cyc[1:]):
        
        # retrieve the respective edge weigth for the current pair
        print(u,v, end=',\t')
        div = G.get_edge_data(u,v)['weight']
        
        # calculate and update n
        r   = n/div
        print(f"{n}\t/\t{div}\t=\t{r}")
        n=r
        
    print('----------------------------------------------------------------------------')

    if n>maxn:
        maxn=n
        mcyc=cyc
这为我们提供了从
inode='A'
开始的所有循环:

[out]:

E A,    100 /   2   =   50.0
A G,    50.0    /   3   =   16.666666666666668
G D,    16.666666666666668  /   50  =   0.33333333333333337
D B,    0.33333333333333337 /   1   =   0.33333333333333337
B C,    0.33333333333333337 /   2   =   0.16666666666666669
C F,    0.16666666666666669 /   3   =   0.05555555555555556
F E,    0.05555555555555556 /   2   =   0.02777777777777778
----------------------------------------------------------------------------
E A,    100 /   2   =   50.0
A B,    50.0    /   50  =   1.0
B C,    1.0 /   2   =   0.5
C F,    0.5 /   3   =   0.16666666666666666
F E,    0.16666666666666666 /   2   =   0.08333333333333333
----------------------------------------------------------------------------
B A,    100 /   50  =   2.0
A G,    2.0 /   3   =   0.6666666666666666
G D,    0.6666666666666666  /   50  =   0.013333333333333332
D B,    0.013333333333333332    /   1   =   0.013333333333333332
----------------------------------------------------------------------------
B A,    100 /   50  =   2.0
A B,    2.0 /   50  =   0.04
----------------------------------------------------------------------------
以及使
n
最大化的循环:

print(f"The loop {mcyc} in G maximizes n with {maxn}")
我已经上传了这个笔记本,以防你想克隆它并在本地测试这种方法

非迭代替代方案-基于nx.dijkstra_路径 根据您的评论,您所追求的似乎不是
遍历网络中的每条路径
,而是如果可能,只遍历n-最大化路径并计算
nmax

这只是Dijkstra最短路径算法的一个变种,具有更新的权重函数

但是,
nx.Dijkstra_路径
在查找循环时遇到问题
nx.Dijkstra_路径('A','A')
产生
A
即使
w(A,A)=math.inf

但我们可以使用一个技巧:

  • 删除节点
    A
    并引入
    Ai
    Ao
  • Ai
  • Ao
  • 链接
    Ai
    Ao
    ,边缘权重等于
    math.inf
  • 计算从
    Ao
    Ai
  • 以下是我在初始答案中提供的图表:

    import math
    Gp = nx.DiGraph()
    
    Gp.add_edges_from([('Ao', 'B'),('B', 'Ai'), ('C','D'),('G','D')], weight=50)
    Gp.add_edges_from([('D','B')], weight=1)
    Gp.add_edges_from([('B','C'),('F','E'),('E','Ai')], weight=2)
    Gp.add_edges_from([('C','F'),('B','G'),('Ao','G')], weight=3)
    
    # this edge is strictly speaking not needed.
    Gp.add_edges_from([('Ai','Ao'),('Ao','Ai')], weight=math.inf)
    
    edge_labels=dict([((u,v,),d['weight'])
                     for u,v,d in Gp.edges(data=True)])
    
    pos=nx.drawing.layout.circular_layout(Gp,scale=10)
    pos['Ai'], pos['B'] = pos['B'], pos['Ai']
    nx.draw_networkx_edge_labels(Gp,pos,edge_labels=edge_labels)
    nx.draw_networkx_labels(Gp,pos,font_color='white')
    nx.draw(Gp,pos, node_size=1500,edge_cmap=plt.cm.Reds)
    

    使用
    nx.dijkstra_路径

    nmpath = nx.dijkstra_path(Gp,'Ao','Ai')
    nmpath
    
    [out]:['Ao','B','C','F','E','Ai']

    我们可以看到该路径的权重如下所示:

    lennmpath=len(nmpath)
    datnmpath=[Gp.get_edge_data(u, nmpath[i+1])['weight'] for u,i in zip(nmpath[:-1], range(lnmpath))]
    
    [out]:[50,2,3,2,2]

    我们可以简单地计算nmax:

    maxn=100; 
    for w in datnmpath: maxn/=w
    print(maxn)
    
    [输出]0.08333


    我已经进行了更新,以便您可以克隆它并在本地测试此方法。

    也许我应该更具体一些,但我指的是非迭代解决方案。特别是我的用例有大约200个节点和更多的连接,这样循环就不可行了。是否有任何内置算法可以帮助您使用“最佳猜测”方法进行遍历?是的,您可以使用
    nx.Dijkstra_path
    和一个小技巧来实现这一点。但是,请注意,您不会像最初所说的那样遍历网络中的每条路径。我在回答中编辑了一个
    非迭代备选方案
    ,并举例说明了如何实现这一点。
    maxn=100; 
    for w in datnmpath: maxn/=w
    print(maxn)