예제 #1
0
class TestMultiGrid(unittest.TestCase):
    '''
    Testing a toroidal MultiGrid
    '''

    torus = True

    def setUp(self):
        '''
        Create a test non-toroidal grid and populate it with Mock Agents
        '''
        width = 3
        height = 5
        self.grid = MultiGrid(width, height, self.torus)
        self.agents = []
        counter = 0
        for x in range(width):
            for y in range(height):
                for i in range(TEST_MULTIGRID[x][y]):
                    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 on the MultiGrid.
        '''
        for agent in self.agents:
            x, y = agent.pos
            assert agent in self.grid[x][y]

    def test_neighbors(self):
        '''
        Test the toroidal MultiGrid neighborhood methods.
        '''

        neighborhood = self.grid.get_neighborhood((1, 1), moore=True)
        assert len(neighborhood) == 8

        neighborhood = self.grid.get_neighborhood((1, 4), moore=True)
        assert len(neighborhood) == 8

        neighborhood = self.grid.get_neighborhood((0, 0), moore=False)
        assert len(neighborhood) == 4

        neighbors = self.grid.get_neighbors((1, 4), moore=False)
        assert len(neighbors) == 0

        neighbors = self.grid.get_neighbors((1, 4), moore=True)
        assert len(neighbors) == 5

        neighbors = self.grid.get_neighbors((1, 1),
                                            moore=False,
                                            include_center=True)
        assert len(neighbors) == 7

        neighbors = self.grid.get_neighbors((1, 3), moore=False, radius=2)
        assert len(neighbors) == 11
예제 #2
0
파일: test_grid.py 프로젝트: GeoESW/mesa
class TestMultiGrid(unittest.TestCase):
    '''
    Testing a toroidal MultiGrid
    '''

    torus = True

    def setUp(self):
        '''
        Create a test non-toroidal grid and populate it with Mock Agents
        '''
        width = 3
        height = 5
        self.grid = MultiGrid(width, height, self.torus)
        self.agents = []
        counter = 0
        for x in range(width):
            for y in range(height):
                for i in range(TEST_MULTIGRID[x][y]):
                    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 on the MultiGrid.
        '''
        for agent in self.agents:
            x, y = agent.pos
            assert agent in self.grid[x][y]

    def test_neighbors(self):
        '''
        Test the toroidal MultiGrid neighborhood methods.
        '''

        neighborhood = self.grid.get_neighborhood((1, 1), moore=True)
        assert len(neighborhood) == 8

        neighborhood = self.grid.get_neighborhood((1, 4), moore=True)
        assert len(neighborhood) == 8

        neighborhood = self.grid.get_neighborhood((0, 0), moore=False)
        assert len(neighborhood) == 4

        neighbors = self.grid.get_neighbors((1, 4), moore=False)
        assert len(neighbors) == 0

        neighbors = self.grid.get_neighbors((1, 4), moore=True)
        assert len(neighbors) == 5

        neighbors = self.grid.get_neighbors((1, 1), moore=False,
                                            include_center=True)
        assert len(neighbors) == 7

        neighbors = self.grid.get_neighbors((1, 3), moore=False, radius=2)
        assert len(neighbors) == 11
예제 #3
0
class DiseaseModel(Model):
    def __init__(self, home_store):
        self.num_agents = 1000
        self.grid = MultiGrid(200, 200, True)
        self.schedule = RandomActivation(self)
        self.running = True

        for i in range(self.num_agents):
            a = Agent(i, self)
            self.schedule.add(a)
            while True:
                #x = round(int(np.random.normal(self.grid.width/2, 10, 1)))
                #y = round(int(np.random.normal(self.grid.height/2, 10, 1)))
                x = self.random.randrange(self.grid.width)
                y = self.random.randrange(self.grid.height)
                if len(
                        self.grid.get_neighbors(
                            (x, y), moore=True, include_center=True,
                            radius=10)) <= 7:
                    self.grid.place_agent(a, (x, y))
                    home_store[i, :] = x, y
                    break

            if i < 1:
                a.infected = 1

        self.datacollector = DataCollector(
            model_reporters={"Tot informed": compute_informed},
            agent_reporters={"Infected": "infected"})

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
예제 #4
0
    def step(self):

        temp_gain = 0

        # fishing or waiting behavior
        if self.model.total_yearly_caught < self.model.yearly_quotum:

            self.fisherman_move()

            # Looking range is set to 0 as fisherman can only locate schools directly below them.
            surrounding = MultiGrid.get_neighbors(self.model.grid, self.pos, True, True,0)

            # Looks for fish to catch
            for agent in surrounding:

                if type(agent) == Fish:

                    if agent.size <= self.model.catch_rate:
                        self.size += agent.size
                        self.model.total_yearly_caught += agent.size
                        agent.size = 0
                    elif self.model.max_load - self.size < self.model.catch_rate:
                        agent.size -= self.model.max_load - self.size
                        self.size = self.model.max_load
                        self.model.total_yearly_caught += self.model.max_load - self.size
                    else:
                        agent.size -= self.model.catch_rate
                        self.size += self.model.catch_rate
                        self.model.total_yearly_caught += self.model.catch_rate
                    break

            # Sells fish if load is full
            if self.size == self.model.max_load:
                self.size    = 0
                temp_gain    += self.model.full_catch_reward

        # paying the weekly cost of living
        temp_gain -= self.model.initial_wallet / self.model.initial_wallet_survival

        # removing if going bankrupt
        if self.wallet <= 0:
            self.model.remove_agent(self)

        # update the rolling gains
        del self.rolling_gains[0]
        self.rolling_gains.append(temp_gain)

        # update the wallet
        self.wallet  += temp_gain

        # update the overall cumulative gain
        self.model.cumulative_gain += temp_gain
예제 #5
0
    def step(self):
        '''
        Randomly move Fish school and spawn new fish every year
        '''

        curr_time = self.model.schedule_Fish.time
        self.move()

        # New fish spawn every 48 weeks (12, 4 week months) (added + 1 just so they don't reproduce immediately)
        if (curr_time + 1) % 48 == 0:
            self.size *= self.model.fish_reproduction_number*random.uniform(0.95,1.05)

        # Looking for Food
        surrounding = MultiGrid.get_neighbors(self.model.grid, self.pos, True, True,0)

        for agent in surrounding:

            if type(agent) == Food and agent.food == True:
                agent.food = False
                self.wallet += self.model.energy_gain
                break
            elif type(agent) == Fisherman:
                pass
            else:
                if self.model.food_bool == True:
                    percentage = 1 - (self.model.split_size - self.size)/self.model.split_size
                    self.energy_loss = 1/(1+0.00005**(percentage-0.5)) + 1
                self.wallet -= self.energy_loss
                break

        # school size shrinks to half its size when energy is depleted
        if self.wallet <= 0 and self.model.food_bool == True:
            self.size /= 2
            self.wallet += self.model.energy_gain

        # Schools above N tonnes will split in half
        if self.size > self.model.split_size and random.uniform(0,1) > 0.75:
            self.model.new_agent(Fish, self.pos, self.size*0.5, self.wallet*0.5, True, 0, False, self.model.energy_loss)
            self.size *= 0.5
            if self.model.food_bool == True:
                self.wallet *= 0.5

        # Schools under a threshold are removed
        if self.size < (self.model.initial_school_size / 20):
            self.model.remove_agent(self)
예제 #6
0
class ContactModel(Model):

    #@jit(nopython=True)
    def __init__(self, N, height, width, exponent, steps):
        self.number_of_agents = N
        self.height = height
        self.width = width
        self.exponent = exponent

        #self.x_locs = np.zeros((N, steps))
        #self.y_locs = np.zeros((N))

        self.direction_range=3
        self.directions = Directions(self.direction_range)
        self.current_step_contacts=[]
        self.adjacency_matrix = np.zeros((N, N))
        self.grid = MultiGrid(self.width, self.height, torus=False)
        self.schedule = BaseScheduler(self)

        self.current_step = 0

         # Add N pedestrians to model (schedule, grid)
        for i in range(self.number_of_agents):
            x = self.random.randrange(1, self.grid.width-1)
            y = self.random.randrange(1, self.grid.height-1)

            pos = (x, y)
            new_human = Pedestrian(i, self, pos, self.exponent, self.directions)

            self.schedule.add(new_human)
            self.grid.place_agent(new_human, pos)

        self.data_collector=DataCollector()

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

    '''
    #@jit(nopython=True)
    def contact_update(self, contact_ids):

        contact_ids  =sorted(contact_ids)
        if contact_ids not in self.current_step_contacts:
            self.current_step_contacts.append(contact_ids)
    '''

    #@jit(nopython=True)
    def update_adjecency_matrix(self):

        agents = self.schedule.agents
        for i, agent in enumerate(agents):
            neighbors = self.grid.get_neighbors(agent.pos, moore=True, radius= 5)
            for neighbor in neighbors:
                if neighbor.unique_id > agent.unique_id:
                    self.adjacency_matrix[agent.unique_id, neighbor.unique_id]+=1



        '''
        neighbors_in_contact = self.model.grid.get_neighbors(self.pos, moore=True, radius = 5)
        if len(neighbors_in_contact) > 0:
            for neighbor in neighbors_in_contact:
                if neighbor.unique_id != self.unique_id:
                    self.model.contact_update((self.unique_id, neighbor.unique_id))

        #TODO: order agent steps, order updates, double or not
        for id_tuple in self.current_step_contacts:
            self.adjacency_matrix[id_tuple[0], id_tuple[1]]+=1
        '''

    #@jit(nopython=True)
    def step(self):
        self.schedule.step()

        #self.update_adjecency_matrix()
        #self.current_step_contacts=[]
        self.data_collector.collect(self)

    #@jit(nopython=True)
    def run(self, N):
        for i in range(N):
            self.current_step+=1
            self.step()
            if i%100 == 0:
                print(i)
예제 #7
0
class Environment(Model):
    """ A model which contains a number of ant colonies. """
    def __init__(self,
                 width,
                 height,
                 n_colonies,
                 n_ants,
                 n_obstacles,
                 decay=0.2,
                 sigma=0.1,
                 moore=False,
                 birth=True,
                 death=True,
                 pheromone_strength=10):
        """
        :param width: int, width of the system
        :param height: int, height of the system
        :param n_colonies: int, number of colonies
        :param n_ants: int, number of ants per colony
        :param decay: float, the rate in which the pheromone decays
        :param sigma: float, sigma of the Gaussian convolution
        :param moore: boolean, True/False whether Moore/vonNeumann is used
        """
        super().__init__()

        # Agent variables
        self.birth = birth
        self.death = death

        self.pheromone_level = 1
        self.pheromone_strength = pheromone_strength
        self.nr_on_track = 0

        # Environment variables
        self.n_ants = n_ants
        self.width = width
        self.height = height
        self.grid = MultiGrid(width, height, False)

        self.moore = moore

        self.sigma = sigma
        self.decay = decay

        # Environment attributes
        self.schedule = RandomActivation(self)

        self.colonies = [
            Colony(self,
                   i, (width // 2, height // 2),
                   n_ants,
                   birth=self.birth,
                   death=self.death) for i in range(n_colonies)
        ]

        self.pheromones = np.zeros((width, height), dtype=np.float)
        self.pheromone_updates = []
        self.found_pheromone = False

        self.food = FoodGrid(self)
        self.food.add_food()

        self.obstacles = []
        for _ in range(n_obstacles):
            self.obstacles.append(Obstacle(self))

        # Metric + data collection
        self.min_distance = distance.cityblock(self.colonies[0].pos,
                                               self.food.get_food_pos()[0])
        self.datacollector = DataCollector(model_reporters={
            "Minimum path length":
            metrics.min_path_length,
            "Mean minimum path length":
            metrics.mean_min_path_length
        },
                                           agent_reporters={
                                               "Agent minimum path length":
                                               lambda x: min(x.path_lengths),
                                               "Encounters":
                                               Ant.count_encounters
                                           })

        # Animation attributes
        self.pheromone_im = None
        self.ax = None

    def step(self):
        """
        Do a single time-step using freeze-dry states, colonies are updated each time-step in random orders, and ants
        are updated per colony in random order.
        """
        self.food.step()
        self.datacollector.collect(self)

        # Update all colonies
        for col in random.sample(self.colonies, len(self.colonies)):
            col.step()

        self.schedule.step()
        self.update_pheromones()
        if not self.check_exit():
            return "ended"
        else:
            return "running"

    def check_exit(self):
        # print(self.pheromones, self.found_pheromone)

        for i in self.pheromones:
            for j in i:
                if j > 1 and len(np.where(self.food.grid > 0)[0]) == 0:
                    self.found_pheromone = True
                    return True
        if self.found_pheromone is False:
            return True

        return False

    def move_agent(self, ant, pos):
        """
        Move an agent across the map.
        :param ant: class Ant
        :param pos: tuple (x, y)
        """
        if self.moore:
            assert np.sum(np.subtract(pos, ant.pos) ** 2) in [1, 2], \
                "the ant can't move from its original position {} to the new position {}, because the distance " \
                "is too large".format(ant.pos, pos)
        else:
            assert np.sum(np.subtract(pos, ant.pos) ** 2) == 1, \
                "the ant can't move from its original position {} to the new position {}, because the distance " \
                "is too large, loc_food {}".format(ant.pos, pos, self.food.get_food_pos())

        self.grid.move_agent(ant, pos)

    def calc_ratio(self):
        """
        Calculate number of ants on a track with pheromones from a specific
        threshold. Return ratio of ants on the track / ants off the track.
        """
        nr_on_track = 0
        for i in range(self.width):
            for j in range(self.height):
                neighborhood = self.grid.get_neighbors((i, j),
                                                       moore=True,
                                                       radius=0,
                                                       include_center=True)
                for agent in neighborhood:
                    if type(agent) == Ant:
                        if self.pheromones[i][j] > self.pheromone_strength:
                            nr_on_track += 1
                            break

        return [nr_on_track, self.n_ants - nr_on_track]

    def get_random_position(self):
        return (np.random.randint(0, self.width),
                np.random.randint(0, self.height))

    def position_taken(self, pos):
        if pos in self.food.get_food_pos():
            return True

        for colony in self.colonies:
            if colony.on_colony(pos):
                return True

        for obstacle in self.obstacles:
            if obstacle.on_obstacle(pos):
                return True

        return False

    def add_food(self):
        """
        Add food somewhere on the map, which is not occupied by a colony yet
        """
        self.food.add_food()

    def place_pheromones(self, pos):
        """
        Add pheromone somewhere on the map
        :param pos: tuple (x, y)
        """
        self.pheromone_updates.append((pos, self.pheromone_level))

    def get_neighbor_pheromones(self, pos, id):
        """
        Get the passable neighboring positions and their respective pheromone levels for the pheromone id
        :param pos:
        :param id:
        :return:
        """
        indices = self.grid.get_neighborhood(pos, self.moore)
        indices = [
            x for x in indices if
            not any([isinstance(x, Obstacle) for x in self.grid[x[0]][x[1]]])
        ]

        pheromones = [self.pheromones[x, y] for x, y in indices]

        return indices, pheromones

    def update_pheromones(self):
        """
        Place the pheromones at the end of a timestep on the grid. This is necessary for freeze-dry time-steps
        """
        for (pos, level) in self.pheromone_updates:
            # self.pheromones[pos] += level
            self.pheromones[pos] += self.pheromone_strength

        self.pheromone_updates = []

        # gaussian convolution using self.sigma
        self.pheromones = gaussian_filter(self.pheromones,
                                          self.sigma) * self.decay

    def animate(self, ax):
        """

        :param ax:
        :return:
        """
        self.ax = ax
        self.animate_pheromones()
        self.animate_colonies()
        self.animate_ants()
        self.animate_food()
        self.animate_obstacles()

    def animate_pheromones(self):
        """
        Update the visualization part of the Pheromones.
        :param ax:
        """

        pheromones = np.rot90(
            self.pheromones.astype(np.float64).reshape(self.width,
                                                       self.height))
        if not self.pheromone_im:
            self.pheromone_im = self.ax.imshow(pheromones,
                                               vmin=0,
                                               vmax=5,
                                               interpolation='None',
                                               cmap="Greens")
        else:
            self.pheromone_im.set_array(pheromones)

    def animate_colonies(self):
        """
        Update the visualization part of the Colonies.
        :return:
        """
        for colony in self.colonies:
            colony.update_vis()

    def animate_food(self):
        """
        Update the visualization part of the FoodGrid.
        :return:
        """
        self.food.update_vis()

    def animate_ants(self):
        """
        Update the visualization part of the Ants.
        """
        for ant in self.schedule.agents:
            ant.update_vis()

    def animate_obstacles(self):
        """
        Update the visualization part of the Obstacles.
        :return:
        """
        for obstacle in self.obstacles:
            obstacle.update_vis()

    def grid_to_array(self, pos):
        """
        Convert the position/indices on self.grid to imshow array.
        :param pos: tuple (int: x, int: y)
        :return: tuple (float: x, float: y)
        """
        return pos[0] - 0.5, self.height - pos[1] - 1.5

    def pheromone_threshold(self, threshold):
        """ Returns an array of the positions in the grid in which
        the pheromone levels are above the given threshold"""
        pher_above_thres = np.where(self.pheromones >= threshold)

        return list(zip(pher_above_thres[0], pher_above_thres[1]))

    def find_path(self, pher_above_thres):
        """ Returns the shortest paths from all the colonies to all the food sources.
        A path can only use the positions in the given array. Therefore, this function
        checks whether there is a possible path for a certain pheremone level.
        Essentially a breadth first search"""
        space_searched = False
        all_paths = []
        food_sources = self.food.get_food_pos()

        # Search the paths for a colony to all food sources
        for colony in self.colonies:
            colony_paths = []
            pos_list = {colony.pos}  # Prooning
            possible_paths = [[colony.pos]]

            # Continue expanding search area until all food sources found
            # or until the entire space is searched
            while food_sources != [] and not space_searched:
                space_searched = True
                temp = []

                for path in possible_paths:
                    for neighbor in self.grid.get_neighborhood(
                            include_center=False,
                            radius=1,
                            pos=path[-1],
                            moore=self.moore):
                        if neighbor in food_sources:
                            food_path = copy(path)
                            food_path.append(neighbor)
                            colony_paths.append(food_path)
                            food_sources.remove(neighbor)

                        # Add epanded paths to the possible paths
                        if neighbor in pher_above_thres and neighbor not in pos_list:
                            space_searched = False
                            temp_path = copy(path)
                            temp_path.append(neighbor)
                            temp.append(temp_path)
                            pos_list.add(neighbor)

                    possible_paths.remove(path)

                possible_paths += temp

        all_paths.append(colony_paths)

        return all_paths
예제 #8
0
class Themepark(Model):
    def __init__(self, N_attr, N_cust, width, height, strategy, theme,
                 max_time, weight, adaptive):
        self.max_time = max_time
        self.N_attr = N_attr
        self.penalty_per = PENALTY_PERCENTAGE
        self.weight = weight
        self.adaptive = adaptive
        self.strategies = STRATEGIES
        self.x_list, self.y_list, self.positions = xlist, ylist, positions
        self.x_list, self.y_list, self.positions = get_attraction_coordinates(
            WIDTH, HEIGHT, self.N_attr, theme)
        self.happinesses = []
        self.path_coordinates = get_coordinates(WIDTH, HEIGHT, NUM_OBSTACLES,
                                                self.N_attr, theme)
        self.N_cust = N_cust  # num of customer agents
        self.total_steps = 0
        self.cust_ids = N_cust
        self.strategy = strategy
        self.grid = MultiGrid(width, height, torus=False)
        self.schedule = BaseScheduler(self)
        self.schedule_Attraction = BaseScheduler(self)
        self.schedule_Customer = BaseScheduler(self)
        self.totalTOTAL = 0  #TODO: DEZE NAAM VERANDEREN
        self.attractions = self.make_attractions()
        self.attraction_history = self.make_attr_hist()
        self.park_score = []
        self.data_dict = {}
        self.hist_random_strat = []
        self.hist_close_strat = []
        self.all_rides_list = []
        self.strategy_composition = self.make_strategy_composition()
        self.customers = self.add_customers(self.N_cust)
        self.monitor = Monitor(self.max_time, self.N_attr, self.positions)
        self.running = True

        # TODO: ALS HET GOED IS KUNNEN AL DEZE INITS WEG, MAAR DIT MOETEN WE WEL NOG EVEN DUBBEL CHECKEN
        # --> dit is gecheckt op het runnen van main_cluster_random_noise
        # self.theme = theme
        # self.starting_positions = [[int((WIDTH/2)-1), 0], [int(WIDTH/2), 0], [int((WIDTH/2)+1), 0]]
        # self.width = width
        # self.height = height
        # self.data = []
        # self.data_customers = []
        # self.memory = 5
        # self.customer_score = []
        # self.only_random = False
        # self.total_waited_time = 0

        # Initialize dictionary of attractions
        for attraction in self.get_attractions():
            self.data_dict[attraction.unique_id] = ({
                "id": attraction.unique_id,
                "length": attraction.attraction_duration,
                "waiting_list": []
            })

        # TODO ADD COMMENT (SNAP NIET WAT DE DATACOLLECTOR IS)
        if len(self.strategies) == 6:
            self.datacollector = DataCollector({
                "Random":
                lambda m: self.strategy_counter(self.strategies[0]),
                "0.00":
                lambda m: self.strategy_counter(self.strategies[1]),
                "0.25":
                lambda m: self.strategy_counter(self.strategies[2]),
                "0.50":
                lambda m: self.strategy_counter(self.strategies[3]),
                "0.75":
                lambda m: self.strategy_counter(self.strategies[4]),
                "1.00":
                lambda m: self.strategy_counter(self.strategies[5]),
            })
        else:
            self.datacollector = DataCollector({
                "0.00":
                lambda m: self.strategy_counter(self.strategies[0]),
                "0.25":
                lambda m: self.strategy_counter(self.strategies[1]),
                "0.50":
                lambda m: self.strategy_counter(self.strategies[2]),
                "0.75":
                lambda m: self.strategy_counter(self.strategies[3]),
                "1.00":
                lambda m: self.strategy_counter(self.strategies[4]),
            })

        self.datacollector2 = DataCollector(
            {"score": lambda m: self.make_score()})

    def make_score(self):
        """
        Get the efficiency score
        """
        ideal = {}
        cust_in_row = 0
        for i in range(len(self.get_attractions())):
            ideal[i] = self.N_cust / self.N_attr
            cust_in_row += self.get_attractions()[i].N_current_cust

        tot_difference = 0
        for i in range(len(self.get_attractions())):

            difference = abs(cust_in_row / self.N_attr -
                             self.get_attractions()[i].N_current_cust)
            tot_difference += difference

        fraction_not_right = (tot_difference / self.N_cust)
        return abs(1 - (fraction_not_right)) * cust_in_row / self.N_cust

    def make_attr_hist(self):
        """
        Initialize a dictionary in which the history of the attractions can be
        added in.
        """
        attraction_history = {}
        for attraction in self.get_attractions():
            attraction_history[attraction] = [0] * (self.max_time + 1)

        return attraction_history

    def strategy_counter(self, strategy):
        """
        Count how many customers of different strategies are at the attractions
        """
        counter_total = {}

        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(attraction_pos,
                                             moore=True,
                                             radius=0,
                                             include_center=True)

            counter = 0
            for agent in self.customers:
                if agent.weight == strategy:
                    counter += 1

        return counter

    def make_strategy_composition(self):
        """
        TODO: ANNEMIJN KAN JIJ HIER COMMENTS BIJ DOEN? + RANDOM_TEST_4 WEGHALEN
        """
        if self.strategy == "Random_test_4":
            self.strategies = ["Random_test_4", 0.0, 0.25, 0.50, 0.75, 1.0]
            dict = {
                self.strategies[0]: 1 / 6,
                self.strategies[1]: 0.20,
                self.strategies[2]: 0.20,
                self.strategies[3]: 0.20,
                self.strategies[4]: 0.20,
                self.strategies[5]: 0.20
            }

            composition_list = []
            for i in range(len(self.strategies)):
                if i == 0:
                    dict[self.strategies[i]] = FRACTION_RANDOM
                    continue
                else:
                    composition_list.append(random.randint(0, 100))
            sum_comp = sum(composition_list)

            sum_comp = sum_comp - sum_comp * FRACTION_RANDOM
            for i in range(len(self.strategies)):
                if i == 0:
                    continue
                else:
                    dict[self.strategies[i]] = composition_list[i -
                                                                1] / sum_comp

        else:
            dict = {
                self.strategies[0]: 0.20,
                self.strategies[1]: 0.20,
                self.strategies[2]: 0.20,
                self.strategies[3]: 0.20,
                self.strategies[4]: 0.20
            }

            composition_list = []
            for i in range(len(self.strategies)):

                composition_list.append(random.randint(0, 100))

            sum_comp = sum(composition_list)

            sum_comp = sum_comp
            for i in range(len(self.strategies)):

                dict[self.strategies[i]] = composition_list[i - 1] / sum_comp

        return dict

    def make_attractions(self):
        """
        Initialize attractions on fixed position.
        """

        attractions = {}
        for i in range(self.N_attr):

            pos = (self.x_list[i], self.y_list[i])
            if self.grid.is_cell_empty(pos):

                name = str(i)
                a = Attraction(i, self, pos, name, self.N_cust, self.weight)
                attractions[i] = a

                self.schedule_Attraction.add(a)
                self.grid.place_agent(a, pos)
        return attractions

    def get_attractions(self):
        """
        Get a list with all attractions.
        """
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)

        attractions = []
        for agent in agents:
            if type(agent) == Attraction:
                attractions.append(agent)

        return attractions

    def calculate_people(self):
        """
        Calculate how many customers are in which attraction.
        """

        counter_total = {}

        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(attraction_pos,
                                             moore=True,
                                             radius=0,
                                             include_center=True)

            counter = 0
            for agent in agents:
                if type(agent) is Customer:
                    counter += 1
                else:
                    attraction = agent

            attraction.N_current_cust = counter
            counter_total[attraction.unique_id] = counter

        return list(counter_total.values())

    def add_customers(self, N_cust, added=False):
        """
        Initialize customers on random positions.
        """

        weights_list = []
        if self.adaptive is True:

            for j in self.strategy_composition.keys():
                for i in range(round(N_cust * self.strategy_composition[j])):
                    weights_list.append(j)

            if len(weights_list) < self.N_cust:
                rand = random.choice(self.strategies)
                weights_list.append(rand)
            elif len(weights_list) > self.N_cust:
                rand = random.choice(weights_list)
                weights_list.remove(rand)

        else:

            # if the strategy is not random add weights to weights_list
            if self.strategy is not "Random":
                for i in range(round(N_cust)):
                    weights_list.append(self.weight)

        cust_list = []
        for i in range(N_cust):

            pos_temp = [
                random.randint(0, WIDTH - 1),
                random.randint(0, HEIGHT - 1)
            ]
            rand_x, rand_y = pos_temp[0], pos_temp[1]

            pos = (rand_x, rand_y)

            if added is True:
                i = self.cust_ids
            if self.strategy == "Random_test_4":
                if weights_list[i] == "Random_test_4":
                    strategy = "Random_test_4"
                else:
                    strategy = "Closest_by"
            else:
                strategy = self.strategy

            # Set weight
            if weights_list == []:
                weight = None
            else:
                weight = weights_list[i]

            # Initialize customer and add customer to the model
            a = Customer(i, self, pos, self.x_list, self.y_list,
                         self.positions, strategy, weight, self.adaptive)
            self.schedule_Customer.add(a)
            self.grid.place_agent(a, pos)
            cust_list.append(a)

        return cust_list

    def calc_waiting_time(self):
        """
        Calculate the waitingtime per attraction
        """

        counter_total = {}

        attractions = self.get_attractions()
        for attraction in attractions:

            counter_total[
                attraction.unique_id] = attraction.current_waitingtime

        return counter_total

    def calculate_people_sorted(self):
        """
        Calculate how many customers are in which attraction.
        Returns a SORTED LIST.
        For example: indexes = [3, 2, 5, 1, 4]
        indicates that attraction3 has the least people waiting.
        """

        counter_total = {}

        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(attraction_pos,
                                             moore=True,
                                             radius=0,
                                             include_center=True)

            counter = 0
            for agent in agents:
                if type(agent) is Customer:
                    counter += 1
                else:
                    attraction = agent

            attraction.N_current_cust = counter
            self.attraction_history[attraction][self.totalTOTAL] = counter
            counter_total[attraction.unique_id] = counter

        return counter_total

    def make_route(self):
        """
        Draw coordinates of a possible path.
        """

        for i in range(len(self.path_coordinates)):
            pos = self.path_coordinates[i]

            if pos not in self.positions:

                # Create path agent
                path = Route(i, self, pos)
                self.schedule.add(path)

                self.grid.place_agent(path, pos)

    # TODO: THEMEPARK SCORE GEBRUIKEN WE NIET MEER, DIT ALLEMAAL VERWIJDEREN OVERAL?
    def get_themepark_score(self):
        """
        Get score of a themepark based on:
            - A total of all waitingtimes for every customer
            - The total number of rides taken
        """
        attractions = self.get_attractions()
        total_wait, total_rides = 0, 0
        for attraction in attractions:
            total_wait += attraction.current_waitingtime

            if attraction.current_a is not None:
                total_rides += 1

        if total_rides == 0:
            return total_rides

        return (total_wait / total_rides)

    def get_strategy_history(self):
        """
        Update history with how many customers chose which strategy.
        """

        customers = self.get_customers()
        randomstrat, closebystrat = 0, 0

        for customer in customers:
            if customer.strategy == "Random" or customer.strategy == "Random_test_4":
                randomstrat += 1
            elif customer.strategy == "Closest_by":
                closebystrat += 1

        self.hist_random_strat.append(randomstrat)
        self.hist_close_strat.append(closebystrat)

    def get_customers(self):
        """
        Returns a list of all the customers in the themepark.
        """
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)

        customers = []

        # Add customers to list
        for agent in agents:
            if type(agent) == Customer:
                customers.append(agent)

        return customers

    def get_data_customers(self):
        """
        Return dictionary with data of customers.
        """

        data = {}
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)

        for agent in agents:
            if type(agent) is Customer:
                data[agent.unique_id] = {
                    "totalwaited": agent.total_ever_waited,
                    "visited_attractions": agent.nmbr_attractions,
                    "strategy": agent.strategy,
                    "swapped_strat": agent.strategy_swap_hist
                }

        return data

# TODO: NET ALS THEMEPARK SCORE GEBRUIKEN WE DIT NEIT MEER TOCH????

    def calc_hapiness(self):
        """
        Calculate mean hapiness of all customers, based on:

        - How many rides were taken
        - Number of times in the same attraction
        - Total waiting time
        """
        customers = self.get_customers()

        scores = []

        for customer in customers:
            history = customer.history
            values = list(history.values())
            total_rides = sum(values)

            if total_rides != 0:
                scores.append(total_rides / self.N_attr -
                              self.totalTOTAL / customer.total_ever_waited)
            else:
                return None

        scores = np.interp(scores, (min(scores), max(scores)), (1, 10))

        return np.mean(scores)

    def get_history_list(self):
        """
        Create a list with the history of the customers.
        """

        customers = self.get_customers()
        histories = {}

        for customer in customers:
            history = customer.history
            values = list(history.values())
            histories[customer.unique_id] = values
        return histories

    def final(self):
        """
        End run and return data.
        """

        # Create list with at every time step the amount of attractions that are active
        attractions = self.get_attractions()
        self.all_rides_list = [0] * len(attractions[0].in_attraction_list)
        for attraction in attractions:
            for i in range(len(attraction.in_attraction_list)):
                self.all_rides_list[i] += attraction.in_attraction_list[i]

        # Change the all_rides_list into fractions
        for i in range(len(self.all_rides_list)):
            self.all_rides_list[i] /= self.N_attr

        # Initialize history list and get agents
        hist_list = []
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)

        # Save history of all customers
        cust_data = self.get_data_customers()
        for agent in agents:
            if type(agent) is Customer:
                sum_attr = sum(agent.history.values())
                if sum_attr > 0:
                    hist_list.append(agent.strategy_swap_hist)
                else:
                    hist_list.append(agent.strategy_swap_hist)

        histories = self.get_history_list()

        # Save data
        try:
            pickle.dump(self.datacollector.get_model_vars_dataframe(),
                        open("../data/strategy_history.p", 'wb'))
            pickle.dump(self.datacollector2.get_model_vars_dataframe(),
                        open("../data/eff_score_history.p", 'wb'))
            pickle.dump(cust_data, open("../data/customers.p", 'wb'))
            pickle.dump(self.park_score[-1], open("../data/park_score.p",
                                                  "wb"))
            pickle.dump(self.happinesses, open("../data/hapiness.p", "wb"))
            pickle.dump(histories, open("../data/cust_history.p", 'wb'))
        except:
            pickle.dump(self.datacollector.get_model_vars_dataframe(),
                        open("data/strategy_history.p", 'wb'))
            pickle.dump(self.datacollector2.get_model_vars_dataframe(),
                        open("data/eff_score_history.p", 'wb'))
            pickle.dump(cust_data, open("data/customers.p", 'wb'))
            pickle.dump(self.park_score[-1], open("data/park_score.p", "wb"))
            pickle.dump(self.happinesses, open("data/hapiness.p", "wb"))
            pickle.dump(histories, open("data/cust_history.p", 'wb'))

        try:
            pickle.dump(self.all_rides_list, open("../data/all_rides.p", "wb"))
        except:
            pickle.dump(self.all_rides_list, open("data/all_rides.p", "wb"))

        print()
        print("RUN HAS ENDED")
        print()

    def save_data(self):
        """
        Save data of all attractions and customers.
        """
        # Get info
        waitinglines = self.calc_waiting_time()

        for i in range(len(self.attractions)):
            self.data_dict[i]["waiting_list"].append(waitinglines.get(i))

        self.park_score.append(sum(waitinglines.values()))
        self.happinesses.append(self.calc_hapiness())

    def step(self):
        """
        Advance the model by one step.
        """

        # Take a step if max steps is not reached
        if self.totalTOTAL < self.max_time:
            self.totalTOTAL += 1
            self.schedule.step()
            self.datacollector.collect(self)
            self.datacollector2.collect(self)

            self.schedule_Attraction.step()
            self.schedule_Customer.step()

            self.total_steps += 1

            self.save_data()
            self.get_strategy_history()

        # Stop simulation
        else:
            for key in self.attraction_history.keys():
                y = self.attraction_history[key]
                x = list(range(0, self.max_time))

            self.final()
class EgyptSim(Model):
    """
    Simulation Model for wealth distribution represented by grain in ancient Egypt
    """

    # Variable declarations for non python programmer sanity
    # Map variables
    height = 30
    width = 30

    # Simulation Variables
    timeSpan = 500
    currentTime = 0
    startingSettlements = 14
    startingHouseholds = 7
    startingHouseholdSize = 5
    startingGrain = 3000
    minAmbition = 0.1
    minCompetency = 0.5
    generationalVariation = 0.9
    knowledgeRadius = 20
    distanceCost = 10
    fallowLimit = 4
    popGrowthRate = 0.1
    fission = False
    fissionChance = 0.7
    rental = True
    rentalRate = 0.5
    totalPopulation = startingSettlements * startingHouseholds * startingHouseholdSize
    totalGrain = startingGrain * startingHouseholds
    startingPopulation = totalPopulation
    projectedHistoricalPopulation = totalPopulation
    maxHouseholdGrain = startingGrain

    # Step variables
    mu = 0
    sigma = 0
    alpha = 0
    beta = 0

    # Visualisation
    description = "A model simulating wealth growth and distribution in Ancient Egypt.\n\nThe model allows one to see how variables such as the flooding of the Nile, human character traits and random chance effect the acquisition and distribution of wealth."

    # List of identifiers and colors for settlements
    SETDICT = {"s1": "#FF0000",
               "s2": "#FF4500",
               "s3": "#BC8F8F",
               "s4": "#00FF00",
               "s5": "#00FFFF",
               "s6": "#0000FF",
               "s7": "#FF00FF",
               "s8": "#FF1493",
               "s9": "#708090",
               "s10": "#DC143C",
               "s11": "#FF8C00",
               "s12": "#FF69B4",
               "s13": "#800000",
               "s14": "#7CFC00",
               "s15": "#008B8B",
               "s16": "#483D8B",
               "s17": "#4B0082",
               "s18": "#FF69B4",
               "s19": "#000000",
               "s20": "#8B4513"}

    def __init__(self, height: int = 30, width: int = 30, timeSpan: int = 500,
                 startingSettlements: int = 14, startingHouseholds: int = 7,
                 startingHouseholdSize: int = 5, startingGrain: int = 3000,
                 minAmbition: float = 0.1, minCompetency: float = 0.5,
                 generationalVariation: float = 0.9, knowledgeRadius: int = 20,
                 distanceCost: int = 10, fallowLimit: int = 4, popGrowthRate: float = 0.1,
                 fission: bool = False, fissionChance: float = 0.7, rental: bool = True,
                 rentalRate: float = 0.5):
        """
        Create a new EgyptSim model
        Args:
            height: The height of the simulation grid
            width: The width of the simulation grid
            timeSpan: The number of years over which the model is to run
            startingSettlements: The starting number of Settlements
            startingHouseholds: The starting number of Households per Settlement
            startingHouseholdSize: The starting number of workers in a Household
            startingGrain: The starting amount of grain for each Household
            minAmbition: The minimum ambition value for a Household
            minCompetency: The minimum competency value for a Household
            generationalVariation: The difference between generations of a Household
            knowledgeRadius: How far outside ther Settlement a Household can "see"
            distanceCost: The cost to move grain per cell away from a settlemnt
            fallowLimit: The number of years a field can lay fallow before it is harvested
            popGrowthRate: The rate at which the population grows
            fission: If Household fission (Moving between settlements) is allowed
            fissionChance: The chance fission occuring
            rental: If land rental is allowed
            rentalRate: The rate at which households will rent land
        """
        super().__init__()
        # Set Parameters
        # Map size
        self.height = height
        self.width = width

        # If the number of starting settlements is greater than the maximum reasonable number of households considering territory and farming area
        # Considers that each household needs at least two field to survive at a minimum number of members, a Settlment needs 9 (territory) + 2 * households
        # Tiles to survive
        if startingSettlements > ((width - 1) * height) // (9 + (startingHouseholds * 2)):
            if startingSettlements > 20:
                self.startingSettlements = 20
            else:
                self.startingSettlements = ((height - 1) * width) // (9 + (startingHouseholds * 2))
            print("Too many starting settlements to support the settlements and household, truncating to: ", self.startingSettlements)
        else:
            self.startingSettlements = startingSettlements
        # Simulation Variables
        self.timeSpan = timeSpan
        self.currentTime = 0
        self.startingHouseholds = startingHouseholds
        self.startingHouseholdSize = startingHouseholdSize
        self.startingGrain = startingGrain
        self.minAmbition = minAmbition
        self.minCompetency = minCompetency
        self.generationalVariation = generationalVariation
        self.knowledgeRadius = knowledgeRadius
        self.distanceCost = distanceCost
        self.fallowLimit = fallowLimit
        self.popGrowthRate = popGrowthRate
        self.fission = fission
        self.fissionChance = fissionChance
        self.rental = rental
        self.rentalRate = rentalRate
        self.totalGrain = startingGrain * startingHouseholds * startingSettlements
        self.totalPopulation = startingSettlements * startingHouseholds * startingHouseholdSize
        self.startingPopulation = self.totalPopulation
        self.projectedHistoricalPopulation = self.startingPopulation
        self.maxHouseholdGrain = startingGrain

        # Scheduler and Grid
        self.schedule = EgyptSchedule(self)
        self.grid = MultiGrid(height = self.height, width = self.width, torus=False)

        # Define specific tables for data collection purposes
        setlist = []
        for i in range(self.startingSettlements):
            setlist.append("s" + str(i + 1) + "_Population")
        tables = {"Settlement Population": setlist}

        # Data collection
        self.datacollector = DataCollector(model_reporters = 
            {"Households": lambda m: m.schedule.get_breed_count(Household),
             "Settlements": lambda m: m.schedule.get_breed_count(Settlement),
             "Total Grain": lambda m: m.totalGrain,
             "Total Population": lambda m: m.totalPopulation,
             "Projected Hisorical Poulation (0.1% Growth)": lambda m: m.projectedHistoricalPopulation,
             "Gini-Index": gini,
             "Maximum Settlement Population": maxSetPop,
             "Minimum Settlement Population": minSetPop,
             "Mean Settlement Poulation" : meanSetPop,
             "Maximum Household Wealth": maxHWealth,
             "Minimum Household Wealth": minHWealth,
             "Mean Household Wealth" : meanHWealth,
             "Number of households with < 33% of wealthiest grain holding": lowerThirdGrainHoldings,
             "Number of households with 33 - 66%  of wealthiest grain holding": middleThirdGrainHoldings,
             "Number of households with > 66% of wealthiest grain holding": upperThirdGrainHoldings 
            },
            tables = tables)

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

    def collectTableData(self):
        setPops = {}
        for s in self.schedule.get_breed(Settlement):
            setPops[s.unique_id + "_Population"] = s.population
        self.datacollector.add_table_row("Settlement Population", setPops, True)

    def setupMapBase(self):
        """
        Create the grid as field and river
        """
        for agent, x, y in self.grid.coord_iter():
            # If on left edge, make a river
            if x == 0:
                uid = "r" + str(x) + "|" + str(y)
                river = River(uid, self, (x, y))
                self.grid.place_agent(river, (x, y))
            # Otherwise make a field
            else:
                uid = "f" + str(x) + "|" + str(y)
                field = Field(uid, self, (x, y), 0.0)
                self.grid.place_agent(field, (x, y))
                self.schedule.add(field)

    def setupSettlementsHouseholds(self):
        """
        Add settlements and households to the simulation
        """
        h = 1
        for i in range(self.startingSettlements):
            # Loop untill a suitable location is found
            while True:
                x = self.random.randrange(1, self.width)
                y = self.random.randrange(self.height)

                flag = False
                cell = self.grid.get_cell_list_contents((x, y))
                # Check that tile is available
                for agent in cell:
                    if agent.settlementTerritory:
                        break
                    else:
                        flag = True
                        break

                if flag:
                    break

            # Add settlement to the grid
            population = self.startingHouseholds * self.startingHouseholdSize
            uid = "s" + str(i + 1) # Use a custom id for the datacollector
            settlement = Settlement(uid, self, (x, y), population, self.startingHouseholds, uid, self.SETDICT[uid])
            self.grid.place_agent(settlement, (x, y))

            # Set the surrounding fields as territory
            local = self.grid.get_neighbors((x, y), moore=True, include_center=True, radius=1)
            for a in local:
                a.settlementTerritory = True

            # Add households for the settlement to the scheduler
            for j in range(self.startingHouseholds):
                huid = "h" + str(h) # Use a custom id for the datacollector
                ambition =  np.random.uniform(self.minAmbition, 1)
                competency = np.random.uniform(self.minCompetency, 1)
                genCount = self.random.randrange(5) + 10
                household = Household(huid, self, settlement, (x, y), self.startingGrain,
                                      self.startingHouseholdSize, ambition, competency, genCount)
                # ! Dont add household to grid, is redundant
                self.schedule.add(household)
                h += 1
            # Add settlement to the scheduler
            self.schedule.add(settlement)

    def setup(self):
        """
        Setup model parameters
        """
        self.setupMapBase()
        self.setupSettlementsHouseholds()

    def step(self):
        self.currentTime += 1
        self.maxHouseholdGrain = 0
        self.setupFlood()
        self.schedule.step()
        self.projectedHistoricalPopulation = round(self.startingPopulation * ((1.001) ** self.currentTime))
        self.datacollector.collect(self)
        # Add settlement data to table 
        self.collectTableData()
        # Cease running once time limit is reached or everyone is dead
        if self.currentTime >= self.timeSpan or self.totalPopulation == 0: 
            self.running = False
 
    def setupFlood(self):
        """
        Sets up common variables used for the flood method in Fields
        """
        self.mu = random.randint(0, 10) + 5
        self.sigma = random.randint(0, 5) + 5
        self.alpha = (2 * self.sigma ** 2)
        self.beta = 1 / (self.sigma * math.sqrt(2 * math.pi))
예제 #10
0
class World(Model):
    def __init__(self, width, height):
        super().__init__()
        self.height = height
        self.width = width

        self.n_ants = int(125)
        self.diffusion_rate = 50
        self.evaporation_rate = 10

        # Para dar identificador único a los agentes
        self.unique_id = 0

        # Creación del planificador y del grid
        self.schedule = RandomActivation(self)
        self.grid = MultiGrid(self.width, self.height, torus=False)

        # Inicialización de patches
        self.setup_patches()

        # Inicialización de hormigas
        self.setup_ants()

        # Ejecución en navegador despues de crear
        self.running = True

    # Inicialización de hormigas
    def setup_ants(self):
        for i in range(self.n_ants):
            # Colocar hormigas aleatorias
            # x = random.randint(0, self.width - 1)
            # y = random.randint(0, self.height - 1)
            # pos = (x, y)
            # Colocar hormigas en el centro
            pos = (int(self.width / 2) - 1, int(self.height / 2) - 1)
            ant = Ant(self.unique_id, self, pos)
            self.unique_id += 1
            self.grid.place_agent(ant, pos)
            self.schedule.add(ant)

    # Inicialización de patches
    def setup_patches(self):
        """Inicialización del mundo"""
        # Colocar 1 patch en cada punto del grid
        for agent, x, y in self.grid.coord_iter():
            patch = Patch(self.unique_id, self, (x, y))
            self.unique_id += 1
            self.grid.place_agent(patch, (x, y))
            # Quizás no es necesario añadir al schedule
            self.schedule.add(patch)

        # Colocar Nido
        self.setup_nest()
        # Colocar Comida
        self.setup_food()
        # Colorear patches
        self.setup_color()

    def setup_nest(self):
        """Creación del nido"""
        # Se pone nido en el centro y 5 cuadros alrededor
        center = (int(self.width / 2) - 1, int(self.height / 2) - 1)
        for agent in self.grid.get_neighbors(center, True, True, 5):
            if isinstance(agent, Patch):
                agent.is_nest = True

        # Distancia al hormiguero
        for (agentSet, x, y) in self.grid.coord_iter():
            for agent in agentSet:
                if isinstance(agent, Patch):
                    agent.nest_scent = 200 - self.distance(center, (x, y))

    @staticmethod
    def distance(pos1, pos2):
        return math.hypot(pos1[0] - pos2[0], pos1[1] - pos2[1])

    def setup_food(self):
        """Creación de la comida"""
        center = (int(self.width / 2) - 1, int(self.height / 2) - 1)
        center_food1 = (int(center[0] + 0.6 * center[0]), int(center[1]))
        center_food2 = (int(center[0] - 0.6 * center[0]),
                        int(center[1] - 0.6 * center[1]))
        center_food3 = (int(center[0] - 0.8 * center[0]),
                        int(center[1] + 0.8 * center[1]))
        for agent in self.grid.get_neighbors(center_food1, True, True, 5):
            if isinstance(agent, Patch):
                agent.food_source_number = 1
                agent.food = random.randint(1, 2)

        for agent in self.grid.get_neighbors(center_food2, True, True, 5):
            if isinstance(agent, Patch):
                agent.food_source_number = 2
                agent.food = random.randint(1, 2)

        for agent in self.grid.get_neighbors(center_food3, True, True, 5):
            if isinstance(agent, Patch):
                agent.food_source_number = 3
                agent.food = random.randint(1, 2)

    def setup_color(self):
        for (agentSet, x, y) in self.grid.coord_iter():
            for agent in agentSet:
                if isinstance(agent, Patch):
                    agent.set_color()

    def step(self):
        self.schedule.step()
예제 #11
0
class EmasModel(Model):
    description = (
        "A model for simulating using EMAS model"
    )

    def __init__(
            self,
            height=HEIGHT,
            width=WIDTH,
            columns=2,
            rows=2,
            death_level=0,
            migration_level=10,
            init_energy=100,
            moore=True,
            reproduction_level=7,
            parent_part_to_child=30,
            base_child_energy=5,
            energy_redistribution_radius=4,
            islands=[]
    ):
        super().__init__()
        self.height: int = height
        self.width: int = width
        self.columns: int = columns
        self.rows: int = rows
        self.death_level: float = death_level
        self.migration_level: float = migration_level
        self.moore: bool = moore
        self.reproduction_level: float = reproduction_level
        self.parent_part_to_child: float = parent_part_to_child
        self.base_child_energy: float = base_child_energy
        self.init_energy: float = init_energy
        self.energy_redistribution_radius: int = energy_redistribution_radius
        self.islands: List[Tuple[Tuple[int, int], Tuple[int, int]]] = islands
        self.grid = MultiGrid(self.height, self.width, torus=True)

        borders_x_indexes = sorted([int(self.width * part / columns) for part in range(1, self.columns)])
        columns_points: Set[Tuple[int, int]] = {(x, y) for x in borders_x_indexes for y in range(self.height)}

        borders_y_indexes = sorted([int(self.height * part / rows) for part in range(1, self.rows)])
        rows_points: Set[Tuple[int, int]] = {(x, y) for x in range(self.width) for y in borders_y_indexes}

        for border_cords in columns_points | rows_points:
            border = IslandBorderAgent(self.next_id(), border_cords, self)
            self.grid.place_agent(border, border_cords)

        islands_x_corners = [-1] + borders_x_indexes + [self.width]
        islands_y_corners = [-1] + borders_y_indexes + [self.height]

        # left lower and right upper corner
        self.islands = [
            ((x, y), (islands_x_corners[x_u + 1], islands_y_corners[y_u + 1]))
            for x_u, x in enumerate(islands_x_corners) if x != self.width
            for y_u, y in enumerate(islands_y_corners) if y != self.height
        ]

    def get_neighborhood(self, pos: Coordinate, include_center=False, radius=1, moore=True):
        next_moves = self.grid.get_neighborhood(pos, moore, include_center, radius)
        island = self.get_island(pos)
        return self._filter_coors_in_island(island, next_moves)

    def redistribute_energy(self, pos: Coordinate, energy: float, include_center=False, radius=10):
        neighbours = self.grid.get_neighbors(pos, self.moore, include_center, radius)
        island = self.get_island(pos)
        close_neighbours = list(filter(lambda n: self._is_in_island(island, n.pos), neighbours))
        emas_neighbours = list(filter(lambda a: isinstance(a, EmasAgent), close_neighbours))
        if emas_neighbours:
            energy_delta = energy / len(emas_neighbours)
            for neighbour in emas_neighbours:
                neighbour.energy += energy_delta

    def get_island(self, pos: Coordinate):
        return list(filter(lambda coors: coors[0][0] < pos[0] < coors[1][0] and coors[0][1] < pos[1] < coors[1][1],
                           self.islands)).pop()

    def _filter_coors_in_island(self, island: Tuple[Tuple[int, int], Tuple[int, int]],
                                positions: List[Tuple[int, int]]):
        return list(filter(lambda move: island[0][0] < move[0] < island[1][0] and island[0][1] < move[1] <
                                        island[1][1], positions))

    def _is_in_island(self, island, pos):
        return island[0][0] < pos[0] < island[1][0] and island[0][1] < pos[1] < island[1][1]

    def _filter_for_emas_agents(self, agents):
        return filter(lambda a: isinstance(a, EmasAgent), agents)

    def get_closest_neighbour_on_island(self, pos: Coordinate):
        island = self.get_island(pos)

        taxi_radius = abs(island[0][0] - island[1][0]) + abs(island[0][1] - island[1][1])

        # moore=False -> find neighbourhood using taxi metric
        neighbours = self.grid.get_neighbors(pos, False, include_center=False, radius=taxi_radius)
        island_neighbours = [
            agent for agent in neighbours if self._is_in_island(island, agent.pos) and isinstance(agent, EmasAgent)
        ]

        closest_neighbour = None
        closest_distance = taxi_radius
        for agent in island_neighbours:
            if self.taxi_distance(pos, agent.pos) < closest_distance:
                closest_distance = self.taxi_distance(pos, agent.pos)
                closest_neighbour = agent

        return closest_neighbour

    def taxi_distance(self, pos_a: Coordinate, pos_b: Coordinate):
        return abs(pos_a[0] - pos_b[0]) + abs(pos_a[1] - pos_b[1])
예제 #12
0
class AntModel(Model):
    def __init__(self, num_ln, num_fj, num_mk_col, num_ft_col, width, height):
        """
        :param num_ln: Number of L. Niger agents
        :param num_fj: Number of F. Japonica agents
        :param num_mk_col: Number of M. Kuricola colonies
        :param num_ft_col: Number of F. Tropicalis colonies
        :param width: Width of the model grid
        :param height: Height of the model grid
        """
        super().__init__()
        self.num_ln = num_ln
        self.num_fj = num_fj
        self.num_mk_col = num_mk_col
        self.num_ft_col = num_ft_col
        self.grid = MultiGrid(width, height, True)
        self.schedule = RandomActivation(self)
        self.running = True

        for h in range(self.num_fj):
            ant = FJaponica(uuid4(), self)
            self.schedule.add(ant)
            self.grid.place_agent(ant, self.grid.find_empty())

        for j in range(self.num_mk_col):
            colony = MKuricolaColony(uuid4(), self)
            self.schedule.add(colony)
            self.grid.place_agent(colony, self.grid.find_empty())

        for k in range(self.num_ft_col):
            colony = FTropicalisColony(uuid4(), self)
            self.schedule.add(colony)
            self.grid.place_agent(colony, self.grid.find_empty())

        for i in range(self.num_ln):
            ant = LNiger(uuid4(), self)
            self.schedule.add(ant)
            self.grid.place_agent(ant, self.grid.find_empty())
            ant._init_post_place()

        self.data_collector = DataCollector(
            model_reporters={},
            agent_reporters={"states": ant_state_collector})
        self.weights_dict = json.load(open("newout.json", "r"))

    def drop_pheromone(self, location):
        """
        Drops a LNPheromone object at the given location if one does not already exist. If one does already exist,
        1 is added to the existing object's 'tracks' field.
        :param location: An (x, y) tuple detailing the location to drop the pheromone.
        :return: None
        """
        if not self.is_pheromone_in_cell(location):
            self.grid.place_agent(LNPheromone(uuid4(), self), location)
        else:
            self.get_pheromone_in_cell(location).tracks += 1

    def is_pheromone_in_cell(self, location):
        """
        Determines if a pheromone already exists in a given cell.
        :param location: The location to check.
        :return: boolean
        """
        return True in [
            type(x) == LNPheromone
            for x in self.grid.get_cell_list_contents(location)
        ]

    def is_ant_in_cell(self, location):
        """
        Determines whether an ant exists in a given cell.
        :param location: The location to check.
        :return: boolean
        """
        return True in [
            isinstance(x, Ant)
            for x in self.grid.get_cell_list_contents(location)
        ]

    def is_colony_in_cell(self, location):
        """
        Determines whether an aphid colony exists in a given cell.
        :param location: The location to check.
        :return: boolean
        """
        return True in [
            type(x) == MKuricolaColony or type(x) == FTropicalisColony
            for x in self.grid.get_cell_list_contents(location)
        ]

    def get_pheromone_in_cell(self, location):
        """
        Returns a LNPheromone object from a cell. ASsumes the cell has already been proven to have a pheromone object
        in it.
        :param location: The cell location to check.
        :return: The LNPheromone object within the cell.
        """
        in_cell_pheromone = None
        for i in self.grid.get_cell_list_contents(location):
            if type(i) == LNPheromone:
                in_cell_pheromone = i
        return in_cell_pheromone

    def get_closest_agent_of_type(self, agent, agent_type):
        """
        Gets the closest agent (besides self) of type agent_type. Returns -1 if it cannot find one.
        :param agent: The agent to find the closest agent_type to.
        :param agent_type: The type of the agent we are looking for.
        :return:
        """
        for radius in range(1, self.grid.width):
            for neighbor in self.grid.get_neighbors(pos=agent.pos,
                                                    moore=True,
                                                    include_center=False,
                                                    radius=radius):
                if isinstance(neighbor, agent_type):
                    return neighbor
        return -1

    def get_closest_colony(self, agent):
        """
        Gets the closest colony to an agent. If an agent is of type colony, it returns itself.
        :param agent: The agent to find the closest colony to.
        :return: The closest colony or -1 if not found.
        """
        return self.get_closest_agent_of_type(agent, Colony)

    @staticmethod
    def distance_between_cells(location_a, location_b):
        """
        Calculates the distance between two cells on the grid.
        :param location_a: First cell location.
        :param location_b: Second cell location.
        :return:
        """
        return np.sqrt((location_a[0] - location_b[0])**2 +
                       (location_a[1] - location_a[1])**2)

    def get_nearest_cell_to_goal(self, goal_cell, possible_cells):
        """
        Returns the cell from a list of possible cells which is closest to the end location.
        :param goal_cell: The goal cell of the agent
        :param possible_cells: Candidate cells.
        :return: The location of the closest cell to the goal cell.
        """
        closest_neighbor_index = -1
        closest_neighbor_distance = np.inf
        for i in range(0, len(possible_cells)):
            dist = self.distance_between_cells(possible_cells[i], goal_cell)
            if dist < closest_neighbor_distance:
                closest_neighbor_index = i
                closest_neighbor_distance = dist
        return possible_cells[closest_neighbor_index]

    def get_number_of_agents_in_radius(self, location, radius, agent_type):
        """
        Returns the number of agents of type agent_type within a radius (not including center) of location.
        :param location: Location to search around.
        :param radius: Radius to search.
        :param agent_type: Type of agent to search for.
        :return: int
        """
        total_agents = 0
        for neighbor in self.grid.get_neighbors(pos=location,
                                                moore=True,
                                                include_center=False,
                                                radius=radius):
            if isinstance(neighbor, agent_type):
                total_agents += 1
        return total_agents

    def get_all_of_agent_type(self, agent_type):
        """
        Returns all instances of agents of type agent_type in the Grid.
        :param agent_type: The type of agent to find.
        :return: A list of agent objects.
        """
        return [
            x for x in self.grid.get_neighbors(pos=(0, 0),
                                               moore=True,
                                               include_center=True,
                                               radius=self.grid.width)
            if isinstance(x, agent_type)
        ]

    def step(self):
        """
        A method called every step that occurs
        :return: None
        """
        self.data_collector.collect(self)
        self.schedule.step()
예제 #13
0
class Themepark(Model):
    def __init__(self, N_attr, N_cust, width, height, strategy, theme, max_time, weight, adaptive):
        self.theme = theme
        self.max_time = max_time
        self.N_attr = N_attr
        self.penalty_per = PENALTY_PERCENTAGE
        self.weight = weight
        self.adaptive = adaptive
        self.strategies = STRATEGIES
        self.x_list, self.y_list, self.positions = xlist, ylist, positions
        self.x_list, self.y_list, self.positions = get_attraction_coordinates(WIDTH, HEIGHT, self.N_attr, theme)
        self.happinesses = []
        self.starting_positions = [[int((WIDTH/2)-1), 0], [int(WIDTH/2), 0], [int((WIDTH/2)+1), 0]]
        self.path_coordinates = get_coordinates(WIDTH, HEIGHT, NUM_OBSTACLES, self.N_attr, theme)
        self.N_attr = N_attr    # num of attraction agents
        self.N_cust = N_cust    # num of customer agents
        self.width = width
        self.height = height
        self.total_steps = 0
        self.cust_ids = N_cust
        self.strategy = strategy
        self.grid = MultiGrid(width, height, torus=False)
        self.schedule = BaseScheduler(self)
        self.schedule_Attraction = BaseScheduler(self)
        self.schedule_Customer = BaseScheduler(self)
        self.totalTOTAL = 0
        self.attractions = self.make_attractions()
        self.attraction_history = self.make_attr_hist()
        self.running = True
        self.data = []
        self.data_customers = []
        self.park_score = []
        self.data_dict = {}
        self.hist_random_strat = []
        self.hist_close_strat = []
        self.all_rides_list = []
        self.strategy_composition = self.make_strategy_composition()
        self.memory = 5
        self.customer_score = []
        self.customers = self.add_customers(self.N_cust)
        self.only_random = False


        for attraction in self.get_attractions():
            self.data_dict[attraction.unique_id] = ({
                               "id": attraction.unique_id,
                               "length": attraction.attraction_duration,
                               "waiting_list": []})

        if len(self.strategies) == 6:
            self.datacollector = DataCollector(

                {"Random": lambda m: self.strategy_counter(self.strategies[0]),
                "0.00": lambda m: self.strategy_counter(self.strategies[1]),
                "0.25": lambda m: self.strategy_counter(self.strategies[2]),
                "0.50": lambda m: self.strategy_counter(self.strategies[3]),
                "0.75": lambda m: self.strategy_counter(self.strategies[4]),
                "1.00": lambda m: self.strategy_counter(self.strategies[5]),
                })
        else:
            self.datacollector = DataCollector(
                {"0.00": lambda m: self.strategy_counter(self.strategies[0]),
                "0.25": lambda m: self.strategy_counter(self.strategies[1]),
                "0.50": lambda m: self.strategy_counter(self.strategies[2]),
                "0.75": lambda m: self.strategy_counter(self.strategies[3]),
                "1.00": lambda m: self.strategy_counter(self.strategies[4]),
                })

        self.datacollector2 = DataCollector(
            {"score": lambda m: self.make_score()})

        self.total_waited_time = 0

        self.monitor = Monitor(self.max_time, self.N_attr, self.positions)

    def make_score(self):
        ideal = {}
        cust_in_row = 0
        for i in range(len(self.get_attractions())):
            ideal[i] = self.N_cust/self.N_attr
            cust_in_row += self.get_attractions()[i].N_current_cust

        tot_difference = 0
        for i in range(len(self.get_attractions())):

            difference = abs(cust_in_row/self.N_attr  - self.get_attractions()[i].N_current_cust)
            tot_difference += difference

        fraction_not_right = (tot_difference/self.N_cust)
        return abs(1-(fraction_not_right)) * cust_in_row/self.N_cust

    def make_attr_hist(self):
        attraction_history = {}
        for attraction in self.get_attractions():

            attraction_history[attraction] = [0] * (self.max_time + 1)
        return attraction_history

    def strategy_counter(self, strategy):
        counter_total = {}

        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(
                attraction_pos,
                moore=True,
                radius=0,
                include_center=True
            )

            counter = 0
            for agent in self.customers:
                if agent.weight == strategy:
                    counter += 1

        return counter

    def make_strategy_composition(self):
        if self.strategy == "Random_test_4":
            self.strategies = ["Random_test_4", 0.0, 0.25, 0.50, 0.75, 1.0]
            dict = {self.strategies[0]: 1/6, self.strategies[1]:0.20, self.strategies[2]:0.20,
                            self.strategies[3]:0.20, self.strategies[4]:0.20, self.strategies[5]: 0.20}

            composition_list = []
            for i in range(len(self.strategies)):
                if i == 0:
                    dict[self.strategies[i]] = FRACTION_RANDOM
                    continue
                else:
                    composition_list.append(random.randint(0,100))
            sum_comp = sum(composition_list)

            sum_comp = sum_comp - sum_comp * FRACTION_RANDOM
            for i in range(len(self.strategies)):
                if i == 0:
                    continue
                else:
                    dict[self.strategies[i]] = composition_list[i-1] /sum_comp

        else:
            dict = {self.strategies[0]: 0.20, self.strategies[1]:0.20, self.strategies[2]:0.20,
                            self.strategies[3]:0.20, self.strategies[4]:0.20}

            composition_list = []
            for i in range(len(self.strategies)):

                composition_list.append(random.randint(0,100))

            sum_comp = sum(composition_list)

            sum_comp = sum_comp
            for i in range(len(self.strategies)):

                dict[self.strategies[i]] = composition_list[i-1] /sum_comp



        return dict

    def make_attractions(self):
        """ Initialize attractions on fixed position."""

        attractions = {}
        for i in range(self.N_attr):

            pos = (self.x_list[i], self.y_list[i])
            if self.grid.is_cell_empty(pos):

                name = str(i)
                a = Attraction(i, self, pos, name, self.N_cust, self.weight)
                attractions[i] = a

                self.schedule_Attraction.add(a)
                self.grid.place_agent(a, pos)
        return attractions

    def get_attractions(self):
        """
        Get a list with all attractions
        """
        agents = self.grid.get_neighbors(
            mid_point,
            moore=True,
            radius=RADIUS,
            include_center=True)

        attractions = []
        for agent in agents:
            if type(agent) == Attraction:
                attractions.append(agent)

        return attractions

    def add_customers(self, N_cust, added=False):
        """ Initialize customers on random positions."""

        weights_list = []
        if self.adaptive is True:

            for j in self.strategy_composition.keys():
                for i in range(round(N_cust*self.strategy_composition[j])):
                    weights_list.append(j)

            if len(weights_list) < self.N_cust:
                rand = random.choice(self.strategies)
                weights_list.append(rand)
            elif len(weights_list) > self.N_cust:
                rand = random.choice(weights_list)
                weights_list.remove(rand)


        else:
            if self.strategy is not "Random":

                # do what normally is done
                for i in range(round(N_cust)):
                    weights_list.append(self.weight)


        cust_list = []
        # weight_counter = 0
        # pick_weight = 0
        for i in range(N_cust):

            # pos_temp = random.choice(self.starting_positions)
            pos_temp = [random.randint(0,WIDTH-1), random.randint(0,HEIGHT-1)]
            rand_x, rand_y = pos_temp[0], pos_temp[1]

            pos = (rand_x, rand_y)

            if added is True:
                i = self.cust_ids
            if self.strategy == "Random_test_4":
                if weights_list[i] == "Random_test_4":
                    strategy = "Random_test_4"
                else:
                    strategy = "Closest_by"
            else:
                strategy = self.strategy


            # Deze if is omdat bij alleen random self.weight none is!
            if weights_list == []:
                weight = None
            else:
                weight = weights_list[i]
            a = Customer(i, self, pos, self.x_list, self.y_list, self.positions, strategy, weight, self.adaptive)

            self.schedule_Customer.add(a)

            self.grid.place_agent(a, pos)
            cust_list.append(a)

        return cust_list

    def calculate_people(self):
        """Calculate how many customers are in which attraction."""

        counter_total = {}

        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(
                attraction_pos,
                moore=True,
                radius=0,
                include_center=True
            )

            counter = 0
            for agent in agents:
                if type(agent) is Customer:
                    counter += 1
                else:
                    attraction = agent

            attraction.N_current_cust = counter
            counter_total[attraction.unique_id] = counter

        return list(counter_total.values())

    def calc_waiting_time(self):

        counter_total = {}

        attractions = self.get_attractions()
        for attraction in attractions:

            counter_total[attraction.unique_id] = attraction.current_waitingtime

        return counter_total


    def calculate_people_sorted(self):
        """
        Calculate how many customers are in which attraction.
        Returns a SORTED LIST.
        For example: indexes = [3, 2, 5, 1, 4]
        indicates that attraction3 has the least people waiting.
        """

        counter_total = {}

        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(
                attraction_pos,
                moore=True,
                radius=0,
                include_center=True
            )

            counter = 0
            for agent in agents:
                if type(agent) is Customer:
                    counter += 1
                else:
                    attraction = agent

            attraction.N_current_cust = counter
            self.attraction_history[attraction][self.totalTOTAL] = counter
            counter_total[attraction.unique_id] = counter
        return counter_total

    def make_route(self):
        """Draw coordinates of a possible path."""

        for i in range(len(self.path_coordinates)):
            pos = self.path_coordinates[i]

            if pos not in self.positions:

                # Create path agent
                path = Route(i, self, pos)
                self.schedule.add(path)

                self.grid.place_agent(path, pos)

    def get_themepark_score(self):
        """
        Get score of a themepark based on:
            - A total of all waitingtimes for every customer
            - TODO
        """
        attractions = self.get_attractions()
        total_wait, total_rides = 0, 0
        for attraction in attractions:
            total_wait += attraction.current_waitingtime

            if attraction.current_a is not None:
                total_rides += 1

        if total_rides == 0:
            return total_rides

        return (total_wait / total_rides)

    def get_strategy_history(self):
        """ Update history with how many customers chose which strategy """

        customers = self.get_customers()
        randomstrat, closebystrat = 0, 0

        for customer in customers:
            if customer.strategy == "Random" or customer.strategy == "Random_test_4":
                randomstrat += 1
            elif customer.strategy == "Closest_by":
                closebystrat += 1

        self.hist_random_strat.append(randomstrat)
        self.hist_close_strat.append(closebystrat)

    def get_customers(self):
        agents = self.grid.get_neighbors(
            mid_point,
            moore=True,
            radius=RADIUS,
            include_center=True)

        customers = []

        # Count customer agents
        for agent in agents:
            if type(agent) == Customer:
                customers.append(agent)
        return customers

    def get_data_customers(self):
        """ Return dictionary with data of customers """

        data = {}
        agents = self.grid.get_neighbors(
            mid_point,
            moore=True,
            radius=RADIUS,
            include_center=True)

        for agent in agents:
            if type(agent) is Customer:
                data[agent.unique_id] = {
                "totalwaited": agent.total_ever_waited,
                "visited_attractions": agent.nmbr_attractions,
                "strategy": agent.strategy,
                "swapped_strat": agent.strategy_swap_hist
                }
        return data

    def calc_hapiness(self):
        """
        Calculate mean hapiness of all customers, based on:

        - How many rides were taken
        - Number of times in the same attraction
        - Total waiting time
        """
        customers = self.get_customers()

        scores = []



        for customer in customers:
            history = customer.history
            values = list(history.values())
            total_rides = sum(values)

            if total_rides != 0:
                scores.append(total_rides / self.N_attr - self.totalTOTAL / customer.total_ever_waited)
            else:
                return None

        scores = np.interp(scores, (min(scores), max(scores)), (1, 10))
        return np.mean(scores)

    def get_history_list(self):

        customers = self.get_customers()


        histories = {}

        for customer in customers:
            history = customer.history
            values = list(history.values())
            histories[customer.unique_id] = values
        return histories

    def final(self):
        """ Return data """
        hist_list = []
        agents = self.grid.get_neighbors(
            mid_point,
            moore=True,
            radius=RADIUS,
            include_center=True)

        attractions = self.get_attractions()
        self.all_rides_list = [0] * len(attractions[0].in_attraction_list)
        for attraction in attractions:
            for i in range(len(attraction.in_attraction_list)):
                self.all_rides_list[i] += attraction.in_attraction_list[i]

        for i in range(len(self.all_rides_list)):
            self.all_rides_list[i] /= self.N_attr
        print("ALL RIDES LIST", self.all_rides_list)

        cust_data = self.get_data_customers()
        for agent in agents:
            if type(agent) is Customer:
                sum_attr = sum(agent.history.values())
                if sum_attr > 0:
                    hist_list.append(agent.strategy_swap_hist)
                else:
                    hist_list.append(agent.strategy_swap_hist)
                # print("swap:",agent.strategy_swap_hist , "sum:",sum_attr)


        # plt.hist(hist_list)
        # plt.show()

        histories = self.get_history_list()

        # save data
        try:
            pickle.dump(self.datacollector.get_model_vars_dataframe(), open("../data/strategy_history.p", 'wb'))
            pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("../data/eff_score_history.p", 'wb'))
            pickle.dump(cust_data, open("../data/customers.p", 'wb'))
            pickle.dump(self.park_score[-1], open("../data/park_score.p", "wb"))
            pickle.dump(self.happinesses, open("../data/hapiness.p", "wb"))
            pickle.dump(histories, open("../data/cust_history.p", 'wb'))
        except:
            pickle.dump(self.datacollector.get_model_vars_dataframe(), open("data/strategy_history.p", 'wb'))
            pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("data/eff_score_history.p", 'wb'))
            pickle.dump(cust_data, open("data/customers.p", 'wb'))
            pickle.dump(self.park_score[-1], open("data/park_score.p", "wb"))
            pickle.dump(self.happinesses, open("data/hapiness.p", "wb"))
            pickle.dump(histories, open("data/cust_history.p", 'wb'))

        try:
            pickle.dump(self.all_rides_list, open("../data/all_rides.p", "wb"))
        except:
            pickle.dump(self.all_rides_list, open("data/all_rides.p", "wb"))

        print()
        print("RUN HAS ENDED")
        print()


    def save_data(self):
        """Save data of all attractions and customers."""

        # Get info
        waitinglines = self.calc_waiting_time()

        for i in range(len(self.attractions)):
            self.data_dict[i]["waiting_list"].append(waitinglines.get(i))

        self.park_score.append(sum(waitinglines.values()))
        self.happinesses.append(self.calc_hapiness())

    def step(self):
        """Advance the model by one step."""

        if self.totalTOTAL < self.max_time:
            self.totalTOTAL += 1
            self.schedule.step()
            self.datacollector.collect(self)
            self.datacollector2.collect(self)

            self.schedule_Attraction.step()

            self.schedule_Customer.step()

            # update memory of attractions
            # attractions = self.get_attractions()
            # for attraction in attractions:
            #     attraction.update_memory()

            self.total_steps += 1

            self.save_data()
            self.get_strategy_history()

        else:
            for key in self.attraction_history.keys():
                y = self.attraction_history[key]
                x = list(range(0, self.max_time))
            self.final()
예제 #14
0
파일: model.py 프로젝트: AnnemijnD/ABMFinal
class Themepark(Model):
    def __init__(self, N_attr, N_cust, width, height, strategy, theme,
                 max_time, weight, adaptive):
        """
        Args:
            N_attr (int): the amount of attractions in the theme park
            N_cust (int): the amout of customers in the theme park
            width (int): the width of the theme park grid
            height (int): the height of the theme park grid
            strategy (str): the strategy of this run (random agents, adaptive agents
                            or adaptive agents with noise)
            theme (str): the setup of the park (circle, random or clustered)
            max_time (int): the number of time steps the park will do in one run
            weight (float): if the customer agents are non-adaptive, this is the strategy
                            they are using
            adaptive (bool): whether customer agents are able to switch strategies
        """
        self.theme = theme
        self.max_time = max_time
        self.N_attr = N_attr
        self.penalty_per = PENALTY_PERCENTAGE
        self.weight = weight
        self.adaptive = adaptive
        self.strategies = STRATEGIES
        self.happinesses = []
        self.N_attr = N_attr
        self.N_cust = N_cust
        self.width = width
        self.height = height
        self.total_steps = 0
        self.cust_ids = N_cust
        self.strategy = strategy
        self.grid = MultiGrid(width, height, torus=False)
        self.schedule = BaseScheduler(self)
        self.schedule_Attraction = BaseScheduler(self)
        self.schedule_Customer = BaseScheduler(self)

        # Cluster or circle coordinates
        if self.theme == "cluster":
            self.x_list, self.y_list, self.positions = xlist, ylist, positions
        elif self.theme == "circle":
            self.x_list, self.y_list, self.positions = get_attraction_coordinates(
                width, height, N_attr, "circle")

        # keeps up the current time
        self.totalTOTAL = 0

        # add attractions to park
        self.attractions = self.make_attractions()
        self.attraction_history = self.make_attr_hist()
        self.running = True
        self.data_dict = {}

        # keep up a history of the strategies
        self.hist_random_strat = []
        self.hist_close_strat = []

        # keep up a history of the occupation of the rides
        self.all_rides_list = []

        # distribution of strategies throughout population
        self.strategy_composition = self.make_strategy_composition()

        # add customers to park
        self.customers = self.add_customers(self.N_cust)

        # keep up park score throughout time
        self.park_score = []

        for attraction in self.get_attractions():
            self.data_dict[attraction.unique_id] = ({
                "id": attraction.unique_id,
                "length": attraction.attraction_duration,
                "waiting_list": []
            })

        # datacollector for the visualisation of the data
        if self.strategy == "Random_test_4":
            self.datacollector = DataCollector({
                "Random":
                lambda m: self.strategy_counter(self.strategies[0]),
                "0.00":
                lambda m: self.strategy_counter(self.strategies[1]),
                "0.25":
                lambda m: self.strategy_counter(self.strategies[2]),
                "0.50":
                lambda m: self.strategy_counter(self.strategies[3]),
                "0.75":
                lambda m: self.strategy_counter(self.strategies[4]),
                "1.00":
                lambda m: self.strategy_counter(self.strategies[5]),
            })

        elif self.strategy == "Random":
            self.datacollector = DataCollector(
                {"Random": lambda m: self.N_cust})

        else:
            self.datacollector = DataCollector({
                "0.00":
                lambda m: self.strategy_counter(self.strategies[0]),
                "0.25":
                lambda m: self.strategy_counter(self.strategies[1]),
                "0.50":
                lambda m: self.strategy_counter(self.strategies[2]),
                "0.75":
                lambda m: self.strategy_counter(self.strategies[3]),
                "1.00":
                lambda m: self.strategy_counter(self.strategies[4]),
            })

        self.datacollector2 = DataCollector(
            {"score": lambda m: self.make_score()})

    def make_score(self):
        """
        Calculates and returns an efficiency score for the enire theme park.
        """

        # calculates the ideal distribution of customers over the attractions per attraction
        ideal = {}
        cust_in_row = 0
        for i in range(len(self.get_attractions())):
            ideal[i] = self.N_cust / self.N_attr
            cust_in_row += self.get_attractions()[i].N_current_cust

        # calculates the difference between the ideal and the real situation
        tot_difference = 0
        for i in range(len(self.get_attractions())):

            difference = abs(cust_in_row / self.N_attr -
                             self.get_attractions()[i].N_current_cust)
            tot_difference += difference

        # the fraction of customers that is not optimally distributed
        fraction_not_right = (tot_difference / self.N_cust)

        # add a penalty by multiplying by the fraction of people currently in a line
        score = abs(1 - (fraction_not_right)) * cust_in_row / self.N_cust
        return score

    def make_attr_hist(self):
        """
        Make history of attractions that are visited for each customer.
        """
        attraction_history = {}
        for attraction in self.get_attractions():

            attraction_history[attraction] = [0] * (self.max_time + 1)
        return attraction_history

    def strategy_counter(self, strategy):
        """
        Input is a strategy, for example "0.25" or "Random", output is
        the number of strategies are adopted at a current time step.
        """
        for attraction_pos in self.positions:
            counter = 0
            for agent in self.customers:
                if agent.weight == strategy:
                    counter += 1
        return counter

    def make_strategy_composition(self):
        """
        Make a composition of all strategies over the entire theme park.
        Returns a dictionary with strategies as keys and the fraction of people
        using this strategy as value.
        """

        # if this is a run with adaptive agents and noise
        if self.strategy == "Random_test_4":
            self.strategies = ["Random_test_4", 0.0, 0.25, 0.50, 0.75, 1.0]

            # make dictionary with fractions (values can be ignored!)
            dict = {
                self.strategies[0]: 0,
                self.strategies[1]: 0.20,
                self.strategies[2]: 0.20,
                self.strategies[3]: 0.20,
                self.strategies[4]: 0.20,
                self.strategies[5]: 0.20
            }

            composition_list = []
            for i in range(len(self.strategies)):
                if i == 0:
                    dict[self.strategies[i]] = FRACTION_RANDOM
                    continue
                else:

                    # choose a random number
                    composition_list.append(random.randint(0, 100))

            sum_comp = sum(composition_list)
            sum_comp = sum_comp - sum_comp * FRACTION_RANDOM
            for i in range(len(self.strategies)):
                if i == 0:
                    continue
                else:

                    # determine the fraction of customer agents with this strategy
                    dict[self.strategies[i]] = composition_list[i -
                                                                1] / sum_comp

        # runs without noise
        else:
            # make dictionary with fractions (values can be ignored!)
            dict = {
                self.strategies[0]: 0.20,
                self.strategies[1]: 0.20,
                self.strategies[2]: 0.20,
                self.strategies[3]: 0.20,
                self.strategies[4]: 0.20
            }

            composition_list = []
            for i in range(len(self.strategies)):

                # choose a random number
                composition_list.append(random.randint(0, 100))

            sum_comp = sum(composition_list)

            for i in range(len(self.strategies)):

                # determine the fraction of agents with this strategy
                dict[self.strategies[i]] = composition_list[i - 1] / sum_comp

        return dict

    def make_attractions(self):
        """
        Initialize attractions on fixed positions, defined in the global
        variables x_list and y_list. Returns a dictionary of attractions
        """

        attractions = {}
        for i in range(self.N_attr):

            pos = (self.x_list[i], self.y_list[i])

            # place attraction if grid cell is empty
            if self.grid.is_cell_empty(pos):

                name = str(i)
                a = Attraction(i, self, pos, name)
                attractions[i] = a

                self.schedule_Attraction.add(a)
                self.grid.place_agent(a, pos)
        return attractions

    def get_attractions(self):
        """
        Return a list with all attractions.
        """
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)

        attractions = []
        for agent in agents:
            if type(agent) == Attraction:
                attractions.append(agent)

        return attractions

    def add_customers(self, N_cust, added=False):
        """
        Initialize customers on random positions.
        Returns a list of all customers
        """

        # a list of weights of which the indices correspond to the id of the agent
        # to who this weight is given
        weights_list = []

        # Adaptive strategy
        if self.adaptive is True:

            # Decide weights for every customer
            for j in self.strategy_composition.keys():
                for i in range(round(N_cust * self.strategy_composition[j])):
                    weights_list.append(j)

            # Add weights for the random strategy
            if len(weights_list) < self.N_cust:
                rand = random.choice(self.strategies)
                weights_list.append(rand)
            elif len(weights_list) > self.N_cust:
                rand = random.choice(weights_list)
                weights_list.remove(rand)

        else:
            if self.strategy is not "Random":
                for i in range(round(N_cust)):
                    print(self.weight)
                    weights_list.append(self.weight)

        cust_list = []
        for i in range(N_cust):

            # Get random location within grid height and width
            pos_temp = [
                random.randint(0, WIDTH - 1),
                random.randint(0, HEIGHT - 1)
            ]
            rand_x, rand_y = pos_temp[0], pos_temp[1]
            pos = (rand_x, rand_y)

            if added is True:
                i = self.cust_ids
            if self.strategy == "Random_test_4":
                if weights_list[i] == "Random_test_4":
                    strategy = "Random_test_4"
                else:
                    strategy = "Closest_by"
            else:
                strategy = self.strategy

            if weights_list == []:
                weight = None
            else:
                weight = weights_list[i]

            # make customer
            a = Customer(i, self, pos, strategy, weight, self.adaptive)
            self.schedule_Customer.add(a)
            self.grid.place_agent(a, pos)
            cust_list.append(a)

        return cust_list

    def calculate_people(self):
        """
        Calculate how many customers are in which attraction.
        Returns a list of which the indices correspond to the ids of the atttraction
        """

        counter_total = {}

        # loop through attractions
        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(attraction_pos,
                                             moore=True,
                                             radius=0,
                                             include_center=True)

            counter = 0

            # find customers in this attraction
            for agent in agents:
                if type(agent) is Customer:
                    counter += 1
                else:
                    attraction = agent

            # update the amount of customers in this attraction
            attraction.N_current_cust = counter
            counter_total[attraction.unique_id] = counter

        return list(counter_total.values())

    def calc_waiting_time(self):
        """
        Return a dictionary of watingtimes for every attraction
        """
        counter_total = {}

        attractions = self.get_attractions()
        for attraction in attractions:

            counter_total[
                attraction.unique_id] = attraction.current_waitingtime

        return counter_total

    def calculate_people_sorted(self):
        """
        Calculate how many customers are in which attraction.
        Returns a dictionary with attraction-ids as keys and customers in line as values.
        """

        counter_total = {}

        # loop through attractions
        for attraction_pos in self.positions:

            agents = self.grid.get_neighbors(attraction_pos,
                                             moore=True,
                                             radius=0,
                                             include_center=True)

            counter = 0

            # find customers in this attraction
            for agent in agents:
                if type(agent) is Customer:
                    counter += 1
                else:
                    attraction = agent

            # update the amount of customers in this attraction
            attraction.N_current_cust = counter
            self.attraction_history[attraction][self.totalTOTAL] = counter
            counter_total[attraction.unique_id] = counter

        return counter_total

    def get_strategy_history(self):
        """ Update history with how many customers chose which strategy """

        customers = self.get_customers()
        randomstrat, closebystrat = 0, 0

        for customer in customers:
            if customer.strategy == "Random" or customer.strategy == "Random_test_4":
                randomstrat += 1
            elif customer.strategy == "Closest_by":
                closebystrat += 1

        self.hist_random_strat.append(randomstrat)
        self.hist_close_strat.append(closebystrat)

    def get_customers(self):
        """Return a list of all customers in the theme park."""
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)

        customers = []

        # Count customer agents
        for agent in agents:
            if type(agent) == Customer:
                customers.append(agent)
        return customers

    def get_data_customers(self):
        """ Return dictionary with data of customers """

        data = {}
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)

        for agent in agents:
            if type(agent) is Customer:
                data[agent.unique_id] = {
                    "totalwaited": agent.total_ever_waited,
                    "visited_attractions": agent.nmbr_attractions,
                    "strategy": agent.strategy,
                    "swapped_strat": agent.strategy_swap_hist
                }
        return data

    def calc_hapiness(self):
        """
        Calculate mean hapiness of all customers, based on:

        - How many rides were taken
        - Number of times in the same attraction
        - Total waiting time

        Returns the mean happiness of all customers
        """
        customers = self.get_customers()
        scores = []

        for customer in customers:
            history = customer.history
            values = list(history.values())
            total_rides = sum(values)

            if total_rides != 0:
                scores.append(total_rides / self.N_attr -
                              self.totalTOTAL / customer.total_ever_waited)
            else:
                return None

        scores = np.interp(scores, (min(scores), max(scores)), (1, 10))
        return np.mean(scores)

    def get_history_list(self):
        """
        Return a dictionary of the history of visited attraction for
        each customer.
        """

        customers = self.get_customers()
        histories = {}

        for customer in customers:
            history = customer.history
            values = list(history.values())
            histories[customer.unique_id] = values
        return histories

    def final(self):
        """ Return and save data at the end of the run."""

        hist_list = []
        agents = self.grid.get_neighbors(mid_point,
                                         moore=True,
                                         radius=RADIUS,
                                         include_center=True)
        attractions = self.get_attractions()

        # Make a list for the fraction of occupied rides at all time steps
        self.all_rides_list = [0] * len(attractions[0].in_attraction_list)
        for attraction in attractions:
            for i in range(len(attraction.in_attraction_list)):
                self.all_rides_list[i] += attraction.in_attraction_list[i]
        for i in range(len(self.all_rides_list)):
            self.all_rides_list[i] /= self.N_attr

        cust_data = self.get_data_customers()
        for agent in agents:
            if type(agent) is Customer:
                sum_attr = sum(agent.history.values())
                if sum_attr > 0:
                    hist_list.append(agent.strategy_swap_hist)
                else:
                    hist_list.append(agent.strategy_swap_hist)

        histories = self.get_history_list()

        # save data
        try:
            pickle.dump(self.datacollector.get_model_vars_dataframe(),
                        open("../data/strategy_history.p", 'wb'))
            pickle.dump(self.datacollector2.get_model_vars_dataframe(),
                        open("../data/eff_score_history.p", 'wb'))
            pickle.dump(cust_data, open("../data/customers.p", 'wb'))
            pickle.dump(self.park_score[-1], open("../data/park_score.p",
                                                  "wb"))
            pickle.dump(self.happinesses, open("../data/hapiness.p", "wb"))
            pickle.dump(histories, open("../data/cust_history.p", 'wb'))
            pickle.dump(self.all_rides_list, open("../data/all_rides.p", "wb"))
        except:
            pickle.dump(self.datacollector.get_model_vars_dataframe(),
                        open("data/strategy_history.p", 'wb'))
            pickle.dump(self.datacollector2.get_model_vars_dataframe(),
                        open("data/eff_score_history.p", 'wb'))
            pickle.dump(cust_data, open("data/customers.p", 'wb'))
            pickle.dump(self.park_score[-1], open("data/park_score.p", "wb"))
            pickle.dump(self.happinesses, open("data/hapiness.p", "wb"))
            pickle.dump(histories, open("data/cust_history.p", 'wb'))
            pickle.dump(self.all_rides_list, open("data/all_rides.p", "wb"))

        print()
        print("RUN HAS ENDED")
        print()

    def save_data(self):
        """Save data of all attractions and customers."""

        # Get info
        waitinglines = self.calc_waiting_time()

        for i in range(len(self.attractions)):
            self.data_dict[i]["waiting_list"].append(waitinglines.get(i))

        self.park_score.append(sum(waitinglines.values()))
        self.happinesses.append(self.calc_hapiness())

    def step(self):
        """Advance the model by one step."""
        if self.totalTOTAL < self.max_time:
            self.totalTOTAL += 1
            self.schedule.step()

            # Collect data for every step
            self.datacollector.collect(self)
            self.datacollector2.collect(self)

            # Step for both attraction and customer
            self.schedule_Attraction.step()
            self.schedule_Customer.step()

            self.total_steps += 1

            # Save data and update strategy history
            self.save_data()
            self.get_strategy_history()

        else:
            for key in self.attraction_history.keys():
                y = self.attraction_history[key]
                x = list(range(0, self.max_time))
            self.final()
예제 #15
0
파일: main.py 프로젝트: ysaikai/LFABM
class Trade(Model):
  verbose = False # Print-monitoring

  os.chdir(os.path.dirname(__file__))
  fpath = os.getcwd() + '/parameters.csv'
  reader = csv.reader(open(fpath, 'r'))
  d = dict()
  for key, value in reader:
    d[key] = float(value)

  height = int(d['height'])
  width = int(d['width'])
  ini_buyers = int(d['ini_buyers'])
  ini_sellers = int(d['ini_sellers'])

  def __init__(self, height=height, width=width, ini_buyers=ini_buyers, ini_sellers=ini_sellers):

    '''Parameters'''
    reader = csv.reader(open(self.fpath, 'r'))
    d = dict()
    for key, value in reader:
      d[key] = float(value)

    self.height = int(d['height'])
    self.width = int(d['width'])
    self.ini_buyers = int(d['ini_buyers'])
    self.ini_sellers = int(d['ini_sellers'])
    self.ini_cash = d['ini_cash']
    self.num_w = int(d['num_w'])
    self.trust_w = d['trust_w']
    self.costs = d['costs'] * ini_buyers
    self.mktresearch = d['mktresearch']
    self.priceRange = d['priceRange']
    self.csa = d['csa']
    self.csa_length = int(d['csa_length'])
    self.network = d['network']

    self.lb = d['lb'] # Lower bound
    self.ub = d['ub'] # Upper bound (in effect, unbounded)
    self.up = d['up'] # Up rate
    self.down = d['down'] # Down rate

    '''
    Entry mode
      0: No entry
      1: Full market research
      2: Whenever Avg cash balance > entryThreshhold with a random position
      3: Whenever Max cash balance > entryThreshhold enter nearby that position
    '''
    self.entry = int(d['entry'])
    self.entryFrequency = int(d['entryFrequency'])
    self.entryThreshhold = d['entryThreshhold'] * self.ini_cash
    self.entryRadius = int(d['entryRadius'])  # Area within high earner that a new seller will plop down

    '''Debugging'''
    self.sellerDebug = d['sellerDebug']
    self.buyerDebug = d['buyerDebug']
    self.networkDebug = d['networkDebug']
    self.utilweightDebug = d['utilweightDebug']
    self.entryDebug = d['entryDebug']

    self.schedule = RandomActivationByType(self)
    self.grid = MultiGrid(self.height, self.width, torus=True)
    self.datacollector = DataCollector(
      {"Sellers": lambda m: m.schedule.get_type_count(Seller),
      "Buyers": lambda m: m.schedule.get_type_count(Buyer)})

    '''Initialization'''
    self.cnt = 0 # Period counter
    self.buyers = {} # Dictionary of buyer instances
    self.sellers = {} # Dictionary of seller instances
    self.sid_alive = []
    self.pi = [0] * (height * width) # Profitability

    prices = {}
    for i in range(ini_sellers):
      prices[i] = self.priceRange * np.random.rand() + 1
    min_price = min(prices.values())
    for i in range(self.num_w):
      prices[i] = min_price * 0.9
    self.prices = prices

    e = {} # Embeddedness
    for i in range(ini_sellers):
      e[i] = 0.8*np.random.rand() + 0.2 # 0.2 - 1.0
    for i in range(self.num_w):
      e[i] = 0
    self.e = e

    '''Create buyers'''
    for i in range(self.ini_buyers):
      # It seems coincidence in the same cell is allowed
      x = np.random.randint(self.width)
      y = np.random.randint(self.height)

      α = d['alpha']
      trust = {}
      β = d['beta']*np.random.rand()
      for j in range(ini_sellers):
        trust[j] = np.random.rand()
      for j in range(self.num_w):
        trust[j] = self.trust_w
      γ = d['gamma']

      '''
      Network ties
        ties[j]=0 means 'no connection with bid=j buyer'
        ties[own bid] = 0 or 1 means nothing.
      '''
      ties = dict(zip(range(ini_buyers),[0]*ini_buyers))

      buyer = Buyer(i, self.grid, (x, y), True, α, trust, β, γ, ties)
      self.buyers[i] = buyer # Dictionary key is an integer
      self.grid.place_agent(buyer, (x, y))
      self.schedule.add(buyer)

    '''Create sellers'''
    for i in range(self.ini_sellers):
      x = np.random.randint(self.width)
      y = np.random.randint(self.height)

      cash = self.ini_cash
      costs = self.costs
      price = self.prices[i]
      w = False
      if i < self.num_w:
        w = True
      e = self.e[i]

      seller = Seller(i, self.grid, (x, y), True, cash, costs, price, w, e)
      self.sellers[i] = seller
      self.grid.place_agent(seller, (x, y))
      self.schedule.add(seller)

    self.running = True

  def step(self):
    '''Initialization'''
    self.cnt += 1
    self.sid_alive = [] # Excluding Wal-Mart

    for sid, seller in self.sellers.items():
      if seller.csa == False:
        '''Adjacent sales'''
        seller.sales = 0
        '''Customer list'''
        seller.customers[self.cnt] = []
      else:
        seller.customers[self.cnt] = seller.customers[self.cnt - 1]

      '''A list of living sellers (excluding Wal-Mart)'''
      if (seller.alive and seller.w == False):
        self.sid_alive.append(sid)
    # For entry
    if self.entry == 1:
      # Initialize the profitability vector
      self.pi = [0] * (self.height * self.width)
    elif self.entry == 2:
      # Calculate the average cash balance (scalar)
      total_cash = 0
      cnt_seller = 0
      total_cash = sum([self.sellers[sid].cash for sid in self.sid_alive])
      self.avg_cash = total_cash / len(self.sid_alive)
    elif self.entry == 3:
      # Calculate the max cash balance (scalar)
      temp_sids = self.sid_alive
      cash_bals = [self.sellers[sid].cash for sid in temp_sids]
      new_sellers = True

      # Loops over maximal sellers until it finds one with no new firms nearby
      while(new_sellers):
        max_cash = max(cash_bals)
        if(max_cash < self.entryThreshhold): break
        max_cash_ind = cash_bals.index(max_cash)
        max_sid = temp_sids[max_cash_ind]
        max_x = self.sellers[max_sid].pos[0]
        max_y = self.sellers[max_sid].pos[1]
        if(self.entryDebug):
          print("Max Cash, sid:", max_sid, ", Cell:(" + str(max_x) + ", " + str(max_y) + ")")
          print("-Neighbor Ages:", end=" ")

        new_sellers = False
        # Check the age of all firms nearby the max cash balance firm
        # (wants to avoid new firms)

        for neighbor in self.grid.get_neighbors((max_x, max_y),True,True,self.entryRadius):
          if(isinstance(neighbor, Seller) and self.entryDebug): print(str(neighbor.age), end=" ")
          if(isinstance(neighbor, Seller) and neighbor.age < 52): new_sellers = True
        if(new_sellers):
          if(self.entryDebug):
            print("\n-New Firm Exists Near sid: ", max_sid, ", Cell:(" + str(max_x) + ", " + str(max_y) + ")")
          del temp_sids[max_cash_ind]
          del cash_bals[max_cash_ind]

    '''
    Entry
      Entry=1
        Determine the most profitable position and whether to enter
        Threshold: the fixed costs
      Entry=2
        Enter whenever Avg cash balance > entryThreshhold
      Entry=3
        Checks that no new firms are near the max balance seller
        Enters within entryRadius units of the seller with max cash balance
    '''
    entry_on = False

    if (self.entry == 1 and self.mktresearch):
      opt = max(self.pi)
      opt_pos = self.pi.index(opt)

      if opt >= self.costs:
        x = opt_pos // self.width
        y = opt_pos % self.width
        entry_on = True

    elif (self.entry == 2 and self.avg_cash > self.entryThreshhold):
      x = np.random.randint(self.width)
      y = np.random.randint(self.height)
      entry_on = True

    elif (self.entry == 3 and max_cash > self.entryThreshhold and not new_sellers):
      x = max_x + np.random.randint(-self.entryRadius,self.entryRadius)
      y = max_y + np.random.randint(-self.entryRadius,self.entryRadius)
      x = x % self.width
      y = y % self.height
      entry_on = True

    if entry_on:
      cash = self.ini_cash
      costs = self.costs
      w = False
      price = np.mean([self.sellers[sid].price for sid in self.sid_alive])
      # e = np.random.choice([self.sellers[sid].e for sid in self.sid_alive])
      e = np.random.rand()
      sid = max([seller.sid for seller in self.sellers.values()]) + 1
      self.sid_alive.append(sid)
      seller = Seller(sid, self.grid, (x, y), True, cash, costs, price, w, e)
      self.sellers[sid] = seller
      self.sellers[sid].customers[self.cnt] = []
      for buyer in self.buyers.values():
        buyer.trust[sid] = self.lb
      self.grid.place_agent(seller, (x, y))
      self.schedule.add(seller)
      self.prices[sid] = price

      if (self.entry >= 1 and self.entryDebug):
        entry_NewFirm(sid, x, y)

      self.mktresearch = False

    '''Move'''
    self.schedule.step()
    self.datacollector.collect(self)
    if self.verbose:
      print([self.schedule.time,
        self.schedule.get_type_count(Seller),
        self.schedule.get_type_count(Buyer)])

    '''Network'''
    if self.network:
      network.formation(self.cnt, self.buyers, self.sellers)


  def run_model(self, step_count):
    for _ in range(step_count):
      self.step()
      '''
      Debugging
      '''
      '''Display trust levels'''
      if self.buyerDebug:
        debug.buyers(self.buyers)
      '''Network'''
      if self.networkDebug:
        debug.network(self.buyers)
      '''Display seller information'''
      if self.sellerDebug:
        debug.sellers(self.cnt, self.num_w, self.sellers, self.buyers)

    '''End of the run'''
    print("\n************\nPut a summary here.\n************")
예제 #16
0
class ContactModel(Model):
    def __init__(self, N, height, width, exponent, steps, seed):
        self.number_of_agents = N
        self.height = height
        self.width = width
        self.exponent = exponent

        self.x_locs = np.zeros((N, steps + 1))
        self.y_locs = np.zeros((N, steps + 1))

        self.current_step = 0  #NEW

        self.current_step_contacts = []
        self.adjacency_matrix = np.zeros((N, N))
        self.grid = MultiGrid(self.width, self.height, torus=False)
        self.schedule = BaseScheduler(self)  #RandomActivation(self)

        # Add N pedestrians to model (schedule, grid)
        taken_pos = []
        for i in range(self.number_of_agents):
            x = self.random.randrange(1, self.grid.width - 1)
            y = self.random.randrange(1, self.grid.height - 1)

            pos = (x, y)
            new_human = Pedestrian(i, self, pos, self.exponent, seed=i)

            self.schedule.add(new_human)
            self.grid.place_agent(new_human, pos)
            self.x_locs[i][0] = x
            self.y_locs[i][0] = y
            taken_pos.append(pos)

        self.data_collector = DataCollector()

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

    def contact_update(self, contact_ids):

        contact_ids = sorted(contact_ids)
        if contact_ids not in self.current_step_contacts:
            self.current_step_contacts.append(contact_ids)

    def update_adjecency_matrix(self):
        '''
        #TODO: order agent steps, order updates, double or not
        for id_tuple in self.current_step_contacts:
            self.adjacency_matrix[id_tuple[0], id_tuple[1]]+=1
        '''

        agents = self.schedule.agents
        for i, agent in enumerate(agents):
            neighbors = self.grid.get_neighbors(agent.pos,
                                                moore=True,
                                                radius=5)
            for neighbor in neighbors:
                if neighbor.unique_id > agent.unique_id:
                    self.adjacency_matrix[agent.unique_id,
                                          neighbor.unique_id] += 1

    def step(self):
        self.schedule.step()
        self.update_adjecency_matrix()
        #self.current_step_contacts=[]
        #self.data_collector.collect(self)

    def run(self, N):
        for i in range(N):

            self.step()

            self.current_step += 1  #NEW

            for agent in self.schedule.agents:
                self.x_locs[agent.unique_id][i + 1] = agent.pos[0]
                self.y_locs[agent.unique_id][i + 1] = agent.pos[1]

            if i % 100 == 0:
                print(i)
예제 #17
0
class miModelo(Model):  #definimos la clase miModelo
    def __init__(
        self, N_humanos
    ):  #constructor, metemos el argumento Número Humanos iniciales
        self.running = True  #permite la ejecución continua
        self.schedule = RandomActivation(self)  # elige el tipo de schedule
        self.grid = MultiGrid(GRID_FINAL_X, GRID_FINAL_Y,
                              False)  #tipo y tamaño de grid
        self.posTorniquetesEntrada = [
        ]  #guarda las posiciones de los torniquites de entrada
        self.posTorniquetesSalida = [
        ]  #guarda las posiciones de los torniquites de salida
        self.posPuertas = []  #guarda las posiciones de las puertas
        self.puertas = []  #guarda los objetos puerta
        self.posUInteriores = calcularUInteriores(
        )  #te calcula todas las posiciones interios del vagón a donde se dirigen los usuarios
        self.contador = 1  # contador de ticks para abrir y cerrar puertas
        self.humanosEntraronTorniquetes = 0  #contador para humanos que entran a torniquetes
        self.humanosSalieronTorniquetes = 0  #contador para humanos que entran a torniquetes
        self.humanosEntraronVagon = 0  #contador para humanos que entran a torniquetes
        self.humanosSalieronVagon = 0  #contador para humanos que entran a torniquetes
        #self.timer = TIMERABIERTO
        pintarTorniquetes(self)  #Dibuja los torniquetes
        pintarPuertas(self)  #Dibuja todas las puertas
        pintarMuros(self)
        #Dibuja todos los muros
        pintarHumanos(self, N_humanos, False)

    def step(self):
        print("Start tick")
        self.schedule.step()
        pintarNuevosHumanos(self, 1)
        # N_humanos = self.random.randint(1,12)
        if self.schedule.get_agent_count() < 2:
            self.running = False
        self.contador += 1
        humanosAEntrar = []
        humanosASalir = []
        if self.contador == TIMERABRIR and self.puertas[0].cerrada:
            humanosAEntrar = self.obtenerHumanosEnRango(
                GRID_INICIAL_X, GRID_FINAL_X, YMURO_TREN, YMURO_TORNIQUETES)
            print("HUMANOS A ENTRAR ", len(humanosAEntrar))
            time.sleep(5)
            for puerta in self.puertas:
                puerta.cerrada = False
                self.contador = 0
            pintarHumanos(self,
                          self.random.randint(MIN_H_LLEGANDO_VAGON,
                                              MAX_H_LLEGANDO_VAGON),
                          True)  #Humanos aleatorio que aparecen en el vagon
        elif self.contador == TIMERCERRAR and not self.puertas[0].cerrada:

            for puerta in self.puertas:
                puerta.cerrada = True
                self.contador = 0
        elif self.contador == TIMERCERRAR - 1 and not self.puertas[0].cerrada:
            humanosEntraron = self.obtenerHumanosEnRango(
                GRID_INICIAL_X, GRID_FINAL_X, GRID_INICIAL_Y + 1, YMURO_TREN)
            humanosNoEntraron = self.obtenerHumanosEnRango(
                GRID_INICIAL_X, GRID_FINAL_X, YMURO_TREN, YMURO_TORNIQUETES)
            print("HUMANOS QUE ENTRARON ", len(humanosEntraron))
            print("HUMANOS QUE NO ENTRARON", len(humanosNoEntraron))
            time.sleep(5)
        # if self.contador == self.timer:
        #     for puerta in self.puertas:
        #         puerta.cerrada =  not puerta.cerrada
        #     if self.timer == 10:
        #         self.timer = 9
        #     elif self.timer == 9:
        #         self.timer = 10
        #     pintarHumanos(self, self.random.randint(30,50), True)
        #     self.contador = 0
        print("Los humanos que han entrado por los torniquetes son ",
              self.humanosEntraronTorniquetes)
        print("Los humanos que han salido por los torniquetes son ",
              self.humanosSalieronTorniquetes)
        print("Los Humanos que han entrado al vagon son ",
              self.humanosEntraronVagon)
        print("Los Humanos que han salido del vagon son ",
              self.humanosSalieronVagon)
        print("---- End of tick ----")

    def getTorniquetesEntrada(self):
        #return [(),(),()]
        return self.posTorniquetesEntrada

    def getPuertas(self):
        #return [(),(),()]
        return self.posPuertas

    def getUInteriores(self):
        return self.posUInteriores

    def getTorniquetesSalida(self):
        return self.posTorniquetesSalida

    def obtenerHumanosEnRango(self, xinicial, xfinal, yinicial, yfinal):
        totalHumanos = []
        for x in range(xinicial, xfinal + 1):
            for y in range(yinicial, yfinal):
                pos = (x, y)
                humanos = self.grid.get_neighbors(pos,
                                                  moore=True,
                                                  include_center=True,
                                                  radius=0)
                humanos = [
                    x for x in humanos
                    if type(x) is Humano and x.direccion == True
                ]
                if len(humanos) > 0:
                    totalHumanos = totalHumanos + humanos
        return totalHumanos