1import functools
2
3import networkx as nx
4
5__all__ = [
6 "edge_betweenness_partition",
7 "edge_current_flow_betweenness_partition",
8]
9
10
11@nx._dispatchable(edge_attrs="weight")
12def edge_betweenness_partition(G, number_of_sets, *, weight=None):
13 """Partition created by iteratively removing the highest edge betweenness edge.
14
15 This algorithm works by calculating the edge betweenness for all
16 edges and removing the edge with the highest value. It is then
17 determined whether the graph has been broken into at least
18 `number_of_sets` connected components.
19 If not the process is repeated.
20
21 Parameters
22 ----------
23 G : NetworkX Graph, DiGraph or MultiGraph
24 Graph to be partitioned
25
26 number_of_sets : int
27 Number of sets in the desired partition of the graph
28
29 weight : key, optional, default=None
30 The key to use if using weights for edge betweenness calculation
31
32 Returns
33 -------
34 C : list of sets
35 Partition of the nodes of G
36
37 Raises
38 ------
39 NetworkXError
40 If number_of_sets is <= 0 or if number_of_sets > len(G)
41
42 Examples
43 --------
44 >>> G = nx.karate_club_graph()
45 >>> part = nx.community.edge_betweenness_partition(G, 2)
46 >>> {0, 1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 16, 17, 19, 21} in part
47 True
48 >>> {
49 ... 2,
50 ... 8,
51 ... 9,
52 ... 14,
53 ... 15,
54 ... 18,
55 ... 20,
56 ... 22,
57 ... 23,
58 ... 24,
59 ... 25,
60 ... 26,
61 ... 27,
62 ... 28,
63 ... 29,
64 ... 30,
65 ... 31,
66 ... 32,
67 ... 33,
68 ... } in part
69 True
70
71 See Also
72 --------
73 edge_current_flow_betweenness_partition
74
75 Notes
76 -----
77 This algorithm is fairly slow, as both the calculation of connected
78 components and edge betweenness relies on all pairs shortest
79 path algorithms. They could potentially be combined to cut down
80 on overall computation time.
81
82 References
83 ----------
84 .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports
85 Volume 486, Issue 3-5 p. 75-174
86 http://arxiv.org/abs/0906.0612
87 """
88 if number_of_sets <= 0:
89 raise nx.NetworkXError("number_of_sets must be >0")
90 if number_of_sets == 1:
91 return [set(G)]
92 if number_of_sets == len(G):
93 return [{n} for n in G]
94 if number_of_sets > len(G):
95 raise nx.NetworkXError("number_of_sets must be <= len(G)")
96
97 H = G.copy()
98 partition = list(nx.connected_components(H))
99 while len(partition) < number_of_sets:
100 ranking = nx.edge_betweenness_centrality(H, weight=weight)
101 edge = max(ranking, key=ranking.get)
102 H.remove_edge(*edge)
103 partition = list(nx.connected_components(H))
104 return partition
105
106
107@nx._dispatchable(edge_attrs="weight")
108def edge_current_flow_betweenness_partition(G, number_of_sets, *, weight=None):
109 """Partition created by removing the highest edge current flow betweenness edge.
110
111 This algorithm works by calculating the edge current flow
112 betweenness for all edges and removing the edge with the
113 highest value. It is then determined whether the graph has
114 been broken into at least `number_of_sets` connected
115 components. If not the process is repeated.
116
117 Parameters
118 ----------
119 G : NetworkX Graph, DiGraph or MultiGraph
120 Graph to be partitioned
121
122 number_of_sets : int
123 Number of sets in the desired partition of the graph
124
125 weight : key, optional (default=None)
126 The edge attribute key to use as weights for
127 edge current flow betweenness calculations
128
129 Returns
130 -------
131 C : list of sets
132 Partition of G
133
134 Raises
135 ------
136 NetworkXError
137 If number_of_sets is <= 0 or number_of_sets > len(G)
138
139 Examples
140 --------
141 >>> G = nx.karate_club_graph()
142 >>> part = nx.community.edge_current_flow_betweenness_partition(G, 2)
143 >>> {0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 16, 17, 19, 21} in part
144 True
145 >>> {8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33} in part
146 True
147
148
149 See Also
150 --------
151 edge_betweenness_partition
152
153 Notes
154 -----
155 This algorithm is extremely slow, as the recalculation of the edge
156 current flow betweenness is extremely slow.
157
158 References
159 ----------
160 .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports
161 Volume 486, Issue 3-5 p. 75-174
162 http://arxiv.org/abs/0906.0612
163 """
164 if number_of_sets <= 0:
165 raise nx.NetworkXError("number_of_sets must be >0")
166 elif number_of_sets == 1:
167 return [set(G)]
168 elif number_of_sets == len(G):
169 return [{n} for n in G]
170 elif number_of_sets > len(G):
171 raise nx.NetworkXError("number_of_sets must be <= len(G)")
172
173 rank = functools.partial(
174 nx.edge_current_flow_betweenness_centrality, normalized=False, weight=weight
175 )
176
177 # current flow requires a connected network so we track the components explicitly
178 H = G.copy()
179 partition = list(nx.connected_components(H))
180 if len(partition) > 1:
181 Hcc_subgraphs = [H.subgraph(cc).copy() for cc in partition]
182 else:
183 Hcc_subgraphs = [H]
184
185 ranking = {}
186 for Hcc in Hcc_subgraphs:
187 ranking.update(rank(Hcc))
188
189 while len(partition) < number_of_sets:
190 edge = max(ranking, key=ranking.get)
191 for cc, Hcc in zip(partition, Hcc_subgraphs):
192 if edge[0] in cc:
193 Hcc.remove_edge(*edge)
194 del ranking[edge]
195 splitcc_list = list(nx.connected_components(Hcc))
196 if len(splitcc_list) > 1:
197 # there are 2 connected components. split off smaller one
198 cc_new = min(splitcc_list, key=len)
199 Hcc_new = Hcc.subgraph(cc_new).copy()
200 # update edge rankings for Hcc_new
201 newranks = rank(Hcc_new)
202 for e, r in newranks.items():
203 ranking[e if e in ranking else e[::-1]] = r
204 # append new cc and Hcc to their lists.
205 partition.append(cc_new)
206 Hcc_subgraphs.append(Hcc_new)
207
208 # leave existing cc and Hcc in their lists, but shrink them
209 Hcc.remove_nodes_from(cc_new)
210 cc.difference_update(cc_new)
211 # update edge rankings for Hcc whether it was split or not
212 newranks = rank(Hcc)
213 for e, r in newranks.items():
214 ranking[e if e in ranking else e[::-1]] = r
215 break
216 return partition