Beispiel #1
0
class TDISModel(Model):
    """A model with some number of agents."""

    def __init__(self, graph):
        self.Graph = graph
        self.schedule = StagedActivation(self, ["step", "selectNextCooperation", "selectNextActive"])
        # Create agents
        for i in self.Graph.NodeList:
            cooperationInit = random.choice(['C', 'D'])
            if cooperationInit == 'C':
                trustfulInit = 1
            else:
                trustfulInit = 0
            activeInit = random.choice([0, 1])
            neighborListInit = self.Graph.neighbor(i)
            a = TDISAgent(i, trustfulInit, activeInit, cooperationInit, 2, neighborListInit, self)
            self.schedule.add(a)

        self.datacollector = DataCollector(
            model_reporters={"trust": compute_trust_porportion,"active":compute_Active_porportion},
            agent_reporters={"Score": "Score"})

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
Beispiel #2
0
class EF_Model(Model):
    def __init__(self,
                 N,
                 threshold,
                 memory_size,
                 nb_strategies,
                 width,
                 height,
                 type_network=None,
                 param_network=None):
        self.num_agents = N

        self.G = nx.Graph()
        self.memory_size = memory_size
        self.threshold = threshold
        self.constant = 0
        self.bar_location = (5, 5)

        self.initial_history = [
            random.randint(0, self.num_agents) for i in range(self.memory_size)
        ]
        self.grid = MultiGrid(width, height, True)
        self.schedule = StagedActivation(self, ['evaluate', 'decide'])
        self.running = True
        #set history n-values (memory-size * 2) [random 100]
        #check model reporters if they can be accessed by agents: dictionnary

        # Create agents

        for i in range(self.num_agents):
            #threshold=random threshold
            #memory=random memory size
            a = Attendee(i, self, nb_strategies)
            self.schedule.add(a)

            #add the condition that agents start at home: in this model, as there are no visuals, it doesn't really matter where they are as going to the bar is only defined by self.attend
            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))

            #Create the graph and links and neighborhood
            if type_network is not None:
                self.G.add_node(a)

        if type_network is not None:
            set_edges(self.G, type_network, param_network)

        #find the adjacent agents in the graph
        for ag in self.schedule.agents:
            ag.find_friends()

        self.datacollector = DataCollector(
            model_reporters={"Attendance": compute_attendance})

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
Beispiel #3
0
class MockModel(Model):
    def __init__(self, shuffle):
        self.log = []
        model_stages = ["stage_one", "stage_two"]
        self.schedule = StagedActivation(self, model_stages, shuffle=shuffle)

        # Make agents
        for name in ["A", "B"]:
            agent = MockStagedAgent(name)
            self.schedule.add(agent)

    def step(self):
        self.schedule.step()
Beispiel #4
0
class MockModel(Model):
    def __init__(self, shuffle):
        self.log = []
        model_stages = ["stage_one", "stage_two"]
        self.schedule = StagedActivation(self, model_stages, shuffle=shuffle)

        # Make agents
        for name in ["A", "B"]:
            agent = MockStagedAgent(name)
            self.schedule.add(agent)

    def step(self):
        self.schedule.step()
Beispiel #5
0
class Experiment:
    def __init__(self, steps):
        self.steps = steps

    def setup_experiment(self,
                         student_count=10,
                         data_collector=DataCollector(),
                         student_params={}):
        self.model = Course()
        gen = Student_Generator(self.model, student_params)
        self.agents = gen.generate_students(self.model, student_count)
        self.schedule = StagedActivation(
            self.model, stage_list=['step', 'interact', 'finish'])
        self.schedule.agents = self.agents
        self.model.schedule = self.schedule
        self.data_collector = data_collector

    def run_experiment(self):
        while self.schedule.steps < self.steps:
            self.schedule.step()
            self.model.step()
            self.data_collector.collect(self.model)
Beispiel #6
0
class BIDModel(Model):
    """A model with some number of agents."""

    def __init__(self, alpha, teta, uncertaintyL, uncertaintyU, graph, ActiveInit):
        self.Graph = graph
        self.schedule = StagedActivation(self, ["step", "selectNextActive"])
        self.Alpha = alpha
        self.Teta = teta
        self.uncertaintyL = uncertaintyL
        self.uncertaintyU = uncertaintyU
        self.Active = ActiveInit
        activeInit = np.random.choice([0, 1], len(self.Graph.NodeList), p=[1 - self.Active, self.Active])
        # Create agents
        for i in self.Graph.NodeList:

            if activeInit[i] == 1:
                beliefInit = random.randint(0, 1)
            else:
                beliefInit = random.randint(-1, 0)

            neighborListInit = self.Graph.neighbor(i)
            a = BIDAgent(i, beliefInit, activeInit[i], 0, neighborListInit, self.Alpha,
                         self.Teta, self.uncertaintyL, self.uncertaintyU,
                         self)
            self.schedule.add(a)

        self.datacollector = DataCollector(
            model_reporters={"BeliefCount": compute_Belief_porportion,
                             "DisbeliefCount": compute_Disbelief_porportion,
                             "UncertainCount": compute_Uncertain_porportion,
                             "active": compute_Active_porportion}
            , agent_reporters={"Belief": "Belief"})

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
Beispiel #7
0
class CityModel(Model):
    def __init__(self, N=2, PassengerPooling=.5, PassengerPopulation=.2, PassengerBlocks={}, width=20, height=10, city_map=[], roads={}, city_blocks=[], routes={}):
        super().__init__()
        self.N = N    # num of cabs
        self.grid = MultiGrid(width, height, torus=False)
        
        model_stages = ['stage_1', 'stage_2', 'stage_3', 'stage_4', 'step']

        self.schedule = StagedActivation(self, model_stages, shuffle=True)
        self.roads = roads
        self.routes = routes
        self.passenger_blocks = PassengerBlocks
        self.unique_id_counter = 0
        self.city_blocks = city_blocks
        self.passenger_population = PassengerPopulation
        self.passenger_pooling = PassengerPooling
        self.max_seats = 3

        #Bidding properties
        self.current_bidding_results = {}
        self.all_biddings = {}

        
        self.datacollector = DataCollector(model_reporters={
                                           "Normal Passenger": get_average_time_normal_passenger,
                                           "Pooling Passenger": get_average_time_pooling_passenger,
                                           "Average": get_average_time_all_passenger,
                                           "Cars carpooling": get_count_cars_carpooling,
                                           "Cars not carpooling": get_count_cars_not_carpooling,
                                           "Empty cars": get_count_cars_empty,
                                           "Passengers Travelling (not pooling)": get_count_passengers_not_pooling_travelling,
                                           "Passengers Travelling (pooling)": get_count_passengers_pooling_travelling,
                                           "Passengers Travelling": get_count_passengers_travelling,
                                           "Overtravelled (in percentage)": get_average_perc_over_travelled_pool_passengers})

        self.fill_blocks_agents()

        self.make_taxi_agents()
        self.addPassengers()

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

    def clear_biddings(self):
        self.current_bidding_results = None
        self.all_biddings = {}

    def update_winners(self):
        #Check if it is the first time being called
        if (self.current_bidding_results == None):
            self.current_bidding_results = {}

            if (len(self.all_biddings) == 0):
                return
        
            passenger_assignment = {}

            number_of_cabs_bidding = len(self.all_biddings)
            first_cab = next(iter(self.all_biddings.keys()))

            passengers_being_bidded = set()

            for cab in self.all_biddings.keys():
                for psg in self.all_biddings[cab].keys():
                    passengers_being_bidded.add(psg)

            number_of_passengers = len(passengers_being_bidded)

            while(len(passenger_assignment) < number_of_cabs_bidding and len(passenger_assignment) < number_of_passengers):
                passengers_all_distances = {}
                passenger_assignment_temp = {}
                for cab in self.all_biddings.keys():
                    if (cab not in passenger_assignment.values()):
                        for psg in passengers_being_bidded:
                            if (psg not in passenger_assignment.keys()):
                                cab_bidding_for_this_pass = psg in self.all_biddings[cab].keys()
                                
                                if(cab_bidding_for_this_pass):
                                    pass_dist = self.all_biddings[cab][psg]
                                else:
                                    pass_dist = math.inf

                                if(psg not in passengers_all_distances or passengers_all_distances[psg] > pass_dist):
                                    passengers_all_distances[psg] = pass_dist
                                    passenger_assignment_temp[psg] = cab if cab_bidding_for_this_pass else None

                #order the passengers by the distance to the closest cab
                passengers_all_distances = sorted(passengers_all_distances.items(), key=lambda kv: kv[1])

                #get the passenger who has the closest cab
                passenger = passengers_all_distances[0][0]
                #get the cab
                cab = passenger_assignment_temp[passenger]

                passenger_assignment[passenger] = cab

            self.current_bidding_results = passenger_assignment

    def bid(self, cab, passengers_offers):
        self.all_biddings[cab] = passengers_offers

    def fill_blocks_agents(self):
        for block in self.city_blocks:
            agent = Grass(self.unique_id_counter, self, block[0], block[1])
            self.schedule.add(agent)
            self.grid.place_agent(agent, block[0])

            self.unique_id_counter = self.unique_id_counter + 1

    def make_taxi_agents(self):
        r = random.SystemRandom()
        for _ in range(self.N):
            possible_places = list(self.roads.keys())
            r.shuffle(possible_places)
            pos = possible_places[0]

            agent = Cab(self.unique_id_counter, self, pos, (1, 0))
            self.schedule.add(agent)
            self.grid.place_agent(agent, pos)
            self.unique_id_counter = self.unique_id_counter + 1

    def step(self):

        self.addPassengers()
        
        self.clear_biddings()

        self.schedule.step()
        self.datacollector.collect(self)

    def addPassengers(self):
        passengers_waiting = [agent.pos for agent in self.schedule.agents if isinstance(agent, Passenger)]
        
        free_spot = list(set(self.passenger_blocks.keys()) - set(passengers_waiting))
        r = random.SystemRandom()
        r.shuffle(free_spot)

        destinations = set(self.passenger_blocks.keys())

        while(len(free_spot)> 0 and \
              (len(passengers_waiting)/len(self.passenger_blocks) < self.passenger_population)):
            
            pos = free_spot.pop(0)

            possible_destinations = list(destinations - set([pos]))
            destination = self.random.choice(possible_destinations)

            #Just to find another position wich has a road block different from
            # the current passenger 
            while(self.passenger_blocks[destination] == self.passenger_blocks[pos]):
                destination = self.random.choice(possible_destinations)

            isCarPooler = random.random() < self.passenger_pooling
            passenger = Passenger(self.unique_id_counter, self, pos, self.passenger_blocks[destination], self.passenger_blocks[pos], isCarPooler)
            self.schedule.add(passenger)
            
            self.grid.place_agent(passenger, pos)
            self.unique_id_counter = self.unique_id_counter + 1

            passengers_waiting.append(pos)
Beispiel #8
0
class HometimeModel(Model):
    """This is a model that allows simulation of secondary school children to
    commute home from school and/or stop off at restaurants"""
    def __init__(self,
                 db_connection,
                 N=100,
                 width=100,
                 height=100,
                 school_x_pos=50,
                 school_y_pos=50):
        """Makes the new model

        Arguments
        =========
        - N - number of agents, default: 100
        - width - the width of grid, default: 100
        - height - height of grid, default: 100
        """
        self.num_agents = N
        model_stages = ["stage_one", "stage_two"]
        self.schedule = StagedActivation(self, model_stages, True)

        self.restaurants = get_all_restaurants(db_connection)
        self.school_x_pos = school_x_pos
        self.school_y_pos = school_y_pos

        self.decay = 0.2

        # this is true when the weather is good, false otherwise
        self.good_weather = True

        for i in range(0, self.num_agents):
            id = i
            model = self

            # Generate weather weight as Normal distribution
            # Mean - 0.5. SD - 0.25
            weather_weight = np.random.normal(0.5, 0.25)

            # Generate likelihood to eat out as Normal distribution
            # Mean - 0.5. SD - 0.25
            likelihood_to_eat_out = np.random.normal(0.5, 0.25)
            likelihood_to_eat_out_weight = 1.0

            # Randomizes likability for each restaurant
            restaurant_likability = {}
            for restaurant in self.restaurants:
                restaurant_name = restaurant[0]
                restaurant_likability[restaurant_name] = np.random.normal(
                    0.5, 0.25)

            restaurant_likability_weight = 1.0

            # Previous visit values
            previous_visits = {}
            for restaurant in self.restaurants:
                restaurant_name = restaurant[0]
                previous_visits[restaurant_name] = 0

            previous_visit_weight = 1.0

            home_x_pos = np.random.uniform(0, width)
            home_y_pos = np.random.uniform(0, height)

            distance_weight = np.random.normal(-0.5, 0.25)

            agent = HometimeAgent(
                id, model, weather_weight, likelihood_to_eat_out,
                likelihood_to_eat_out_weight, restaurant_likability,
                restaurant_likability_weight, previous_visits,
                previous_visit_weight, home_x_pos, home_y_pos, distance_weight)
            self.schedule.add(agent)

        self.running = True

        self.datacollector = DataCollector(
            agent_reporters={"Last Choice": "last_choice"},
            model_reporters={"Good weather": "good_weather"})

    def step(self):
        self.datacollector.collect(self)
        # change the weather
        if random() < config.percentage_bad_weather:
            self.good_weather = False
        else:
            self.good_weather = True

        self.schedule.step()
Beispiel #9
0
class ReputationSim(Model):
    def __init__(self, study_path='study.json', opened_config=False):

        if opened_config:
            config = study_path
        else:
            with open(study_path) as json_file:
                config = json.load(json_file, object_pairs_hook=OrderedDict)

        #save the config with the output

        self.transaction_numbers = []
        transaction_number = 0
        # print(json.dumps(config['ontology'], indent=2))
        self.parameters = config['parameters']
        super().__init__(self.parameters['seed'])

        self.time = dt.datetime.now().isoformat()
        #filename = self.parameters['output_path'] + 'params_' + self.parameters['param_str'] + self.time[0:10] + '.json'
        filename = self.parameters['output_path'] + 'params_' + self.parameters[
            'param_str'][:-1] + '.json'

        pretty = json.dumps(config, indent=2, separators=(',', ':'))
        with open(filename, 'w') as outfile:
            outfile.write(pretty)
        outfile.close()
        self.transaction_report = self.transaction_report()
        self.seconds_per_day = 86400

        tuplist = [
            (good, [])
            for good, chance in self.parameters["chance_of_supplying"].items()
        ]
        self.suppliers = OrderedDict(tuplist)

        tuplist = [(good, []) for good, chance in
                   self.parameters["criminal_chance_of_supplying"].items()]
        self.criminal_suppliers = OrderedDict(tuplist)

        self.initial_epoch = self.get_epoch(self.parameters['initial_date'])
        self.final_epoch = self.get_epoch(self.parameters['final_date'])
        self.next_transaction = 0
        self.end_tick = self.get_end_tick()
        self.goodness_distribution = self.get_truncated_normal(
            *tuple(self.parameters['goodness']))
        self.fire_supplier_threshold_distribution = self.get_truncated_normal(
            *tuple(self.parameters['fire_supplier_threshold']))
        self.forget_discount_distribution = self.get_truncated_normal(
            *tuple(self.parameters['forget_discount']))
        self.criminal_transactions_per_day_distribution = self.get_truncated_normal(
            *tuple(self.parameters['criminal_transactions_per_day']))
        self.transactions_per_day_distribution = self.get_truncated_normal(
            *tuple(self.parameters['transactions_per_day']))
        self.criminal_agent_ring_size_distribution = self.get_truncated_normal(
            *tuple(self.parameters['criminal_agent_ring_size']))
        self.open_to_new_experiences_distribution = self.get_truncated_normal(
            *tuple(self.parameters['open_to_new_experiences']))
        self.criminal_goodness_distribution = self.get_truncated_normal(
            *tuple(self.parameters['criminal_goodness']))
        self.rating_perception_distribution = self.get_truncated_normal(
            *tuple(self.parameters['rating_perception']))
        self.cobb_douglas_distributions = {
            good: self.get_truncated_normal(*tuple(statlist))
            for good, statlist in
            self.parameters['cobb_douglas_utilities'].items()
        }
        self.price_distributions = {
            good: self.get_truncated_normal(*tuple(statlist))
            for good, statlist in self.parameters['prices'].items()
        }
        self.need_cycle_distributions = {
            good: self.get_truncated_normal(*tuple(statlist))
            for good, statlist in self.parameters['need_cycle'].items()
        }
        self.criminal_need_cycle_distributions = {
            good: self.get_truncated_normal(*tuple(statlist))
            for good, statlist in
            self.parameters['criminal_need_cycle'].items()
        }

        #this stage_list facilitiates ten different time periods within a day for trades
        stage_list = [
            'step', 'choose_partners', 'choose_partners', 'choose_partners',
            'choose_partners', 'choose_partners', 'choose_partners',
            'choose_partners', 'choose_partners', 'choose_partners',
            'choose_partners'
        ]

        self.schedule = StagedActivation(self,
                                         stage_list=stage_list,
                                         shuffle=True,
                                         shuffle_between_stages=True)

        # Create agents
        agent_count = 0

        if self.parameters['deterministic_mode']:
            num_criminals = math.ceil(self.parameters['num_users'] *
                                      self.parameters['chance_of_criminal'])

            # nsuppliers = {good:int(self.parameters['num_users']*chance
            #                       ) for good, chance in self.parameters['chance_of_supplying'].items()}

            # First get the number of suppliers that is to be had in the scenario, by adding up all of the
            # chances of being a supplier , and then taking the percent of the total, flooring with an int again
            # then create a dict for how many of each supplier there are.  then, go through the agents designated
            # as good and assing suppliers, starting from the highest likelihood down to the lowest
            # these are for the good agents. The bad agents go by another algorithm of what they supply, that is
            # related to the price

            #criminal suppliers
            chance_of_supplier = 0
            for good, chance in self.parameters[
                    'criminal_chance_of_supplying'].items():
                chance_of_supplier += chance

            num_suppliers1 = round(num_criminals * chance_of_supplier)
            sorted_suppliers = sorted(
                self.parameters['criminal_chance_of_supplying'].items(),
                key=lambda x: x[1],
                reverse=True)

            sup_count = 0
            nsuppliers = OrderedDict()
            for good, chance in sorted_suppliers:
                if sup_count < num_suppliers1:
                    rounded = round(num_suppliers1 * chance)
                    num_sup_this_good = rounded if rounded > 0 else 1
                    num_sup_this_good = min(num_sup_this_good,
                                            (num_suppliers1 - sup_count))
                    sup_count = sup_count + num_sup_this_good
                    nsuppliers[good] = num_sup_this_good

            for good, num_suppliers in nsuppliers.items():
                for _ in range(num_suppliers):
                    a = globals()['ReputationAgent'](agent_count,
                                                     self,
                                                     criminal=True,
                                                     supply_list=[good])
                    self.schedule.add(a)
                    self.criminal_suppliers[good].append(agent_count)
                    agent_count += 1

            #criminal consumers
            for _ in range(num_criminals - num_suppliers1):
                a = globals()['ReputationAgent'](agent_count,
                                                 self,
                                                 criminal=True,
                                                 supply_list=[])
                self.schedule.add(a)
                agent_count += 1

            #good suppliers
            chance_of_supplier = 0
            for good, chance in self.parameters['chance_of_supplying'].items():
                chance_of_supplier += chance

            num_suppliers1 = round(
                (self.parameters['num_users'] - num_criminals) *
                chance_of_supplier)
            sorted_suppliers = sorted(
                self.parameters['chance_of_supplying'].items(),
                key=lambda x: x[1],
                reverse=True)

            sup_count = 0
            nsuppliers = OrderedDict()
            for good, chance in sorted_suppliers:
                if sup_count < num_suppliers1:
                    rounded = round(num_suppliers1 * chance)
                    num_sup_this_good = rounded if rounded > 0 else 1
                    num_sup_this_good = min(num_sup_this_good,
                                            (num_suppliers1 - sup_count))
                    sup_count = sup_count + num_sup_this_good
                    nsuppliers[good] = num_sup_this_good

            for good, num_suppliers in nsuppliers.items():
                for _ in range(num_suppliers):
                    a = globals()['ReputationAgent'](agent_count,
                                                     self,
                                                     criminal=False,
                                                     supply_list=[good])
                    self.schedule.add(a)
                    agent_count += 1

            #good consumers
            for i in range(agent_count, self.parameters['num_users']):
                a = globals()['ReputationAgent'](agent_count,
                                                 self,
                                                 criminal=False,
                                                 supply_list=[])
                self.schedule.add(a)
                agent_count += 1

        else:
            for _ in range(self.parameters['num_users']):
                a = globals()['ReputationAgent'](agent_count, self)
                self.schedule.add(a)
                agent_count += 1

        self.print_agent_goodness()

    def get_end_tick(self):
        #final_tick = (final_epoch - initial_epoch) / (days / tick * miliseconds / day)

        secs = self.final_epoch - self.initial_epoch
        final_tick = secs / (self.parameters['days_per_tick'] *
                             self.seconds_per_day)
        return final_tick

    def transaction_report(self):
        #path = self.parameters['output_path'] + 'transactions_' +self.parameters['param_str'] + self.time[0:10] + '.tsv'
        path = self.parameters[
            'output_path'] + 'transactions_' + self.parameters[
                'param_str'][:-1] + '.tsv'
        file = open(path, "w")
        return (file)

    def get_epoch(self, date_time):
        #date_time = '29.08.2011 11:05:02'
        pattern = '%d.%m.%Y %H:%M:%S'
        epoch = int(time.mktime(time.strptime(date_time, pattern)))
        return epoch

    def get_next_transaction(self):
        if not self.transaction_numbers:
            self.transaction_numbers = list(range(0, 10000))
            shuffle(self.transaction_numbers)
        self.next_transaction = self.transaction_numbers.pop()
        return self.next_transaction

    def print_transaction_report_line(self,
                                      from_agent,
                                      to_agent,
                                      payment,
                                      tags,
                                      payment_unit='',
                                      parent='',
                                      rating='',
                                      type='payment'):
        time = (self.schedule.time * self.parameters['days_per_tick'] *
                self.seconds_per_day) + self.initial_epoch
        time = int(time + random.uniform(0, self.seconds_per_day / 10))

        network_val = self.parameters['network']
        timestamp_val = time
        type_val = type
        from_val = from_agent
        to_val = to_agent
        value_val = rating if rating else payment
        unit_val = '' if rating else payment_unit
        parent_val = self.get_next_transaction() if rating else parent
        child_val = self.get_next_transaction()
        title_val = ''
        input_val = ''
        tags_val = tags
        format_val = ''
        block_val = ''
        parent_value_val = payment if rating else ''
        parent_unit_val = payment_unit if rating else ''

        self.transaction_report.write(
            "{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\t{13}\t{14}\t{15}\n"
            .format(network_val, timestamp_val, type_val, from_val, to_val,
                    value_val, unit_val, child_val, parent_val, title_val,
                    input_val, tags_val, format_val, block_val,
                    parent_value_val, parent_unit_val))

        #self.transaction_report.flush()

    def print_agent_goodness(self, userlist=[-1]):
        #output a list of given users, sorted by goodness.  if the first item of the list is -1, then output all users

        #path = self.parameters['output_path'] + 'users_' + self.parameters['param_str'] + self.time[0:10] + '.tsv'
        path = self.parameters['output_path'] + 'users_' + self.parameters[
            'param_str'][:-1] + '.tsv'

        with open(path, 'w') as outfile:
            agents = self.schedule.agents if userlist and userlist[
                0] == -1 else userlist
            outlist = [(agent.unique_id, agent.goodness) for agent in agents]
            sorted_outlist = sorted(outlist,
                                    key=operator.itemgetter(1),
                                    reverse=True)
            for id, goodness in sorted_outlist:
                outfile.write("{0}\t{1}\n".format(id, goodness))
        outfile.close()

    def get_truncated_normal(self, mean=0.5, sd=0.2, low=0, upp=1.0):
        rv = truncnorm((low - mean) / sd, (upp - mean) / sd,
                       loc=mean,
                       scale=sd)
        return rv

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

    def go(self):
        while self.schedule.time < self.get_end_tick():
            self.step()
        self.transaction_report.close()
Beispiel #10
0
class TotC(Model):
    """
    Main model for the tragedy of the commons
    """
    def __init__(self,
                 initial_herdsmen=5,
                 initial_sheep_per_herdsmen=0,
                 initial_edges=5,
                 l_coop=0,
                 l_fairself=0,
                 l_fairother=0,
                 l_negrecip=0,
                 l_posrecip=0,
                 l_conf=0):
        super().__init__()
        self.width = GRID_SIZE
        self.height = GRID_SIZE

        self.grass = []
        self.herdsmen = []
        self.initial_herdsmen = initial_herdsmen
        self.initial_sheep_per_herdsmen = initial_sheep_per_herdsmen
        self.sheep_survival_rate = []

        self.l_coop = l_coop
        self.l_fairself = l_fairself
        self.l_fairother = l_fairother
        self.l_negrecip = l_negrecip
        self.l_posrecip = l_posrecip
        self.l_conf = l_conf

        self.G = nx.gnm_random_graph(initial_herdsmen, initial_edges)

        Sheep.sheepdeaths = 0
        Herdsman.i = 0
        Herdsman.x = np.zeros(initial_herdsmen, dtype=np.int8)

        self.schedule_Grass = RandomActivation(self)
        self.schedule_Herdsman = StagedActivation(
            self, stage_list=["advance", "step"], shuffle=True)
        self.schedule_Sheep = RandomActivation(self)
        self.schedule = RandomActivation(self)

        self.grid = MultiGrid(self.width, self.height, torus=True)

        # "Grass" is the number of sheep that the grass can sustain
        self.datacollector = DataCollector({
            "Grass":
            lambda m: self.get_expected_grass_growth() / .5,
            "Sheep":
            lambda m: self.get_sheep_count(),
            "Sheep deaths":
            lambda m: Sheep.sheepdeaths
        })

        self.init_population()

        # required for the datacollector to work
        self.running = True
        self.datacollector.collect(self)

    def add_herdsman(self):
        """
        At a herdsman at a random position on the grid.
        """
        x = random.randrange(self.width)
        y = random.randrange(self.height)
        herdsman = self.new_agent(Herdsman, (x, y))
        self.herdsmen.append(herdsman)

    def init_grass(self):
        """
        Initialise a patch of grass at every square on the grid.
        """
        for agent, x, y in self.grid.coord_iter():
            self.grass.append(self.new_agent(Grass, (x, y)))

    def init_herdsman(self):
        """
        Spawn `initial_herdsmen' herdsmen on the field.
        """
        for i in range(getattr(self, "initial_herdsmen")):
            self.add_herdsman()

    def init_node_attr(self):
        """
        Assign the unique herdsman ID as attribute to graph nodes for the social
        network.
        """
        N = self.get_herdsman_count()
        for i in range(getattr(self, "initial_herdsmen")):
            for j in range(getattr(self, "initial_herdsmen")):
                if i is not j:
                    if nx.has_path(self.G, source=i, target=j) == True:
                        if nx.shortest_path_length(self.G, source=i,
                                                   target=j) == 1:
                            if sum(nx.common_neighbors(self.G, i, j)) > 5:
                                self.herdsmen[i].friendship_weights.append(1)
                            else:
                                self.herdsmen[i].friendship_weights.append(
                                    .75 + .05 *
                                    sum(nx.common_neighbors(self.G, i, j)))
                        elif nx.shortest_path_length(self.G,
                                                     source=i,
                                                     target=j) == 1:
                            if sum(nx.common_neighbors(self.G, i, j)) > 10:
                                self.herdsmen[i].friendship_weights.append(1)
                            else:
                                self.herdsmen[i].friendship_weights.append(
                                    .5 + .05 *
                                    sum(nx.common_neighbors(self.G, i, j)))
                        else:
                            self.herdsmen[i].friendship_weights.append(
                                1 / nx.shortest_path_length(
                                    self.G, source=i, target=j))
                    else:
                        self.herdsmen[i].friendship_weights.append(1 / N)

    def init_population(self):
        """
        Initialise grass, herdsmen, sheep, and the social network
        """
        self.init_grass()
        self.init_herdsman()
        self.init_node_attr()

    def get_expected_grass_growth(self):
        """
        Get an estimate of the expected grass growth for the next timestep. 
        If grass is fully grown it will return 0.0123 (the average grass growth
        over its lifetime.
        """
        return sum([
            grass.next_density() if grass.density < 0.99 else 0.0123
            for grass in self.grass
        ])

    def get_grass_count(self):
        """
        Get a sum of all grass densities.
        """
        return sum([grass.density for grass in self.grass])

    def get_herdsman_count(self):
        return self.schedule_Herdsman.get_agent_count()

    def get_sheep_count(self):
        return self.schedule_Sheep.get_agent_count()

    def new_agent(self, agent_type, pos):
        """
        Create new agent, and add it to the scheduler.
        """
        agent = agent_type(self.next_id(), self, pos)
        self.grid.place_agent(agent, pos)
        getattr(self, f"schedule_{agent_type.__name__}").add(agent)

        return agent

    def remove_agent(self, agent):
        """
        Remove agent from the grid and the scheduler.
        """
        self.grid.remove_agent(agent)
        getattr(self, f"schedule_{type(agent).__name__}").remove(agent)

    def run_model(self, step_count=200):
        """
        Runs the model for a specific amount of steps.
        """
        for i in range(step_count):
            self.step()

    def step(self):
        """
        Calls the step method for grass and sheep.
        """
        self.schedule_Grass.step()
        a = self.get_sheep_count()
        self.schedule_Sheep.step()
        b = self.get_sheep_count()
        c = b / a if a > 0 else 0
        self.sheep_survival_rate.append(c)
        self.schedule_Herdsman.step()
        self.schedule.step()

        # save statistics
        self.datacollector.collect(self)
Beispiel #11
0
class RoadModel(Model):
    """
    A model with a number of cars, Nagel-Schreckenberg
    """
    def __init__(self, N, length=100, lanes=1, timer=3):
        self.num_agents = N
        self.grid = SingleGrid(length, lanes, torus=True)
        model_stages = [
            "acceleration", "braking", "randomisation", "move", "delete"
        ]
        self.schedule = StagedActivation(self, stage_list=model_stages)

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

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

        self.running = True

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

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

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

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

        :param agent: The agents that gets deleted
        """
        # remove from schedule
        self.schedule.remove(agent)
        # remove from grid
        self.grid.remove_agent(agent)
Beispiel #12
0
class FestivalModel(Model):
    def __init__(self,
                 num_party: int = 20,
                 num_guard: int = 5,
                 num_trouble: int = 5,
                 num_celeb: int = 5,
                 num_hippie: int = 20,
                 learning=True,
                 pareto_fight=False,
                 pareto=False,
                 lucia=False):
        super().__init__()
        self.num_agents = num_party + num_guard + num_trouble + num_celeb + num_hippie
        self.num_party = num_party
        self.num_guard = num_guard
        self.num_trouble = num_trouble
        self.num_celeb = num_celeb
        self.num_hippie = num_hippie
        self.pareto = pareto
        self.pareto_fight = pareto_fight
        self.lucia = lucia

        self.schedule = StagedActivation(
            self, ['send_proposes', 'process_proposes', 'step', 'die'])
        self.space = ContinuousSpace(100, 100, False)
        self.datacollector = DataCollector(
            model_reporters={
                "Alive agents":
                lambda model: model.schedule.get_agent_count(),
                "Mean happiness":
                lambda model: np.mean([
                    a.happiness for a in filter(lambda x: x.type == 'guest',
                                                model.schedule.agents)
                ]),
                "Mean fullness":
                lambda model: np.mean([
                    a.fullness for a in filter(lambda x: x.type == 'guest',
                                               model.schedule.agents)
                ])
            })

        for i in range(self.num_party):
            x, y = np.random.rand(2) * 100
            a_ = PartyPerson('Party%d' % i, self, (x, y), learning)
            self.schedule.add(a_)
            self.space.place_agent(a_, (x, y))

        for i in range(self.num_guard):
            x, y = np.random.rand(2) * 100
            a_ = Guard('Guard%d' % i, self, (x, y), learning)
            self.schedule.add(a_)
            self.space.place_agent(a_, (x, y))

        for i in range(self.num_trouble):
            x, y = np.random.rand(2) * 100
            a_ = Troublemaker('Trouble%d' % i, self, (x, y), learning)
            self.schedule.add(a_)
            self.space.place_agent(a_, (x, y))

        for i in range(self.num_celeb):
            x, y = np.random.rand(2) * 100
            a_ = Celebrity('Celeb%d' % i, self, (x, y), learning)
            self.schedule.add(a_)
            self.space.place_agent(a_, (x, y))

        for i in range(self.num_hippie):
            x, y = np.random.rand(2) * 100
            a_ = Hippie('Hippie%d' % i, self, (x, y), learning)
            self.schedule.add(a_)
            self.space.place_agent(a_, (x, y))

        for x, y in ((x, y) for x in [40, 60] for y in [40, 60]):
            s_ = Store('StoreX%dY%d' % (x, y), self, (x, y))
            self.schedule.add(s_)
            self.space.place_agent(s_, (x, y))

        for x, y in ((x, y) for x in [20, 80] for y in [20, 80]):
            s_ = Stage('StageX%dY%d' % (x, y), self, (x, y))
            self.schedule.add(s_)
            self.space.place_agent(s_, (x, y))

        if lucia:
            x, y = 0, 0
            a_ = Lucia('Lucia%d' % i, self, (x, y), learning)
            self.schedule.add(a_)
            self.space.place_agent(a_, (x, y))

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

    def fight(self, agent1: Guest, agent2: Guest):
        assert self == agent1.model == agent2.model, "Can't fight between other festival's guests"
        buffers = {agent1: 0., agent2: 0.}
        buffers_joy = {agent1: 0., agent2: 0.}

        for agent in (agent1, agent2):
            if agent.role == 'troublemaker':
                buffers[agent] += 1
            else:
                buffers[agent] -= 3
            if self.pareto_fight:
                p1 = [0.25, 0.25, 0.25, 0.25]
                p2 = [0.04, 0.16, 0.16, 0.64]
                index = np.random.choice(np.arange(0, 4),
                                         p=p1 if self.pareto else p2)
                store = [(0, 0), (0.2, -0.7), (-0.7, 0.2), (-0.5, -0.5)]

                select = store[index]
                buffers_joy[agent] += select[
                    0] if agent.role == 'troublemaker' else select[1]

            buffers[agent] += agent.tastes['fight']
            buffers[agent] += 0.5 * random.random() - 0.25

        for agent in (agent1, agent2):
            agent.happiness += buffers[agent]
            if self.pareto_fight:
                agent.enjoyment += buffers_joy[agent]

        agent1.learn((agent2.role, 'fight'), buffers[agent1])
        agent2.learn((agent1.role, 'fight'), buffers[agent2])
        print("A fight is happening")

    def party(self, agent1: Guest, agent2: Guest):
        assert self == agent1.model == agent2.model
        buffers = {agent1: 0., agent2: 0.}
        for agent in (agent1, agent2):
            if agent.role == 'party':
                buffers[agent] += 1
            if agent.role == 'guard':
                buffers[agent] -= 3
            buffers[agent] += agent.tastes['party']
            buffers[agent] += 0.5 * random.random() - 0.25

        for agent in (agent1, agent2):
            agent.happiness += buffers[agent]

        agent1.learn((agent2.role, 'party'), buffers[agent1])
        agent2.learn((agent1.role, 'party'), buffers[agent2])

        print("A party is happening")

    def calm(self, agent1: Guest, agent2: Guest):  # Incorporate this in fight?
        assert self == agent1.model == agent2.model
        assert agent1.role == 'guard' or agent2.role == 'guard', "This interaction is forbidden"
        buffers = {agent1: 0., agent2: 0.}
        if agent1.role == 'guard':
            guard = agent1
            guest = agent2
        elif agent2.role == 'guard':
            guard = agent2
            guest = agent1
        else:
            guard = None
            guest = None
            print(
                "This interaction should not be happening, we don't have a guard involved"
            )
            return

        if guest.role == 'troublemaker':
            buffers[guard] += 1
            buffers[guest] -= 1
        else:
            buffers[guard] -= 2
            buffers[guest] -= 2

        for agent in (agent1, agent2):
            agent.happiness += buffers[agent]

        agent1.learn((agent2.role, 'calm'), buffers[agent1])
        agent2.learn((agent1.role, 'calm'), buffers[agent2])

        print("Calming is happening")

    def selfie(self, agent1: Guest, agent2: Guest):
        assert self == agent1.model == agent2.model
        buffers = {agent1: 0, agent2: 0}

        if agent1.role == 'celebrity':
            celeb = agent1
            guest = agent2
        elif agent2.role == 'celebrity':
            celeb = agent2
            guest = agent1
        else:
            print("No celeb in selfie")
            return

        if guest.role == 'troublemaker':
            self.fight(celeb, guest)
            return
        elif guest.role == 'guard':
            buffers[celeb] += 1
            buffers[guest] -= 1
        else:
            buffers[celeb] += 1
            buffers[guest] += 1

        for agent in (celeb, guest):
            buffers[agent] += agent.tastes['selfie']
            buffers[agent] += 0.5 * random.random() - 0.25

        for agent in (agent1, agent2):
            agent.happiness += buffers[agent]

        agent1.learn((agent2.role, 'selfie'), buffers[agent1])
        agent2.learn((agent1.role, 'selfie'), buffers[agent2])

        print("Selfie is happening")

    def smoke(self, agent1: Guest, agent2: Guest):
        assert self == agent1.model == agent2.model
        buffers = {agent1: 0., agent2: 0.}

        if agent1.role == 'hippie':
            hippie = agent1
            guest = agent2
        elif agent2.role == 'hippie':
            hippie = agent2
            guest = agent1
        else:
            print("No hippie in smoking")
            return

        if guest.role == 'hippie':
            buffers[hippie] += 2
            buffers[guest] += 2
        elif guest.role == 'celebrity':
            buffers[hippie] += 1
            buffers[guest] -= 2
        elif guest.role == 'guard':
            buffers[hippie] -= 2
            buffers[guest] += 1
        else:
            buffers[hippie] += 1
            buffers[guest] += 0.5

        for agent in (hippie, guest):
            buffers[agent] += agent.tastes['smoke']
            buffers[agent] += 0.5 * random.random() - 0.25

        for agent in (agent1, agent2):
            agent.happiness += buffers[agent]

        agent1.learn((agent2.role, 'smoke'), buffers[agent1])
        agent2.learn((agent1.role, 'smoke'), buffers[agent2])

        print("Smoking is happening")

    def blessing(self, agent1: Guest, agent2: Guest):
        assert self == agent1.model == agent2.model
        buffers = {agent1: 0., agent2: 0.}

        if agent1.role == 'lucia':
            lucia = agent1
            guest = agent2
        elif agent2.role == 'lucia':
            lucia = agent2
            guest = agent1
        else:
            print("No hippie in smoking")
            return

        buffers[lucia] += 0.5
        buffers[guest] += 0.5

        for agent in (lucia, guest):
            buffers[agent] += agent.tastes['blessing']
            buffers[agent] += 0.5 * random.random() - 0.25

        for agent in (agent1, agent2):
            agent.happiness += buffers[agent]

        agent1.learn((agent2.role, 'blessing'), buffers[agent1])
        agent2.learn((agent1.role, 'blessing'), buffers[agent2])

        print("blessing is happening")
class Contact_Trace_Model(Model):
    """
    The model class holds the model-level attributes, manages the agents, and generally handles
    the global level of our model.

    There is only one model-level parameter: how many agents the model contains. When a new model
    is started, we want it to populate itself with the given number of agents.

    The scheduler is a special model component which controls the order in which agents are activated.
    """

    def __init__(
        self,
        num_agents=10,
        num_sick=1,
        infection_chance=0.1,
        incubation_period=[2, 6],
        presypmtomatic_infectious_period=[0, 3],
        infectious_period=[5, 10],
        percent_asymptomatic=0,
        immunity_percent=1,
        percent_employed_small=0.5,
        perecent_employed_medium=0.25,
        percent_employed_large=0.25,
        family_size=[0, 8],
        random_contact_mean=5,
        random_contact_sd=2,
        contact_trace_percent=0.75,
        false_positive_rate=0.1,
        false_negative_rate=0.1,
        percent_tested_per_day=0.01,
        turn_around_time=2,
    ):

        super().__init__()
        self.num_agents = num_agents

        # self.schedule = RandomActivation(self)
        self.schedule = StagedActivation(self, stage_list=["move", "infect", "test"])
        # self.grid = MultiGrid(width=width, height=height, torus=False)

        # get workplaces

        self.infection_chance = infection_chance
        self.incubation = incubation_period
        self.infectious_period = infectious_period
        self.infection_chance = infection_chance
        self.incubation_period = incubation_period
        self.presypmtomatic_infectious_period = presypmtomatic_infectious_period
        self.percent_asymptomatic = percent_asymptomatic
        self.immunity_percent = immunity_percent
        self.percent_employed_small = percent_employed_small
        self.perecent_employed_medium = perecent_employed_medium
        self.percent_employed_large = percent_employed_large
        self.family_size = family_size
        self.random_contact_mean = random_contact_mean
        self.random_contact_sd = random_contact_sd
        self.contact_trace_percent = contact_trace_percent
        self.false_positive_rate = false_positive_rate
        self.false_negative_rate = false_negative_rate
        self.percent_tested_per_day = percent_tested_per_day
        self.turn_around_time = turn_around_time

        # num_classrooms = math.ceil(num_agents / max_class_size)
        # for i in range(1, num_classrooms + 1):
        #    self.class_dict[i] = {
        #        "students": [],
        #        "count": 0,
        #        "infected": False,
        #    }

        random_contacts = np.random.normal(
            self.random_contact_mean, self.random_contact_sd, self.num_agents
        )

        family_dict = {}

        # people still available to be in a family. if this gets to 0, remaining
        # agents will have no family members (should be at end only)
        family_available = self.num_agents

        non_family = set(range(1, self.num_agents, 1))

        for i in range(self.num_agents):
            agent = Contact_Trace_Agent(i, self)

            agent.random_contacts = max(math.floor(random_contacts[i]), 0)

            if family_available <= 0:
                print(f"agent {i} has no one left to be in their family")

            # if you're in a family already, that's your family, if not generate one
            if agent.unique_id in family_dict:
                agent.family = family_dict[agent.unique_id]
            else:
                family_size = min(
                    family_available,
                    random.randrange(self.family_size[0], self.family_size[1] + 1, 1,),
                )

                family_list = []

                # grab random id in range of num_agents, if that person is not in a
                # family already, add them to list, repeat until the family is the
                # right size
                family_counter = 0
                while family_counter < family_size:
                    person = random.randrange(0, self.num_agents, 1,)

                    if person not in family_dict:
                        family_list.append(person)
                        family_counter += 1

                # now that we have the list of family members, assingn them all
                # to the family
                for f in family_list:
                    family_dict[f] = family_list

                # assign the agent's family list
                agent.family = family_list

                # remove these people from family_available
                family_available += -family_size

            agent.random_people = list(non_family - set(agent.family))

            if num_sick > 0:
                agent.sick = True
                agent.pre_infectious = True
                agent.state = "pre_infectious"
                agent.incubation = random.randrange(
                    self.incubation[0], self.incubation[1] + 1, 1
                )

                agent.infectious_period = random.randrange(
                    self.infectious_period[0], (self.infectious_period[1]) + 1, 1,
                )

                num_sick += -1

            # job_asigned = False
            # while not dining_asigned:
            #    dining_option = random.choice(list(self.dining_dict.keys()))

            #    if self.dining_dict[dining_option]["count"] < max_dining:
            #        agent.dining = dining_option
            #        self.dining_dict[dining_option]["count"] += 1
            #        dining_asigned = True
            #        break
            #    else:
            #        continue

            self.schedule.add(agent)

        self.running = True
        # self.datacollector = DataCollector(model_reporters={"Number Sick": num_sick})
        self.datacollector = DataCollector(
            model_reporters={
                "Percent Ever Sick": percent_sick,
                "Number Infectious": num_infectious,
                "Tested and Quarantined": quarantined,
            }
        )

    def step(self):
        """
        A model step. Used for collecting data and advancing the schedule
        """
        self.step_tests = self.percent_tested_per_day * self.num_agents

        self.datacollector.collect(self)
        self.schedule.step()
Beispiel #14
0
class MarketModel(Model):
    def __init__(self,
                 n_agents,
                 population_composition={'zero_information': {
                     'R': 1
                 }},
                 settle_type='limit',
                 dt=1 / 252,
                 init_rf=0.02,
                 n_shares=1000,
                 init_agent_wealth=1000,
                 glob_risk_aversion=0.5,
                 glob_loss_aversion=2.5,
                 confidance_levels=(0.7, 3),
                 glob_interact_rate=0.25,
                 agent_particip_rate=1,
                 init_price=50,
                 init_dividend=5,
                 dividend_freq=4,
                 dividend_growth=0.01,
                 dividend_vol=0.2,
                 div_noise_sig=0.1,
                 price_adj_speed=0.1,
                 max_short=0.0001,
                 max_long=0.02):
        super().__init__()
        self.running = True
        self.n_agents = n_agents
        self.population_composition = population_composition
        #self.glob_risk_aversion = glob_risk_aversion
        self.confidance_levels = confidance_levels
        self.glob_interact_rate = glob_interact_rate
        self.rf_rate = init_rf  #to be controlled by a regulator agent in the future
        self.eta = price_adj_speed
        self.max_short = max_short
        self.max_long = max_long
        self.current_step = 0
        self.dt = dt
        self.stock = Stock(ticker="STK",
                           model=self,
                           init_price=init_price,
                           outstanding_shares=n_shares,
                           init_dividend=init_dividend,
                           dividend_freq=dividend_freq,
                           dividend_growth=dividend_growth,
                           dividend_vol=dividend_vol,
                           div_noise_sig=div_noise_sig)
        self.schedule = StagedActivation(self, ['stage1', 'stage2', 'stage3'])
        self.order_book = OrderBook()
        self.settle_type = settle_type
        agent_id = 0
        # if sum(population_composition[strat] for strat in population_composition) - 1.0 > 1e-06:
        if sum(population_composition[strat][beh]
               for strat in population_composition
               for beh in population_composition[strat]) - 1.0 > 1e-06:
            raise NameError(
                'population_compositions elements must sum up to 1')
        init_shares = n_shares / n_agents
        for strat in population_composition:
            for beh in population_composition[strat]:
                for i in range(
                        int(population_composition[strat][beh] *
                            self.n_agents)):
                    a = MarketAgent(agent_id, self, init_shares,
                                    init_agent_wealth, glob_risk_aversion,
                                    glob_loss_aversion, beh, strat,
                                    agent_particip_rate)
                    self.schedule.add(a)
                    agent_id += 1
        while agent_id < self.n_agents:
            init_shares = n_shares / n_agents
            strat = choice(list(population_composition.keys()))
            beh = choice(list(population_composition[strat].keys()))
            a = MarketAgent(agent_id, self, init_shares, init_agent_wealth,
                            glob_risk_aversion, glob_loss_aversion, beh, strat,
                            agent_particip_rate)
            self.schedule.add(a)
            agent_id += 1

        self.global_wealth = sum(
            [agent.wealth for agent in self.schedule.agents])
        self.agg_sells = 0
        self.agg_buys = 0
        self.available_sells = 0
        self.available_buys = 0
        self.buy_ratio = 0
        self.sell_ratio = 0
        self.matched_trades = []
        self.datacollector = ModDataCollector(model_reporters={
            "Global Wealth":
            "global_wealth",
            "Price":
            "stock.price",
            "Return":
            "stock.last_return",
            "Vol":
            "stock.vol",
            "Skew":
            "stock.skew",
            "Kurt":
            "stock.kurt",
            "Dividend":
            "stock.dividend",
            "Agg Sells":
            "agg_sells",
            "Agg Buys":
            "agg_buys",
            "Av Sells":
            "available_sells",
            "Av Buys":
            "available_buys",
            "Buy Ratio":
            "buy_ratio",
            "Sell Ratio":
            "sell_ratio",
            "Matched Trades":
            "matched_trades"
        },
                                              agent_reporters={
                                                  "Wealth":
                                                  "wealth",
                                                  "Cash":
                                                  "cash",
                                                  "Stock Weight":
                                                  "stock_weight",
                                                  "Stock Shares":
                                                  "stock_shares",
                                                  "Demand":
                                                  "share_demand",
                                                  "Target Trade":
                                                  "target_shares",
                                                  "Actual Trade":
                                                  "trade_shares",
                                                  "Price Expectation":
                                                  "strategy.exp_p_d"
                                              })
        self.net = self.generate_net()

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
        self.settle()
        for agent in self.schedule.agents:
            agent.cash *= (1 + self.rf_rate)**self.dt
        if self.current_step % ((self.dt**-1) / self.stock.dividend_freq) == 0:
            self.stock.update_dividend()
            for agent in self.schedule.agents:
                agent.cash += (self.stock.dividend /
                               self.stock.dividend_freq) * agent.stock_shares
        self.global_wealth = sum(
            [agent.wealth for agent in self.schedule.agents])
        self.current_step += 1

    def settle(self):
        if self.settle_type == 'limit':
            self.matched_trades = self.order_book.get_matched_trades()
            self.order_book.clear()
            for trade in self.matched_trades:
                buy_agent = self.schedule.agents[trade.buy_agent]
                sell_agent = self.schedule.agents[trade.sell_agent]
                buy_agent.stock_shares += trade.quantity
                buy_agent.cash -= trade.quantity * trade.price
                sell_agent.stock_shares -= trade.quantity
                sell_agent.cash += trade.quantity * trade.price
            self.stock.price = self.calculate_VWAP()
        elif self.settle_type == 'market':
            sells = [x for x in self.order_book.orders if x.side == 'sell']
            buys = [x for x in self.order_book.orders if x.side == 'buy']

            self.agg_sells = sum([x.quantity for x in sells])
            self.agg_buys = sum([x.quantity for x in buys])

            if self.agg_sells == 0 or self.agg_buys == 0:
                self.stock.price = self.stock.price
                return

            self.available_sells = min(
                self.agg_sells, self.stock.outstanding_shares)  #add Inventory
            self.available_buys = min(self.agg_buys,
                                      self.stock.outstanding_shares)

            self.buy_ratio = (min(self.agg_buys, self.available_sells) /
                              self.agg_buys)
            self.sell_ratio = (min(self.agg_sells, self.available_buys) /
                               self.agg_sells)

            self.stock.price = self.stock.price * (
                1 + self.eta * (self.agg_buys - self.agg_sells)
            )  # find a better price mechanism
            # rho = 0.95
            # f = rho / (1 + self.rf_rate - rho)
            # g = (1/self.rf_rate) * (1 + f) * (self.stock.init_dividend - self.glob_risk_aversion
            #                      * (self.stock.div_noise_sig**2) * (1000/self.n_agents))
            # self.stock.price = f * self.stock.dividend + g
            for order in self.order_book.orders:
                # need to prelist if using RandomScheduler
                agent = self.schedule.agents[order.agent_id]
                if order.side == 'buy':
                    trade_quantity = self.buy_ratio * order.quantity
                    agent.stock_shares += trade_quantity
                    agent.cash -= trade_quantity * self.stock.price
                if order.side == 'sell':
                    trade_quantity = self.sell_ratio * order.quantity
                    agent.stock_shares -= trade_quantity
                    agent.cash += trade_quantity * self.stock.price
            self.order_book.clear()

    def calculate_VWAP(self):
        trades = [x for x in self.matched_trades if x.quantity > 0]
        volume = sum([x.quantity for x in trades])
        if volume <= 0: return self.stock.price
        return sum(
            multiply([x.quantity for x in trades], [x.price
                                                    for x in trades])) / volume

    def generate_net(self):
        net = nx.scale_free_graph(self.n_agents,
                                  alpha=0.1,
                                  beta=0.01,
                                  gamma=0.89)
        net = nx.to_undirected(net)
        nodes = list(net.nodes)
        shuffle(nodes)
        for agent, node in zip(self.schedule.agents, nodes):
            agent.node = node
            net.nodes[node]['agent_id'] = agent.agent_id
            net.nodes[node]['strat'] = agent.strategy.strat_name
        return net
Beispiel #15
0
class RegimeModel(Model):
    # A model of a regime

    def __init__(self, num_nodes, productivity, demand, shape, network_param,
                 resource_inequality, capacity_inequality, uncertainty, shock):

        # Initialize graph
        self.num_nodes = num_nodes
        self.G = create_graph(shape, num_nodes, network_param)
        self.G = max(nx.connected_component_subgraphs(self.G),
                     key=lambda g: len(g.nodes()))

        # Initialize other attributes
        self.grid = NetworkGrid(self.G)
        self.schedule = StagedActivation(self,
                                         stage_list=[
                                             'add_link', 'cut_link',
                                             'settle_env_transfer',
                                             'settle_link_transfer'
                                         ],
                                         shuffle=True,
                                         shuffle_between_stages=True)
        self.productivity = productivity
        self.demand = demand
        self.resource_inequality = resource_inequality
        self.capacity_inequality = capacity_inequality
        self.uncertainty = uncertainty
        self.datacollector = DataCollector({
            "Gini Coeff. of Capacity": gini_capacity,
            "Gini Coeff. of Resources": gini_resources,
            "Satisfied": num_satisfied,
            "Dissatisfied": num_dissatisfied
        })
        self.shock = shock

        # Initialize agents on graph (cap capacity at 25 to avoid overflow errors)
        for i, node in enumerate(self.G.nodes()):
            a = RegimeAgent(i, self, self.demand,
                            math.exp(paretovariate(1 / resource_inequality)),
                            min(25, paretovariate(1 / capacity_inequality)),
                            True)
            self.schedule.add(a)
            self.grid.place_agent(a, node)

        for e in self.G.edges():
            capacity_transfer = expovariate(1 / self.uncertainty)
            agents = ([
                self.G.nodes[e[0]]['agent'][0], self.G.nodes[e[1]]['agent'][0]
            ])
            resource_transfer = calculate_transfer(
                self.productivity, agents[0].capacity + capacity_transfer,
                agents[1].capacity + capacity_transfer, capacity_transfer)

            # Give the agent with the higher capacity 2*transfer capacity to
            # simulate a prior interaction where the transfer was made, when
            # both the nodes had their current capacity + transfer.
            max_capacity_agent = max(agents, key=attrgetter('capacity'))
            min_capacity_agent = min(agents, key=attrgetter('capacity'))
            max_capacity_agent.capacity += 2 * capacity_transfer
            min_capacity_agent.exp_resources += resource_transfer

            # Initialize edge attributes for transfer rates, memory of
            # resource transfers, and which agent is the patron.
            self.G.edges[e]['capacity_t'] = capacity_transfer
            self.G.edges[e]['resource_t'] = resource_transfer
            self.G.edges[e]['exp_resources'] = [
                resource_transfer, resource_transfer
            ]
            self.G.edges[e]['patron'] = max_capacity_agent

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

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

    def run_model(self, n):
        for i in range(n):
            if i == n // 2:
                # Halfway through simulation, add shock.
                self.productivity *= self.shock
            self.step()
Beispiel #16
0
class SnetSim(Model):
    def __init__(self, study_path='study.json'):

        self.gepResult = None
        with open(study_path) as json_file:
            config = json.load(json_file, object_pairs_hook=OrderedDict)

        #save the config with the output
        filename = config['parameters']['output_path'] + study_path
        #make sure the output_path folder exists
        if not os.path.exists(config['parameters']['output_path']):
            os.makedirs(config['parameters']['output_path'])
        pretty = json.dumps(config, indent=2, separators=(',', ':'))
        with open(filename, 'w') as outfile:
            outfile.write(pretty)
        outfile.close()

        # print(json.dumps(config['ontology'], indent=2))
        self.parameters = config['parameters']
        super().__init__(self.parameters['seed'])
        self.reproduction_report = self.reproduction_report()
        self.blackboard = config['blackboard']
        self.ontology = config['ontology']
        self.registry = registry
        self.emergent_functions = OrderedDict()
        self.emergent_functions_arity = OrderedDict()
        self.emergent_functions_call_number = 0
        self.stochastic_pattern = re.compile(r'_stochastic\d+')
        self.prefix_pattern = re.compile(r'^f\d+_')

        pickle_config_path = config['parameters'][
            'output_path'] + 'pickles/' + 'index.p'

        if pickle_config_path and os.path.exists(pickle_config_path):
            with open(pickle_config_path, 'rb') as cachehandle:
                pickle_config = pickle.load(cachehandle)
        else:
            pickle_config = OrderedDict([("count", 0),
                                         ("pickles", OrderedDict())])

        self.pickle_count = pickle_config[
            'count']  # contains the next number for the pickle file
        self.pickles = pickle_config['pickles']

        self.resultTuple = ()
        # self.cache = LRU(max_size = 512)
        self.cache = LRU()

        # Buyers gather offers by ranking those who offer to sell the product that have a price overlap.
        # call choose partners several times to ensure that all parts that the supply chain has a
        # chance to be settled in multiple trades, or offer networks have a chance to be filled.
        # In step the agent has a chance to put out a new message given the knowledge of purchases
        # made on the last round

        stage_list = [
            'step',
            'gather_offers',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
            'choose_partners',
        ]

        self.schedule = StagedActivation(self,
                                         stage_list=stage_list,
                                         shuffle=True,
                                         shuffle_between_stages=True)

        # Create agents

        # first initial agents then random agents
        initial_blackboard = copy.deepcopy(self.blackboard)
        self.blackboard = []
        agent_count = 0
        for i, message in enumerate(initial_blackboard):
            if message['type'] in self.parameters['agent_parameters']:
                agent_parameters = self.parameters['agent_parameters'][
                    message['type']]
            else:
                agent_parameters = None
            for _ in range(self.parameters['blackboard_agents'][i]):
                a = globals()[message['type']](agent_count, self, message,
                                               agent_parameters)
                self.schedule.add(a)
                agent_count += 1

        for agent_type, n in self.parameters['random_agents'].items():
            if agent_type in self.parameters['agent_parameters']:
                agent_parameters = self.parameters['agent_parameters'][
                    agent_type]
            else:
                agent_parameters = None
            for i in range(n):
                a = globals()[agent_type](agent_count, self, None,
                                          agent_parameters)
                self.schedule.add(a)
                agent_count += 1

        print("Final line of snet sim init")

    def remove_suffix(self, func_name):
        cut_tuple = func_name
        if (func_name):
            stochastic_suffix = self.stochastic_pattern.search(func_name)
            if (stochastic_suffix):
                stochastic_suffix = stochastic_suffix.group()
                cut_tuple = func_name[:-len(stochastic_suffix)]
        return cut_tuple

    @cachedmethod('cache')
    @pickleThis
    def memoise_pickle(self, tuple_key):
        result = None

        try:
            cut_tuple = self.remove_suffix(tuple_key[0])
            if len(self.resultTuple) and cut_tuple:
                result = self.registry[cut_tuple](*self.resultTuple)()
            else:
                result = self.registry[cut_tuple]()
        except IOError as e:
            print("I/O error({0})".format(e))
        except ValueError as e:
            print("ValueError({0})".format(e))
        except AttributeError as e:
            print("AttributeError({0})".format(e))
        except TypeError as e:
            print("TypeError({0})".format(e))
        except RuntimeError as e:
            print("RuntimeError({0})".format(e))
        except IndexError as e:
            print("IndexError({0})".format(e))
        except:
            print("Unexpected error:", sys.exc_info()[0])
            raise

        return result

    def remove_prefix(self, func_name):
        cut_tuple = func_name
        if (func_name):
            call_number_prefix = self.prefix_pattern.search(func_name)
            if (call_number_prefix):
                call_number_prefix = call_number_prefix.group()
                cut_tuple = func_name[len(call_number_prefix):]
        return cut_tuple

    def get_call_prefix(self, func_name):
        call_prefix = None
        if (func_name):
            call_number_prefix = self.prefix_pattern.search(func_name)
            if (call_number_prefix):
                call_prefix = call_number_prefix.group()
        return call_prefix

    def call_emergent_function(self, gep_result, root):
        print("SnetSim calling emergent function with root {0}  :  {1}".format(
            root, gep_result))
        self.gepResult = copy.deepcopy(gep_result)
        func_tuple = self.call_memoise_pickle(root)

        print("SnetSim called emergent function with root {0} with result {1}".
              format(root, func_tuple))
        return func_tuple

    def call_memoise_pickle(self, root):
        # right now, self.emergentfunctions looks like:
        # 		f1: a,b,f2,c,d
        # 		f2: e,d,f3,f,g
        # 		f3: h,i,j
        #
        #You should go through the original problem that you had in the modulargep.txt file in the singularitynet directory
        #its going to be a matter of creating a registry for a functionlist on the fly from the real registry I think.
        result = None
        func_tuple = (None, None)
        if root:
            result_list = []
            func_list = []
            # argTuple = ()
            if root in self.gepResult:
                args = self.gepResult[root]
                # argTuple = tuple(args)
                for arg in args:
                    temp_func_tuple, temp_result = self.call_memoise_pickle(
                        arg)
                    result_list.append(temp_result)
                    func_list.append(temp_func_tuple)
            carried_back = tuple(func_list)
            strip_prefix = self.remove_prefix(root)
            func_tuple = (strip_prefix, carried_back)

            self.resultTuple = tuple(
                result_list
            )  # You have to set a global to memoise and pickle correctly
            if strip_prefix is not None:
                result = self.memoise_pickle(func_tuple)

        return func_tuple, result

    def reproduction_report(self):
        file = None
        path = self.parameters['output_path'] + 'reproduction_report.csv'
        file = open(path, "w")
        file.write(
            "time;agent;label;utility;agi_tokens;buyer_score;seller_score;sign_displayed;bought_items\n"
        )

        return file

    def print_reproduction_report_line(self, agent, utility, bought_items):
        a = self.schedule.time
        b = agent.unique_id
        c = agent.message['label']
        d = utility
        e = agent.agiTokens
        f = agent.max_buyer_score
        g = agent.max_seller_score
        h = agent.message['sign']
        i = bought_items

        self.reproduction_report.write(
            "{0};{1};{2};{3};{4};{5};{6};{7};{8}\n".format(
                a, b, c, d, e, f, g, h, i))
        self.reproduction_report.flush()

    def print_logs(self):
        filename = self.parameters['output_path'] + "logs/log" + str(
            self.schedule.time) + ".txt"

        pretty = json.dumps(self.blackboard, indent=2, separators=(',', ':'))
        with open(filename, 'w') as outfile:
            outfile.write(pretty)
        outfile.close()
        #json.dump(self.blackboard, outfile)

        pickle_config_path = self.parameters[
            'output_path'] + 'pickles/' + 'index.p'
        pickle_config = OrderedDict([('count', self.pickle_count),
                                     ('pickles', self.pickles)])

        with open(pickle_config_path, 'wb') as outfile:
            pickle.dump(pickle_config, outfile)
        outfile.close()

    def visualize(self):
        # todo: visualize changes in price and test score and relative wealth
        pass

    def step(self):
        """Advance the model by one step."""
        print("IN SnetSim step, time " + str(self.schedule.time))
        self.print_logs()
        # self.visualize() after learning agents are implemented
        self.schedule.step()

    def go(self):
        for i in range(self.parameters['max_iterations']):
            print("iteration " + str(i))
            self.step()
Beispiel #17
0
class FormationFlying(Model):

    # =========================================================================
    #   Create a new FormationFlying model.
    #
    #   Args:
    #       n_flights: Number of flights
    #       width, height: Size of the space, in kilometers.
    #       speed: cruise-speed of flights in m/s.
    #       communication_range: How far around should each Boid look for its neighbors
    #       separation: What's the minimum distance each Boid will attempt to
    #                   keep from any other the three drives.
    # =========================================================================
    def __init__(
            self,
            n_flights=2,
            n_origin_airports=2,
            n_destination_airports=2,
            width=1500,  # [km]
            height=1500,
            speed=0.220,  #[km/second]
            max_speed=0.500,
            communication_range=1000,  #[km]
            departure_window=3,
            origin_airport_x=[
                0.0, 0.3
            ],  # the origin airports are randomly generated within these boundaries
            origin_airport_y=[0.0, 0.3],
            destination_airport_x=[0.7, 0.9],  # same for destination airports
            destination_airport_y=[0.7, 0.9],
            fuel_reduction=0.75,
            negotiation_method=1,
            joining_method=0,
            alliance_ratio=0.30,
            manager_ratio=0.40,
            offer_ratio=0.80,
            entrance_fee=50,
            bid_increase=10):

        # =====================================================================
        #   Initialize parameters, the exact values will be defined later on.
        # =====================================================================

        self.n_flights = n_flights
        self.n_origin_airports = n_origin_airports
        self.n_destination_airports = n_destination_airports
        self.vision = communication_range
        self.speed = speed
        self.max_speed = max_speed
        self.height = height
        self.width = width

        # The agents are activated in random order at each step, in a space that
        # has a certain width and height and that is not toroidal
        # (which means that edges do not wrap around)
        self.schedule = StagedActivation(self,
                                         stage_list=["step", "advance"],
                                         shuffle=True)  # This line has changed
        # in V9 on 13-oct. You could add additional methods to the "stage_list" if you want to do more substeps of a
        # negotiation within one agent step.
        self.space = ContinuousSpace(width, height, False)

        # These are values between [0,1] that limit the boundaries of the
        # position of the origin- and destination airports.
        self.origin_airport_x = origin_airport_x
        self.origin_airport_y = origin_airport_y
        self.destination_airport_x = destination_airport_x
        self.destination_airport_y = destination_airport_y

        self.destination_agent_list = []
        self.departure_window = departure_window
        self.fuel_reduction = fuel_reduction
        self.negotiation_method = negotiation_method
        self.joining_method = joining_method
        self.alliance_ratio = alliance_ratio
        self.manager_ratio = manager_ratio
        self.offer_ratio = offer_ratio
        self.entrance_fee = entrance_fee
        self.bid_increase = bid_increase

        self.fuel_savings_closed_deals = 0

        self.total_planned_fuel = 0

        self.manager_counter = 0
        self.new_formation_counter = 0
        self.add_to_formation_counter = 0
        self.formation_counter = 0
        self.agents_in_formation = 0

        self.total_fuel_consumption = 0
        self.alliance_fuel_consumption = 0
        self.alliance_planned_fuel = 0
        self.total_flight_time = 0
        self.total_delay = 0

        self.origin_list = []
        self.destination_list = []

        self.make_airports()
        self.make_agents()
        self.running = True

        self.datacollector = DataCollector(model_reporter_parameters,
                                           agent_reporter_parameters)

    # =========================================================================
    #  Create all flights, the flights are not all initialized at the same time,
    #  but within a departure window.
    # =========================================================================

    def make_agents(self):

        for i in range(self.n_flights):

            departure_time = self.random.uniform(0, self.departure_window)
            pos = self.random.choice(self.origin_list)
            destination_agent = self.random.choice(self.destination_agent_list)
            destination_pos = destination_agent.pos
            flight = Flight(
                i,
                self,
                pos,
                destination_agent,
                destination_pos,
                departure_time,
                self.speed,
                self.max_speed,
                self.vision,
            )
            self.space.place_agent(flight, pos)
            self.schedule.add(flight)

    # =============================================================================
    #   Create all airports. The option "inactive_airports" gives you the
    #   opportunity to have airports close later on in the simulation.
    # =============================================================================
    def make_airports(self):

        inactive_airports = 0
        for i in range(self.n_origin_airports):
            x = self.random.uniform(
                self.origin_airport_x[0],
                self.origin_airport_x[1]) * self.space.x_max
            y = self.random.uniform(
                self.origin_airport_y[0],
                self.origin_airport_y[1]) * self.space.y_max
            closure_time = 0
            pos = np.array((x, y))
            airport = Airport(i + self.n_flights, self, pos, "Origin",
                              closure_time)
            self.space.place_agent(airport, pos)
            self.schedule.add(
                airport
            )  # they are only plotted if they are part of the schedule

        for i in range(self.n_destination_airports):
            x = self.random.uniform(
                self.destination_airport_x[0],
                self.destination_airport_x[1]) * self.space.x_max
            y = self.random.uniform(
                self.destination_airport_y[0],
                self.destination_airport_y[1]) * self.space.y_max
            if inactive_airports:
                closure_time = 50
                inactive_airports = 0
            else:
                closure_time = 0
            pos = np.array((x, y))
            airport = Airport(i + self.n_flights + self.n_origin_airports,
                              self, pos, "Destination", closure_time)
            self.space.place_agent(airport, pos)
            self.destination_agent_list.append(airport)
            self.schedule.add(
                airport
            )  # agents are only plotted if they are part of the schedule

    # =========================================================================
    # Define what happens in the model in each step.
    # =========================================================================
    def step(self):
        all_arrived = True
        total_deal_value = 0
        for agent in self.schedule.agents:
            if type(agent) is Flight:
                total_deal_value += agent.deal_value
                if agent.state != "arrived":
                    all_arrived = False
        if all_arrived:
            self.running = False

        # This is a verification that no deal value is created or lost (total deal value
        # must be 0, and 0.001 is chosen here to avoid any issues with rounded numbers)
        if abs(total_deal_value) > 0.001:
            raise Exception("Deal value is {}".format(total_deal_value))

        self.schedule.step()
        self.datacollector.collect(self)
Beispiel #18
0
class OpinionModel(Model):
    '''
    A model with some number of agents

    Keyword arguments:
    N -- Number of agents
    neighborhoods -- An NxX matrix.
    neighborhoods[a] is agent a\'s list of neighbors.
    The neighborhoods is not actually a matrix.
    Each inner list may be of different length.
    intial_opinions -- This is a list size N of opinions.
    Each inner list must have the same length, the opinions
    are then labeled Opinion0, Opinion1, ..., OpinionZ.
    potentials -- Potentials is a 1-D list of functions
    Each function describes how agents are influenced by innodes.
    coupling -- AxA matrix, where A = |opinions|. Describes how
    opinions affect each other.
    '''
    def __init__(self,
                 N,
                 neighborhoods,
                 weights,
                 initial_opinions,
                 potentials,
                 coupling,
                 schedule="simultaneous"):
        self.ALPHA = .001
        self.num_agents = N
        self.neighborhoods = neighborhoods
        self.initial_opinions = initial_opinions
        self.potentials = potentials
        self.coupling = coupling

        if weights is None:
            self.weights = [None for i in range(self.num_agents)]
        else:
            self.weights = weights

        #Set schedule
        if schedule == 'simultaneous':
            self.schedule = StagedActivation(
                self,
                stage_list=["simultaneousStep", "simultaneousAdvance"],
                shuffle=False)
        elif schedule == 'pairwise':
            self.schedule = StagedActivation(
                self,
                stage_list=["reset", "pairwiseStep", "noise"],
                shuffle=True)
            #stage_list is where you add "coupling" and "noise".

        #Create agents
        for i in range(self.num_agents):
            a_params = OpinionAgentParameters(i, self, self.neighborhoods[i],
                                              self.weights[i],
                                              self.potentials[i],
                                              initial_opinions[i])
            if schedule == 'simultaneous':
                a = OpinionAgent(a_params)
            elif schedule == 'pairwise':
                a = OpinionAgent(a_params)
            self.schedule.add(a)

        ag_reps = dict()
        for i in range(len(self.schedule.agents[0].opinions)):
            ag_reps["Opinion" + str(i)] = self.makeLam(i)

        self.datacollector = DataCollector(agent_reporters=ag_reps)

    def step(self):
        '''
        Advance the model one step
        '''
        self.datacollector.collect(self)
        self.schedule.step()

    def run(self, steps):
        for i in range(steps):
            self.step()

    def total_change(self):
        sum = 0
        for j in range(len(self.schedule.agents[0].opinions)):
            for i in range(self.num_agents):
                sum += abs(self.schedule.agents[i].opinions[0] -
                           self.schedule.agents[i].nextOpinion[0])
        return sum

    def makeLam(self, i):
        '''
        Don't use outside of the context of the OpinionModel's init method.
        This function is needed in order for the DataCollector to work properly,
        intializing the lambdas inside __init__ inside a for loop causes the last
        value of the iterator to be used for all of the functions, causing
        unwanted behavior. So that's why this function exists.
        '''
        return lambda a: a.opinions[i]