class ForestFire(Model): ''' Simple Forest Fire model. ''' def __init__(self, height, width, density): ''' Create a new forest fire model. Args: height, width: The size of the grid to model density: What fraction of grid cells have a tree in them. ''' # Initialize model parameters self.height = height self.width = width self.density = density # Set up model objects self.schedule = RandomActivation(self) self.grid = Grid(height, width, torus=False) self.datacollector = DataCollector( {"Fine": lambda m: self.count_type(m, "Fine"), "On Fire": lambda m: self.count_type(m, "On Fire"), "Burned Out": lambda m: self.count_type(m, "Burned Out")}) # Place a tree in each cell with Prob = density for (contents, x, y) in self.grid.coord_iter(): if random.random() < self.density: # Create a tree new_tree = TreeCell((x, y)) # Set all trees in the first column on fire. if x == 0: new_tree.condition = "On Fire" self.grid._place_agent((x, y), new_tree) self.schedule.add(new_tree) self.running = True def step(self): ''' Advance the model by one step. ''' self.schedule.step() self.datacollector.collect(self) # Halt if no more fire if self.count_type(self, "On Fire") == 0: self.running = False @staticmethod def count_type(model, tree_condition): ''' Helper method to count trees in a given condition in a given model. ''' count = 0 for tree in model.schedule.agents: if tree.condition == tree_condition: count += 1 return count
class ConwaysGameOfLife(Model): ''' Represents the 2-dimensional array of cells in Conway's Game of Life. ''' def __init__(self, height=50, width=50, server=True): ''' Create a new playing area of (height, width) cells. ''' # Set up the grid and schedule. # Use SimultaneousActivation which simulates all the cells # computing their next state simultaneously. This needs to # be done because each cell's next state depends on the current # state of all its neighbors -- before they've changed. self.schedule = SimultaneousActivation(self) self.server = server # Use a simple grid, where edges wrap around. self.grid = Grid(height, width, torus=True) #Datacollector -- default for this model is no data collection, but one can use OABM to assign one. #so this is an empty DataCollector instance from MESA self.datacollector = DataCollector() # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for (contents, x, y) in self.grid.coord_iter(): cell = Cell((x, y), self) if self.random.random() < 0.1: cell.state = cell.ALIVE self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.running = True def step(self): ''' Have the scheduler advance each cell by one step ''' self.schedule.step() def run_model(self, n=None): if n: self.num_steps = n if self.server == False: for _ in range(self.num_steps): self.step() return self else: from .server import server server.launch()
class InspectionModel(Model): ''' Simple Restaurant Inspection model. ''' def __init__(self, height, width, density): ''' Create a new restaurant inspection model. Args: height, width: The size of the grid to model density: What fraction of grid cells have a restaurant in them. ''' # Initialize model parameters self.height = height self.width = width self.density = density # Set up model objects self.schedule = RandomActivation(self) self.grid = Grid(height, width, torus=False) self.datacollector = DataCollector( {"Good": lambda m: self.count_type(m, "Good"), "Bad": lambda m: self.count_type(m, "Bad")}) # Place a restaurant in each cell with Prob = density for (contents, x, y) in self.grid.coord_iter(): if random.random() < self.density: # Create a restaurant new_restaurant = RestaurantCell((x, y)) self.grid._place_agent((x, y), new_restaurant) self.schedule.add(new_restaurant) self.running = True def step(self): ''' Advance the model by one step. ''' self.schedule.step() self.datacollector.collect(self) @staticmethod def count_type(model, restaurant_hygiene): ''' Helper method to count restaurants in a given condition in a given model. ''' count = 0 for restaurant in model.schedule.agents: if restaurant.hygiene == restaurant_hygiene and restaurant.rating != 'Closed': count += 1 return count
class MockModel(Model): """ Test model for testing """ def __init__(self, width, height, key1=103, key2=104): self.width = width self.height = height self.key1 = key1, self.key2 = key2 self.schedule = SimultaneousActivation(self) self.grid = Grid(width, height, torus=True) for (c, x, y) in self.grid.coord_iter(): a = MockAgent(x + y * 100, self, x * y * 3) self.grid.place_agent(a, (x, y)) self.schedule.add(a) def step(self): self.schedule.step()
class ConwaysGameOfLife(Model): """ Represents the 2-dimensional array of cells in Conway's Game of Life. """ def __init__(self, size, **kwargs): """ Create a new playing area of (height, width) cells. """ # Set up the grid and schedule. # Use SimultaneousActivation which simulates all the cells # computing their next state simultaneously. This needs to # be done because each cell's next state depends on the current # state of all its neighbors -- before they've changed. self.schedule = SimultaneousActivation(self) # Use a simple grid, where edges wrap around. self.grid = Grid(size, size, torus=True) # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for (_contents, x, y) in self.grid.coord_iter(): cell = Cell((x, y), self) if self.random.random() < 0.1: cell.state = cell.ALIVE self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.running = True def step(self): """ Have the scheduler advance each cell by one step """ self.schedule.step() def on_click(self, x, y, **kwargs): print(x, y) cell = self.grid[x][y] cell.state = cell.ALIVE
class CGoLModel(Model): ''' Represents the 2-dimensional array of cells in Conway's Game of Life. ''' def __init__(self, height, width): ''' Create a new playing area of (height, width) cells. ''' # Set up the grid and schedule. # Use SimultaneousActivation which simulates all the cells # computing their next state simultaneously. This needs to # be done because each cell's next state depends on the current # state of all its neighbors -- before they've changed. self.schedule = SimultaneousActivation(self) # Use a simple grid, where edges wrap around. self.grid = Grid(height, width, torus=True) # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for (contents, x, y) in self.grid.coord_iter(): pos = (x, y) init_state = CGoLCell.DEAD # Initially, make 10% of the cells ALIVE. if random.random() < 0.1: init_state = CGoLCell.ALIVE cell = CGoLCell(pos, self, init_state) # Put this cell in the grid at position (x, y) self.grid.place_agent(cell, pos) # Add this cell to the scheduler. self.schedule.add(cell) self.running = True def step(self): ''' Advance the model by one step. ''' self.schedule.step()
class ConwaysGameOfLife(Model): ''' Represents the 2-dimensional array of cells in Conway's Game of Life. ''' def __init__(self, height=50, width=50): ''' Create a new playing area of (height, width) cells. ''' # Set up the grid and schedule. # Use SimultaneousActivation which simulates all the cells # computing their next state simultaneously. This needs to # be done because each cell's next state depends on the current # state of all its neighbors -- before they've changed. self.schedule = SimultaneousActivation(self) # Use a simple grid, where edges wrap around. self.grid = Grid(height, width, torus=True) # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for (contents, x, y) in self.grid.coord_iter(): cell = Cell((x, y), self) if self.random.random() < 0.1: cell.state = cell.ALIVE self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.running = True def step(self): ''' Have the scheduler advance each cell by one step ''' self.schedule.step()
class CivilViolenceModel(Model): """ Model 1 from "Modeling civil violence: An agent-based computational approach," by Joshua Epstein. http://www.pnas.org/content/99/suppl_3/7243.full Attributes: height: grid height width: grid width citizen_density: approximate % of cells occupied by citizens. cop_density: approximate % of calles occupied by cops. citizen_vision: number of cells in each direction (N, S, E and W) that citizen can inspect cop_vision: number of cells in each direction (N, S, E and W) that cop can inspect legitimacy: (L) citizens' perception of regime legitimacy, equal across all citizens max_jail_term: (J_max) active_threshold: if (grievance - (risk_aversion * arrest_probability)) > threshold, citizen rebels arrest_prob_constant: set to ensure agents make plausible arrest probability estimates movement: binary, whether agents try to move at step end max_iters: model may not have a natural stopping point, so we set a max. """ def __init__(self, height, width, citizen_density, cop_density, citizen_vision, cop_vision, legitimacy, max_jail_term, active_threshold=.1, arrest_prob_constant=2.3, movement=True, max_iters=1000): super(CivilViolenceModel, self).__init__() self.height = height self.width = width self.citizen_density = citizen_density self.cop_density = cop_density self.citizen_vision = citizen_vision self.cop_vision = cop_vision self.legitimacy = legitimacy self.max_jail_term = max_jail_term self.active_threshold = active_threshold self.arrest_prob_constant = arrest_prob_constant self.movement = movement self.running = True self.max_iters = max_iters self.iteration = 0 self.schedule = RandomActivation(self) self.grid = Grid(height, width, torus=True) model_reporters = { "Quiescent": lambda m: self.count_type_citizens(m, "Quiescent"), "Active": lambda m: self.count_type_citizens(m, "Active"), "Jailed": lambda m: self.count_jailed(m)} agent_reporters = { "x": lambda a: a.pos[0], "y": lambda a: a.pos[1], 'breed': lambda a: a.breed, "jail_sentence": lambda a: getattr(a, 'jail_sentence', None), "condition": lambda a: getattr(a, "condition", None), "arrest_probability": lambda a: getattr(a, "arrest_probability", None) } self.dc = DataCollector(model_reporters=model_reporters, agent_reporters=agent_reporters) unique_id = 0 if self.cop_density + self.citizen_density > 1: raise ValueError( 'Cop density + citizen density must be less than 1') for (contents, x, y) in self.grid.coord_iter(): if random.random() < self.cop_density: cop = Cop(unique_id, (x, y), vision=self.cop_vision, model=self) unique_id += 1 self.grid[y][x] = cop self.schedule.add(cop) elif random.random() < ( self.cop_density + self.citizen_density): citizen = Citizen(unique_id, (x, y), hardship=random.random(), regime_legitimacy=self.legitimacy, risk_aversion=random.random(), threshold=self.active_threshold, vision=self.citizen_vision, model=self) unique_id += 1 self.grid[y][x] = citizen self.schedule.add(citizen) def step(self): """ Advance the model by one step and collect data. """ self.schedule.step() self.dc.collect(self) self.iteration += 1 if self.iteration > self.max_iters: self.running = False @staticmethod def count_type_citizens(model, condition, exclude_jailed=True): """ Helper method to count agents by Quiescent/Active. """ count = 0 for agent in model.schedule.agents: if agent.breed == 'cop': continue if exclude_jailed and agent.jail_sentence: continue if agent.condition == condition: count += 1 return count @staticmethod def count_jailed(model): """ Helper method to count jailed agents. """ count = 0 for agent in model.schedule.agents: if agent.breed == 'citizen' and agent.jail_sentence: count += 1 return count
class ColorPatchModel(Model): ''' represents a 2D lattice where agents live ''' def __init__(self, width, height): ''' Create a 2D lattice with strict borders where agents live The agents next state is first determined before updating the grid ''' self._grid = Grid(width, height, torus=False) self._schedule = SimultaneousActivation(self) # self._grid.coord_iter() # --> should really not return content + col + row # -->but only col & row # for (contents, col, row) in self._grid.coord_iter(): # replaced content with _ to appease linter for (_, row, col) in self._grid.coord_iter(): cell = ColorCell((row, col), self, ColorCell.OPINIONS[random.randrange(0, 16)]) self._grid.place_agent(cell, (row, col)) self._schedule.add(cell) self.running = True def step(self): ''' Advance the model one step. ''' self._schedule.step() # the following is a temporary fix for the framework classes accessing # model attributes directly # I don't think it should # --> it imposes upon the model builder to use the attributes names that # the framework expects. # # Traceback included in docstrings @property def grid(self): """ /mesa/visualization/modules/CanvasGridVisualization.py is directly accessing Model.grid 76 def render(self, model): 77 grid_state = defaultdict(list) ---> 78 for y in range(model.grid.height): 79 for x in range(model.grid.width): 80 cell_objects = model.grid.get_cell_list_contents([(x, y)]) AttributeError: 'ColorPatchModel' object has no attribute 'grid' """ return self._grid @property def schedule(self): """ mesa_ABM/examples_ABM/color_patches/mesa/visualization/ModularVisualization.py", line 278, in run_model while self.model.schedule.steps < self.max_steps and self.model.running: AttributeError: 'NoneType' object has no attribute 'steps' """ return self._schedule
class TestBaseGrid(unittest.TestCase): ''' Testing a non-toroidal grid. ''' torus = False def setUp(self): ''' Create a test non-toroidal grid and populate it with Mock Agents ''' self.grid = Grid(3, 5, self.torus) self.agents = [] counter = 0 for y in range(3): for x in range(5): if TEST_GRID[y][x] == 0: continue counter += 1 # Create and place the mock agent a = MockAgent(counter, None) self.agents.append(a) self.grid.place_agent(a, (x, y)) def test_agent_positions(self): ''' Ensure that the agents are all placed properly. ''' for agent in self.agents: x, y = agent.pos assert self.grid[y][x] == agent def test_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, get_cell_list_contents accurately reports that fact. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.get_cell_list_contents([(x, y)]) def test_listfree_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, get_cell_list_contents accurately reports that fact, even when single position is not wrapped in a list. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.get_cell_list_contents((x, y)) def test_iter_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, iter_cell_list_contents accurately reports that fact. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.iter_cell_list_contents([(x, y)]) def test_listfree_iter_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, iter_cell_list_contents accurately reports that fact, even when single position is not wrapped in a list. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.iter_cell_list_contents((x, y)) def test_neighbors(self): ''' Test the base neighborhood methods on the non-toroid. ''' neighborhood = self.grid.get_neighborhood((1, 1), moore=True) assert len(neighborhood) == 8 neighborhood = self.grid.get_neighborhood((4, 1), moore=True) assert len(neighborhood) == 5 neighborhood = self.grid.get_neighborhood((0, 0), moore=False) assert len(neighborhood) == 2 neighbors = self.grid.get_neighbors((4, 1), moore=False) assert len(neighbors) == 0 neighbors = self.grid.get_neighbors((4, 1), moore=True) assert len(neighbors) == 2 neighbors = self.grid.get_neighbors((1, 1), moore=False, include_center=True) assert len(neighbors) == 3 neighbors = self.grid.get_neighbors((3, 1), moore=False, radius=2) assert len(neighbors) == 4 def test_coord_iter(self): ci = self.grid.coord_iter() # no agent in first space first = next(ci) assert first[0] is None assert first[1] == 0 assert first[2] == 0 # first agent in the second space second = next(ci) assert second[0].unique_id == 1 assert second[0].pos == (1, 0) assert second[1] == 1 assert second[2] == 0
class EpsteinCivilViolence(Model): """ Model 1 from "Modeling civil violence: An agent-based computational approach," by Joshua Epstein http://www.pnas.org/content/99/suppl_3/7243.full Attributes: height: grid height width: grid width citizen_density: approximate % of cells occupied by citizens. cop_density: approximate % of calles occupied by cops. citizen_vision: number of cells in each direction (N, S, E and W) that citizen can inspect cop_vision: number of cells in each direction (N, S, E and W) that cop can inspect legitimacy: (L) citizens' perception of regime legitimacy, equal across all citizens max_jail_term: (J_max) active_threshold: if (grievance - (risk_aversion * arrest_probability)) > threshold, citizen rebels arrest_prob_constant: set to ensure agents make plausible arrest probability estimates movement: binary, whether agents try to move at step end max_iters: model may not have a natural stopping point, so we set a max. """ def __init__( self, height=40, width=40, citizen_density=0.7, cop_density=0.074, citizen_vision=7, cop_vision=7, legitimacy=0.8, max_jail_term=1000, active_threshold=0.1, arrest_prob_constant=2.3, movement=True, initial_unemployment_rate=0.1, corruption_level=0.1, susceptible_level=0.3, honest_level=0.6, max_iters=1000, ): super().__init__() self.height = height self.width = width self.citizen_density = citizen_density self.cop_density = cop_density self.citizen_vision = citizen_vision self.cop_vision = cop_vision self.legitimacy = legitimacy self.max_jail_term = max_jail_term self.active_threshold = active_threshold self.arrest_prob_constant = arrest_prob_constant self.movement = movement self.initial_unemployment_rate = initial_unemployment_rate self.corruption_level = corruption_level self.susceptible_level = susceptible_level self.max_iters = max_iters self.iteration = 0 self.schedule = RandomActivation(self) self.grid = Grid(height, width, torus=True) model_reporters = { "Quiescent": lambda m: self.count_type_citizens(m, "Quiescent"), "Active": lambda m: self.count_type_citizens(m, "Active"), "Jailed": lambda m: self.count_jailed(m), "Employed": lambda m: self.count_employed(m), "Corrupted": lambda m: self.count_moral_type_citizens(m, "Corrupted"), "Honest": lambda m: self.count_moral_type_citizens(m, "Honest"), "Susceptible": lambda m: self.count_moral_type_citizens(m, "Susceptible") } agent_reporters = { "x": lambda a: a.pos[0], "y": lambda a: a.pos[1], "breed": lambda a: a.breed, "jail_sentence": lambda a: getattr(a, "jail_sentence", None), "condition": lambda a: getattr(a, "condition", None), "arrest_probability": lambda a: getattr(a, "arrest_probability", None), "is_employed": lambda a: getattr(a, "is_employed", None), "moral_condition": lambda a: getattr(a, "moral_condition", None), } self.datacollector = DataCollector(model_reporters=model_reporters, agent_reporters=agent_reporters) unique_id = 0 if self.cop_density + self.citizen_density > 1: raise ValueError( "Cop density + citizen density must be less than 1") if self.initial_unemployment_rate > 1: raise ValueError( "initial_unemployment_rate must be between [0,1] ") if self.corruption_level + self.susceptible_level > 1: raise ValueError("moral level must be less than 1 ") for (contents, x, y) in self.grid.coord_iter(): if self.random.random() < self.cop_density: cop = Cop(unique_id, self, (x, y), vision=self.cop_vision) unique_id += 1 self.grid[y][x] = cop self.schedule.add(cop) elif self.random.random() < (self.cop_density + self.citizen_density): moral_state = "Honest" is_employed = 1 if self.random.random() < self.initial_unemployment_rate: is_employed = 0 p = self.random.random() if p < self.corruption_level: moral_state = "Corrupted" elif p < self.corruption_level + self.susceptible_level: moral_state = "Susceptible" citizen = Citizen( unique_id, self, (x, y), #updated hardship formula: if agent is employed hardship is alleviated hardship=self.random.random() - (is_employed * self.random.uniform(0.05, 0.15)), legitimacy=self.legitimacy, #updated regime legitimacy, so inital corruption rate is taken into consideration regime_legitimacy=self.legitimacy - self.corruption_level, risk_aversion=self.random.random(), active_threshold=self.active_threshold, #updated threshold: if agent is employed threshold for rebelling is raised threshold=self.active_threshold + (is_employed * self.random.uniform(0.05, 0.15)), vision=self.citizen_vision, is_employed=is_employed, moral_state=moral_state, ) unique_id += 1 self.grid[y][x] = citizen self.schedule.add(citizen) self.running = True self.datacollector.collect(self) def step(self): """ Advance the model by one step and collect data. """ self.schedule.step() # collect data self.datacollector.collect(self) self.iteration += 1 if self.iteration > self.max_iters: self.running = False @staticmethod def count_type_citizens(model, condition, exclude_jailed=False): """ Helper method to count agents by Quiescent/Active. """ count = 0 for agent in model.schedule.agents: if agent.breed == "cop": continue if exclude_jailed and agent.jail_sentence: continue if agent.condition == condition: count += 1 return count @staticmethod def count_moral_type_citizens(model, moral_condition, exclude_jailed=False): """ Helper method to count agents by Quiescent/Active. """ count = 0 for agent in model.schedule.agents: if agent.breed == "cop": continue if exclude_jailed and agent.jail_sentence: continue if agent.moral_state == moral_condition: count += 1 return count @staticmethod def count_jailed(model): """ Helper method to count jailed agents. """ count = 0 for agent in model.schedule.agents: if agent.breed == "citizen" and agent.jail_sentence: count += 1 return count @staticmethod def count_employed(model): """ Helper method to count employed agents. """ count = 0 for agent in model.schedule.agents: if agent.breed == "cop": continue if agent.is_employed == 1: count += 1 return count @staticmethod def count_corrupted(model): """ Helper method to count corrupted agents. """ count = 0 for agent in model.schedule.agents: if agent.breed == "cop": continue if agent.is_corrupted == 1: count += 1 return count
class CivilViolenceModel(Model): """ Model 1 from "Modeling civil violence: An agent-based computational approach," by Joshua Epstein. http://www.pnas.org/content/99/suppl_3/7243.full Attributes: height: grid height width: grid width citizen_density: approximate % of cells occupied by citizens. cop_density: approximate % of calles occupied by cops. citizen_vision: number of cells in each direction (N, S, E and W) that citizen can inspect cop_vision: number of cells in each direction (N, S, E and W) that cop can inspect legitimacy: (L) citizens' perception of regime legitimacy, equal across all citizens max_jail_term: (J_max) active_threshold: if (grievance - (risk_aversion * arrest_probability)) > threshold, citizen rebels arrest_prob_constant: set to ensure agents make plausible arrest probability estimates movement: binary, whether agents try to move at step end max_iters: model may not have a natural stopping point, so we set a max. propaganda_agent_density: % of propaganda agent propaganda_allowed: True if we are allowing propaganda """ def __init__( self, height=40, width=40, citizen_density=70, cop_density=4, citizen_vision=7, cop_vision=7, legitimacy=82, max_jail_term=30, active_threshold=4, arrest_prob_constant=2.3, movement=True, max_iters=1000, propaganda_agent_density=2, propaganda_factor=1, exposure_threshold=10, ): super().__init__() self.height = height self.width = width self.citizen_density = citizen_density / 100 self.cop_density = cop_density / 100 self.propaganda_agent_density = propaganda_agent_density / 100 self.citizen_vision = citizen_vision self.cop_vision = cop_vision self.legitimacy = legitimacy / 100 self.max_jail_term = max_jail_term self.active_threshold = active_threshold / 100 self.arrest_prob_constant = arrest_prob_constant self.movement = movement self.max_iters = max_iters # initiate the model's grid and schedule self.iteration = 0 self.schedule = RandomActivation(self) self.grid = Grid(height, width, torus=True) self.propaganda_factor = propaganda_factor / 1000 self.exposure_threshold = exposure_threshold # initiate data collectors for agent state feedback model_reporters = { "Quiescent": lambda m: self.count_type_citizens(m, False), "Active": lambda m: self.count_type_citizens(m, True), "Jailed": lambda m: self.count_jailed(m), "Active Propaganda Agents": lambda m: self.count_propaganda_agents(m), "Total Inactive Grievance": lambda m: self.report_total_inactive_grievance(m), "Total Inactive Net Risk": lambda m: self.report_total_inactive_net_risk(m), "Total Influence": lambda m: self.report_total_influence(m), "Ripeness Index": lambda m: self.report_ripeness_index(m) } agent_reporters = { "x": lambda a: a.pos[0], "y": lambda a: a.pos[1], 'breed': lambda a: a.agent_class, "jail_sentence": lambda a: getattr(a, 'jail_time', None), "active": lambda a: getattr(a, "active", None), "arrest_probability": lambda a: getattr(a, "arrest_probability", None) } self.datacollector = DataCollector(model_reporters=model_reporters, agent_reporters=agent_reporters) unique_id = 0 if self.cop_density + self.citizen_density + self.propaganda_agent_density > 1: raise ValueError( 'Cop density + citizen density + propaganda agent density must be less than 1' ) # initialize agents in the grid with respect to the given densities for (contents, x, y) in self.grid.coord_iter(): if self.random.random() < self.propaganda_agent_density: agent = PropagandaAgent( unique_id, self, influence=self.random.random(), exposure_threshold=self.exposure_threshold, vision=self.citizen_vision, pos=(x, y)) unique_id += 1 self.grid[y][x] = agent self.schedule.add(agent) elif self.random.random( ) < self.cop_density + self.propaganda_agent_density: cop = CopAgent(unique_id, self, vision=self.cop_vision, pos=(x, y)) unique_id += 1 self.grid[y][x] = cop self.schedule.add(cop) elif (self.random.random() < self.cop_density + self.citizen_density + self.propaganda_agent_density): citizen = PopulationAgent( unique_id, self, hardship=self.random.random(), legitimacy=self.legitimacy, risk_aversion=self.random.random(), threshold=self.active_threshold, susceptibility=self.random.random(), propaganda_factor=self.propaganda_factor, vision=self.citizen_vision, pos=(x, y)) unique_id += 1 self.grid[y][x] = citizen self.schedule.add(citizen) self.running = True self.datacollector.collect(self) def step(self): # Advance the model by one step and collect data. self.schedule.step() self.datacollector.collect(self) self.iteration += 1 if self.iteration > self.max_iters: self.running = False @staticmethod def count_type_citizens(model, count_actives, exclude_jailed=True): """ Helper method to count agents by Quiescent/Active depending on ther active flag. """ count = 0 for agent in model.schedule.agents: if agent.agent_class in [COP_AGENT_CLASS, PROPAGANDA_AGENT_CLASS]: continue if exclude_jailed and agent.jail_time: continue if count_actives and agent.active: count += 1 elif not count_actives and not agent.active: count += 1 return count @staticmethod def count_jailed(model): """ Helper method to count jailed agents. (Both propaganda and population) """ count = 0 for agent in model.schedule.agents: if agent.agent_class in [ POPULATION_AGENT_CLASS, PROPAGANDA_AGENT_CLASS ] and agent.jail_time: count += 1 return count @staticmethod def count_propaganda_agents(model): """ Helper method to count non jailed propaganda agents. """ count = 0 for agent in model.schedule.agents: if agent.agent_class in [PROPAGANDA_AGENT_CLASS ] and not agent.jail_time: count += 1 return count @staticmethod def report_total_influence(model): """ Helper method to count total influence of propaganda agents. """ total = 0. for agent in model.schedule.agents: if agent.agent_class in [PROPAGANDA_AGENT_CLASS ] and not agent.jail_time: total += agent.total_influence return total @staticmethod def report_total_inactive_grievance(model): """ Helper method to count total grievance of non-jailed, inactive population agents. """ total = 0. average = 0. for agent in model.schedule.agents: if agent.agent_class in [ POPULATION_AGENT_CLASS ] and not agent.active and not agent.jail_time: total += agent.grievance return total @staticmethod def report_total_inactive_net_risk(model): """ Helper method to count total net risk of non jailed, inactive population agents. """ total = 0. for agent in model.schedule.agents: if agent.agent_class in [ POPULATION_AGENT_CLASS ] and not agent.active and not agent.jail_time: total += agent.net_risk return total @staticmethod def report_ripeness_index(model): """ Helper method to count ripeness index, as defined in Epsteins paper: RI = E[G] * Q / E[R], where: E[G]: Expected value for total grievance of all non-jailed agents E[R]: Expected value for total risk aversion of all non-jailed agents """ count, E_R, E_G = 0., 0., 0. for agent in model.schedule.agents: if agent.agent_class in [POPULATION_AGENT_CLASS ] and not agent.jail_time: count += 1 E_R += agent.risk_aversion E_G += agent.grievance E_R /= count E_G /= count # number of inactive population agents Q = model.count_type_citizens(model, count_actives=False) return float(E_G) * Q / E_R
class TestBaseGrid(unittest.TestCase): ''' Testing a non-toroidal grid. ''' torus = False def setUp(self): ''' Create a test non-toroidal grid and populate it with Mock Agents ''' width = 3 # width of grid height = 5 # height of grid self.grid = Grid(width, height, self.torus) self.agents = [] counter = 0 for x in range(width): for y in range(height): if TEST_GRID[x][y] == 0: continue counter += 1 # Create and place the mock agent a = MockAgent(counter, None) self.agents.append(a) self.grid.place_agent(a, (x, y)) def test_agent_positions(self): ''' Ensure that the agents are all placed properly. ''' for agent in self.agents: x, y = agent.pos assert self.grid[x][y] == agent def test_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, get_cell_list_contents accurately reports that fact. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.get_cell_list_contents([(x, y)]) def test_listfree_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, get_cell_list_contents accurately reports that fact, even when single position is not wrapped in a list. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.get_cell_list_contents((x, y)) def test_iter_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, iter_cell_list_contents accurately reports that fact. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.iter_cell_list_contents([(x, y)]) def test_listfree_iter_cell_agent_reporting(self): ''' Ensure that if an agent is in a cell, iter_cell_list_contents accurately reports that fact, even when single position is not wrapped in a list. ''' for agent in self.agents: x, y = agent.pos assert agent in self.grid.iter_cell_list_contents((x, y)) def test_neighbors(self): ''' Test the base neighborhood methods on the non-toroid. ''' neighborhood = self.grid.get_neighborhood((1, 1), moore=True) assert len(neighborhood) == 8 neighborhood = self.grid.get_neighborhood((1, 4), moore=False) assert len(neighborhood) == 3 neighborhood = self.grid.get_neighborhood((1, 4), moore=True) assert len(neighborhood) == 5 neighborhood = self.grid.get_neighborhood((0, 0), moore=False) assert len(neighborhood) == 2 neighbors = self.grid.get_neighbors((4, 1), moore=False) assert len(neighbors) == 0 neighbors = self.grid.get_neighbors((4, 1), moore=True) assert len(neighbors) == 0 neighbors = self.grid.get_neighbors((1, 1), moore=False, include_center=True) assert len(neighbors) == 3 neighbors = self.grid.get_neighbors((1, 3), moore=False, radius=2) assert len(neighbors) == 2 def test_coord_iter(self): ci = self.grid.coord_iter() # no agent in first space first = next(ci) assert first[0] is None assert first[1] == 0 assert first[2] == 0 # first agent in the second space second = next(ci) assert second[0].unique_id == 1 assert second[0].pos == (0, 1) assert second[1] == 0 assert second[2] == 1 def test_agent_move(self): # get the agent at [0, 1] agent = self.agents[0] self.grid.move_agent(agent, (1, 1)) assert agent.pos == (1, 1) # move it off the torus and check for the exception if not self.torus: with self.assertRaises(Exception): self.grid.move_agent(agent, [-1, 1]) with self.assertRaises(Exception): self.grid.move_agent(agent, [1, self.grid.height + 1]) else: self.grid.move_agent(agent, [-1, 1]) assert agent.pos == (self.grid.width - 1, 1) self.grid.move_agent(agent, [1, self.grid.height + 1]) assert agent.pos == (1, 1) def test_agent_remove(self): agent = self.agents[0] x, y = agent.pos self.grid.remove_agent(agent) assert agent.pos is None assert self.grid.grid[x][y] is None
class Epidemic(Model): ''' Represents the 2-dimensional array of cells in Conway's Game of Life. ''' def __init__(self, height, width, map): ''' Create a new playing area of (height, width) cells and map. ''' # global time self.globaltime = 0 # Greyscale image self.map = map # Set up the grid and schedule. # Use SimultaneousActivation which simulates all the cells # computing their next state simultaneously. This needs to # be done because each cell's next state depends on the current # state of all its neighbours -- before they've changed. self.schedule = SimultaneousActivation(self) # Use a simple grid, where edges wrap around. self.grid = Grid(height, width, torus=True) # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for (contents, x, y) in self.grid.coord_iter(): cell = Cell((x, y), self) # Creating a sea in the middle of the grid if self.map[x, y] == 1.0: if y > 37.5 and y < 55 and x > 37.5 and x < 62.5: cell.state = cell.ALIVE cell.starttime = 0 cell.endtime = 5000 cell.mobility = cell.IMMOBILE cell.infection = random() cell.infectious = True cell.mutability = cell.IMMUTABLE # Ardipithecus K if x > 77 and x < 81 and y > 60 and y < 64: cell.state = cell.DEAD cell.mobility = cell.MOBILE cell.infection = 0. cell.starttime = 0 cell.endtime = 60 cell.infectious = True if x > 50 and x < 54 and y > 67 and y < 71: # if y > 60 and y < 65 and x > 65 and x < 70: cell.state = cell.DEAD cell.mobility = cell.MOBILE cell.infection = 0. cell.starttime = 1950 cell.endtime = 2050 cell.infectious = True if x > 71 and x < 75 and y > 52 and y < 56: # if y > 60 and y < 65 and x > 65 and x < 70: cell.state = cell.DEAD cell.starttime = 2050 cell.endtime = 2150 cell.mobility = cell.MOBILE cell.infection = 0. cell.infectious = True else: cell.mobility = cell.IMMOBILE cell.activity = cell.INACTIVE self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.running = True self.datacollector = DataCollector( model_reporters={"Infection": compute_infection}) def step(self): ''' Have the scheduler advance each cell by one step ''' # global time self.globaltime += 1 if self.globaltime == 88: for (contents, x, y) in self.grid.coord_iter(): cell = Cell((x, y), self) # Ardipithecus R if x > 77 and x < 81 and y > 60 and y < 64: cell.state = cell.DEAD cell.mobility = cell.MOBILE cell.infection = 0. cell.starttime = 90 #1150 cell.endtime = 150 #1250 cell.infectious = True cell.globaltime = self.globaltime self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.datacollector.collect(self) self.schedule.step()
class infection_model(Model): def __init__(self, height=100, width=100, dummy="", density=0.5, p_inf=0.1, p_rec=0.3, p_reinf=0.05, p_test=0.1, p_death=0.2, test_n=0, hood="Moore", datacollector={}): ''' Create a new playing area of (height, width) cells. ''' # Use SimultaneousActivation which simulates all the cells # computing their next state simultaneously. This needs to # be done because each cell's next state depends on the current # state of all its neighbors -- before they've changed. self.height = height self.width = width self.schedule = SimultaneousActivation(self) # Use a simple grid, where edges wrap around. self.grid = Grid(height, width, torus=True) # Use the DataCollector method to store the relevant information of our # model. This helps with plotting in the web socke, but also with running #more models at the same time using BatchRunner (in batch.py) self.datacollector = DataCollector( model_reporters=self.compute_reporters()) # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for (contents, x, y) in self.grid.coord_iter(): cell = Cell((x, y), self, p_inf, p_rec, p_reinf, p_test, p_death, test_n, hood) if self.random.random() < density: cell.state = cell.INFECTED self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.measure_CA = [] self.running = True self.datacollector.collect(self) def step(self): ''' Have the scheduler advance each cell by one step ''' self.measure_CA = [a for a in self.schedule.agents] self.schedule.step() # collect data self.datacollector.collect(self) def compute_reporters(self): ''' Returns A dictionary of the fractions of the population that are Infected, Quarantined, Recovered or Dead ''' mod_rep = { "Fraction Infected": lambda m: self.count_infected(m, self.height * self.width), "Fraction Quarantined": lambda m: self.count_quarantined(m, self.height * self.width), "Fraction Recovered": lambda m: self.count_recovered(m, self.height * self.width), "Fraction Dead": lambda m: self.count_dead(m, self.height * self.width), } return mod_rep @staticmethod def count_infected(model, grid_size): """ Helper method to count INFECTED cells in the model. """ list_state = [ a for a in model.schedule.agents if (a.state == a.INFECTED or a.state == a.QUARANTINED) ] return len(list_state) / grid_size @staticmethod def count_recovered(model, grid_size): """ Helper method to count RECOVERED cells in the model. """ list_state = [ a for a in model.schedule.agents if (a.state == a.RECOVERED or a.state == a.DEAD) ] return len(list_state) / grid_size @staticmethod def count_quarantined(model, grid_size): """ Helper method to count QUARANTINED cells in the model. """ list_state = [ a for a in model.schedule.agents if a.state == a.QUARANTINED ] return len(list_state) / grid_size @staticmethod def count_dead(model, grid_size): ''' Helper method to count DEAD cells in the model. ''' list_state = [a for a in model.schedule.agents if a.state == a.DEAD] return len(list_state) / grid_size
class EpiDyn(Model): ''' Represents the 2-dimensional model for epidemic dynamics ''' schedule_types = { "Random": RandomActivation, "Simultaneous": SimultaneousActivation } def __init__(self, height=100, width=100, dummy="", schedule_type="Simultaneous", startblock=1, density=0.1, p_infect=0.25, p_death=0.0, spatial=1, groupsize=4, quarantine_delay=7, neighbourdic={}, groupswitch=True, switchperx=2): ''' Create the CA field with (height, width) cells. ''' #setting an explicit seed allows you to reproduce interesting runs #self.random.seed(30) # Set up the grid and schedule. self.schedule_type = schedule_type self.schedule = self.schedule_types[self.schedule_type](self) self.neighbourdic = neighbourdic self.quarantine_delay = quarantine_delay self.groupswitch = groupswitch self.switchperx = switchperx self.counter = 0 # Use a simple grid, where edges wrap around. self.grid = Grid(height, width, torus=True) self.datacollector = DataCollector({ "Infectious": lambda m: self.count_infectious(m, width * height), "Removed": lambda m: self.count_removed(m, width * height), "Exposed": lambda m: self.count_removed(m, width * height) }) # Place a cell at each location, with default SENSTIVE, # and some (a 2x2 block) initialized to INFECTIOUS for (contents, x, y) in self.grid.coord_iter(): cell = Cell((x, y), self, spatial, unique_id=int(0.5 * (x + y) * (x + y + 1) + y)) cell.state = cell.SENSITIVE cell.p_infect = p_infect cell.p_death = p_death cell.groupsize = groupsize if startblock: if ((x == height / 2 or x == height / 2 + 1) and (y == height / 2 or y == height / 2 + 1)): cell.state = cell.INFECTIOUS elif self.random.random() < density: cell.state = cell.INFECTIOUS self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.measure_CA = [] self.running = True self.datacollector.collect(self) def step(self): ''' Have the scheduler advance each cell by one step ''' #Need this seperately so the Reset button works fo no group switches if self.counter == 0: self.neighbourdic.clear() if (self.counter - self.quarantine_delay) % self.switchperx == 0: if self.groupswitch == 1: self.neighbourdic.clear() self.measure_CA = [a for a in self.schedule.agents] self.schedule.step() # collect data self.datacollector.collect(self) self.counter = self.counter + 1 @staticmethod def count_infectious(model, grid_size): """ Helper method to count cells in a given state in a given model. """ list_state = [ a for a in model.schedule.agents if a.state == a.INFECTIOUS ] return len(list_state) / grid_size @staticmethod def count_removed(model, grid_size): """ Helper method to count cells in a given state in a given model. """ list_state = [a for a in model.schedule.agents if a.state == a.REMOVED] return len(list_state) / grid_size @staticmethod def count_exposed(model, grid_size): """ Helper method to count cells in a given state in a given model. """ list_state = [ a for a in model.schedule.agents if a.state == a.NEIGHBOUR ] return len(list_state) / grid_size
class ConwaysGameOfLife(Model): """ Represents the 2-dimensional array of cells in Conway's Game of Life. """ def __init__(self, data, height=10, width=10, part="Part 1"): """ Create a new playing area of (height, width) cells. """ # Set up the grid and schedule. # Use SimultaneousActivation which simulates all the cells # computing their next state simultaneously. This needs to # be done because each cell's next state depends on the current # state of all its neighbors -- before they've changed. self.schedule = SimultaneousActivation(self) # Use a simple grid, where edges wrap around. self.grid = Grid(height, width, torus=False) self.dc = DataCollector({ "Empty": lambda m: self.count_type(m, Cell.DEAD), "Occupied": lambda m: self.count_type(m, Cell.ALIVE), }) self.numalive = 0 # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for (contents, x, y) in self.grid.coord_iter(): if data[(len(data) - 1) - y][x] == ".": state = Cell.FLOOR else: state = Cell.DEAD cell = Cell((x, y), self, state, part) self.grid.place_agent(cell, (x, y)) self.schedule.add(cell) self.running = True self.dc.collect(self) def step(self): """ Have the scheduler advance each cell by one step """ print(self.numalive) prev = self.numalive self.schedule.step() self.schedule.step() self.dc.collect(self) self.numalive = self.count_type(self, Cell.ALIVE) if prev == self.numalive: self.running = False @staticmethod def count_type(model, condition): """ Helper method to count trees in a given condition in a given model. """ count = 0 for spot in model.schedule.agents: if spot.state == condition: count += 1 return count