Beispiel #1
0
 def __init__(self, N):
     self.num_agents = N
     self.schedule = mt.RandomActivation(self)
     # create and add agents
     for i in range(self.num_agents):
         a = MoneyAgent(i, self)
         self.schedule.add(a)
Beispiel #2
0
    def __init__(self, num_agents, graph_spec, init_wealth, default_policy, default_eps):
        self.num_agents = num_agents
        self.agent_init_wealth = init_wealth
        self.running = True
        
        if type(graph_spec) == nx.classes.graph.Graph:
            self.graph = ms.NetworkGrid(graph_spec)
        elif type(graph_spec) == str:
            self.graph = ms.NetworkGrid(nx.readwrite.read_gexf(graph_spec))
        self.schedule = mt.RandomActivation(self)

        # create and add agents 
        for aid in range(self.num_agents):
            # select a graph node
            position = list(self.graph.G.nodes)[rnd.choice(range(len(list(self.graph.G.nodes))))]
            # create an agent
            agent = BaseParrondoAgent(aid, self, position, default_policy, default_eps)
            # add it to the scheduler
            self.schedule.add(agent)
            # assign it to a location
            self.graph.place_agent(agent, position)

        # add data collector
        self.datacollector = md.DataCollector(
            model_reporters = {"Total wealth": indicators.total_wealth, 
                               "Mean wealth": indicators.mean_wealth,
                               "Median wealth": indicators.median_wealth,
                               },
            agent_reporters = {"Wealth": "wealth"}
            )
Beispiel #3
0
    def __init__(self, width):
        self.running = True
        self.num_agents = width
        self.schedule = mt.RandomActivation(self)
        self.grid = ms.NetworkGrid(
            nx.grid_graph(dim=[self.num_agents], periodic=False))
        self.x = [(x) for x in range(self.num_agents)]

        self.datacollector = md.DataCollector(
            model_reporters={
                'Average opinion': vote_result,
                'Agent opinions': individual_votes
            },
            agent_reporters={'Opinion': 'opinion'})

        for uid in range(self.num_agents):
            a = Sznajd1DAgent(uid, self)
            self.schedule.add(a)
            self.grid.place_agent(a, self.x[uid])
Beispiel #4
0
    def __init__(self, N, width, height):
        self.num_agents = N
        self.running = True
        self.grid = ms.MultiGrid(width, height, True)
        self.schedule = mt.RandomActivation(self)

        # create and add agents
        for i in range(self.num_agents):
            # create an agent
            a = MoneyAgent(i, self)
            # add it to the scheduler
            self.schedule.add(a)
            # assign it to a location
            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)
            self.grid.place_agent(a, (x,y))

        # add data collector
        self.datacollector = md.DataCollector(
            model_reporters = {"Gini": indicators.gini_index},
            agent_reporters = {"Wealth": "wealth"}
            )
Beispiel #5
0
    def __init__(self, N, width, height, temptation):
        self.num_agents = N
        self.running = True
        self.grid = ms.MultiGrid(width, height, True)
        self.schedule = mt.RandomActivation(self)
        self.temptation = temptation

        # create and add agents
        for i in range(self.num_agents):
            # create an agent
            a = PDAgent(i, self, temptation)
            # add it to the scheduler
            self.schedule.add(a)
            # assign it to a location
            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)
            self.grid.place_agent(a, (x,y))

        # add data collector
        self.datacollector = md.DataCollector(
            model_reporters = {"Defectors_rate": defectors_rate},
            agent_reporters = {"Strategy": "strategy"}
            )
Beispiel #6
0
    def __init__(self,
                 positions_per_level,
                 actor_retire_probs,
                 vac_trans_prob_mat,
                 dismissal_schedule,
                 growth_orders,
                 shrink_orders,
                 level_addition,
                 level_removal,
                 start_fract_attr,
                 prob_attr_per_step,
                 vac_ben_def_mat,
                 data_collector,
                 shock_step=0,
                 vac_move_period=0):
        """
        :param positions_per_level: list of ints, of positions per level
                                    e.g. [10,20,30] == 10 positions in level 1, 20 in level 2, 30 in level 3

        :param actor_retire_probs: list of ints, the per-actor, per actor-step probability of retirement, for each
                                   level. E.g. with [0.3, 0,1, 0.4], each actor in level 1 has a probability of
                                   0,3 of retiring, each actor-step

        :param vac_trans_prob_mat: list of lists, where each sublist is a row of a transition probability
                                          matrix. The vacancy transition probability matrix is a NxN+1 matrix;
                                          N=number of levels and the last column indicates the probability of a vacancy
                                          retiring, i.e. of calling in an actor from outside the system. If e.g. N=3:

                                                      Level 1     Level 2     Level 3     Retire
                                          Level 1    [[0.3,         0.4,        0.1,        0.2],
                                          Level 2     [0.1,         0.4,        0.4,        0.1],
                                          Level 3     [0.05,        0.05,       0.2,        0.7]]

                                          Some example of interpretations are "a vacancy in level 1 has a 0.4
                                          probability of moving within level 1", or "a vacancy in level 3 has a
                                          probability of 0.1 to retire" or "a vacancy in level 3 has a probability of
                                          0.3 to move to level 2".
                                          NB: rows must sum to 1.
                                          NB: this code assumes that higher rows represent higher levels in the
                                          hierarchy, so level 1 > 2 > 3
                                          Further details on vacancy movements can be found in entity.vacancy.step

        :param dismissal_schedule: dict, indicating how actors' retirement probabilities should be changed at the
                                   specified actor-steps. So, e.g. {5: [0.4, 0.4, 0.6], 6: [0.2, 0.2, 0.4]} means that
                                    at actor-step five the retirement probabilities of actors in levels 1, 2, and 3 will
                                    be 0.4, 0.4, and 0.6 (respectively), and at actor-step 6 the retirement
                                    probabilities of actors in levels 1, 2, and 3 will be 0.2, 0.2, and 0.4,
                                    respectively. Besides step five and step six we use the actor retirement
                                    probabilities given by actor_retire_probs.

        :param growth_orders: dict, indicating how many positions should be added to different levels, at the specified
                              actor-steps. So, e.g. {20: [10, 50, 150], 40: [5, 5, 0]} means that at actor-step twenty
                              we will add ten new positions in level one, fifty new positions in level two, and one
                              hundred and fifty new positions in level three. while at step forty we add five positions
                              each to levels one and two. Besides step twenty and forty we do not increase the size of
                              the system.

        :param shrink_orders: dict, indicating how many positions should be removed from different levels, at the
                              specified actor-steps. So, e.g. {12: [4, 20, 13], 77: [1, 0, 40]} means that at
                              actor-step twelve we remove remove four positions from level 1, twenty positions from
                              level two, and thirteen positions from level three, while at actor-step seventy-seven we
                              remove one position from level one, leave level two as is, and remove forty posotions from
                              level three. Besides step twelve and seventy-seven we do not decrease the size of the
                              system.

        :param level_addition: dict, indicating: the step at which we want to add a new level, the new level's position
                               within the existing hierarchy (e.g. top, or second-to-last), how many positions will be
                               in the new level, updated actor retirement and vacancy transition probabilities for the
                               whole system -- these last two are in the same format as when we initially parametrise
                               the model, albeit with larger shape to accommodate the new level.
                               NB: assume that we only add one level at one step, i.e. does not accommodate adding
                                   multiple levels, either at once or in several steps. This limitation reflects the
                                   extreme rarity and significance of level additions in real systems.

        :param level_removal: dict, indicating: the step at which we want to remove an existing level, the old level's
                              position within the existing hierarchy (e.g. top, or second-to-last), and updated actor
                              retirement and vacancy transition probabilities for the whole system -- these last two are
                              in the same format as when we initially parametrise the model, albeit with smaller shape
                              to accommodate the level loss.
                              NB: assume that we only add one level at one step, i.e. does not accommodate adding
                                  multiple levels, either at once or in several steps. This limitation reflects the
                                  extreme rarity and significance of level additions in real systems.

        :param start_fract_attr: float, gender ratio with which we initialise actors at the beginning of the model,
                                     e.g. 0.6 means that at model initialisation sixty percent of all actors are female

        :param prob_attr_per_step: dict, indicating the probability that an actor called from the outside by
                                           a vacancy retirement will be female, at the designated actor steps. So,
                                           e.g. {20: 0.6, 21: 0.7, 22: 0.7} means that at actor step twenty each
                                           newly-called actor has a probability of 0.6 of being female, while at each
                                           of actor steps twenty-one and twenty-two each newly-called actor has a
                                           probability of 0.7 of being female.
                                           NB: this dict must be defined for ALL actor-steps of the model

        :param vac_ben_def_mat: changes in some unit associated with vacancy movements. E.g. this matrix

                                               [[1, 2, 3, 4],
                                                [-1, 3, 4, 5],
                                                [-2, -1, 5, 6]]

                                               refers to changes in a family's utility as it moves up or down the
                                               "niceness" scale of housing: moves up increase utility, moves down
                                               decrease it.

        :param data_collector: dict, indicating the data collector functions that harvest measures from the model.
                               Has form {"title_of_data_collector":name_of_collector_function"}.
                               NB: data collector functions live in collectors.py

        :param shock_step: int, an actor-step at which a shock of particular note occurs, e.g. a major system expansion.
                           By default shock_step == 0.

        :param vac_move_period: int, the number of model steps that we give vacancies to work their way out of the
                                    system. The classic, simplest formulation of vacancy chain analysis assumed that
                                    vacancies make their way out of the system within some natural time unit, like a
                                    year, which here is operationalised as the "actor-step". In model terms, the
                                    vacancy_move_period is the number of model steps BETWEEN actor steps; only vacancies
                                    are allowed to move in these "vacancy steps" and only actors can move during "actor
                                    steps". By default this is 0, i.e. vacancies move as often as actors.
                                    NB: adjust this number by consulting collectors.get_count_vacancies_still_in_system

        """
        super().__init__()
        # set parameters
        self.num_levels, self.positions_per_level = len(
            positions_per_level), positions_per_level
        self.dismissal_schedule = dismissal_schedule
        self.shrink_orders, self.growth_orders = shrink_orders, growth_orders
        self.level_addition, self.level_removal = level_addition, level_removal
        self.start_fract_attr, self.prob_attr_per_step = start_fract_attr, prob_attr_per_step
        self.act_ret_probs, self.vac_trans_prob_mat = actor_retire_probs, vac_trans_prob_mat
        self.vac_trans_mat_num_cols = len(vac_trans_prob_mat[0])
        self.vac_ben_def_mat = vac_ben_def_mat
        self.data_collector = DataCollector(model_reporters=data_collector)
        self.shock_step, self.vac_mov_period = shock_step, vac_move_period

        # define the scheduler
        self.schedule = time.RandomActivation(self)

        # make a container for retired moving agents, i.e. those actors and vacancies that have left the system
        self.retirees = {"actor": [], "vacancy": []}

        # initialise system: make positions and occupy them with actors; all starting positions are actor-occupied
        # NB: levels and positions are 1-indexed
        self.positions = {}
        for lvl in range(self.num_levels):
            for spot in range(self.positions_per_level[lvl]):
                self.create_position(
                    lvl + 1, spot + 1,
                    "actor")  # +1 in order to 1-index the positions codes