def SIS_process(G, degree_prob, tmax, tau, gamma): N = G.order() plt.figure(5) plt.clf() plt.figure(6) plt.clf() for index, starting_node in enumerate([x * N / 10. for x in range(10)]): plt.figure(5) t, S, I = EoN.fast_SIS(G, tau, gamma, initial_infecteds=[starting_node], tmax=tmax) #print(I[-1]) subt = scipy.linspace(0, tmax, 501) subI = EoN.subsample(subt, t, I) plt.plot(subt, subI) if I[-1] > 100: plt.figure(6) shift = EoN.get_time_shift(t, I, 1000) plt.plot(subt - shift, subI) plt.figure(5) plt.savefig('sw_SIS_epi_N{}_p{}_k{}_tau{}.pdf'.format(N, p, k, tau)) plt.figure(6) plt.savefig('sw_SIS_epi_N{}_p{}_k{}_tau{}_shifted.pdf'.format( N, p, k, tau))
def process_degree_distribution(N, Pk, color, Psi, DPsi, symbol, label, count): report_times = scipy.linspace(0, 30, 3000) sums = 0 * report_times for cnt in range(count): G = generate_network(Pk, N) t, S, I, R = EoN.fast_SIR(G, tau, gamma, rho=rho) plt.plot(t, I * 1. / N, '-', color=color, alpha=0.1, linewidth=1) subsampled_I = EoN.subsample(report_times, t, I) sums += subsampled_I * 1. / N ave = sums / count plt.plot(report_times, ave, color='k') #Do EBCM N = G.order( ) #N is arbitrary, but included because our implementation of EBCM assumes N is given. t, S, I, R = EoN.EBCM_uniform_introduction(N, Psi, DPsi, tau, gamma, rho, tmin=0, tmax=10, tcount=41) plt.plot(t, I / N, symbol, color=color, markeredgecolor='k', label=label) for cnt in range(3): #do 3 highlighted simulations G = generate_network(Pk, N) t, S, I, R = EoN.fast_SIR(G, tau, gamma, rho=rho) plt.plot(t, I * 1. / N, '-', color='k', linewidth=0.1)
def simulate_process(graph_function, iterations, tmax, tcount, rho, kave, tau, gamma, symbol): Isum = scipy.zeros(tcount) report_times = scipy.linspace(0, tmax, tcount) for counter in range(iterations): G = graph_function() t, S, I = EoN.fast_SIS(G, tau, gamma, rho=rho, tmax=tmax) I = EoN.subsample(report_times, t, I) Isum += I plt.plot(report_times, Isum * 1. / (N * iterations), symbol)
def SIR_process(G, degree_prob, tau, gamma, tmax=10): N = G.order() plt.figure(2) plt.clf() plt.figure(3) plt.clf() plt.figure(5) plt.clf() for index, starting_node in enumerate([x * N / 100. for x in range(100)]): plt.figure(2) t, S, I, R = EoN.fast_SIR(G, tau, gamma, initial_infecteds=[starting_node]) subt = scipy.linspace(0, t[-1], 101) subI, subR = EoN.subsample(subt, t, I, R) plt.plot(subt, subI) if R[-1] > 500: plt.figure(3) shift = EoN.get_time_shift(t, R, threshold) plt.plot(subt - shift, subI) plt.figure(5) plt.plot(subt - shift, subR) #t, S, I, R = EoN.EBCM(degree_prob, tau, gamma, rho) rho = 1. / N def psi(x): return sum(degree_prob[k] * x**k for k in degree_prob) def psiPrime(x): return sum(k * degree_prob[k] * x**(k - 1) for k in degree_prob) t, S, I, R = EoN.EBCM_uniform_introduction(N, psi, psiPrime, tau, gamma, rho, tmax=tmax) shift = EoN.get_time_shift(t, R, threshold) plt.figure(2) #plt.savefig('sw_SIR_epi_N{}_p{}_k{}_tau{}.pdf'.format(N,p,k,tau)) plt.figure(3) plt.plot(t - shift, I, '--') plt.xlabel('$t$', fontsize=18) plt.ylabel('$I$', fontsize=18) #plt.set_xtick_labels(fontsize = 15) xmax = get_xmax(t - shift, I) plt.axis(xmax=xmax) plt.savefig('sw_SIR_epi_N{}_p{}_k{}_tau{}_shifted.pdf'.format( N, p, k, tau)) plt.figure(5) plt.plot(t - shift, R, '--')
def process_degree_distribution(Gbig, Gsmall, color, Psi, DPsi, symbol): t, S, I, R = EoN.fast_SIR(Gsmall, tau, gamma, rho=rho) plt.plot(t, I * 1. / Gsmall.order(), ':', color=color) t, S, I, R = EoN.fast_SIR(Gbig, tau, gamma, rho=rho) plt.plot(t, I * 1. / Gbig.order(), color=color) N = Gbig.order( ) #N is arbitrary, but included because our implementation of EBCM assumes N is given. t, S, I, R = EoN.EBCM(N, lambda x: (1 - rho) * Psi(x), lambda x: (1 - rho) * DPsi(x), tau, gamma, 1 - rho) I = EoN.subsample(report_times, t, I) plt.plot(report_times, I / N, symbol, color=color, markeredgecolor='k')
def add_timeseries(self, t, S, I, R=None, colordict=None, label=None, **kwargs): r'''This allows us to include some additional timeseries for comparision with the simulation. So for example, if we perform a simulation and want to plot the simulation but also a prediction, this is what we would use. :Arguments: **t** list the times **S** list the number susceptible at each time **I** list the number infected at each time **R** list (default None) the number recovered at each time **colordict** dict (default None) a dictionary mapping 'S', 'I', and (if SIR) 'R' to the color desired for their plots. Defaults to the same as the simulation **label** (string) The label to be used for these plots in the legend. ****kwargs** any matplotlib key word args to affect how the curve is shown. :Returns: **ts** timeseries object :Modifies: This adds the timeseries object `ts` to the internal _time_series_list_ ''' if (R is not None and not self.SIR): raise EoN.EoNError("cannot define R if SIR isn't True") if (R is None and self.SIR): raise EoN.EoNError("cannot have SIR True if no R defined") if colordict is None: colordict = self.colordict ts = self._time_series_(t, S, I, R, self.SIR, colordict=colordict, label=label, **kwargs) self._time_series_list_.append(ts) return ts
def sim_update_colordict(self, colordict): r'''updates the colordict for the simulation :Arguments: **colordict** dict the new colordict ''' if not (colordict.has_key('S') and colordict.has_key('I')): raise EoN.EoNError("colordict must have keys 'S' and 'I'") if self.SIR and not colordict.has_key('R'): raise EoN.EoNError("if SIR, then colordict must have key 'R'") self.colordict = colordict
def update_ts_colordict(self, ts, colordict): r'''updates the colordict for time series plots :Arguments: **ts** timeseries object the timeseries object whose key word args we are updating. **colordict** dict the new colordict ''' if not (colordict.has_key('S') and colordict.has_key('I')): raise EoN.EoNError("colordict must have keys 'S' and 'I'") if self.SIR and not colordict.has_key('R'): raise EoN.EoNError("if SIR, then colordict must have key 'R'") ts.colordict = colordict
def add_timeseries(self, t, S, I, R=None, colordict=None, label=None, **kwargs): r'''This allows us to include some additional timeseries for comparision with the simulation. The most likely source of these would be an analytic calculation. Arguments : t (list) the times S (list) the number susceptible at each time I (list) the number infected at each time R (list default None) the number recovered at each time colordict (dict) a dictionary mapping 'S', 'I', and (if SIR) 'R' to the color desired for their plots. Defaults to the same as the simulation label (string) The label to be used for these plots in the legend. **kwargs any matplotlib key word args to affect how the curve is shown. Returns : ts timeseries object ''' if (R is not None and not self.SIR): raise EoN.EoNError("cannot define R if SIR isn't True") if (R is None and self.SIR): raise EoN.EoNError("cannot have SIR True if no R defined") if colordict is None: colordict = self.colordict ts = self._time_series_(t, S, I, R, self.SIR, colordict=colordict, label=label, **kwargs) self._time_series_list_.append(ts) return ts
def transmission_tree(self): r''' Produces a MultiDigraph whose edges correspond to transmission events. If SIR, then this is a tree (or a forest). :Returns: **T** a directed Multi graph T has all the information in ``transmissions``. An edge from u to v with time t means u transmitted to v at time t. :Warning: Although we refer to this as a "tree", if the disease is SIS, there are likely to be cycles and/or repeated edges. If the disease is SIR but there are multiple initial infections, then this will be a "forest". If it's an SIR, then this is a tree (or forest). The graph contains only those nodes that are infected at some point. ''' if self._transmissions_ is None: raise EoN.EoNError("transmissions were not provided when created") T = nx.MultiDiGraph() for t, u, v in self._transmissions_: if u is not None: T.add_edge(u, v, time=t) return T
def sim_and_plot(G, tau, gamma, rho, tmax, tcount, ax): t, S, I = EoN.fast_SIS(G, tau, gamma, rho=rho, tmax = tmax) report_times = scipy.linspace(0, tmax, tcount) I = EoN.subsample(report_times, t, I) ax.plot(report_times, I/N, color='grey', linewidth=5, alpha=0.3) t, S, I, = EoN.SIS_heterogeneous_meanfield_from_graph(G, tau, gamma, rho=rho, tmax=tmax, tcount=tcount) ax.plot(t, I/N, '--') t, S, I = EoN.SIS_compact_pairwise_from_graph(G, tau, gamma, rho=rho, tmax=tmax, tcount=tcount) ax.plot(t, I/N) t, S, I = EoN.SIS_homogeneous_pairwise_from_graph(G, tau, gamma, rho=rho, tmax=tmax, tcount=tcount) ax.plot(t, I/N, '-.')
def run_epidemics(G, tau, gamma, weight, num_init, perc_infec, full=False): ''' ''' time = None nodes = list(G.nodes()) n_nodes = len(nodes) n_iter = 0 while time is None: np.random.shuffle(nodes) full_data = EoN.fast_SIR(G, tau, gamma, initial_infecteds=nodes[0:num_init], transmission_weight=weight, return_full_data=True) infec = full_data.I() recov = full_data.R() for i in range(infec.shape[0]): if infec[i] + recov[i] >= perc_infec * n_nodes: time = full_data.t()[i] break n_iter += 1 if n_iter > 1000: print("Could not reach desired infection rate after 1000 iterations") return None if full is True: return full_data else: return full_data.get_statuses(time=time)
def SIRD(graph, dict_p, tmax = 100, IC = {}, node_seed=-1): for key in dict_p.keys(): if key == 'inf_rate': inf_rate = dict_p['inf_rate'] elif key == 'rec_rate': rec_rate = dict_p['rec_rate'] elif key == 'death_rate': death_rate = dict_p['death_rate'] elif key == 'N_init': N_init = dict_p['N_init'] H = nx.DiGraph() #the spontaneous transitions H.add_edge('Inf', 'Dead', rate = death_rate,weight_label='expose2infect_weight') H.add_edge('Inf', 'Rec', rate = rec_rate) J = nx.DiGraph() #the induced transitions J.add_edge(('Inf', 'Sus'), ('Inf', 'Inf'), rate = inf_rate) if len(IC) == 0: set_node_status(graph, dict_p,node_seed=node_seed) IC = defaultdict(lambda:'Sus') for i in list(np.random.randint(dict_p['N'],size = math.ceil(N_init))): IC[i] = 'Inf' return_statuses = ['Sus', 'Inf', 'Rec', 'Dead'] sim = EoN.Gillespie_simple_contagion(graph, H, J, IC, return_statuses, tmax=tmax, \ return_full_data=True) return sim,dict_p
def run_until_prev(input_net, H, J, initial_conditions, prev_start_SD): net = input_net.copy() next_step_IC = initial_conditions t = None S = None E = None I = None R = None curr_prev = 0 while (curr_prev < prev_start_SD): # Run for one time step ------------------------------------------------ full_net_one_step = EoN.Gillespie_simple_contagion(net, H, J, next_step_IC, return_statuses, tmax = 1, return_full_data=True) t_one_step = full_net_one_step.t() S_one_step = full_net_one_step.S() E_one_step = full_net_one_step.summary()[1]['E'] I_one_step = full_net_one_step.I() R_one_step = full_net_one_step.R() # Concatenate results of the single time step -------------------------- if ((t is None) and (S is None) and (E is None) and (I is None) and (R is None)): t = t_one_step S = S_one_step E = E_one_step I = I_one_step R = R_one_step else: t = np.concatenate((t, (t_one_step + t[-1])), axis=None) S = np.concatenate((S, S_one_step), axis=None) E = np.concatenate((E, E_one_step), axis=None) I = np.concatenate((I, I_one_step), axis=None) R = np.concatenate((R, R_one_step), axis=None) # Get prevalence ------------------------------------------------------- curr_prev = (E[-1] + I[-1]) / N # Get initial conditions for next step of simulation ------------------- nodes_one_step_final = full_net_one_step.get_statuses(list(range(N)), t_one_step[-1]) next_step_IC = defaultdict(lambda: 'S') for node in range(N): status = nodes_one_step_final[node] next_step_IC[node] = status # Create complete returnable object of simulation -------------------------- to_add = list() to_add.append(t) to_add.append(S) to_add.append(E) to_add.append(I) to_add.append(R) full_net = full_net_one_step last_time_step_dictionary = full_net.get_statuses(time=full_net.t()[-1]) to_return = [last_time_step_dictionary, to_add, t[-1]] return to_return
def visualize(self): """Visualize graph like tree""" tree = nx.bfs_tree(self.__graph, self.__root) plt.figure(figsize=(8, 8)) pos = eon.hierarchy_pos(tree, self.__root) nx.draw(self.__graph, pos=pos, with_labels=True, arrows=True) plt.show()
def sim_update_colordict(self, colordict): r''' CHANGES NEEDED. I think just make the test check that keys of colordict and possible statuses match. updates the colordict for the simulation :Arguments: **colordict** dict the new colordict ''' if not (colordict.has_key('S') and colordict.has_key('I')): raise EoN.EoNError("colordict must have keys 'S' and 'I'") if self.SIR and not colordict.has_key('R'): raise EoN.EoNError("if SIR, then colordict must have key 'R'") self.colordict = colordict
def run_sis(original, attacked, budget, num_sim=numSim): """run SIS simulations on both graphs.""" graphs = {'original': original, 'attacked': attacked} rows = [] for name in graphs: G = graphs[name] numNode = G.order() print('Simulating SIS on {}'.format(name)) for ns in range(num_sim): if ns % 50 == 0: print("numSim: {}".format(ns)) #print("numSim: {}".format(ns)) S = [i for i in range(numNode) if G.nodes[i]['target']] SP = list(set(range(numNode)) - set(S)) if args.graph_type not in ['Airport', 'Protein', 'Brain']: sim = EoN.fast_SIS(graphs[name], TAU, GAMMA, tmax=TMAX, return_full_data=True) else: sim = EoN.fast_SIS(graphs[name], TAU, GAMMA, tmax=TMAX, transmission_weight='weight', return_full_data=True) ## average results over the last 10 steps inf_ratio_target = np.mean([ Counter(sim.get_statuses(S, i).values())['I'] / len(S) for i in range(-1, -11, -1) ]) #INF = [Counter(sim.get_statuses(S, i).values())['I'] / len(S) for i in range(TMAX)] #with open('tmp.p', 'wb') as fid: # pickle.dump(INF, fid) inf_ratio_bystander = np.mean([ Counter(sim.get_statuses(SP, i).values())['I'] / len(SP) for i in range(-1, -11, -1) ]) rows.append((name, inf_ratio_target, inf_ratio_bystander, budget)) return pd.DataFrame( rows, columns=['graph', 'ratio targets', 'ratio bystanders', 'budget'])
def epidemy_with_recover(graph, initial_nodes, transmission_rate, recovery_rate, plot_tittle='', return_full_data=False): if return_full_data: return EoN.fast_SIR(graph, transmission_rate, gamma=recovery_rate, initial_infecteds=initial_nodes, return_full_data=return_full_data) else: t, S, I, R = EoN.fast_SIR(graph, transmission_rate, gamma=recovery_rate, initial_infecteds=initial_nodes) max_time_index = 0 biggest_number_infected = 0 for i in range(0, len(I)): if I[i] > biggest_number_infected: print(f'Infectados:{I[i]} = Limiar:{biggest_number_infected}') biggest_number_infected = I[i] max_time_index = i t = t * 100 plt.title(plot_tittle) plt.plot(t, I, label='Infectados') plt.plot(t, S, label='Suscetivel') plt.plot(t, R, label='Removidos') plt.hlines(I[max_time_index], t[0], t[max_time_index], colors='k') plt.vlines(t[max_time_index], I[0], I[max_time_index], colors='k') plt.xlim(0, max(t)) plt.ylim(0, graph.number_of_nodes()) plt.xticks([t[max_time_index]]) plt.yticks([I[max_time_index]]) plt.legend(loc='best') plt.show()
def _animation_update(self, t, drawn_nodes, drawn_I, time_markers): status = EoN.get_statuses(self.G, self.node_history, t) Inodelist = [node for node in self.nodelist if status[node] == 'I'] drawn_nodes.set_color([self.colordict[status[node]] for node in self.nodelist]) drawn_I[0].remove() drawn_I[0] = nx.draw_networkx_nodes(self.G, pos=self.pos, nodelist=Inodelist, color = self.colordict['I'], ax = self.network_axes, **self.kwargs) for tm in time_markers: tm.remove() self._highlight_time(t, time_markers)
def R(self): r''' See notes for S Returns the number recovered at each time Generally better to get these all through summary()''' if 'R' in self._possible_statuses_: return self._summary_[1]['R'] else: raise EoN.EoNError("'R' is not a possible status")
def update_ts_colordict(self, ts, colordict): r''' CHANGES NEEDED. I think just make the test check that keys of colordict and possible statuses match. updates the colordict for time series plots :Arguments: **ts** timeseries object the timeseries object whose key word args we are updating. **colordict** dict the new colordict ''' if not (colordict.has_key('S') and colordict.has_key('I')): raise EoN.EoNError("colordict must have keys 'S' and 'I'") if self.SIR and not colordict.has_key('R'): raise EoN.EoNError("if SIR, then colordict must have key 'R'") ts.colordict=colordict
def __init__(self, t, S, I, R=None, colordict=None, label=None, **kwargs): if colordict is None: raise EoN.EoNError("colordict must be defined") self._S_ = S self._I_ = I self._R_ = R self._t_ = t self.colordict = colordict self.label=label self.plt_kwargs = kwargs
def create_simulation( sim_name, sq_rate, qs_rate, it_rate, si_rate, population_size, initial_infection_number, ): matrix_size = int(round(population_size**(0.5))) G = nx.grid_2d_graph(matrix_size, matrix_size) initial_infections = [(randint(0, matrix_size), randint(0, matrix_size)) for _ in range(initial_infection_number)] H = nx.DiGraph() H.add_edge('Susc', 'Quar', rate=sq_rate) H.add_edge('Quar', 'Susc', rate=qs_rate) H.add_edge('Infe', 'Trea', rate=it_rate) H.add_edge('Trea', 'Quar', rate=0.05) J = nx.DiGraph() J.add_edge(('Infe', 'Susc'), ('Infe', 'Infe'), rate=si_rate) IC = defaultdict(lambda: 'Susc') for node in initial_infections: IC[node] = 'Infe' return_statuses = ['Susc', 'Infe', 'Trea', 'Quar'] sim_kwargs = { 'color_dict': { 'Susc': '#5cb85c', 'Infe': '#d9534f', 'Trea': '#f0ad4e', 'Quar': '#0275d8', }, 'pos': {node: node for node in G}, 'tex': False, } sim = EoN.Gillespie_simple_contagion( G, H, J, IC, return_statuses, tmax=150, return_full_data=True, sim_kwargs=sim_kwargs, ) produce_visualization(sim_name, sim, population_size) convert_video(sim_name)
def legend(self, timeseries_plot_index = 0, loc='best'): #timeseries plot can be: #integer from 0 to len(timeseries)-1 # or string 'All' if not self.timeseries_axi: raise EoN.EoNError("no time series axes defined") elif timeseries_plot_index == 'All': for ax in self.timeseries_axi: ax.legend(loc=loc) else: self.timeseries_axi[timeseries_plot_index].legend(loc=loc)
def do_calcs_and_plot(G, trans_time_fxn, rec_time_fxn, trans_time_args, rec_time_args, R0fxn, symbol): As = [] for tau in taus: P, A = EoN.estimate_nonMarkov_SIR_prob_size_with_timing(G,trans_time_fxn=trans_time_fxn, rec_time_fxn = rec_time_fxn, trans_time_args = (tau,), rec_time_args=rec_time_args) As.append(A) plt.figure(1) plt.plot(taus, As, symbol) plt.figure(2) plt.plot( R0fxn(taus), As, symbol)
def transmissions(self): r'''Returns a list of tuples (t,u,v) stating that node u infected node v at time t. In the standard code, if v was already infected at tmin, then the source is None Note - this only includes successful transmissions. So if u tries to infect v, but fails because v is already infected this is not recorded.''' if self._transmissions_ is None: raise EoN.EoNError("transmissions were not provided when created") return self._transmissions_
def simulateGraph(clusteringAlg, params, full_data=False): record.print('\n') record.print( "building populace into graphs with the {} clustering algorithm". format(clusteringAlg.__name__)) start = time.time() graph = nx.Graph() clusterGroups(graph, 'sp_hh_id', homeInfectivity, clusterDenseGroup) record.print("{} weights of size {} have been added for {} homes".format( graph.size(), 1, len(popsByCategory['sp_hh_id'].keys()))) clusterGroups(graph, 'work_id', workInfectivity, clusteringAlg, params) clusterGroups(graph, 'school_id', workInfectivity, clusteringAlg, params) stop = time.time() record.print( "The final graph finished in {} seconds. with properties:".format( (stop - start))) record.print("{edges: {}, nodes: }".format(graph.size())) return (graph) record.print("running event-based simulation") if full_data: simResult = EoN.fast_SIR(graph, globalInfectionRate, recoveryRate, rho=0.0001, transmission_weight='transmission_weight', return_full_data=True) else: simResult = EoN.fast_SIR(graph, globalInfectionRate, recoveryRate, rho=0.0001, transmission_weight='transmission_weight', return_full_data=False) stop = time.time() record.print("finished in {} seconds".format(stop - start)) return simResult
def epidemy_without_recover(graph, initial_nodes, transmission_rate, plot_tittle='', return_full_data=False): if return_full_data: return EoN.fast_SIR(graph, transmission_rate, gamma=0, initial_infecteds=initial_nodes, return_full_data=return_full_data) else: t, S, I, R = EoN.fast_SIR(graph, transmission_rate, gamma=0, initial_infecteds=initial_nodes) max_time_index = 0 for i in range(0, len(I)): if I[i] > 0.9 * graph.number_of_nodes(): print( f'Infectados:{I[i]} = Limiar:{0.9*graph.number_of_nodes()}' ) max_time_index = i break t = t * 100 plt.plot(t, I, label=plot_tittle) #plt.plot(t, S, label='Suscetivel', color='b') #plt.hlines(I[max_time_index], t[0], t[max_time_index], colors='k') #plt.vlines(t[max_time_index], I[0], I[max_time_index], colors='k') #plt.xticks([t[max_time_index]]) #plt.yticks([I[max_time_index]]) plt.legend(loc='best')
def S(self): r''' If ``'S'`` is a state, then this will return the number susceptible at each time. Else it raises an error Generally better to get these all through ``summary()`` ''' if 'S' in self._possible_statuses_: return self._summary_[1]['S'] else: raise EoN.EoNError("'S' is not a possible status")
def generate_network(Pk, N, ntries=100): r'''Generates an N-node random network whose degree distribution is given by Pk''' counter = 0 while counter < ntries: counter += 1 ks = [] for ctr in range(N): ks.append(Pk()) if sum(ks) % 2 == 0: break if sum(ks) % 2 == 1: raise EoN.EoNError("cannot generate even degree sum") G = nx.configuration_model(ks) return G