networkx中的传递闭包

时间:2018-10-08 21:41:46

标签: python networkx

考虑以下示例:

import numpy as np
import networkx as nx

a = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]])

G = nx.from_numpy_matrix(a, create_using=nx.MultiDiGraph())

T = nx.transitive_closure(G)

print(nx.to_numpy_matrix(T))

传递闭包缺少预期的自我循环。为什么? (文档链接不起作用。)“预期”是指“根据标准定义”,例如Wikipedia definition。我预计会使用不同的定义,但这是什么?

1 个答案:

答案 0 :(得分:1)

看起来像一个实现错误。该文档字符串在定义上很清楚:“一个图形G + =(V,E +),这样,并且仅当存在从到的非空路径时,对于V中的所有v,w在E +中都有一个边(v,w)在G中从v到w。”自环符合此定义。

在将TC复制为给定G的副本之后,算法归结为

for v in G:
    TC.add_edges_from((v, u) for u in nx.dfs_preorder_nodes(G, source=v)
                      if v != u)

因此,永远不会由于if v != u而添加自循环。排除的原因是,dfs_preorder_nodes的输出将以v(源)开始,无论那里有什么边,当然我们也不想添加循环(v, v)正因为如此。但是,由于依赖于dfs_preorder_nodes的副作用,该算法从未确定v本身是否可以通过非空路径v到达。 / p>

因此,要获得通常意义上的传递闭包,我们需要为循环上的每个节点(v, v)添加循环v。像这样:

T = nx.transitive_closure(G)

for cycle in nx.simple_cycles(G):
    T.add_edges_from((v, v) for v in cycle)

在矩阵形式中,T现在

[[4. 2. 2.]
 [2. 4. 2.]
 [2. 2. 4.]]

循环被添加多次。如果您关心多重性(尽管我真的看不到传递闭包应该具有什么边缘多重性),可以这样做,以防止多次添加边缘:

cycles = frozenset().union(*[frozenset(cycle) for cycle in nx.simple_cycles(G)])
T.add_edges_from((v, v) for v in cycles)

然后T

[[1. 2. 2.]
 [2. 1. 2.]
 [2. 2. 1.]]