import graph_tool.all as gt
import numpy as np
import datetime as dt
import visualization
###############################################
### NOTE: We use the largest component, not ###
### the entire graph for the calculation ###
###############################################
###############################################
### functions used by all percolation modes ###
###############################################
def percolation(percolated_graph,intact_graph):
return 100.0*(1.0-float(percolated_graph.num_vertices())/float(intact_graph.num_vertices()))
def print_info(flc, glc):
print 'filtered graph - vertices: '+str(flc.num_vertices())+' / edges: '+str(flc.num_edges())
print 'percolation: '+str(percolation(flc,glc))+'%'
# the function below was needed in previous versions of CoRiA because the set of set members was nested within another set
#def read_redis_smembers(redis,key):
# s = redis.smembers(key) #read set
#return [i.strip() for i in [l.strip('[]').split(',') for l in s][0]] #write list and strip of useless characters
#################################
####### percolation modes #######
#################################
# These percolation modes take as input the mode name and n - a dictionary of
# numbers of nodes to take out (as keys) and corresponding percentages.
# They return a dictionary of percentage keys and percolation values.
# Advanced percolation modes nest this dictionary within a dictionary of groups.
# Therefore, they require a loop over these groups, which can be e.g. metrics or countries.
#################################
#### BASIC PERCOLATION MODES ####
#################################
def failure(self, mode_name, n):
print 'Calculating percolation due to random failure'
# initialise
counter = 0
results = {}
# take a random sample from the largest component
for v in np.random.choice(list(self.glc.vertices()),size=max(n.keys()),replace=False):
self.exclusion_map[self.g.vertex(v)] = 0
counter += 1
if counter in n.keys():
print counter,'nodes removed'
# graph without the excluded vertices (i.e. those that have value 0 in the exclusion map)
f = gt.GraphView(self.g, vfilt = self.exclusion_map)
# largest component of graph f
flc = gt.GraphView(self.g, vfilt = gt.label_largest_component(f))
print_info(flc,self.glc)
results[n[counter]] = percolation(flc,self.glc)
# visualize deterioration
# visualization.draw_deterioration(self,self.sfdp,mode_name+'_'+str(int(n[counter]))+'_pct')
return results
#####################################################################
def random_walk(self, mode_name, n):
print 'Calculating percolation due to random walk'
#first vertex for random walk
start = self.glc.vertex(np.random.randint(0,self.glc.num_vertices()), use_index=False)
#do random walk
alternate_list = list(self.label_map.a)
np.random.shuffle(alternate_list)
results = rw(self,start,n,alternate_list,mode_name)
#return dict(zip(percentages,percolations))
return results
#####################################################################
#################################
## ADVANCED PERCOLATION MODES ###
#################################
def target_list(self, mode_name, n):
print 'Calculating percolation due to targeted attack , i.e. taking out top nodes from a target list'
# instantiate results dictionary and target lists
results = {}
nodes_max = {}
#loop through all metrics
all_metrics = list(self.base_metrics.keys() + self.advanced_metrics.keys())
for metric in all_metrics:
#get nodes with highest value of metric
nodes_max[metric] = self.redis.zrange(self.metric_prefix+metric+self.normalization_suffix, -max(n.keys()), -1, withscores=False, score_cast_func=float).reverse()
#loop through all scores
all_scores = list(self.scores.keys() + self.advanced_scores.keys())
for score in all_scores:
#get nodes with highest value of score
nodes_max[score] = self.redis.zrange(self.score_prefix+score, -max(n.keys()), -1, withscores=False, score_cast_func=float).reverse()
#loop through all metrics and scores
for metric in all_metrics+all_scores:
print 'Taking out top nodes for metric',metric
# initialise variables and exclusion map
counter = 0
self.exclusion_map.a = 1
results[metric] = {}
for node in nodes_max[metric]:
vertex = gt.find_vertex(self.g,self.label_map,node)[0]
self.exclusion_map[vertex] = 0
counter += 1
if counter in n.keys():
print counter,'nodes removed'
# graph without the excluded vertices (i.e. those that have value 0 in the exclusion map)
f = gt.GraphView(self.g, vfilt = self.exclusion_map)
# largest component of graph f
flc = gt.GraphView(self.g, vfilt = gt.label_largest_component(f))
print_info(flc,self.glc)
results[metric][n[counter]] = percolation(flc,self.glc)
# visualize deterioration
# visualization.draw_deterioration(self,self.sfdp,mode_name+'_'+metric+'_'+str(int(n[counter]))+'_pct')
return results
#####################################################################
def hybrid_mode(self, mode_name, n):
print 'Calculating percolation due to random walk starting from node with highest value of metric'
# instantiate results dictionary and alternate lists for random walk
results = {}
alternate_lists = {}
#loop through all metrics
all_metrics = list(self.base_metrics.keys() + self.advanced_metrics.keys())
for metric in all_metrics:
#get nodes with highest value of metric
temp_list = self.redis.zrange(self.metric_prefix+metric+self.normalization_suffix, 0, -1, withscores=False, score_cast_func=float)
alternate_lists[metric] = [node for node in reversed(temp_list)]
#loop through all scores
all_scores = list(self.scores.keys() + self.advanced_scores.keys())
for score in all_scores:
#get nodes with highest value of score
temp_list = self.redis.zrange(self.score_prefix+score, 0, -1, withscores=False, score_cast_func=float)
alternate_lists[score] = [node for node in reversed(temp_list)]
#loop through all metrics and scores
for metric in all_metrics+all_scores:
print 'Starting from node with highest value of metric',metric
#initialise exclusion vertex property map
self.exclusion_map.a = 1
#first vertex for random walk
start = gt.find_vertex(self.g,self.label_map,alternate_lists[metric][0])[0]
#do random walk
results[metric] = rw(self,start,n,alternate_lists[metric],mode_name+'_'+metric)
return results
def russian(self, mode_name, n):
print 'Calculating percolation due to shutting off the Russian network from the internet'
# instantiate results dictionary and target lists
#results = {}
#nodes_max = {}
self.exclusion_map.a = 0
counter = 0
results = {}
for v in self.g.vertices():
if self.g.vp.country_code[v] == 'RU':
print 'Shutting off node',int(v),'because it\'s Russian!'
self.exclusion_map[v] = 1
counter += 1
# if counter in n.keys():
# print counter,'nodes removed'
# graph without the excluded vertices (i.e. those that have value 0 in the exclusion map)
# f = gt.GraphView(self.g, vfilt = self.exclusion_map)
# largest component of graph f
# flc = gt.GraphView(self.g, vfilt = gt.label_largest_component(f))
# print_info(flc,self.glc)
# results[n[counter]] = percolation(flc,self.glc)
# visualize deterioration
# visualization.draw_deterioration(self,self.sfdp,mode_name+'_'+metric+'_'+str(int(n[counter]))+'_pct')
f = gt.GraphView(self.g, vfilt = self.exclusion_map)
flc = gt.GraphView(self.g, vfilt = gt.label_largest_component(f))
#results[max(n.values())] = percolation(flc,self.g)
# visualize deterioration
print 'Creating visualization #1 of the deterioration.'
visualization.draw_deterioration(self,self.g.vp.sfdp,mode_name+"_SFDP_inverse")
print 'Creating visualization #2 of the deterioration.'
visualization.draw_deterioration(self,self.g.vp.Random,mode_name+"_Random_inverse")
print 'Creating visualization #3 of the deterioration.'
visualization.draw_deterioration(self,self.g.vp.Radial,mode_name+"_Radial_inverse")
#return results
#####################################################################
############## Random Walk for the RW deletion modes ################
#####################################################################
# takes as input a start vertex, the number of vertices to take out
# and an alternate list of vertices if the random walk reaches a dead end
def rw(self, vertex, n, alternate_list, mode_name):
# initialise
results = {}
self.exclusion_map[vertex] = 0 #take out start vertex
# initialise graph filters
# graph without the excluded vertices (i.e. those that have value 0 in the exclusion map)
f = gt.GraphView(self.g, vfilt = self.exclusion_map)
# largest component of graph f
flc = gt.GraphView(self.g, vfilt = gt.label_largest_component(f))
if 1 in n.keys():
print '1 node removed'
print_info(flc,self.glc)
results[n[1]] = percolation(flc,self.glc)
# visualize deterioration
# visualization.draw_deterioration(self,self.sfdp,mode_name+'_'+str(int(n[1]))+'_pct')
for i in range(max(n.keys())-1):
neighbours = list(vertex.all_neighbours())
flag = 0 #decision flag
# choose a random neighbour
if len(neighbours) > 0:
np.random.shuffle(neighbours)
for neighbour in neighbours:
if self.exclusion_map[neighbour] != 0:
vertex = neighbour
flag = 1
break
# to be executed if no neighbours exist - choose the next node out of an alternative list
if flag == 0:
# create a list of already used list members
used_list = []
for node in alternate_list:
vertex = gt.find_vertex(self.g,self.label_map,node)[0]
used_list.append(node)
if self.exclusion_map[vertex] != 0:
break
if len(used_list) > 0:
for used_node in used_list:
# remove used members from alternate list. This reduces calculation time in next iteration
alternate_list.remove(used_node)
self.exclusion_map[vertex] = 0 #take out vertex
f = gt.GraphView(self.g, vfilt = self.exclusion_map) #update graph (filtered)
if i+2 in n.keys():
flc = gt.GraphView(self.g, vfilt = gt.label_largest_component(f)) #update largest component
print i+2,'nodes removed'
print_info(flc,self.glc)
results[n[i+2]] = percolation(flc,self.glc)
# visualize deterioration
# visualization.draw_deterioration(self,self.sfdp,mode_name+'_'+str(int(n[i+2]))+'_pct')
return results
##############################
##############################
########## THE END ###########
##############################
##############################