def test_getters_and_setters(self): tg_simple = graph.graph(self.simple_dict) simple_with_new_element = self.simple_dict.copy() simple_with_new_element['C'] = {} simple_with_new_element['C']['D'] = 5 tg_simple.put_edge('C', 'D', 5) self.assertEqual(tg_simple.graph_please(), simple_with_new_element, 'Put edge works properly') self.assertEqual(tg_simple.get_edge('A', 'B'), 2, 'get_edge() works') self.assertTrue(tg_simple.edge_exists('A', 'C')) self.assertFalse(tg_simple.edge_exists('not', 'exist')) self.assertEqual(tg_simple.distance(['A', 'B', 'C']), 4, 'Distance calculated on a route works') self.assertEqual(tg_simple.distance(['A', 'A', 'A']), 0, 'Distance on a route taht does not exist is 0') ##### # input errors ##### tg_input_errors = graph.graph(self.medium_dict) tg_input_errors.put_edge('A', 'D', 'F') tg_input_errors.put_edge('A', 222, 4) tg_input_errors.put_edge(None, 'D', 5) self.assertEqual( tg_simple.graph_please(), simple_with_new_element, '3 inserts of bizarre inputs are ignored. Errors are not thrown ') self.assertIsNone(tg_simple.get_edge('not', 'exist'), 'get_edge() works on bad input')
def test_constructors(self): tg_empty = graph.graph() self.assertEqual(tg_empty.graph_please(), self.empty_dict, 'Constructor with no params gives empty graph') tg = graph.graph(self.simple_dict) self.assertEqual( tg.graph_please(), self.simple_dict, 'Constructor with dictionary gives dictionary as the graph') # Input Errors tg_with_list = graph.graph(self.empty_list) self.assertEqual(tg_with_list.graph_please(), self.empty_dict, 'Constructor with list gives empty graph') tg_with_string = graph.graph('string here') self.assertEqual(tg_with_string.graph_please(), self.empty_dict, 'Constructor with string gives empty graph') bizarre_dictionary = {'A': 4, 'B': {'C': '4', 'D': 4}} only_valid_values_from_bizarre = {'A': {}, 'B': {'D': 4}} tg_bizarre = graph.graph(bizarre_dictionary) self.assertEqual( tg_bizarre.graph_please(), only_valid_values_from_bizarre, 'Constructor with invalid values in the dictionary ignores bad input' )
def test_list_methods(self): tg = graph.graph(self.large_dict) expected_list = ['A', 'C'] self.assertCountEqual(tg.neighbours_going_out_list('D'), expected_list, 'neighbours list finds neighbours of D') self.assertCountEqual(tg.neighbours_going_out_list('L'), self.empty_list, 'neighbours list finds neighbours of L - none') ##### # input errors ##### self.assertEqual(tg.neighbours_going_out_list('Z'), self.empty_list, 'neighbours_going_out_list() on node that !exist')
def test_graph_methods(self): tg = graph.graph(self.simple_dict) expected_graph = {'B': {'C': 2}} self.assertEqual( tg.graph_with_node_removed('A').graph_please(), expected_graph, 'Node removal works 1 of 2') tg = graph.graph(self.large_dict) expected_graph = { 'C': { 'H': 45, 'D': 5 }, 'B': { 'C': 3, 'D': 6 }, 'E': { 'B': 3, 'F': 3 }, 'D': { 'C': 3 }, 'G': { 'H': 14 }, 'F': { 'E': 2, 'D': 7, 'G': 2 }, 'I': { 'H': 2, 'J': 2 }, 'H': { 'I': 2, 'C': 45, 'J': 2 }, 'K': { 'J': 15, 'L': 4 }, 'J': { 'I': 2, 'H': 2, 'K': 15 } } self.assertEqual( tg.graph_with_node_removed('A').graph_please(), expected_graph, 'Node removal works 2 of 2') expected_graph = { 'A': { 'C': 4, 'B': 9 }, 'C': { 'H': 45, 'D': 5 }, 'B': { 'C': 3, 'D': 6 }, 'E': { 'A': 33, 'B': 3, 'F': 3 }, 'D': { 'A': 5, 'C': 3 }, 'G': { 'H': 14 }, 'F': { 'A': 12, 'E': 2, 'D': 7, 'G': 2 }, 'I': { 'H': 2, 'J': 2 }, 'H': { 'I': 2, 'C': 45, 'J': 2 }, 'K': { 'J': 15 }, 'J': { 'I': 2, 'H': 2, 'K': 15 } } self.assertEqual( tg.graph_with_node_removed('L').graph_please(), expected_graph, 'Node removal works on leaf nodes (no outgoing edges)') ##### # input errors ##### tg = graph.graph(self.medium_dict) self.assertEqual( tg.graph_with_node_removed('noelement').graph_please(), self.medium_dict, 'Node removal works for nodes that do not exist')
def test_route_methods(self): short = graph.graph(self.simple_dict) self.assertEqual(short.shortest_route('A', 'D'), self.empty_list, ' shortest_route() works - test 1 of 3') med = graph.graph(self.medium_dict) self.assertEqual(med.shortest_route('A', 'F'), self.empty_list, ' shortest_route() works - test 2 of 3') expected_list = ['A', 'C', 'H', 'J', 'K', 'L'] large = graph.graph(self.large_dict) self.assertEqual(large.shortest_route('A', 'L'), expected_list, ' shortest_route() works - test 3 of 3') expected_list = ['A', 'C', 'D', 'A'] self.assertEqual(large.shortest_route('A', 'A'), expected_list, ' shortest_route() works on a loop, from A to A') self.assertFalse(short.route_exists(['A', 'A'])) self.assertTrue(large.route_exists(['F', 'A', 'B', 'D', 'C', 'H'])) self.assertFalse(large.route_exists(['C', 'E'])) expected_list = [['F', 'E', 'A'], ['F', 'E', 'B', 'C', 'D', 'A'], ['F', 'E', 'B', 'D', 'A'], ['F', 'D', 'A']] self.assertCountEqual( med.calculate_all_routes('F', 'A'), expected_list, ' calculate_all_routes() on medium sample data ') exptected_list = [] graph_of_unconnected_nodes = graph.graph({'A': {}, 'B': {}}) self.assertIsNone( graph_of_unconnected_nodes.calculate_all_routes('A', 'B'), ' calculate_all_routes() on unconnected graph') self.assertEqual(graph_of_unconnected_nodes.shortest_route('A', 'B'), self.empty_list, ' shorest_route() on unconnected graph') self.assertFalse(graph_of_unconnected_nodes.route_exists(['A', 'B']), ' route_exists() on unconnected graph') expected_list = [] empty_graph = graph.graph() self.assertIsNone(empty_graph.calculate_all_routes('A', 'B'), ' calculate_all_routes() on empty graph') self.assertEqual(empty_graph.shortest_route('A', 'B'), self.empty_list, ' shorest_route() on empty graph') self.assertFalse(empty_graph.route_exists(['A', 'B']), ' route_exists() on empty graph') ##### # input errors ##### self.assertEqual( large.shortest_route('A', 'Z'), self.empty_list, ' shortest_route() works on nodes that do no exist - test 1 of 3') self.assertEqual( large.shortest_route('X', 'A'), self.empty_list, ' shortest_route() works on nodes that do no exist - test 2 of 3') self.assertEqual( large.shortest_route('X', 'Z'), self.empty_list, ' shortest_route() works on nodes that do no exist - test 3 of 3') self.assertEqual(large.shortest_route(1, 'A'), self.empty_list, ' shortest_route() works on integers - test 1 of 3') self.assertEqual(large.shortest_route('C', 1), self.empty_list, ' shortest_route() works on integers - test 2 of 3') self.assertEqual(large.shortest_route(1, 4), self.empty_list, ' shortest_route() works on integers - test 3 of 3') self.assertFalse(short.route_exists(['A', 'Z'])) self.assertFalse(short.route_exists(['Z', 'C'])) self.assertFalse(short.route_exists(['Z', 'Z'])) self.assertFalse(short.route_exists(self.empty_list))
def main(): """ None -> None This serves as the main program. """ # Initialize classes. Argparser, statistics, information collector, graph and parser. arg_parser = argparser() stats_record = statistics() info_collector = collector() epi_graph = graph() file_parser = parser() # Get the options from the arguments passed in by the user. print("Gathering simulation parameters...") options = arg_parser.collect_and_return_args() options.R_0 = abs(float(options.R_0)) options.life_time = abs(float(options.life_time)) options.death_rate = abs(float(options.death_rate)) options.infected_count = abs(int(options.infected_count)) options.daily_travel_percentage = abs( float(options.daily_travel_percentage)) travel_p = options.daily_travel_percentage if (travel_p >= .003): os.system('cls' if os.name == 'nt' else 'clear') raise Exception( "ERROR: Daily travel percentage must be less than .003.") # Get the total amount of initially infected people. initial_inf_count = abs(options.infected_count) file_parser.open_and_read_city_file( options.cities_file) # Read the city file and save info into parser. file_parser.open_and_read_plane_file( options.planes_file) # Read the plane file and save info into parser. # Get the total number of hours the program should simulate based on the number of days it should run. days_to_run = abs(int(round(float(options.sim_time)))) if (options.life_time == 0): os.system('cls' if os.name == 'nt' else 'clear') raise Exception("ERROR: Life time must be greater than zero.") hours_to_run = (days_to_run * 24) cities = list( ) # Create a list to hold all city classes used in simulation. # Declare rate of reproduction, hour, and day variables for the main loop. hour = 1 day = 1 total_person_count = 0 if (days_to_run < 2): os.system('cls' if os.name == 'nt' else 'clear') raise Exception( "ERROR: Epidemic simulation needs to run longer than 2 days.") # Create list of cities. for c in file_parser.cities_list: nc = city(c, file_parser.planes_list, travel_p, options) cities.append(nc) stats_record.add_city(nc) # Add cities as locations to visit and calculate distance between cities. for i in cities: for j in cities: i.add_cities(j) total_person_count += len(i.people) # Infect the correct amount of people. num_inf = 0 while (num_inf < initial_inf_count): # Choose the city and person randomly to infect. city_to_inf = random.choice(cities) #choose a random person to infect in that city person_to_inf = random.choice(city_to_inf.people) #check to make sure that person is not already infected if (person_to_inf.infected == True): #if that person is already infected continue and find somebody who is not continue #once you found somebody infect them person_to_inf.infect() #add to the infected count and decrease the healthy count for that city city_to_inf.inf_count += 1 city_to_inf.healthy_count -= 1 num_inf += 1 # Clear the system to display proper program information. os.system('cls' if os.name == 'nt' else 'clear') # indexes for totals, used in people totals dead_count_ind = 0 infected_count_ind = 1 immune_count_ind = 2 healthy_count_ind = 3 infected_travelers_per_day = 0 try: while (stats_record.Re > 0.3): # Program has run for the total number of hours requested, exit. if (hours_to_run == hour): break # Increment hour after checking if the simulation reached the end. hour += 1 # totals of people status people_totals = [0, 0, 0, 0] flight_total = 0 healthy_each_day = 0 # Call update methods for city objects and record data. for location in cities: stats_record.add_vessels(location.tick()) # If end of day, add totals for each location. people_totals[dead_count_ind] += location.dead_count people_totals[infected_count_ind] += location.inf_count people_totals[immune_count_ind] += location.immune_count people_totals[healthy_count_ind] += location.healthy_count healthy_each_day += location.healthy_count flight_total += location.flights_counter if (hour % 24 == 0): info_collector.track_healthy(location.healthy_count, location.name) infected_travelers_per_day += location.sent_infected_people location.sent_infected_people = 0 location.flights_counter = 0 stats_record.Re = float(people_totals[healthy_count_ind] / stats_record.totalPop) * options.R_0 if not people_totals[infected_count_ind]: break # Collect daily contagion information for graphing purposes. if (hour % 24 == 0): info_collector.add_to_daysplot(day) info_collector.add_to_dplot(people_totals[dead_count_ind]) info_collector.add_to_iplot(people_totals[infected_count_ind]) info_collector.add_to_implot(people_totals[immune_count_ind]) info_collector.add_flights(flight_total) info_collector.add_infected_travelers( infected_travelers_per_day) infected_travelers_per_day = 0 info_collector.total_healthy.append(healthy_each_day) day += 1 # Call update method for vƒessel objects and update the active and inactive vessel lists. for vessel in stats_record.activevessels: if vessel.tick(): stats_record.activevessels.remove( vessel) #remove an active flight from actives list stats_record.inactivevessels.append( vessel) #add flight to inactive flights list # Display the current contagion information stats_record.curr_contagion_info(hour, hours_to_run) except: print("\nWARNING: Keyboard interrupt. Printing statistics...") stats_record.print_stats(days_to_run, total_person_count) sys.stdout.write("\n") return #print overal simulation statistics stats_record.print_stats(days_to_run, total_person_count) sys.stdout.write("\n") #produce a time series graph of the contagion spreading over the period of time the simulation modeled. stats_record.print_time_series_table(info_collector.days_plot, info_collector.immune_plot, info_collector.infected_plot, info_collector.dead_plot) epi_graph.create_and_show_graphs( info_collector.days_plot, info_collector.immune_plot, info_collector.infected_plot, info_collector.dead_plot, info_collector.healthy_city_info, info_collector.flight_info, info_collector.infected_travelers_plot) sys.stdout.write("\n") return