def run_inf_prob_vs_perc_sus(name: str, diseases: Sequence[Disease], new_network: Callable[[], Network], flicker_config: RandomFlickerConfig, num_trials: int, rng): """ Save the plot and csv of infection probability vs percent susceptible. """ results: Dict[float, List[float]] = defaultdict(lambda: []) print(f'Running {name}') pbar = tqdm(total=num_trials * len(diseases)) for disease, _ in it.product(diseases, range(num_trials)): net = new_network() flicker = flicker_config.make_behavior(net.M, net.intercommunity_edges) sir0 = make_starting_sir(net.N, 1, rng) perc_sus = np.sum( simulate(net.M, sir0, disease, flicker, 100, None, rng)[-1][0] > 0 ) / net.N results[disease.trans_prob].append(perc_sus) pbar.update() x_coords = tuple(results.keys()) collected_data = np.array([list(values) for values in results.values()]) quartiles = np.quantile(collected_data, (.25, .75), axis=1, interpolation='midpoint') y_coords = np.mean(collected_data, axis=1) plt.figure() plt.title(name) plt.xlim(0, 1) plt.ylim(0, 1) plt.xlabel('Infection Probability') plt.ylabel('Survival Percentage') plt.plot(x_coords, y_coords) plt.fill_between(x_coords, quartiles[0], quartiles[1], alpha=.4) plt.savefig(f'results/{name}.png', format='png', dpi=200)
def run_agent_generated_trial(args: Tuple[Disease, AgentBehavior, int, Any])\ -> Optional[Tuple[float, float, float]]: """ args: (disease to use in the simulation, the behavior agents have when generating the network, the number of agents in the network, an instance of np.random.default_rng) """ disease, agent_behavior, N, rand = args sim_len = 200 sims_per_trial = 150 net = make_agent_generated_network(N, agent_behavior) if net is None: return None to_flicker = partitioning.fluidc_partition(net.G, 50) proportion_flickering = len(to_flicker) / net.E social_good = rate_social_good(net) network_behavior = StaticFlickerBehavior(net.M, to_flicker, (True, False), "Probs don't change this") avg_sus = np.mean([ np.sum( simulate(net.M, make_starting_sir(net.N, 1), disease, network_behavior, sim_len, None, rand)[-1][0] > 0) for _ in range(sims_per_trial) ]) / net.N return proportion_flickering, avg_sus, social_good
def run_social_circles_trial( args: Tuple[Dict[networkgen.Agent, int], Tuple[int, int], Disease, Any] ) -> Optional[Tuple[float, float, float]]: agent_to_quantity, grid_dims, disease, rand = args sim_len = 200 sims_per_trial = 150 target_communities = 25 sc_results = networkgen.make_social_circles_network(agent_to_quantity, grid_dims, rand=rand) if sc_results is None: return None net, _, = sc_results if nx.number_connected_components(net.G) > target_communities: return None to_flicker = partitioning.fluidc_partition(net.G, target_communities) proportion_flickering = len(to_flicker) / net.E social_good_score = rate_social_good(net) network_behavior = StaticFlickerBehavior(net.M, to_flicker, (True, False), "Probs don't change this") avg_sus = np.mean([ np.sum( simulate(net.M, make_starting_sir(net.N, 1), disease, network_behavior, sim_len, None, rand)[-1][0] > 0) for _ in range(sims_per_trial) ]) / net.N return proportion_flickering, avg_sus, social_good_score
def run_connected_community_trial(args: Tuple[ConnectedCommunityConfiguration, Disease, Any])\ -> Optional[Tuple[float, float, float]]: """ args: (ConnectedCommunityConfiguration to use, disease to use, default_rng instance) return: (proportion of edges that flicker, the average number of remaining susceptible agents) or None on failure. """ sim_len = 200 sims_per_trial = 150 configuration, disease, rand = args inner_degrees = configuration.make_inner_degrees() outer_degrees = configuration.make_outer_degrees() net = networkgen.make_connected_community_network(inner_degrees, outer_degrees, rand) # If a network couldn't be successfully generated, return None to signal the failure if net is None: return None to_flicker = {(u, v) for u, v in net.edges if net.communities[u] != net.communities[v]} proportion_flickering = len(to_flicker) / net.E social_good = rate_social_good(net) behavior = StaticFlickerBehavior(net.M, to_flicker, (True, False), "Probs don't change this") avg_sus = np.mean([np.sum(simulate(net.M, make_starting_sir(net.N, 1), disease, behavior, sim_len, None, rand)[-1][0] > 0) for _ in range(sims_per_trial)]) / net.N return proportion_flickering, avg_sus, social_good
def __call__(self, encoding: np.ndarray) -> float: net = self._enc_to_G(encoding) M = net.M to_flicker = fluidc_partition(net.G, net.N//20) flicker_behavior = StaticFlickerBehavior(M, to_flicker, (True, False), '') avg_sus = np.mean([np.sum(simulate(M, make_starting_sir(len(M), 1), self._disease, flicker_behavior, self._sim_len, None, self._rand)[-1][0] > 0) for _ in range(self._n_sims)]) / len(M) cost = 2-avg_sus-rate_social_good(net, self._decay_func) return cost
def experiment(make_network, seed): """ return: list of (high_reach_survival_rate, high_reach_sim_time, low_reach_survival_rate, low_reach_sim_time) """ rng = np.random.default_rng(seed) hr_net = make_network(high_reach) lr_net = make_network(low_reach) sir0 = make_starting_sir(hr_net.N, 1, rng) hr_sirs = simulate(hr_net.M, sir0, disease, make_behavior(high_reach, make_network, rng), sim_len_cap, rng, None) lr_sirs = simulate(lr_net.M, sir0, disease, make_behavior(low_reach, make_network, rng), sim_len_cap, rng, None) return (calc_survival_rate(hr_sirs), len(hr_sirs), calc_survival_rate(lr_sirs), len(lr_sirs))
def cc_pressure_vs_none_entry_point(): rng = np.random.default_rng(0xbeefee) num_trials = 1000 disease = Disease(4, .4) inner_bounds = 1, 15 outer_bounds = 1, 5 community_size = 20 n_communities = 25 make_ccn = MakeConnectedCommunity(community_size, inner_bounds, n_communities, outer_bounds, rng) pressure_configurations = [ SimplePressureConfig(radius, prob, rng) for radius, prob in it.product((1, 2, 3), (.25, .5, .75)) ] # pressure_experiment(make_ccn, pressure_configurations, disease, num_trials, rng) net = make_ccn() simulate(net.M, make_starting_sir(net.N, 1, rng), disease, pressure_configurations[1].make_behavior(net), 100, nx.spring_layout(net.G))
def elitist_experiment(): rng = np.random.default_rng() path = 'networks/elitist-500.txt' name = fio.get_network_name(path) net = fio.read_network(path) r, fp = 2, .75 update_connections, uc_name = (sd.SimplePressureBehavior(net, rng, r, fp), f'Pressure(r={r}, fp={fp})') # update_connections, uc_name = sd.no_update, 'Static' disease = sd.Disease(4, .2) sir0 = sd.make_starting_sir(net.N, (0, ), rng) survival_rates = np.array([ simulate_return_survival_rate(net, disease, update_connections, rng, sir0) for _ in range(500) ]) title = f'{disease} {uc_name}\n{name} Survival Rates' plt.title(title) plt.boxplot(survival_rates) plt.savefig(title + '.png', format='png')
def main(): n_trials = 100 max_steps = 100 rng = np.random.default_rng(0) disease = Disease(4, .2) names = ('elitist-500', 'cavemen-50-10', 'spatial-network', 'cgg-500', 'watts-strogatz-500-4-.1') paths = fio.network_names_to_paths(names) behavior_configs = (RandomFlickerConfig(.5, 'Random .5', rng), StaticFlickerConfig((True, False), 'Static .5')) for net_name, path in zip(names, paths): net = fio.read_network(path) to_flicker = tuple((u, v) for u, v in net.edges if net.communities[u] != net.communities[v]) proportion_flickering = len(to_flicker) / net.E social_good = rate_social_good(net) trial_to_pf = tuple(proportion_flickering for _ in range(n_trials)) trial_to_sg = tuple(social_good for _ in range(n_trials)) print(f'Running simulations for {net_name}.') for config in behavior_configs: behavior = config.make_behavior(net.M, to_flicker) sim_results = [ get_final_stats( simulate(net.M, make_starting_sir(net.N, 1, rng), disease, behavior, max_steps, None, rng=rng)) for _ in tqdm(range(n_trials)) ] results = BasicExperimentResult(f'{net_name} {config.name}', sim_results, trial_to_pf, trial_to_sg) results.save_csv(RESULTS_DIR) results.save_box_plots(RESULTS_DIR) results.save_perc_sus_vs_social_good(RESULTS_DIR)
def run_experiments(args: Tuple[str, int, int, Disease, Sequence[FlickerConfig], str])\ -> Optional[FlickerComparisonResult]: """ Run a batch of experiments and return a tuple containing the network's name, number of flickering edges, and a mapping of behavior name to the final amount of susceptible nodes. Return None on failure. args: (path to the network, number of sims to run for each behavior, simulation length, disease, a sequence of configs for the flickers to use, the name of the baseline flicker to compare the other results to) """ network_path, num_sims, sim_len, disease, flicker_configs, baseline_flicker_name = args net = fio.read_network(network_path) intercommunity_edges = {(u, v) for u, v in net.edges if net.communities[u] != net.communities[v]} behavior_to_results: Dict[str, Sequence[float]] = {} for config in flicker_configs: behavior = config.make_behavior(net.M, intercommunity_edges) # The tuple comprehension is pretty arcane, so here is an explanation. # Each entry is the sum of the number of entries in the final SIR where # the days in S are greater than 0. That is to say, the number of # susceptible agents at the end of the simulation. perc_sus = tuple( np.sum( simulate(net.M, make_starting_sir(net.N, 1), disease, behavior, sim_len, None)[-1][0] > 0) / net.N for _ in range(num_sims)) behavior_to_results[behavior.name] = perc_sus return FlickerComparisonResult(fio.get_network_name(network_path), num_sims, sim_len, len(intercommunity_edges) / net.E, behavior_to_results, baseline_flicker_name)
def pressure_test_entry_point(): rng = np.random.default_rng() net = fio.read_network('networks/cavemen-50-10.txt') simulate(net.M, make_starting_sir(net.N, (0, ), rng), Disease(4, 0.3), SimplePressureBehavior(net, 1), 200, None, rng)
def choose_by_centrality(net, centrality_measure, max_or_min): degrees = dict(centrality_measure(net.G)) # type: ignore patient0 = max_or_min(degrees.keys(), key=lambda k: degrees[k]) return sd.make_starting_sir(net.N, (patient0, ), rng)
def choose_infected_node(): """This experiment is for choosing nodes with specific attributes to be patient 0""" rng = np.random.default_rng() r, fp = 2, .25 disease = sd.Disease(4, .3) n_trials = 500 seed = 0 def choose_by_centrality(net, centrality_measure, max_or_min): degrees = dict(centrality_measure(net.G)) # type: ignore patient0 = max_or_min(degrees.keys(), key=lambda k: degrees[k]) return sd.make_starting_sir(net.N, (patient0, ), rng) sir_strats = ( ('Highest Degree', lambda net: choose_by_centrality(net, nx.degree_centrality, max)), ('Random', lambda net: sd.make_starting_sir(net.N, 1, rng)), ('Lowest Degree', lambda net: choose_by_centrality(net, nx.degree_centrality, min)), ('Highest Eigenvector Centrality', lambda net: choose_by_centrality( net, nx.eigenvector_centrality_numpy, max)), ('Lowest Eigenvector Centrality', lambda net: choose_by_centrality( net, nx.eigenvector_centrality_numpy, min))) networks: Tuple[MakeNetwork, ...] = ( MakeConnectedCommunity(20, (15, 20), 25, (3, 6), rng), MakeConnectedCommunity(10, (5, 10), 50, (3, 6), rng), MakeWattsStrogatz(500, 4, .01, seed), MakeWattsStrogatz(500, 4, .02, seed), MakeWattsStrogatz(500, 5, .01, seed), MakeBarabasiAlbert(500, 2, seed), MakeBarabasiAlbert(500, 3, seed), MakeBarabasiAlbert(500, 4, seed), MakeErdosRenyi(500, .01, seed), MakeErdosRenyi(500, .02, seed), MakeErdosRenyi(500, .03, seed), MakeGrid(25, 20), MakeGrid(50, 10), MakeGrid(100, 5), LoadNetwork('evolved-low-communicability-100'))[-1:] print(f'Running {len(networks)*len(sir_strats)} experiments') experiment_to_survival_rates = {} for make_net, (strat_name, sir_strat) in it.product(networks, sir_strats): survival_rates = [] for _ in tqdm(range(n_trials), desc=f'{make_net.class_name} & {strat_name}'): net = make_net() update_connections = sd.SimplePressureBehavior(net, rng, r, fp) sir0 = sir_strat(net) survival_rate = simulate_return_survival_rate( net, disease, update_connections, rng, sir0) survival_rates.append(survival_rate) title = f'{strat_name} Patient 0\n{make_net.class_name} Survival Rates' plt.figure() plt.title(title) plt.xlim(0, 1.0) plt.ylim(0, n_trials) plt.hist(survival_rates, bins=None) plt.savefig(os.path.join('results', title + '.png'), format='png') experiment_to_survival_rates[title] = survival_rates # save the raw data with open(os.path.join('results', 'patient-0-sensitivity.csv'), 'w', newline='') as csv_file: writer = csv.writer(csv_file) for experiment_name, survival_rates in experiment_to_survival_rates.items( ): writer.writerow([experiment_name]) writer.writerow(survival_rates)