In [416]:
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
from itertools import combinations
In [417]:
n = 8
sign = ['+', '-']
nodes = np.arange(1,n+1,1)
triangles = list(combinations(nodes,3))
In [418]:
# add Graph
G = nx.Graph()
# add nodes
G.add_nodes_from(nodes)
In [419]:
for n1 in G.nodes():
for n2 in G.nodes():
if n1 != n2:
s = np.random.choice(sign,p=[.5,.5])
G.add_edge(n1,n2,sign=s)
Original = G.copy()
In [420]:
pos = nx.spring_layout(G)
In [421]:
def partial_draw_network(G,pos,node_color='#ADD8E6',width=3,include_signs=True):
edge_labels = nx.get_edge_attributes(G,'sign')
edge_colors = ['g' if e[2]['sign'] == '+' else 'r' for e in G.edges(data=True)]
nx.draw(G, pos=pos, edge_color=edge_colors, width=width, node_color=node_color, with_labels=True)
if include_signs:
nx.draw_networkx_edge_labels(G, pos=pos, edge_labels=edge_labels, font_size=20)
def draw_network(G,pos,node_color='#ADD8E6',width=3,include_signs=True):
partial_draw_network(G,pos,node_color,width,include_signs)
plt.axis('off')
plt.show()
In [429]:
# draw current state
plt.figure(figsize=[15,15])
draw_network(G,pos)
In [423]:
def is_stable(signs = []):
count = signs.count('+')
return ((count == 3) | (count == 1))
def get_stability(all_signs):
stable = 0
unstable = 0
for signs in all_signs:
if is_stable(signs):
stable += 1
else:
unstable += 1
return {'stable': stable, 'unstable': unstable}
def get_signs(G,triangle = []):
assert len(triangle) == 3
prevs = []
signs = []
for n1 in triangle:
for n2 in triangle:
if (n1 != n2) & (n2 not in prevs):
value = G[n1][n2]['sign']
signs.append(value)
prevs.append(n1)
return signs
def get_all_signs(G,all_triangles):
return [get_signs(G,t) for t in all_triangles]
In [424]:
# get all the triangle signs
triangle_signs = get_all_signs(G,triangles)
# print out the network stability info
output = get_stability(triangle_signs)
print(output)
In [425]:
def make_triangle_stable(G,triangle):
signs = get_signs(G,triangle)
while(not is_stable(signs)):
plus_count = signs.count('+')
# randomly choose two nodes
n1 = np.random.choice(triangle)
n2 = np.random.choice(np.setdiff1d(triangle, [n1]))
# flip the sign
s = G[n1][n2]['sign']
if s == '+':
s = '-'
else:
s = '+'
G[n1][n2]['sign'] = s
# pull the latest.
signs = get_signs(G,triangle)
In [426]:
while output['unstable'] > 0:
# randomly choose an unstable triangle
unstable_triangles = [t for t in triangles if not is_stable(get_signs(G,t))]
unstable_triangle_index = np.random.choice(np.arange(0,len(unstable_triangles),1))
unstable_triangle = unstable_triangles[unstable_triangle_index]
# fix unstable_triangle
make_triangle_stable(G,unstable_triangle)
# pull latest and check for network stability
triangle_signs = get_all_signs(G,triangles)
output = get_stability(triangle_signs)
triangle_signs = get_all_signs(G,triangles)
output = get_stability(triangle_signs)
print(output)
In [428]:
# draw prior and current state
plt.figure(figsize=[10,10])
plt.subplot(1,2,1)
partial_draw_network(Original,pos,include_signs=False)
plt.subplot(1,2,2)
partial_draw_network(G,pos,include_signs=False)
plt.tight_layout()
plt.show()
print()
print('red = "negative" relationship')
print('green = "positive" relationship')
In [ ]: