예제 #1
0
파일: test_space.py 프로젝트: tubks/mesa
class TestSingleGrid(unittest.TestCase):
    def setUp(self):
        self.space = SingleGrid(50, 50, False)
        self.agents = []
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = MockAgent(i, None)
            self.agents.append(a)
            self.space.place_agent(a, pos)

    def test_agent_positions(self):
        """
        Ensure that the agents are all placed properly.
        """
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = self.agents[i]
            assert a.pos == pos

    def test_remove_agent(self):
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = self.agents[i]
            assert a.pos == pos
            assert self.space.grid[pos[0]][pos[1]] == a
            self.space.remove_agent(a)
            assert a.pos is None
            assert self.space.grid[pos[0]][pos[1]] is None

    def test_empty_cells(self):
        if self.space.exists_empty_cells():
            pytest.deprecated_call(self.space.find_empty)
            for i, pos in enumerate(list(self.space.empties)):
                a = MockAgent(-i, pos)
                self.space.position_agent(a, x=pos[0], y=pos[1])
        assert self.space.find_empty() is None
        with self.assertRaises(Exception):
            self.space.move_to_empty(a)

    def move_agent(self):
        agent_number = 0
        initial_pos = TEST_AGENTS_GRID[agent_number]
        final_pos = (7, 7)

        _agent = self.agents[agent_number]

        assert _agent.pos == initial_pos
        assert self.space.grid[initial_pos[0]][initial_pos[1]] == _agent
        assert self.space.grid[final_pos[0]][final_pos[1]] is None
        self.space.move_agent(_agent, final_pos)
        assert _agent.pos == final_pos
        assert self.space.grid[initial_pos[0]][initial_pos[1]] is None
        assert self.space.grid[final_pos[0]][final_pos[1]] == _agent
예제 #2
0
class TestSingleGrid(unittest.TestCase):
    def setUp(self):
        self.space = SingleGrid(50, 50, False)
        self.agents = []
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = MockAgent(i, None)
            self.agents.append(a)
            self.space.place_agent(a, pos)

    def test_agent_positions(self):
        '''
        Ensure that the agents are all placed properly.
        '''
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = self.agents[i]
            assert a.pos == pos

    def test_remove_agent(self):
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = self.agents[i]
            assert a.pos == pos
            assert self.space.grid[pos[0]][pos[1]] == a
            self.space.remove_agent(a)
            assert a.pos is None
            assert self.space.grid[pos[0]][pos[1]] is None

    def move_agent(self):
        agent_number = 0
        initial_pos = TEST_AGENTS_GRID[agent_number]
        final_pos = (7, 7)

        _agent = self.agents[agent_number]

        assert _agent.pos == initial_pos
        assert self.space.grid[initial_pos[0]][initial_pos[1]] == _agent
        assert self.space.grid[final_pos[0]][final_pos[1]] is None
        self.space.move_agent(_agent, final_pos)
        assert _agent.pos == final_pos
        assert self.space.grid[initial_pos[0]][initial_pos[1]] is None
        assert self.space.grid[final_pos[0]][final_pos[1]] == _agent
예제 #3
0
파일: test_space.py 프로젝트: bangtree/mesa
class TestSingleGrid(unittest.TestCase):
    def setUp(self):
        self.space = SingleGrid(50, 50, False)
        self.agents = []
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = MockAgent(i, None)
            self.agents.append(a)
            self.space.place_agent(a, pos)

    def test_agent_positions(self):
        '''
        Ensure that the agents are all placed properly.
        '''
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = self.agents[i]
            assert a.pos == pos

    def test_remove_agent(self):
        for i, pos in enumerate(TEST_AGENTS_GRID):
            a = self.agents[i]
            assert a.pos == pos
            assert self.space.grid[pos[0]][pos[1]] == a
            self.space.remove_agent(a)
            assert a.pos is None
            assert self.space.grid[pos[0]][pos[1]] is None

    def move_agent(self):
        agent_number = 0
        initial_pos = TEST_AGENTS_GRID[agent_number]
        final_pos = (7, 7)

        _agent = self.agents[agent_number]

        assert _agent.pos == initial_pos
        assert self.space.grid[initial_pos[0]][initial_pos[1]] == _agent
        assert self.space.grid[final_pos[0]][final_pos[1]] is None
        self.space.move_agent(_agent, final_pos)
        assert _agent.pos == final_pos
        assert self.space.grid[initial_pos[0]][initial_pos[1]] is None
        assert self.space.grid[final_pos[0]][final_pos[1]] == _agent
예제 #4
0
class EvacuationModel(Model):
    """
    This is a simulation of a crowd evacuation from a building.
    Several variables are taken into account: the knowledge of the emergency exits, the age and weight of the agents
    and the presence of stewards that can guide agents toward the emergency exits.
    Agents have different strategies to escape the building such as taking the shortest path to an exit or a random one.

    The goal is to study which combinations of agent types are more likely to escape the building and save themselves and
    how the amount of casualties varies with respect to the different variables.
    """
    def __init__(self,
                 N=10,
                 K=0,
                 width=50,
                 height=50,
                 fire_x=1,
                 fire_y=1,
                 civil_info_exchange=True):
        self.num_civilians = N
        self.num_stewards = K
        self.civil_info_exchange = civil_info_exchange
        self.fire_initial_pos = (fire_x, fire_y)
        self.warning_UI = ""
        self.agents_alive = N + K  # Agents alive and inside the building
        self.agents_saved = []  # Agents that managed to get out
        self.agents_killed = []  # Agents that perished during the evacuation
        self.grid = SingleGrid(height, width, False)
        self.graph = None  # General graph representing walkable terrain
        self.schedule = RandomActivation(
            self)  # Every tick, agents move in a different random order
        # Create exits
        self.pos_exits = [(0, 5), (0, 25), (0, 45)]
        for i in range(3):
            self.pos_exits.append((self.grid.width - 1, 14 + i))

        self.draw_environment(self.pos_exits)
        self.graph = path_finding.create_graph(self)
        # Define data collector
        model_collector = {
            "Agents killed": lambda killed: len(self.agents_killed),
            "Agents saved": lambda saved: len(self.agents_saved)
        }
        for exit_pos in self.pos_exits:
            title = "Exit {}".format(exit_pos)
            model_collector[title] = partial(count_agents_saved, exit_pos)
        self.datacollector = DataCollector(model_reporters=model_collector)
        # Create fire
        # for pos in self.fire_initial_pos:  # Only 1 source of fire since we are setting it from UI
        x, y = self.fire_initial_pos
        if not self.is_inside_square((x, y), (0, 29),
                                     (25, 39)) and not self.is_inside_square(
                                         (x, y), (0, 10), (25, 20)):
            pos = self.fire_initial_pos
        else:
            pos = (1, 1)
            self.warning_UI = "<b>WARNING:</b> Sorry but the position of the fire is outside of the building, " \
                              "change the setting and click reset simulation."
        fire_agent = FireAgent(pos, self)
        self.schedule.add(fire_agent)
        self.grid.place_agent(fire_agent, pos)
        # Create civilian agents
        for i in range(self.num_civilians):

            # a civilian agent will know at least the main entrance to the building
            known_exits = self.pos_exits[-3:]
            a = CivilianAgent(i, self, known_exits)

            self.schedule.add(a)
            # Add the agent to a random grid cell

            while True:
                # pick the random coordinate
                x = self.random.randrange(1, self.grid.width - 1)
                y = self.random.randrange(1, self.grid.height - 1)
                # check if the point is empty and inside of the building
                if self.grid.is_cell_empty((x, y)) and not self.is_inside_square((x, y), (0, 29), (25, 39)) \
                        and not self.is_inside_square((x, y), (0, 10), (25, 20)):
                    break

            self.grid.place_agent(a, (x, y))

        # Create steward agents
        for i in range(self.num_civilians,
                       self.num_civilians + self.num_stewards):

            # a steward agent will know all exits.
            known_exits = self.pos_exits
            a = StewardAgent(i, self, known_exits)

            self.schedule.add(a)
            # Add the agent to a random grid cell

            while True:
                # pick the random coordinate
                x = self.random.randrange(1, self.grid.width - 1)
                y = self.random.randrange(1, self.grid.height - 1)
                # check if the point is empty and inside of the building
                if self.grid.is_cell_empty((x, y)) and not self.is_inside_square((x, y), (0, 29), (25, 39)) \
                        and not self.is_inside_square((x, y), (0, 10), (25, 20)):
                    break

            self.grid.place_agent(a, (x, y))

        self.running = True  # Set this to false when we want to finish simulation (e.g. all agents are out of building)
        self.datacollector.collect(self)

    @staticmethod
    def is_inside_square(point, bottom_left, top_right):
        return bottom_left[0] <= point[0] <= top_right[0] and bottom_left[
            1] <= point[1] <= top_right[1]

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

        # Halt if no more agents in the building
        if self.count_agents(self) == 0:
            self.running = False

    def remove_agent(self, agent, reason, **kwargs):
        """
        Removes an agent from the simulation. Depending on the reason it can be
        Args:
            agent (Agent):
            reason (Reasons):

        Returns:
            None
        """
        if reason == Reasons.SAVED:
            self.agents_saved.append(agent)
        elif reason == Reasons.KILLED_BY_FIRE:
            self.agents_killed.append(agent)

        self.agents_alive -= 1
        self.schedule.remove(agent)
        self.grid.remove_agent(agent)

    def draw_environment(self, exits=None):
        length_E = int(self.grid.height /
                       5)  # length of the vertical segments of the E
        depth_E = int(self.grid.width /
                      2)  # length of the horizontal segments of the E
        for i in range(3):
            start = max(0, 2 * i * length_E)
            self.draw_wall((0, start), (0, start + length_E - 1))
        for i in range(2):
            start = 2 * i * length_E + length_E
            self.draw_wall((depth_E, start), (depth_E, start + length_E - 1))
        # Horizontal lines of the E (BB)
        aux_y_coord = [
            length_E, 2 * length_E, 3 * length_E - 1, 4 * length_E - 1
        ]
        for y in aux_y_coord:
            self.draw_wall((0, y), (depth_E, y))
        top_left_corner = (0, self.grid.height - 1)
        top_right_corner = (self.grid.width - 1, self.grid.height - 1)
        bottom_right_corner = (self.grid.width - 1, 0)
        # Draw long contour lines E
        self.draw_wall((0, 0), bottom_right_corner)
        self.draw_wall(top_left_corner, top_right_corner)
        self.draw_wall(bottom_right_corner, top_right_corner)

        # Draw exits
        self.draw_exits(exits)

    def draw_wall(self, start, end):
        """
        Draws a line that goes from start point to end point.

        Args:
            start (List): Coordinates of line's starting point
            end (List): Coordinates of line's end point

        Returns:
            None
        """
        diff_x, diff_y = np.subtract(end, start)
        wall_coordinates = np.asarray(start)

        if self.grid.is_cell_empty(wall_coordinates.tolist()):
            w = WallAgent(wall_coordinates.tolist(), self)
            self.grid.place_agent(w, wall_coordinates.tolist())

        while diff_x != 0 or diff_y != 0:
            if abs(diff_x) == abs(diff_y):
                # diagonal wall
                wall_coordinates[0] += np.sign(diff_x)
                wall_coordinates[1] += np.sign(diff_y)
                diff_x -= 1
                diff_y -= 1
            elif abs(diff_x) < abs(diff_y):
                # wall built in y dimension
                wall_coordinates[1] += np.sign(diff_y)
                diff_y -= 1
            else:
                # wall built in x dimension
                wall_coordinates[0] += np.sign(diff_x)
                diff_x -= 1
            if self.grid.is_cell_empty(wall_coordinates.tolist()):
                w = WallAgent(wall_coordinates.tolist(), self)
                self.grid.place_agent(w, wall_coordinates.tolist())

    def draw_exits(self, exits_list):
        for ext in exits_list:
            e = ExitAgent(ext, self)
            if not self.grid.is_cell_empty(ext):
                # Only walls should exist in the grid at this time, so no need to remove it from scheduler
                agent = self.grid.get_cell_list_contents(ext)
                self.grid.remove_agent(agent[0])
            # Place exit
            self.schedule.add(e)
            self.grid.place_agent(e, ext)

    def spread_fire(self, fire_agent):
        fire_neighbors = self.grid.get_neighborhood(fire_agent.pos,
                                                    moore=True,
                                                    include_center=False)
        for grid_space in fire_neighbors:
            if self.grid.is_cell_empty(grid_space):
                # Create new fire agent and add it to grid and scheduler
                new_fire_agent = FireAgent(grid_space, self)
                self.schedule.add(new_fire_agent)
                self.grid.place_agent(new_fire_agent, grid_space)
            else:
                # If human agents, eliminate them and spread anyway
                agent = self.grid.get_cell_list_contents(grid_space)[0]
                if isinstance(agent, (CivilianAgent, StewardAgent)):
                    new_fire_agent = FireAgent(grid_space, self)
                    self.remove_agent(agent, Reasons.KILLED_BY_FIRE)
                    self.schedule.add(new_fire_agent)
                    self.grid.place_agent(new_fire_agent, grid_space)

    @staticmethod
    def count_agents(model):
        """
        Helper method to count agents alive and still in the building.
        """
        count = 0
        for agent in model.schedule.agents:
            agent_type = type(agent)
            if (agent_type == CivilianAgent) or (agent_type == StewardAgent):
                count += 1
        return count
예제 #5
0
class Anthill(Model):
    def __init__(self):

        self.grid = SingleGrid(WIDTH, HEIGHT, False)
        self.schedule = RandomActivation(self)
        self.running = True
        self.internalrate = 0.2
        self.ant_id = 1
        self.tau = np.zeros((WIDTH, HEIGHT))
        self.datacollector = DataCollector({
            "Total number of Ants":
            lambda m: self.get_total_ants_number(),
            "mean tau":
            lambda m: self.evaluation1(),
            "sigma":
            lambda m: self.evaluation2(),
            "sigma*":
            lambda m: self.evaluation3(),
        })

        # List containing all coordinates of the boundary, initial ants location and brood location
        self.bound_vals = []
        self.neigh_bound = []
        self.datacollector.collect(self)

        for i in range(WIDTH):
            for j in range(HEIGHT):
                if i == 0 or j == 0 or i == WIDTH - 1 or j == HEIGHT - 1:
                    self.bound_vals.append((i, j))
                if i == 1 or i == WIDTH - 2 or j == 1 or j == HEIGHT - 2:
                    self.neigh_bound.append((i, j))

        # Make a Fence boundary
        b = 0
        for h in self.bound_vals:
            br = Fence(b, self)

            self.grid.place_agent(br, (h[0], h[1]))
            b += 1

    def step(self):
        '''Advance the model by one step.'''
        # Add new ants into the internal area ont he boundary

        for xy in self.neigh_bound:

            # Add with probability internal rate and if the cell is empty
            if self.random.uniform(
                    0, 1) < self.internalrate and self.grid.is_cell_empty(
                        xy) == True:

                a = Ant(self.ant_id, self)

                self.schedule.add(a)
                self.grid.place_agent(a, xy)

                self.ant_id += 1

        # Move the ants
        self.schedule.step()
        self.datacollector.collect(self)

        # Remove all ants on bounary

        for (agents, i, j) in self.grid.coord_iter():
            if (i, j) in self.neigh_bound and type(agents) is Ant:

                self.grid.remove_agent(agents)
                self.schedule.remove(agents)

        data_tau.append(self.mean_tau_ant)
        data_sigma.append(np.sqrt(self.sigma))
        data_sigmastar.append(self.sigmastar)

        if len(data_sigmastar) > 20:
            if abs(data_sigmastar[-2] - data_sigmastar[-1]) < 0.0000001 or len(
                    data_sigmastar) == 2000:
                try:
                    # TAU
                    with open("results/m1_tau_5.pkl", 'rb') as f:
                        tau_old = pickle.load(f)
                        tau_old[int(len(tau_old) + 1)] = data_tau
                        f.close()
                    pickle.dump(tau_old, open("results/m1_tau_5.pkl", 'wb'))

                except:
                    pickle.dump({1: data_tau},
                                open("results/m1_tau_5.pkl", 'wb'))

                try:
                    # SIGMA
                    with open("results/m1_sigma_5.pkl", 'rb') as f:
                        sigma_old = pickle.load(f)
                        sigma_old[int(len(sigma_old) + 1)] = data_sigma
                        f.close()
                    pickle.dump(sigma_old, open("results/m1_sigma_5.pkl",
                                                'wb'))

                except:
                    pickle.dump({1: data_sigma},
                                open("results/m1_sigma_5.pkl", 'wb'))

                try:
                    # SIGMASTAR
                    with open("results/m1_sigmastar_5.pkl", 'rb') as f:
                        sigmastar_old = pickle.load(f)
                        sigmastar_old[int(len(sigmastar_old) +
                                          1)] = data_sigmastar
                        f.close()
                    pickle.dump(sigmastar_old,
                                open("results/m1_sigmastar_5.pkl", 'wb'))

                except:
                    pickle.dump({1: data_sigmastar},
                                open("results/m1_sigmastar_5.pkl", 'wb'))

                try:
                    # MATRIX
                    with open("results/m1_matrix_5.pkl", 'rb') as f:
                        matrix_old = pickle.load(f)
                        matrix_old[int(len(matrix_old) + 1)] = self.tau
                        f.close()
                    pickle.dump(matrix_old,
                                open("results/m1_matrix_5.pkl", 'wb'))

                except:
                    pickle.dump({1: self.tau},
                                open("results/m1_matrix_5.pkl", 'wb'))
                print(
                    "_______________________________________________________________________"
                )
                print("DONE")
                self.running = False

        # with open("tau2_new.txt", "a") as myfile:
        #     myfile.write(str(self.mean_tau_ant) + '\n')
        # with open("sigma2_new.txt", "a") as myfile:
        #     myfile.write(str(np.sqrt(self.sigma)) + '\n')
        # with open("datasigmastar2_new.txt","a") as myfile:
        #     myfile.write(str(self.sigmastar) + "\n")

    def get_total_ants_number(self):
        total_ants = 0
        for (agents, _, _) in self.grid.coord_iter():
            if type(agents) is Ant:
                total_ants += 1
        return total_ants

    def evaluation1(self):

        ##creat a empty grid to store currently information
        total_ants = np.zeros((WIDTH, HEIGHT))

        ## count the number of currently information
        for (agents, i, j) in self.grid.coord_iter():

            if type(agents) is Ant:
                total_ants[i][j] = 1
            else:
                total_ants[i][j] = 0

        ##update the tau
        self.tau = self.tau + total_ants

        ##calcualte the mean tau
        self.mean_tau_ant = self.tau.sum() / ((WIDTH - 2)**2)

        return self.mean_tau_ant

    def evaluation2(self):

        ## we need to minus the mean tau so we need to ensure the result of boundary is zero
        ## so we let the bounday equal mean_tau_ant in this way the (tau-mean_tau_ant) is zero of boundary
        for site in self.bound_vals:
            self.tau[site[0]][site[1]] = self.mean_tau_ant

        ## calculate the sigmaa
        self.sigma = ((self.tau - self.mean_tau_ant)**2).sum() / (
            (WIDTH - 2)**2)

        ## rechange the boundaryy
        for site in self.bound_vals:
            self.tau[site[0]][site[1]] = 0

        return np.sqrt(self.sigma)

    def evaluation3(self):
        ## calculate the sigmastar
        self.sigmastar = np.sqrt(self.sigma) / self.mean_tau_ant

        return self.sigmastar
class modelSim(Model):
    """ 
    details of the world 
    
    introduce time is when animal agents first get introduced into the wrold
    disp_rate is the dispersal rate for experiment 3
    dist is perceptual strength for animals if fixed
    det is decision determinacy of animals if fixed
    cog_fixed determines if cognition of animals is fixed to particular values or is allowed to evolve
    if skip_300 is True, patchiness values are not calculated for the first 300 steps-- this makes the model run faster
    collect_cog_dist creates a seperate dataframe for all cognition values for agents at every timestep
    if evolve_disp is true, dispersion rate of plants is free to evolve
    """

    def __init__(self, introduce_time, disp_rate, dist, det, cog_fixed = False, \
                 skip_300 = True, collect_cog_dist = False, evolve_disp = False):

        self.skip_300 = skip_300
        self.cog_fixed = cog_fixed
        self.evolve_disp = evolve_disp
        self.collect_cog_dist = collect_cog_dist
        self.dist = dist
        self.det = det
        self.disp_rate = disp_rate
        self.intro_time = introduce_time
        (self.a1num, self.a2num) = (20, 20)
        self.schedule = RandomActivation(
            self)  # agents take a step in random order
        self.grid = SingleGrid(
            200, 200,
            True)  # the world is a grid with specified height and width

        self.initialize_perception()

        disp = np.power(self.disp_rate, range(0, 100))
        self.disp = disp / sum(disp)
        self.grid_ind = np.indices((200, 200))
        positions = np.maximum(abs(100 - self.grid_ind[0]),
                               abs(100 - self.grid_ind[1]))
        self.positions = np.minimum(positions, 200 - positions)

        self.agentgrid = np.zeros(
            (self.grid.width, self.grid.height
             ))  # allows for calculation of patchiness of both agents
        self.coggrid = np.full(
            (self.nCogPar, self.grid.width, self.grid.height), 101.0)
        self.dispgrid = np.full((2, self.grid.width, self.grid.height), 101.0)
        self.age = []
        (self.nstep, self.unique_id, self.reprod, self.food, self.death,
         self.combat) = (0, 0, 0, 0, 0, 0)

        self.cmap = colors.ListedColormap([
            'midnightblue', 'mediumseagreen', 'white', 'white', 'white',
            'white', 'white'
        ])  #'yellow', 'orange', 'red', 'brown'])
        bounds = [0, 1, 2, 3, 4, 5, 6, 7]
        self.norm = colors.BoundaryNorm(bounds, self.cmap.N)

        self.expect_NN = []
        self.NN = [5, 10]
        for i in self.NN:
            self.expect_NN.append(
                (math.factorial(2 * i) * i) / (2**i * math.factorial(i))**2)

        grid_ind_food = np.indices((21, 21))
        positions_food = np.maximum(abs(10 - grid_ind_food[0]),
                                    abs(10 - grid_ind_food[1]))
        self.positions_food = np.minimum(positions_food, 21 - positions_food)
        if self.collect_cog_dist:
            self.cog_dist_dist = pd.DataFrame(columns=[])
            self.cog_dist_det = pd.DataFrame(columns=[])

        for i in range(self.a1num):  # initiate a1 agents at random locations
            self.introduce_agents("A1")
        self.nA1 = self.a1num
        self.nA2 = 0
#     self.agent_steps = {}

    def initialize_perception(self):
        self.history = pd.DataFrame(columns=[
            "nA1", "nA2", "age", "LIP5", "LIP10", "LIPanim5", "LIPanim10",
            "Morsita5", "Morsita10", "Morsitaanim5", "Morsitaanim10", "NN5",
            "NN10", "NNanim5", "NNanim10", "reprod", "food", "death", "combat",
            "dist", "det", "dist_lower", "det_lower", "dist_upper",
            "det_upper", "dist_ci", "det_ci"
        ])
        self.nCogPar = 2
        (self.start_energy, self.eat_energy, self.tire_energy, self.reproduction_energy, self.cognition_energy) \
        = (10, 5, 3, 20, 1)

    def introduce_agents(self, which_agent):
        x = random.randrange(self.grid.width)
        y = random.randrange(self.grid.height)

        if which_agent == "A1":
            if self.grid.is_cell_empty((x, y)):
                a = A1(self.unique_id, self, self.start_energy, disp_rate=0)
                self.unique_id += 1
                self.grid.position_agent(a, x, y)
                self.schedule.add(a)
                self.agentgrid[x][y] = 1
            else:
                self.introduce_agents(which_agent)
        elif which_agent == "A2":
            if self.cog_fixed:
                c = (self.dist, self.det)
            else:
                c = tuple([0] * self.nCogPar)
            a = A2(self.unique_id,
                   self,
                   self.start_energy,
                   cognition=c,
                   disp_rate=0)
            self.unique_id += 1
            if self.agentgrid[x][y] == 1:
                die = self.grid.get_cell_list_contents([(x, y)])[0]
                die.dead = True
                self.grid.remove_agent(die)
                self.schedule.remove(die)
                self.grid.place_agent(a, (x, y))
                self.schedule.add(a)
                self.agentgrid[x][y] = 2
                self.coggrid[:, x, y] = c
            elif self.agentgrid[x][y] == 0:
                self.grid.place_agent(a, (x, y))
                self.schedule.add(a)
                self.agentgrid[x][y] = 2
                self.coggrid[:, x, y] = c

    def flatten_(self, n, grid, full_grid=False, mean=True, range_=False):
        if full_grid:
            return (grid[n].flatten())
        i = grid[n].flatten()
        if mean:
            i = np.delete(i, np.where(i == 101))
            if len(i) == 0:
                # if range_:
                return ([0] * 4)
            #else:
            #    return(0)
            if range_:
                if self.cog_fixed:
                    return ([np.mean(i)] * 4)
                return (np.concatenate(
                    ([np.mean(i)], np.percentile(i, [2.5, 97.5]),
                     self.calculate_ci(i))))
            return ([np.mean(i), 0, 0, 0])
        else:
            return (i)

    def calculate_ci(self, data):
        if np.min(data) == np.max(data):
            return ([0.0])
        return ([
            np.mean(data) - st.t.interval(
                0.95, len(data) - 1, loc=np.mean(data), scale=st.sem(data))[0]
        ])

    def return_zero(self, num, denom):
        if self.nstep == 1:
            #     print("whaaat")
            return (0)
        if denom == "old_nA2":
            denom = self.history["nA2"][self.nstep - 2]
        if denom == 0.0:
            return 0
        return (num / denom)

    def nearest_neighbor(self, agent):  # fix this later
        if agent == "a1":
            x = np.argwhere(self.agentgrid == 1)
            if len(x) <= 10:
                return ([-1] * len(self.NN))
            elif len(x) > 39990:
                return ([0.97, 0.99])
        #  if self.nstep<300 and self.skip_300:
        #      return([-1,-1] )
        else:
            x = np.argwhere(self.agentgrid == 2)
            if len(x) <= 10:
                return ([-1] * len(self.NN))
        density = len(x) / (self.grid.width)**2
        expect_NN_ = self.expect_NN
        expect_dist = np.array(expect_NN_) / (density**0.5)
        distances = [0, 0]
        for i in x:
            distx = abs(x[:, 0] - i[0])
            distx[distx > 100] = 200 - distx[distx > 100]
            disty = abs(x[:, 1] - i[1])
            disty[disty > 100] = 200 - disty[disty > 100]
            dist = (distx**2 + disty**2)**0.5
            distances[0] += (np.partition(dist, 5)[5])
            distances[1] += (np.partition(dist, 10)[10])
        mean_dist = np.array(distances) / len(x)
        out = mean_dist / expect_dist
        return (out)

    def quadrant_patch(
        self, agent
    ):  # function to calculate the patchiness index of agents at every step
        if agent == "a1":
            x = self.agentgrid == 1
        else:
            x = self.agentgrid == 2
        gsize = np.array([5, 10])
        gnum = 200 / gsize
        qcs = []
        for i in range(2):
            x_ = x.reshape(int(gnum[i]), gsize[i], int(gnum[i]),
                           gsize[i]).sum(1).sum(2)
            mean = np.mean(x_)
            var = np.var(x_)
            if mean == 0.0:
                return ([-1] * 4)
            lip = 1 + (var - mean) / (mean**2)
            morsita = np.sum(x) * ((np.sum(np.power(x_, 2)) - np.sum(x_)) /
                                   (np.sum(x_)**2 - np.sum(x_)))
            qcs += [lip, morsita]
        return (qcs)

    def l_function(self, agent):
        if agent == "a1":
            x = np.argwhere(self.agentgrid == 1)
        else:
            x = np.argwhere(self.agentgrid == 2)
            if len(x) == 0:
                return (-1)
        distances = np.array([])
        for i in x:
            distx = abs(x[:, 0] - i[0])
            distx[distx > 100] = 200 - distx[distx > 100]
            disty = abs(x[:, 1] - i[1])
            disty[disty > 100] = 200 - disty[disty > 100]
            dist = (distx**2 + disty**2)**0.5
            distances = np.concatenate((distances, dist[dist != 0]))
        l = np.array([])
        for i in np.arange(5, 51, 5):
            l = np.append(l, sum(distances < i))
        k = (l * 200**2) / (len(x)**2)
        l = (k / math.pi)**0.5
        return (abs(l - np.arange(5, 51, 5)))

    def collect_hist(self):
        if self.nstep < 300 and self.skip_300:
            NNcalc = [-1, -1]  #self.nearest_neighbor("a1")
            NNanimcalc = [-1, -1]  #self.nearest_neighbor("a2")
        else:
            NNcalc = self.nearest_neighbor("a1")
            NNanimcalc = self.nearest_neighbor("a2")
        quadrantcalc = self.quadrant_patch("a1")
        quadrantanimcalc = self.quadrant_patch("a2")
        dist_values = self.flatten_(0,
                                    grid=self.coggrid,
                                    mean=True,
                                    range_=False)
        det_values = self.flatten_(1,
                                   grid=self.coggrid,
                                   mean=True,
                                   range_=False)
        # l_f = 0#self.l_function("a1")
        dat = {
            "nA1": self.nA1,
            "nA2": self.nA2,
            "age": self.return_zero(sum(self.age), self.nA2),
            "LIP5": quadrantcalc[0],
            "LIP10": quadrantcalc[2],
            "LIPanim5": quadrantanimcalc[0],
            "LIPanim10": quadrantanimcalc[2],
            "Morsita5": quadrantcalc[1],
            "Morsita10": quadrantcalc[3],
            "Morsitaanim5": quadrantanimcalc[1],
            "Morsitaanim10": quadrantanimcalc[3],
            "NN5": NNcalc[0],
            "NN10": NNcalc[1],
            "NNanim5": NNanimcalc[0],
            "NNanim10":
            NNanimcalc[1],  #"l_ripley" : l_f,# self.nearest_neighbor("a2"),  
            "reprod": self.return_zero(self.reprod, "old_nA2"),
            "food": self.return_zero(self.food, self.nA2),
            "death": self.return_zero(self.death, "old_nA2"),
            "combat": self.return_zero(self.combat, "old_nA2"),
            "dist": dist_values[0],
            "det": det_values[0],
            "dist_lower": dist_values[1],
            "det_lower": det_values[1],
            "dist_upper": dist_values[2],
            "det_upper": det_values[2],
            "dist_ci": dist_values[3],
            "det_ci": det_values[3],
            "disp_a1": self.flatten_(0, grid=self.dispgrid)[0],
            "disp_a2": self.flatten_(1, grid=self.dispgrid)[0]
        }
        self.history = self.history.append(dat, ignore_index=True)
        self.age = []
        (self.reprod, self.food, self.death, self.combat) = (0, 0, 0, 0)
        if self.collect_cog_dist:
            if (self.nstep % 10) == 0:
                self.cog_dist_dist[str(self.nstep - 1)] = self.flatten_(
                    0, grid=self.coggrid, full_grid=True, mean=False)
                self.cog_dist_det[str(self.nstep - 1)] = self.flatten_(
                    1, grid=self.coggrid, full_grid=True, mean=False)

    def step(self):
        self.nstep += 1  # step counter
        if self.nstep == self.intro_time:
            for i in range(self.a2num):
                self.introduce_agents("A2")
        self.schedule.step()
        self.nA1 = np.sum(self.agentgrid == 1)
        self.nA2 = np.sum(self.agentgrid == 2)
        self.collect_hist()
        if self.nstep % 10 == 0:
            sys.stdout.write((str(self.nstep) + " " + str(self.nA1) + " " +
                              str(self.nA2) + "\n"))

    def visualize(self):
        f, ax = plt.subplots(1)
        self.agentgrid = self.agentgrid.astype(int)
        ax.imshow(self.agentgrid,
                  interpolation='nearest',
                  cmap=self.cmap,
                  norm=self.norm)
        # plt.axis("off")
        return (f)
예제 #7
0
파일: sd_env.py 프로젝트: vishalbelsare/ABM
class SDGrid(Model):
    ''' Model class for iterated, spatial social dilemma model. '''

    schedule_types = {"Sequential": BaseScheduler,
                      "Random": RandomActivation,
                      "Simultaneous": SimultaneousActivation}

    # This dictionary holds the payoff for this agent,
    # keyed on: (my_move, other_move)

    #NOTE: Payoffs must be given by the user in the format below as a dict object. 
    
    def __init__(self, height=0, width=0, schedule_type="Random", payoffs=None, seed=2514, p = .1, implement = "Epstein", num_RL =500, ep_length=1):
        '''
        Create a new Spatial Prisoners' Dilemma Model.
        Args:
            height, width: Grid size. There will be one agent per grid cell.
            schedule_type: Can be "Sequential", "Random", or "Simultaneous".
                           Determines the agent activation regime.
            payoffs: (required) Dictionary of (move, neighbor_move) payoffs.
        '''
        #Set default grid size if none inputted by user
        if height == 0:
            h = 50
        else:
            h = height
        if width == 0:
            w = 50
        else:
            w = width
        
        assert height or width < 0, "Grid heigth and width must be positive numbers."

        if payoffs:
            self.payoff = payoffs
        
        else: 
            self.payoff = {(C, C): 5,
                        (C, D): -5,
                        (D, C): 6,
                        (D, D): -6}

        self.grid = SingleGrid(h, w, torus=True)
        self.schedule_type = schedule_type
        self.schedule = self.schedule_types[self.schedule_type](self)
        self.implement = implement
        self.ep_length = ep_length
        self.num_RL = num_RL
        #FIXME: THis is a bandaid fix for MESA's loop bug (see trello for SD ABM):

        self.kill_list = []
        self.fertile_agents = []

        if self.implement == "Epstein":
            leave_empty = np.random.choice(a = [False, True], size = (width, height), p = [p, 1-p])
        else:
            pass

        # Create agents: automatically populates agents and grid; 
        count = 0
        for x in range(width):
            for y in range(height):
                
                if implement == "Epstein":
                    if leave_empty[x, y]:
                        continue
                    else:
                        agent = SDAgent(count, (x, y), self)
                        count +=1
                else:
                    agent = SDAgent(count, (x, y), self)
                    count +=1

                self.grid.place_agent(agent, (x, y))
                self.schedule.add(agent)
########################################################################################################################
        #FIXME: may need to make an unique id for agents to do this correctly
        #FIXME: this will have to be generalized later for when multipe batches of episodes are being run
########################################################################################################################
        # learners = np.random.choice([self.schedule._agents], self.num_RL) 

        # #switch them to learn mode
        # for agent in learners:
        #     agent.learn_mode = True
        

        # TODO: Make data collection easier for user; need to do same in BWT / Cartel

        self.datacollector = DataCollector(model_reporters={
            "Learning Cooperating_Agents":
            lambda m: (len([a for a in m.schedule.agents if a.move == C and a.unique_id == 1] )),
            "Learning Defecting_Agents": 
            lambda n: (len([b for b in n.schedule.agents if b.move == D and b.unique_id == 1] ))
        })

        self.running = True
        self.datacollector.collect(self)

    def step(self):

        self.schedule.step()
        for agent in self.schedule.agents:
            if agent.unique_id == 1:
                agent.learn = True
                #print('agent 1 has learn set to {}'.format(agent.learn))
                agent.update_policy()
        # collect data
        self.datacollector.collect(self)

        # self.purge()
        # self.replicate_agents()

        #if (self.schedule.time % self.ep_length == 0) and (self.schedule.time > 0):
            #print(self.schedule.time)
            
            # learners = random.sample(self.schedule.agents, self.num_RL) 
            # for agent in learners:
            #     agent.learn = True
        
            # for agent in learners:
            #     agent.update_policy()
            #     agent.learn = False
            #     if agent == learners[-1]: 
            #         print("################################# Update finished #################################")
            

        
    def replicate_agents(self):
        
        if self.fertile_agents is not None:

            for agent in self.fertile_agents:
                if agent.pos is not None:
                    try:
                        agent.replicate()
                    except ValueError:
                        #print("Caught a bad egg, boss!")
                        continue


    def purge(self):

        if len(self.kill_list)>0:
            for agent in self.kill_list:
                self.grid.remove_agent(agent)
                self.schedule.remove(agent)
        
            self.kill_list = []
        else:
            pass


    def run(self, n):
        ''' Run the model for n steps. '''
        for _ in range(n):
            self.step()
예제 #8
0
class RoadModel(Model):
    """
    A model with a number of cars, Nagel-Schreckenberg
    """
    def __init__(self, N, length=100, lanes=1, timer=3):
        self.num_agents = N
        self.grid = SingleGrid(length, lanes, torus=True)
        model_stages = [
            "acceleration", "braking", "randomisation", "move", "delete"
        ]
        self.schedule = StagedActivation(self, stage_list=model_stages)

        # Create agent
        for i in range(self.num_agents):
            agent = CarAgent(i, self, False)
            # Add to schedule
            self.schedule.add(agent)
            # Add to grid (randomly)
            self.grid.position_agent(agent)

        # Add the traffic light
        self.traffic_light = TrafficLight(0, self, timer, 20, 20)
        self.average_velocity = CarAgent.init_velocity
        self.datacollector = DataCollector(agent_reporters={
            "Position": "pos",
            "Velocity": "velocity"
        },
                                           model_reporters={
                                               "Average Velocity":
                                               "average_velocity",
                                               "Amount of cars": "agent_count",
                                               "On Ramp Queue":
                                               get_on_ramp_queue,
                                               "Waiting Queue":
                                               get_waiting_queue
                                           })

        self.running = True

    def step(self):
        """
        The model takes a new step and updates
        """
        # Calculate amount of agents
        self.agent_count = len(self.schedule.agents)
        # Calculate average velocity
        self.average_velocity = np.mean(
            [a.velocity for a in self.schedule.agents])
        # Collect data
        self.datacollector.collect(self)
        # Run a step of the traffic light
        self.traffic_light.step()
        # Run next step
        self.schedule.step()

    def add_agent(self, label, x_corr):
        """
        Adds an agent to the scheduler and model on a particular coordinate

        :param label: The label of the agents that gets created
        :param x_corr: The x-coordinate of where the agent will be spawned
        """
        # Create agent
        agent = CarAgent(label, self, True)
        # Add to schedule
        self.schedule.add(agent)
        # Add to grid on a certain position
        self.grid.position_agent(agent, x_corr, 0)

    def delete_agent(self, agent):
        """
        Deletes an agent from the scheduler and model

        :param agent: The agents that gets deleted
        """
        # remove from schedule
        self.schedule.remove(agent)
        # remove from grid
        self.grid.remove_agent(agent)
예제 #9
0
class GTModel(Model):
    def __init__(self, debug, size, i_n_agents, i_strategy, i_energy,
                 child_location, movement, k, T, M, p, d, strategies_to_count,
                 count_tolerance, mutation_type, death_threshold, n_groups):
        self.grid = SingleGrid(size, size, torus=True)
        self.schedule = RandomActivation(self)
        self.running = True
        self.debug = debug
        self.size = size
        self.agent_idx = 0
        self.i_energy = i_energy

        # Payoff matrix in the form (my_move, op_move) : my_reward
        self.payoff = {
            ('C', 'C'): 2,
            ('C', 'D'): -3,
            ('D', 'C'): 3,
            ('D', 'D'): -1,
        }
        # Constant for max population control (cost of surviving)
        self.k = k
        # Constant for controlling dying of old age
        self.M = M
        # Minimum lifespan
        self.T = T
        # Minimum energy level to reproduce
        self.p = p
        # Mutation "amplitude"
        self.d = d
        # Whether to spawn children near parents or randomly
        self.child_location = child_location
        # Specify the type of movement allowed for the agents
        self.movement = movement
        # Specify how the agents mutate
        self.mutation_type = mutation_type
        # The minimum total_energy needed for an agent to survive
        self.death_threshold = death_threshold

        # Vars regarding which strategies to look for
        self.strategies_to_count = strategies_to_count
        self.count_tolerance = count_tolerance

        # Add agents (one agent per cell)
        all_coords = [(x, y) for x in range(size) for y in range(size)]
        agent_coords = self.random.sample(all_coords, i_n_agents)

        for _ in range(i_n_agents):
            group_idx = (None if n_groups is None else self.random.choice(
                range(n_groups)))
            agent = GTAgent(self.agent_idx, group_idx, self, i_strategy.copy(),
                            i_energy)
            self.agent_idx += 1
            self.schedule.add(agent)
            self.grid.place_agent(agent, agent_coords.pop())

        # Collect data
        self.datacollector = DataCollector(
            model_reporters={
                **{
                    'strategies': get_strategies,
                    'n_agents': total_n_agents,
                    'avg_agent_age': avg_agent_age,
                    'n_friendlier': n_friendlier,
                    'n_aggressive': n_aggressive,
                    'perc_cooperative_actions': perc_cooperative_actions,
                    'n_neighbors': n_neighbor_measure,
                    'avg_delta_energy': avg_delta_energy,
                    'perc_CC': perc_CC_interactions,
                    'lin_fit_NC': coop_per_neig,
                    'lin_fit_NC_intc': coop_per_neig_intc,
                },
                **{
                    label: strategy_counter_factory(strategy, count_tolerance)
                    for label, strategy in strategies_to_count.items()
                }
            })

    def alpha(self):
        # Return the cost of surviving, alpha
        DC = self.payoff[('D', 'C')]
        CC = self.payoff[('C', 'C')]
        N = len(self.schedule.agents)

        return self.k + 4 * (DC + CC) * N / (self.size * self.size)

    def time_to_die(self, agent):
        # There is a chance every iteration to die of old age: (A - T) / M
        # There is a 100% to die if the agents total energy reaches 0
        return (agent.total_energy < self.death_threshold
                or self.random.random() < (agent.age - self.T) / self.M)

    def get_child_location(self, agent):
        if self.child_location == 'global':
            return self.random.choice(sorted(self.grid.empties))

        elif self.child_location == 'local':
            # Iterate over the radius, starting at 1 to find empty cells
            for rad in range(1, int(self.size / 2)):
                possible_steps = [
                    cell for cell in self.grid.get_neighborhood(
                        agent.pos,
                        moore=False,
                        include_center=False,
                        radius=rad,
                    ) if self.grid.is_cell_empty(cell)
                ]

                if possible_steps:
                    return self.random.choice(possible_steps)

            # If no free cells in radius size/2 pick a random empty cell
            return self.random.choice(sorted(self.grid.empties))

    def maybe_mutate(self, agent):
        # Mutate by adding a random d to individual Pi's
        if self.mutation_type == 'stochastic':
            # Copy the damn list
            new_strategy = agent.strategy.copy()
            # There is a 20% chance of mutation
            if self.random.random() < 0.2:
                # Each Pi is mutated uniformly by [-d, d]
                for i in range(4):
                    mutation = self.random.uniform(-self.d, self.d)
                    new_val = new_strategy[i] + mutation
                    # Keep probabilities in [0, 1]
                    new_val = (0 if new_val < 0 else
                               1 if new_val > 1 else new_val)
                    new_strategy[i] = new_val

        # Mutate by choosing a random strategy from the list set
        elif self.mutation_type == 'fixed':
            new_strategy = random.choice(
                list(self.strategies_to_count.values()))

        elif self.mutation_type == 'gaussian_sentimental':
            # Copy the damn list
            new_strategy = agent.strategy.copy()
            # There is a 20% chance of mutation
            if self.random.random() < 0.2:
                # Each Pi is mutated by a value drawn from a gaussian
                # with mean=delta_energy
                for i in range(4):
                    mutation = self.random.normalvariate(
                        (agent.delta_energy + self.alpha()) / 14, self.d)
                    new_val = new_strategy[i] + mutation
                    # Keep probabilities in [0, 1]
                    new_val = (0 if new_val < 0 else
                               1 if new_val > 1 else new_val)
                    new_strategy[i] = new_val

        return new_strategy

    def maybe_reproduce(self, agent):
        # If we have the energy to reproduce, do so
        if agent.total_energy >= self.p:
            # Create the child
            new_strategy = self.maybe_mutate(agent)
            child = GTAgent(self.agent_idx, agent.group_id, self, new_strategy,
                            self.i_energy)
            self.agent_idx += 1

            # Set parent and child energy levels to p/2
            child.total_energy = self.p / 2
            agent.total_energy = self.p / 2

            # Place child (Remove agent argument for global child placement)
            self.schedule.add(child)
            self.grid.place_agent(child, self.get_child_location(agent))

    def step(self):
        if self.debug:
            print('\n\n==================================================')
            print('==================================================')
            print('==================================================')
            pprint(vars(self))

        # First collect data
        self.datacollector.collect(self)

        # Then check for dead agents and for new agents
        for agent in self.schedule.agent_buffer(shuffled=True):
            # First check if dead
            if self.time_to_die(agent):
                self.grid.remove_agent(agent)
                self.schedule.remove(agent)

            # Otherwise check if can reproduce
            else:
                self.maybe_reproduce(agent)

        # Finally, step each agent
        self.schedule.step()

    def check_strategy(self, agent):
        # Helper function to check which strategy an agent would count as
        def is_same(strategy, a_strategy):
            tol = self.count_tolerance
            return all(strategy[i] - tol < a_strategy[i] < strategy[i] + tol
                       for i in range(4))

        return [
            name for name, strat in self.strategies_to_count.items()
            if is_same(strat, agent.strategy)
        ]