-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathspread.py
159 lines (132 loc) · 5.15 KB
/
spread.py
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import networkx as nx
import random
import numpy
import math
""" Spread models """
""" Simulation of spread for Independent Cascade (IC) and Weighted Cascade (WC).
Suits (un)directed graphs.
Assumes the edges point OUT of the influencer, e.g., if A->B or A-B, then "A influences B".
"""
def IC_model(G, a, p, random_generator): # a: the set of initial active nodes
# p: the system-wide probability of influence on an edge, in [0,1]
A = set(a) # A: the set of active nodes, initially a
B = set(a) # B: the set of nodes activated in the last completed iteration
converged = False
while not converged:
nextB = set()
for n in B:
for m in set(G.neighbors(n)) - A: # G.neighbors follows A-B and A->B (successor) edges
prob = random_generator.random() # in the range [0.0, 1.0)
if prob <= p:
nextB.add(m)
B = set(nextB)
if not B:
converged = True
A |= B
return len(A)
def WC_model(G, a, random_generator): # a: the set of initial active nodes
# each edge from node u to v is assigned probability 1/in-degree(v) of activating v
A = set(a) # A: the set of active nodes, initially a
B = set(a) # B: the set of nodes activated in the last completed iteration
converged = False
if nx.is_directed(G):
my_degree_function = G.in_degree
else:
my_degree_function = G.degree
while not converged:
nextB = set()
for n in B:
for m in set(G.neighbors(n)) - A:
prob = random_generator.random() # in the range [0.0, 1.0)
p = 1.0/my_degree_function(m)
if prob <= p:
nextB.add(m)
B = set(nextB)
if not B:
converged = True
A |= B
return len(A)
def IC_model_max_hop(G, a, p, max_hop, random_generator): # a: the set of initial active nodes
# p: the system-wide probability of influence on an edge, in [0,1]
A = set(a) # A: the set of active nodes, initially a
B = set(a) # B: the set of nodes activated in the last completed iteration
converged = False
while (not converged) and (max_hop > 0):
nextB = set()
for n in B:
for m in set(G.neighbors(n)) - A: # G.neighbors follows A-B and A->B (successor) edges
prob = random_generator.random() # in the range [0.0, 1.0)
if prob <= p:
nextB.add(m)
B = set(nextB)
if not B:
converged = True
A |= B
max_hop -= 1
return len(A)
def WC_model_max_hop(G, a, max_hop, random_generator): # a: the set of initial active nodes
# each edge from node u to v is assigned probability 1/in-degree(v) of activating v
A = set(a) # A: the set of active nodes, initially a
B = set(a) # B: the set of nodes activated in the last completed iteration
converged = False
if nx.is_directed(G):
my_degree_function = G.in_degree
else:
my_degree_function = G.degree
while (not converged) and (max_hop > 0):
nextB = set()
for n in B:
for m in set(G.neighbors(n)) - A:
prob = random_generator.random() # in the range [0.0, 1.0)
p = 1.0 / my_degree_function(m)
if prob <= p:
nextB.add(m)
B = set(nextB)
if not B:
converged = True
A |= B
max_hop -= 1
return len(A)
""" Evaluates a given seed set A, simulated "no_simulations" times.
Returns a tuple: (the mean, the stdev).
"""
def MonteCarlo_simulation(G, A, p, no_simulations, model, random_generator=None):
if random_generator is None:
random_generator = random.Random()
random_generator.seed(next(iter(A))) # initialize random number generator with first seed in the seed set, to make experiment repeatable; TODO evaluate computational cost
results = []
if model == 'WC':
for i in range(no_simulations):
results.append(WC_model(G, A, random_generator=random_generator))
elif model == 'IC':
for i in range(no_simulations):
results.append(IC_model(G, A, p, random_generator=random_generator))
return (numpy.mean(results), numpy.std(results))
def MonteCarlo_simulation_max_hop(G, A, p, no_simulations, model, max_hop=2, random_generator=None):
"""
calculates approximated influence spread of a given seed set A, with
information propagation limited to a maximum number of hops
example: with max_hops = 2 only neighbours and neighbours of neighbours can be activated
:param G: networkx input graph
:param A: seed set
:param p: probability of influence spread (IC model)
:param no_simulations: number of spread function simulations
:param model: propagation model
:param max_hops: maximum number of hops
:return:
"""
if random_generator is None:
random_generator = random.Random()
random_generator.seed(next(iter(A))) # initialize random number generator with first seed in the seed set, to make experiment repeatable; TODO evaluate computational cost
results = []
if model == 'WC':
for i in range(no_simulations):
results.append(WC_model_max_hop(G, A, max_hop, random_generator))
elif model == 'IC':
for i in range(no_simulations):
results.append(IC_model_max_hop(G, A, p, max_hop, random_generator))
return (numpy.mean(results), numpy.std(results))
if __name__ == "__main__":
G = nx.path_graph(100)
print(nx.classes.function.info(G))
print(MonteCarlo_simulation(G, [0, 2, 4, 6, 8, 10], 0.1, 100, 'IC'))