鉴于此图:
import igraph as ig
g=ig.Graph.Erdos_Renyi(10, 0.5, directed=True)
我们可以使用triad_census功能轻松找到其三合会人口普查:
tc = g.triad_census()
如果我们打印'tc',我们会得到类似的结果:
003 : -2147483648 | 012 : 5 | 102 : 2 | 021D: 4
021U: 6 | 021C: 8 | 111D: 9 | 111U: 14
030T: 5 | 030C: 3 | 201 : 6 | 120D: 9
120U: 5 | 120C: 21 | 210 : 18 | 300 : 4
也就是说,对于每个三元组类型,我们都有在图表中找到它的次数。
与“三合会人口普查”不同,“黑社会名单”不仅会给出三合会的找到次数,还会给出每次出现的参与者节点。据我所知,这里的问题是“三合会列表算法”不一定与“三合会人口普查算法”相同,第二种算法的计算成本较低。
我尝试通过查看同构,定义每个三元组,然后在图中搜索它们:
# Set up the 16 possible triads
triad_dict=dict()
#003 A,B,C, the empty graph.
triad = ig.Graph(n = 3, directed=True)
triad_dict['003'] = triad
#012 A->B, C, the graph with a single directed edge.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1)])
triad_dict['012'] = triad
#102 A<->B, C, the graph with a mutual connection between two vertices.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(0,2)])
triad_dict['102'] = triad
#021D A<-B->C, the out-star.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(0,2)])
triad_dict['021D'] = triad
#021U A->B<-C, the in-star.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(1,0),
(2,0)])
triad_dict['021U'] = triad
#021C A->B->C, directed line.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(1,2)])
triad_dict['021C'] = triad
#111D A<->B<-C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(0,2)])
triad_dict['111D'] = triad
#111U A<->B->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(0,2),(2,0)])
triad_dict['111U'] = triad
#030T A->B<-C, A->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(2,1),
(0,2)])
triad_dict['030T'] = triad
#030C A<-B<-C, A->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(1,0),
(2,1),
(0,2)])
triad_dict['030C'] = triad
#201 A<->B<->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),(1,0),
(1,2),(2,1)])
triad_dict['201'] = triad
#120D A<-B->C, A<->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(0,2),
(1,2), (2,1)])
triad_dict['120D'] = triad
#120U A->B<-C, A<->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(2,1),
(0,2), (2,0)])
triad_dict['120U'] = triad
#120C A->B->C, A<->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(1,2),
(0,2), (2,0)])
triad_dict['120C'] = triad
#210 A->B<->C, A<->C.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1),
(1,2), (2,1),
(0,2), (2,0)])
triad_dict['210'] = triad
#300 A<->B<->C, A<->C, the complete graph.
triad = ig.Graph(n = 3, directed=True)
triad.add_edges([(0,1), (1,0),
(1,2), (2,1),
(0,2), (2,0)])
triad_dict['300'] = triad
seq = ['300',
'210',
'120C', '120U', '120D', '201',
'030C', '030T','111U','111D',
'021C','021U','021D','102',
'012',
'003']
#Search isomorphisms for every triad
isomorphisms = dict()
for key in seq:
isomorphisms[key] = g.get_subisomorphisms_vf2(triad_dict[key])
但是,如果我们有A&lt; - &gt; B&lt; - &gt; C,它将与几个三元组相关联:
A<->B<->C
A->B->C
A<->B->C
etc.
我只想考虑更完整的三元组(具有更多边缘的三元组)并丢弃其子三元组。我们可以清理isomorphisms字典中的重复三元组,从更高阶(更多边)到更低阶层,例如:
#Search isomorphisms for every triad
seen = []
for key in seq:
isos = isomorphisms[key]
isos = [i for i in isos if i not in seen]
isomorphisms[key] = isos
seen.extend(isos)
但是,这不是一个选项,因为图表表示节点之间的一组对话。如果发生了两次不同的对话:
A->B->C->D (1)
A->B->C (2)
(图表是多线的)
脚本将删除(1),因为它会认为(2)是对应于(1)的子图,但它不一定是真的,因为在这种情况下它们代表不同的对话。
答案 0 :(得分:0)
您可以将子图同构词列为特定主题,请参阅http://igraph.sourceforge.net/doc/python/igraph.GraphBase-class.html#get_subisomorphisms_vf2
这实际上是一个错误的答案,因为你会发现包含你要搜索的主题的诱导子图。见评论。
不幸的是(目前)唯一的方法是从C开始编写一个回调函数,每次找到一个motif时都会调用它。 http://igraph.sourceforge.net/doc/html/ch17s03.html#igraph_motifs_randesu_callback