forked from frbkrm/HomophilicNtwMinorities
-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate_homophilic_graph_degree_dynamic_asymmetric.py
171 lines (126 loc) · 4.57 KB
/
generate_homophilic_graph_degree_dynamic_asymmetric.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
160
161
162
163
164
"""
Generators for BA homophilic graph.
The algorithm is based on paper 'scale-free homophilic network'
by almedia et al (2013).
written by: Fariba Karimi
Date: 27-07-2016
"""
import networkx as nx
from collections import defaultdict
import random
import bisect
import copy
def homophilic_barabasi_albert_graph_asym(N, m , minority_fraction, h_ab , h_ba):
"""Return homophilic random graph using BA preferential attachment model.
A graph of n nodes is grown by attaching new nodes each with m
edges that are preferentially attached to existing nodes with high
degree. The connections are established by linking probability which
depends on the connectivity of sites and the similitude (similarities).
similitude varies ranges from 0 to 1.
Parameters
----------
N : int
Number of nodes
m : int
Number of edges to attach from a new node to existing nodes
seed : int, optional
Seed for random number generator (default=None).
minority_fraction : float
fraction of minorities in the network
similitude: float
value between 0 to 1. similarity between nodes. if nodes have same attribute
their similitude (distance) is smaller.
Returns
-------
G : Graph
Notes
-----
The initialization is a graph with with m nodes and no edges.
References
----------
.. [1] A. L. Barabasi and R. Albert "Emergence of scaling in
random networks", Science 286, pp 509-512, 1999.
"""
# a = min
#h_ab = 0.8
#h_ba = 0.2
h_aa = 1 - h_ab
h_bb = 1 - h_ba
# Add m initial nodes (m0 in barabasi-speak)
G = nx.Graph()
minority = int(minority_fraction * N)
minority_nodes = random.sample(range(N),minority)
node_attribute = {}
for n in range(N):
if n in minority_nodes:
G.add_node(n , color = 'red')
node_attribute[n] = 'minority'
else:
G.add_node(n , color = 'blue')
node_attribute[n] = 'majority'
dist = defaultdict(int)
#create homophilic distance ### faster to do it outside loop ###
for n1 in range(N):
n1_attr = node_attribute[n1]
for n2 in range(N):
n2_attr = node_attribute[n2]
if n1_attr == n2_attr:
if n1_attr == 'minority':
dist[(n1,n2)] = h_aa
else:
dist[(n1,n2)] = h_bb
else:
if n1_attr == 'minority':
dist[(n1,n2)] = h_ab
else:
dist[(n1,n2)] = h_ba
target_list=list(range(m))
source = m
time_step = 1
#selective_nodes = random.sample(range(minority),40) + random.sample(range(minority,N),40) # to evaluate degree dynamic
degree_dynamic = defaultdict(dict)
sum_degree_time = defaultdict(float) #for calculating sum(qk), keys = time, values = total prob. sum
existing_nodes = list(range(m))
while source < N:
targets , prob_sum = _pick_targets(G,source,target_list,dist,m)
sum_degree_time[time_step] = prob_sum
if targets != set(): #if the node does find the neighbor
G.add_edges_from(zip([source]*m,targets))
##### calculate degree dynamic ####
for n_ in existing_nodes:
degree_dynamic[n_][time_step] = G.degree(n_)
target_list.append(source)
existing_nodes.append(source)
time_step += 1
source += 1
#print('#################################')
return G , degree_dynamic , sum_degree_time
def _pick_targets(G,source,target_list,dist,m):
prob_sum = 0.0
target_prob_dict = {}
for target in target_list:
target_prob = (1-dist[(source,target)])* (G.degree(target)+0.00001)
#print target_prob
#prob_sum += target_prob
target_prob_dict[target] = target_prob
prob_sum = sum(target_prob_dict.values())
targets = set()
target_list_copy = copy.copy(target_list)
count_looking = 0
if prob_sum == 0:
return targets
while len(targets) < m:
count_looking += 1
if count_looking > len(G): # if node fails to find target
break
rand_num = random.random()
cumsum = 0.0
for k in target_list_copy:
cumsum += float(target_prob_dict[k]) / prob_sum
if rand_num < cumsum:
targets.add(k)
target_list_copy.remove(k)
break
return targets , prob_sum
if __name__ == '__main__':
graph = homophilic_barabasi_albert_graph_assym(N = 100, m = 2 , minority_fraction = 0.5, h_ab=0.5 , h_ba = 0.5)