我正在比较同构的一大组networkx图,其中大多数图不应该是同构的(例如,假设0-20%与列表中的某些东西同构)。
我尝试了以下方法。
graphs = [] # A list of networkx graphs
unique = [] # A list of unique graphs
for new in graphs:
for old in unique:
if nx.is_isomorphic(new, old[0]):
break
else:
unique.append([new])
这让我得到了更快的减少集,但我仍然觉得它太慢而不适合理想使用。是否有一些更快的算法来处理这类问题(比较传递的可交换属性对)或将此算法扩展到多核设置(在20核机器上运行)的方法。
我已经根据节点数/边数过滤了这些数据集,我们可以假设任何过滤类型的操作都无法使nx.is_isomorphic函数更快。我现在也无法轻松更改工具,因此使用编译包不是一种选择。
其他信息:
图形倾向于大约16-20个节点,总共24-48个边缘,存在大量互连,因此每个节点大约有8个边缘。每个边缘都有标记,但是只使用了2-3种边缘。
答案 0 :(得分:7)
你能使用Linux发行版中提供的nauty(http://users.cecs.anu.edu.au/~bdm/nauty/)吗?这有一个规范的标签算法,速度快,可能适用于您的问题。规范标记使同构图相同(经典化)。例如,使用来自一组随机图的graph6格式输出给出以下同构图计数
$ cat g6.py
import networkx as nx
for i in range(100000):
print(nx.generate_graph6(nx.fast_gnp_random_graph(4,0.2),header=False))
$ python g6.py |nauty-labelg |sort |uniq -c
>A labelg
>Z 100000 graphs labelled from stdin to stdout in 0.21 sec.
4898 C`
167 C^
10 C~
26408 C?
39392 C@
19684 CB
1575 CF
1608 CJ
1170 CN
288 Cr
4800 CR
这是4个节点的11个图 -
$ cat atlas.py
import networkx as nx
for g in nx.atlas.graph_atlas_g()[8:19]:
print(nx.generate_graph6(g,header=False))
$ python atlas.py |nauty-labelg |sort |uniq -c
>A labelg
>Z 11 graphs labelled from stdin to stdout in 0.00 sec.
1 C`
1 C^
1 C~
1 C?
1 C@
1 CB
1 CF
1 CJ
1 CN
1 Cr
1 CR
如果运行速度太慢,并行化这种方法会很容易。
答案 1 :(得分:5)
正如其他人所提到的,如果您想留在Python + Networkx中,可以使用could_be_isomorphic
来过滤图表。
问题是这种方法需要2个图表作为输入,而不是数百万。如果用这种方法比较每对图形,则需要很长时间。
查看sourcecode of could_be_isomorphic
,它会比较两个图的度,三角和派系序列数。如果它们不相等,则图形不能是同构的。
您可以在功能中打包此指纹,根据此指纹对图表进行排序,并将其与itertools.groupby
分组。将会有绝大多数单独的图表。然后可以检查具有相同指纹的少数图形的同构性。
使用100 000个随机图表列表:
yourVariable = intent.getStringExtra("duration");
yourSecondVariable = intent.getStringExtra("packageType");
至少有2张图表共享了500个指纹。如果添加边缘类型信息,则会出现更少的常见指纹。
这是一个包含3000个图表的示例,每个图表包含10到14个节点:
many_graphs = [nx.fast_gnp_random_graph(random.randint(16, 22), 0.2) for _ in range(100000)]
它在不到1s内找到4个同构对:
import networkx as nx
from itertools import groupby
import random
many_graphs = [nx.fast_gnp_random_graph(
random.randint(10, 14), 0.3) for _ in range(3000)]
def graph_fingerprint(g):
order = g.order()
d = g.degree()
t = nx.triangles(g)
c = nx.number_of_cliques(g)
props = [[d[v], t[v], c[v]] for v in d]
props.sort()
# TODO: Add count of edge types.
return(props)
sorted_graphs = sorted(many_graphs, key=graph_fingerprint)
for f, g in groupby(sorted_graphs, key=graph_fingerprint):
similar_graphs = list(g)
n = len(similar_graphs)
if n > 1:
print("Found %d graphs which could be isomorphic." % n)
for i in range(n):
for j in range(i + 1, n):
g1, g2 = similar_graphs[i], similar_graphs[j]
if g1 != g2 and nx.is_isomorphic(g1, g2):
print(" %s and %s are isomorphic!" %
(nx.generate_graph6(g1,header=False), nx.generate_graph6(g2,header=False)))
这是最后两个同构图。 " IDOCCY @ GG":
和" IOGC @ \ dS?":
以下是两张图表,它们具有相同的指纹,但不是同构的:
指纹识别可以并行完成。排序和分组必须在1个CPU上进行,但每个组的同构检查可以在不同的CPU中完成。
答案 2 :(得分:1)
您可以在PyPy上尝试使用代码,该代码为纯Python代码提供即时编译。为了提高性能,他们说出来......
...在很大程度上取决于正在执行的任务的类型。所有基准测试的几何平均值比CPython
快0.13或7.5倍
如果您的工作负载受CPU限制(看起来像这样)并且Python进程长时间运行(因此可以执行JIT编译),那么性能提升可能会很大。 NetworkX是纯Python(它具有可选的依赖关系,如numpy,但它们需要额外的功能),特别是isomorph
模块。我尝试了PyPy 5.7.1和networkx/algorithms/isomorphism/tests/test_isomorphism.py
次传球。该套件通常有一些失败:
Ran 2952 tests in 51.311s
FAILED (failures=3, skipped=54)
Test failed: <unittest.runner.TextTestResult run=2952 errors=0 failures=3>
在Python 2.7.12上,它是:
Ran 2952 tests in 88.915s
OK (skipped=54)