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

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

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

G = nx.DiGraph()

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


edge_labels=dict([((u,v,),d['weight'])
                 for u,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,node_size=1500,edge_cmap=plt.cm.Reds)
pylab.show()

digraph

初始值为 n 和起始节点 A,同时假设所有节点都有入边和出边,我想遍历网络中的每条路径并不断划分以有向边的值开始n,然后找到最大化n的路径,这样我再次到达节点A。

例如,如果 n = 100,这是不同图的示例路径,我遍历一些路径并返回最终值:

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

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

解决方法

初始答案 - 基于 nx.simple_cycles

有很多方法可以实现您的目标,但这里有一个建议:

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

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'),'G'),('A','G')],weight=3)

edge_labels=dict([((u,v,),d['weight'])
                 for u,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,font_color='white')
nx.draw(G,node_size=1500,edge_cmap=plt.cm.Reds)

enter image description here

现在我们在 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,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}")
[out]:
The loop ['E','A','B','C','F','E'] in G maximizes n with 0.08333333333333333

我已上传此笔记本 here,以防您更喜欢克隆它并在本地测试此方法。

非迭代替代方案 - 基于 nx.dijkstra_path

根据您的评论,您所追求的似乎不是 to traverse every path in the network,但如果可能,请仅遍历 n 最大化路径并计算 nmax

这只是具有更新权重函数的 Dijkstra 最短路径算法的变体。

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

但是可以使用一个技巧:

  1. 移除节点A并引入AiAo
  2. Ai 替换 A 的所有入边
  3. Ao 替换 A 的所有外边
  4. AiAo 链接起来,边权重等于 math.inf
  5. 计算从AoAi的最短路径

这是我在最初回答中提供的图表的样子:

import math
Gp = nx.DiGraph()

Gp.add_edges_from([('Ao','Ai'),weight=50)
Gp.add_edges_from([('D',weight=1)
Gp.add_edges_from([('B','Ai')],weight=2)
Gp.add_edges_from([('C',('Ao',weight=3)

# this edge is strictly speaking not needed.
Gp.add_edges_from([('Ai','Ao'),weight=math.inf)

edge_labels=dict([((u,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,edge_labels=edge_labels)
nx.draw_networkx_labels(Gp,font_color='white')
nx.draw(Gp,edge_cmap=plt.cm.Reds)

enter image description here

使用 nx.dijkstra_path 我们有:

nmpath = nx.dijkstra_path(Gp,'Ao','Ai')
nmpath

[输出]: ['Ao','E','Ai']

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

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

[输出]:[50,2,3,2]

我们可以简单地计算 nmax:

maxn=100; 
for w in datnmpath: maxn/=w
print(maxn)

[输出] 0.08333333333333333

我已更新 the notebook,因此您可以克隆它并在本地测试此方法。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res