Example #1
1
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
Example #2
0
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
Example #4
0
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()
Example #5
0
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
Example #6
0
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()
Example #7
0
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()
Example #8
0
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
Example #10
0
File: model.py Project: GeoESW/mesa
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
Example #11
0
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
Example #12
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
Example #13
0
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
Example #14
0
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
Example #15
0
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()
Example #16
0
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
Example #17
0
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
Example #18
0
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