-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil_robustness.py
More file actions
129 lines (114 loc) · 4.63 KB
/
util_robustness.py
File metadata and controls
129 lines (114 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# code adapted from
# https://github.com/tsantanam/networkx-robustness/blob/v0.0.7/src/networkx_robustness/networkx_robustness.py
# with some shortcuts
import networkx as nx
import random
def simulate_random_attack(G=None, attack_fraction=0.1, stepSize=10, weight=None):
"""
Simulate random attack on a network
:param G: networkx graph
:param attack_fraction: fraction of nodes to be attacked (default: 0.1)
:param stepSize: number of nodes to be removed in each step (default: 20)
:param weight: weight of edges (default: None)
:return: initial (float), frac (list), apl (list)
"""
# copy the graph to avoid changing the original graph
G = G.copy()
G = G.to_undirected() # make sure the graph is undirected for the robustness analysis
# get the number of nodes
G_nodes = G.number_of_nodes()
# get the initial fraction of nodes in the largest connected component
lcc_size = len(max(nx.connected_components(G), key=len))
initial = lcc_size / G_nodes
try:
aveShortPath = nx.average_shortest_path_length(G, weight=weight)
except nx.NetworkXError:
aveShortPath = -1
# initialize lists
frac = [initial]
apl = [aveShortPath]
numNodes = [G_nodes]
# simulate random attack in batches
for i in range(0, int(G_nodes * attack_fraction), stepSize):
G.remove_nodes_from(random.sample(list(G.nodes()), stepSize))
# get the largest component
Gc = G.subgraph(max(nx.connected_components(G), key=len))
# calculate metrics
numNodes.append(G.number_of_nodes())
frac.append(Gc.number_of_nodes() / G.number_of_nodes())
if Gc.number_of_nodes() > 1:
apl.append(nx.average_shortest_path_length(Gc, weight=weight))
else:
apl.append(0)
return frac, apl, numNodes
def simulate_degree_attack(G=None, attack_fraction=0.1, stepSize=10, weight=None):
"""
Simulate random attack on a network
:param G: networkx graph
:param attack_fraction: fraction of nodes to be attacked (default: 0.1)
:param stepSize: number of nodes to be removed in each step (default: 20)
:param weight: weight of edges (default: None)
:return: initial (float), frac (list), apl (list)
"""
# copy the graph to avoid changing the original graph
G = G.copy()
G = G.to_undirected() # make sure the graph is undirected for the robustness analysis
# get the number of nodes
G_nodes = G.number_of_nodes()
# get the initial fraction of nodes in the largest connected component
lcc_size = len(max(nx.connected_components(G), key=len))
initial = lcc_size / G_nodes
try:
aveShortPath = nx.average_shortest_path_length(G, weight=weight)
except nx.NetworkXError:
aveShortPath = -1
# initialize lists
frac = [initial]
apl = [aveShortPath]
numNodes = [G_nodes]
#get the degree of each node
degree = nx.degree_centrality(G)
# sort the nodes by degree
degree = sorted(degree, key=degree.get, reverse=True)
# simulate degree attack
for i in range(0, int(G_nodes * attack_fraction)):
# remove the node with the highest degree
G.remove_nodes_from(degree[i:i+stepSize])
# get the largest connected component of G
Gc = G.subgraph(max(nx.connected_components(G), key=len))
# calculate metrics
numNodes.append(G.number_of_nodes())
frac.append(Gc.number_of_nodes() / G.number_of_nodes())
if Gc.number_of_nodes() > 1:
apl.append(nx.average_shortest_path_length(Gc, weight=weight))
else:
apl.append(0)
return frac, apl, numNodes
def molloy_reed(G=None):
"""
Compute the Molloy-Reed criterion for a network
:param G: networkx graph
:return: Molloy-Reed criterion
"""
# get the average squared degree
avg_sq_degree = sum([d ** 2 for n, d in G.degree()]) / G.number_of_nodes()
# get the average degree
avg_degree = sum([d for n, d in G.degree()]) / G.number_of_nodes()
# compute the Molloy-Reed criterion
molloy_reed = avg_sq_degree/avg_degree
return molloy_reed
def critical_threshold(G=None):
"""
Compute the critical threshold for a network
:param G: networkx graph
:return: critical threshold
"""
# get the average squared degree
avg_sq_degree = sum([d ** 2 for n, d in G.degree()]) / G.number_of_nodes()
# get the average degree
avg_degree = sum([d for n, d in G.degree()]) / G.number_of_nodes()
# compute the Molloy-Reed criterion
molloy_reed = avg_sq_degree/avg_degree
# compute the critical threshold
critical_threshold = 1 - (1/(molloy_reed-1))
return critical_threshold