基于有向图的邻接矩阵计算其割点、割边、压缩图,并用networkx可视化绘制

85 篇文章 2 订阅
23 篇文章 0 订阅
该文章介绍了一种使用Python和networkx库处理有向图的方法,包括计算邻接矩阵、可达矩阵,识别割点和割边,以及进行图的压缩。通过矩阵运算,高效地找出图的强连通分量,并用networkx进行可视化展示。
摘要由CSDN通过智能技术生成

基于有向图的邻接矩阵计算其割点、割边、压缩图,并用networkx可视化绘制

为什么基于邻接矩阵计算图的割点、割边、压缩图

由于矩阵计算过程,被广泛优化;
因此,采用矩阵计算方法实施割点、割边、压缩图的计算,效率高、逻辑简单。

实现python代码

import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout

# 有向图的邻接矩阵
M = np.array([
    #1, 2, 3, 4, 5, 6, 7, 8
    [0, 0, 0, 0, 0, 1, 0, 0],   #u1->u6
    [0, 0, 0, 0, 1, 0, 0, 0],   #u2->u5
    [0, 1, 0, 1, 0, 0, 0, 0],   #u3->u2, u3->u4
    [0, 0, 0, 0, 0, 0, 0, 1],   #u4->u8
    [0, 1, 1, 0, 0, 0, 0, 0],   #u5->u2, u5->u3
    [0, 0, 0, 0, 0, 0, 1, 0],   #u6->u7
    [0, 0, 0, 1, 0, 0, 0, 0],   #u7->u4
    [0, 0, 0, 0, 0, 1, 0, 0]    #u8->u6
], int)
print('邻接矩阵:\n', M)
nVerts = M.shape[0]             #顶点个数

# IM = I(单位阵) + M(邻接矩阵)————在邻接矩阵基础上,添加自环结构
IM = np.identity(nVerts, int) + M
# R = ((I + M) ** (n-1) == 1).astype(int),构造可达矩阵
# 矩阵的n次幂——矩阵连乘n次
R = (np.linalg.matrix_power(IM, nVerts - 1) > 0).astype(int)
print('可达矩阵:\n', R)

# 由R * R.T保持对称边,去除非对称边
sR = R * R.T
print('对称矩阵:\n', sR)

# 按对称矩阵sR中的行数据实施分组汇总
rows = [ [''.join(sR[i, :].astype(str)), i] for i in range(nVerts) ]
print('行数组编码组=\n', rows)
grps = {}
for row in rows:
    if row[0] in grps.keys():
        grps[row[0]].append( row[1])
    else:
        grps[row[0]] = [row[1]]
print('按相同编码实施顶点分组结果:\n', grps )
# 计算分组数量
nGroups = len(list(grps.keys()))
print('分组数量=', nGroups)

groupInfo = list(grps.values())
groups = {}
for grpNo, elems in enumerate(groupInfo):
    for elem in elems:
        groups[elem] = grpNo
print('按强连通特性分组的节点组:\n', groups)

# 压缩图的邻接矩阵
compactR = np.zeros((nGroups, nGroups))               
# 遍历邻接矩阵获取组建连接信息
connGroups = {}
for i in range(nVerts):
    for j in range(nVerts):
        if i == j: continue                     #相同顶点关系继续
        if groups[i] == groups[j]: continue     #同组关系继续
        if M[i, j] == 1:                        
            compactR[groups[i], groups[j]] = 1  #记录压缩图中的组间有向边
            cn = (groups[i], groups[j])         #不同组间的连接关系
            if cn in connGroups.keys():
                connGroups[cn] += [(i, j)]
            else:
                connGroups[cn] = [(i, j)] 
print('组间连接关系=\n', connGroups)   

# 根据组间连接关系获取候选割点、割边集合
cutEdges = []       #割边
cutVerts = []       #割点
for key in connGroups.keys():
    vals = connGroups[key]                  
    if len(vals) == 1:
        print('割边', vals)
        cutEdges += vals        #添加割边
        cutVerts += vals[0]     #添加割点

# 根据邻接矩阵计算每个顶点的度数——为真实割点判断提供依据
# 顶点度数=行求和(出度)+ 列求和(入度)
vertDegrees = [np.sum(M[i, :]) + np.sum(M[:, i]) for i in range(nVerts)]
print('顶点度数=\n', vertDegrees)
print('候选割点=\n', cutVerts)
# 筛选掉度=1的候选割点————条件:割点的度数必须 > 1
cutVerts = [v for v in cutVerts if vertDegrees[v] > 1]        
print('割点\n', cutVerts)

# 绘图
plt.figure()
plt.title('Directed graph')
dg = nx.DiGraph()                           #构造有向图
for i in range(nVerts):
    for j in range(nVerts):
        if M[i, j] == 1:
            dg.add_edge(i, j)               #添加有向边
# 智能布局节点位置            
pos = graphviz_layout(dg, prog='dot')       
nx.draw(dg, with_labels = True, pos = pos)  #绘制有向图
# 绘制红色割边
nx.draw_networkx_edges(dg, pos = pos, edgelist=cutEdges, width=1.0, edge_color='r')
# 绘制红色割点
nx.draw_networkx_nodes(dg, pos = pos, nodelist=cutVerts, node_color='r')
plt.show()

# 根据压缩图的邻接矩阵,可绘图压缩图
plt.figure()
plt.title('compact graph')
dg1 = nx.DiGraph()
for i in range(nGroups):
    for j in range(nGroups):
        if compactR[i, j] == 1:
            dg1.add_edge(i, j)
pos1 = graphviz_layout(dg1, prog='dot')       
nx.draw(dg1, with_labels = True, pos = pos)  #绘制有向图
plt.show()

代码运行效果

邻接矩阵:
[[0 0 0 0 0 1 0 0]
[0 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 0]
[0 0 0 0 0 0 0 1]
[0 1 1 0 0 0 0 0]
[0 0 0 0 0 0 1 0]
[0 0 0 1 0 0 0 0]
[0 0 0 0 0 1 0 0]]
可达矩阵:
[[1 0 0 1 0 1 1 1]
[0 1 1 1 1 1 1 1]
[0 1 1 1 1 1 1 1]
[0 0 0 1 0 1 1 1]
[0 1 1 1 1 1 1 1]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]]
对称矩阵:
[[1 0 0 0 0 0 0 0]
[0 1 1 0 1 0 0 0]
[0 1 1 0 1 0 0 0]
[0 0 0 1 0 1 1 1]
[0 1 1 0 1 0 0 0]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]]
行数组编码组=
[[‘10000000’, 0], [‘01101000’, 1], [‘01101000’, 2], [‘00010111’, 3], [‘01101000’, 4], [‘00010111’, 5], [‘00010111’, 6], [‘00010111’, 7]]
按相同编码实施顶点分组结果:
{‘10000000’: [0], ‘01101000’: [1, 2, 4], ‘00010111’: [3, 5, 6, 7]}
分组数量= 3
按强连通特性分组的节点组:
{0: 0, 1: 1, 2: 1, 4: 1, 3: 2, 5: 2, 6: 2, 7: 2}
组间连接关系=
{(0, 2): [(0, 5)], (1, 2): [(2, 3)]}
割边 [(0, 5)]
割边 [(2, 3)]
顶点度数=
[1, 3, 3, 3, 3, 3, 2, 2]
候选割点=
[0, 5, 2, 3]
割点
[5, 2, 3]
可视化图中割边(红色)和割点(红色节点)的效果图
压缩图的可视化效果

结论:

图(graph),是表达对象关系的有效方法;
而针对复杂图的分析,由于结构多变,故用程序逻辑法求解的话,难以编程。
通过使用矩阵计算方法,获取图中的相关信息,对于图分析可起到简捷、高效的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值