| import functools |
|
|
| import networkx as nx |
|
|
| __all__ = [ |
| "edge_betweenness_partition", |
| "edge_current_flow_betweenness_partition", |
| ] |
|
|
|
|
| @nx._dispatchable(edge_attrs="weight") |
| def edge_betweenness_partition(G, number_of_sets, *, weight=None): |
| """Partition created by iteratively removing the highest edge betweenness edge. |
| |
| This algorithm works by calculating the edge betweenness for all |
| edges and removing the edge with the highest value. It is then |
| determined whether the graph has been broken into at least |
| `number_of_sets` connected components. |
| If not the process is repeated. |
| |
| Parameters |
| ---------- |
| G : NetworkX Graph, DiGraph or MultiGraph |
| Graph to be partitioned |
| |
| number_of_sets : int |
| Number of sets in the desired partition of the graph |
| |
| weight : key, optional, default=None |
| The key to use if using weights for edge betweenness calculation |
| |
| Returns |
| ------- |
| C : list of sets |
| Partition of the nodes of G |
| |
| Raises |
| ------ |
| NetworkXError |
| If number_of_sets is <= 0 or if number_of_sets > len(G) |
| |
| Examples |
| -------- |
| >>> G = nx.karate_club_graph() |
| >>> part = nx.community.edge_betweenness_partition(G, 2) |
| >>> {0, 1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 16, 17, 19, 21} in part |
| True |
| >>> {2, 8, 9, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33} in part |
| True |
| |
| See Also |
| -------- |
| edge_current_flow_betweenness_partition |
| |
| Notes |
| ----- |
| This algorithm is fairly slow, as both the calculation of connected |
| components and edge betweenness relies on all pairs shortest |
| path algorithms. They could potentially be combined to cut down |
| on overall computation time. |
| |
| References |
| ---------- |
| .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports |
| Volume 486, Issue 3-5 p. 75-174 |
| http://arxiv.org/abs/0906.0612 |
| """ |
| if number_of_sets <= 0: |
| raise nx.NetworkXError("number_of_sets must be >0") |
| if number_of_sets == 1: |
| return [set(G)] |
| if number_of_sets == len(G): |
| return [{n} for n in G] |
| if number_of_sets > len(G): |
| raise nx.NetworkXError("number_of_sets must be <= len(G)") |
|
|
| H = G.copy() |
| partition = list(nx.connected_components(H)) |
| while len(partition) < number_of_sets: |
| ranking = nx.edge_betweenness_centrality(H, weight=weight) |
| edge = max(ranking, key=ranking.get) |
| H.remove_edge(*edge) |
| partition = list(nx.connected_components(H)) |
| return partition |
|
|
|
|
| @nx._dispatchable(edge_attrs="weight") |
| def edge_current_flow_betweenness_partition(G, number_of_sets, *, weight=None): |
| """Partition created by removing the highest edge current flow betweenness edge. |
| |
| This algorithm works by calculating the edge current flow |
| betweenness for all edges and removing the edge with the |
| highest value. It is then determined whether the graph has |
| been broken into at least `number_of_sets` connected |
| components. If not the process is repeated. |
| |
| Parameters |
| ---------- |
| G : NetworkX Graph, DiGraph or MultiGraph |
| Graph to be partitioned |
| |
| number_of_sets : int |
| Number of sets in the desired partition of the graph |
| |
| weight : key, optional (default=None) |
| The edge attribute key to use as weights for |
| edge current flow betweenness calculations |
| |
| Returns |
| ------- |
| C : list of sets |
| Partition of G |
| |
| Raises |
| ------ |
| NetworkXError |
| If number_of_sets is <= 0 or number_of_sets > len(G) |
| |
| Examples |
| -------- |
| >>> G = nx.karate_club_graph() |
| >>> part = nx.community.edge_current_flow_betweenness_partition(G, 2) |
| >>> {0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 16, 17, 19, 21} in part |
| True |
| >>> {8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33} in part |
| True |
| |
| |
| See Also |
| -------- |
| edge_betweenness_partition |
| |
| Notes |
| ----- |
| This algorithm is extremely slow, as the recalculation of the edge |
| current flow betweenness is extremely slow. |
| |
| References |
| ---------- |
| .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports |
| Volume 486, Issue 3-5 p. 75-174 |
| http://arxiv.org/abs/0906.0612 |
| """ |
| if number_of_sets <= 0: |
| raise nx.NetworkXError("number_of_sets must be >0") |
| elif number_of_sets == 1: |
| return [set(G)] |
| elif number_of_sets == len(G): |
| return [{n} for n in G] |
| elif number_of_sets > len(G): |
| raise nx.NetworkXError("number_of_sets must be <= len(G)") |
|
|
| rank = functools.partial( |
| nx.edge_current_flow_betweenness_centrality, normalized=False, weight=weight |
| ) |
|
|
| |
| H = G.copy() |
| partition = list(nx.connected_components(H)) |
| if len(partition) > 1: |
| Hcc_subgraphs = [H.subgraph(cc).copy() for cc in partition] |
| else: |
| Hcc_subgraphs = [H] |
|
|
| ranking = {} |
| for Hcc in Hcc_subgraphs: |
| ranking.update(rank(Hcc)) |
|
|
| while len(partition) < number_of_sets: |
| edge = max(ranking, key=ranking.get) |
| for cc, Hcc in zip(partition, Hcc_subgraphs): |
| if edge[0] in cc: |
| Hcc.remove_edge(*edge) |
| del ranking[edge] |
| splitcc_list = list(nx.connected_components(Hcc)) |
| if len(splitcc_list) > 1: |
| |
| cc_new = min(splitcc_list, key=len) |
| Hcc_new = Hcc.subgraph(cc_new).copy() |
| |
| newranks = rank(Hcc_new) |
| for e, r in newranks.items(): |
| ranking[e if e in ranking else e[::-1]] = r |
| |
| partition.append(cc_new) |
| Hcc_subgraphs.append(Hcc_new) |
|
|
| |
| Hcc.remove_nodes_from(cc_new) |
| cc.difference_update(cc_new) |
| |
| newranks = rank(Hcc) |
| for e, r in newranks.items(): |
| ranking[e if e in ranking else e[::-1]] = r |
| break |
| return partition |
|
|