Пример #1
0
class ConveyModel(Model):
    """A model with some number of agents."""

    def __init__(self, N, width, height):
        super().__init__()
        self.num_agents = N
        self.grid = MultiGrid(width, height, True)
        self.schedule = BaseScheduler(self)

        # Create agents
        for i in range(self.num_agents):
            a = ConwayAgent(i, self)
            # Add the agent to a random grid cell
            x = random.randrange(self.grid.width)
            y = random.randrange(self.grid.height)
            while(len(self.grid.get_cell_list_contents((x,y)))):
                x = random.randrange(self.grid.width)
                y = random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))
            self.schedule.add(a)
        self.i = i

        self.datacollector = DataCollector(
            agent_reporters={"State": lambda a: a.die})

    def step(self):
        self.datacollector.collect(self)
        new_agents = []
        for (x, y) in product(range(self.grid.width), range(self.grid.height)):
            ns = self.grid.iter_neighbors((x,y), True)
            neighbors = 0
            for n in ns:
                if(n):
                    neighbors += 1
            if(self.grid[x][y]):  # live cell
                if(neighbors < 2):  # underpopulation
                    list(self.grid[x][y])[0].die = 1
                elif(neighbors > 3):  # overpopulation
                    list(self.grid[x][y])[0].die = 1
            else:  # dead cell
                if(neighbors == 3):
                    new_agents.append((x, y))
        for (x, y) in product(range(self.grid.width), range(self.grid.height)):
            if self.grid[x][y]:
                a = list(self.grid[x][y])[0]
                if a.die:
                    self.grid.remove_agent(a)
                    self.schedule.remove(a)
        for na in new_agents:
            self.i += 1
            a = ConwayAgent(self.i, self)
            self.grid.place_agent(a, na)
            self.schedule.add(a)
Пример #2
0
class Board(Model):
    def __init__(self, width, height):
        self.running = True
        self.grid = MultiGrid(width, height, False)  #true for toroidal grid
        self.schedule = BaseScheduler(self)

        self.adversary_pieces = []
        self.agent_pieces = []

        self.initialize_grid()

    def initialize_grid(self):
        '''
		Here we initialize the d by d board with pits and pieces
		'''

        #initialize the pits
        num_pits = (d // 3) - 1
        for j in range(1, d - 1):
            for i in random.sample(list(range(0, d)), d)[0:num_pits]:
                pit = Pit('pit', self)
                self.grid.place_agent(pit, (i, j))

        #init all pieces
        num_pieces = d // 3
        for j in range(d):
            j_off = j + 1
            if j_off % 3 == 1:
                piece_adv = Piece('wumpus', self, 'adversary')
                piece_agent = Piece('wumpus', self, 'agent')
            elif j_off % 3 == 2:
                piece_adv = Piece('hero', self, 'adversary')
                piece_agent = Piece('hero', self, 'agent')
            else:
                piece_adv = Piece('mage', self, 'adversary')
                piece_agent = Piece('mage', self, 'agent')

            self.grid.place_agent(piece_adv, (j, 0))
            self.grid.place_agent(piece_agent, (j, d - 1))

            self.adversary_pieces.append(piece_adv)
            self.agent_pieces.append(piece_agent)

    def get_adversary_piece(self):
        '''
		Here is where player enters coordinates of piece they want to move. Checks for invalid inputs and protects
		against them
		'''
        pos = ''
        agents = []

        while not is_valid_position(pos) or agents == [] or agents[
                0].name == 'pit' or agents[0].player == 'agent':
            print("Enter position of piece you want to move (sep by spaces): ",
                  end='')
            pos = input()

            if not is_valid_position(pos):
                print('invalid argument')
                continue

            x, y = int(pos.split()[0]) - 1, int(pos.split()[1]) - 1

            agents = list(self.grid[x][y])

            if agents != []:
                if agents[0].name == 'pit':
                    print('cannot select a pit')
                    continue

                if agents[0].player == 'adversary':
                    piece = agents[0]
                    return piece

                else:
                    print('You cannot move agent\'s pieces')
                    continue
            else:
                print('cannot select empty square')

    def get_agent_piece_and_move(self):
        '''
		here we will call minimax from minimax.py. This will return the agent piece that will move along with the coordinate
		it will move to
		'''
        start = time.time()
        _, _, piece, pos = minimax(self, depth, float('-inf'), float('inf'),
                                   True)
        print('time passed:', time.time() - start)

        return piece, pos

    def winner(self):
        '''
		here we will implement the winning condition
		we will return the value True and the player who won. we want the game to stop
		when win() == True.. and we will implement this in the step function
		'''
        return self.adversary_pieces == [] or self.agent_pieces == []

    def collision_check(self, piece):
        x, y = piece.pos
        agents = list(self.grid[x][y])
        #pop piece from agents
        agents.remove(piece)

        for agent in agents:
            if agent.name == 'pit':
                self.grid.remove_agent(piece)
                self._remove_piece_from_list(piece)
            elif agent.player != piece.player:
                if agent.name == piece.name:
                    self.grid.remove_agent(piece)
                    self.grid.remove_agent(agent)

                    self._remove_piece_from_list(piece)
                    self._remove_piece_from_list(agent)

                elif agent.name in ['hero', 'wumpus'
                                    ] and piece.name in ['hero', 'wumpus']:
                    agent_to_remove = agent if agent.name == 'wumpus' else piece
                    self.grid.remove_agent(agent_to_remove)
                    self._remove_piece_from_list(agent_to_remove)

                elif piece.name in ['mage', 'hero'
                                    ] and agent.name in ['mage', 'hero']:
                    agent_to_remove = agent if agent.name == 'hero' else piece
                    self.grid.remove_agent(agent_to_remove)
                    self._remove_piece_from_list(agent_to_remove)
                elif piece.name in ['mage', 'wumpus'
                                    ] and agent.name in ['mage', 'wumpus']:
                    agent_to_remove = agent if agent.name == 'mage' else piece
                    self.grid.remove_agent(agent_to_remove)
                    self._remove_piece_from_list(agent_to_remove)

    def _remove_piece_from_list(self, piece):
        if piece.player == 'agent':
            self.agent_pieces.remove(piece)
        else:
            self.adversary_pieces.remove(piece)

    def distance_to_board(self):
        #calculates manhattan distance from each piece to all of other pieces then adds all those up
        #also weights attacking pieces and vulnerable pieces so that agent runs towards
        #pieces it can capture and runs away from pieces that can capture it

        opposing_offense = {'wumpus': 'mage', 'mage': 'hero', 'hero': 'wumpus'}
        opposing_defense = {j: i for i, j in opposing_offense.items()}
        total = 0
        for ag_piece in self.agent_pieces:
            for adv_piece in self.adversary_pieces:
                weight = 1
                x1, y1 = ag_piece.pos
                x2, y2 = adv_piece.pos

                if opposing_offense[ag_piece.name] == adv_piece.name:
                    weight = 2
                elif opposing_defense[ag_piece.name] == adv_piece.name:
                    weight = -2

                total += weight * (abs(x1 - x2) + abs(y1 - y2))
        return total / len(self.agent_pieces)

    def evaluate(self):
        #returns the score for the whole board (made for agent's favor)
        try:
            return len(self.agent_pieces) - len(self.adversary_pieces) + (
                eval_weight / self.distance_to_board())
        except:
            return len(self.agent_pieces) - len(self.adversary_pieces)

    def step(self):
        '''
		Each time step is called, player enters move and their piece moves. Agent also moves its piece that was returned from
		get_agent_piece_and_move(). This is essentially two turns of the game: player's turn and agent's turn. 

		'''
        if not self.winner():
            adversary_piece = self.get_adversary_piece()
            self.schedule.add(adversary_piece)
            self.schedule.step()

            self.collision_check(adversary_piece)
            self.schedule.remove(adversary_piece)

            agent_piece, agent_pos = self.get_agent_piece_and_move()
            if agent_piece != None:
                agent_piece.move(pos=agent_pos)
                self.collision_check(agent_piece)
        else:
            print('Game Over')
Пример #3
0
class LandModel(Model):



    """
    Main model
    """
    def __init__(self,
                 percentage_buyers, # Percentage of buyers to be added acording to the available land  
                 percentage_high_income, #Percentage that are high income
                 rich_market_reach, # The amount of properties the rich can bid
                 poor_market_reach, # The amount of properties the poor can bid
                 base_price, # The land base price
                 base_income, # The base income for all buyers
                 rich_poor_std, #Standard deviation for the rich and poor
                 num_cities, # The number of cities
                 b, # Constant for the wtp formula                 
                 urbanization_over_rural_roductivity, # Constant for the probability of selling
                 size, # tuple: (width, height)                                  
                 alpha = 0.5,# The alpha parameter (preference)
                 amenities = "uniform", #The amenities
                 rural_productivity = "uniform", # The rural productivity
                 buyer_mode =  cons.BID_SCHEME.BEST,
                 max_epochs = 10, #number of epochs
                 max_urbanization = np.inf # Maximum number of urbanization units
                 ): 


        position = "CENTRAL"

        #print('')
        #print('Rich: ' + str(rich_market_reach) + ' Poor: ' + str(poor_market_reach))

        #Variables for batch run
        self.num_epochs = 0
        self.max_epochs = max_epochs
        self.max_urbanization = max_urbanization
        self.running = True

        #Scheduler
        self.schedule = BaseScheduler(self)

        #Assigns variables to the model
        self.base_price = base_price
        self.base_income = base_income
        self.rich_poor_std = rich_poor_std

        self.rich_market_reach = rich_market_reach
        self.poor_market_reach = poor_market_reach

        self.b = b

        self.w2 = urbanization_over_rural_roductivity
        self.w1 = 1 - self.w2

        self.epyslon = 0

        self.alpha = alpha

        self.buyer_mode = buyer_mode

        #Sets up the grid

        #Size of Grid
        self.width = size[0]
        self.height = size[1]
        self.grid = MultiGrid(self.width, self.height, True) # Multigrid - Agents can share a cell

        #Assign the shapes
        self.grid_shape = (self.width, self.height)


        #Distribution variables
        self.amenities = self.get_distribution(amenities)
        self.rural_productivity = self.get_distribution(rural_productivity)

        #Starts the patches as an empty matix
        self.patches = np.empty((self.width, self.height), dtype = object)


        #Invokes the city generator
        # Checks if will import from raster
        if str(num_cities).upper() == 'RASTER':
            centers, city_fun = CityGenerator.import_from_raster(self.grid_shape)

        else:    
            # Handles the city creation (at random) and the corresponding centers
            centers, city_fun = CityGenerator.make_cities_fun(self.grid_shape, num_cities = num_cities, position = position)

        self.city_centers = centers

        #Calculates max city distance (for the city proximity function)
        self.max_city_distance = self.get_max_city_distance()

        #Starts land patches and city pathces (both are sets to guarantee O(1) lookup)
        self.land_patches = set()
        self.city_patches = set()


        #Iterates over each possible patch and assigns city or land
        for index in list(itertools.product(range(self.width), range(self.height))):

            patch = LandPatch("land_patch_" + str(index), self)
            patch.type = city_fun(index)

            if(patch.type == cons.LAND_TYPES.CITY):
                self.city_patches.add(patch)
                patch.convert_to_city()
            else:
                self.land_patches.add(patch)
                patch.convert_to_land()

            self.grid.place_agent(patch, index)
            self.patches[index] = patch
            patch.set_properties() # Initializes patch


        #The number of sellers will be the number of land patches
        num_sellers = len(self.land_patches)


        self.percentage_buyers = percentage_buyers
        if(percentage_buyers <= 0 or percentage_buyers > 100):
            raise ValueError('Percentage of buyers is incorrect: ' + str(percentage_buyers))

        # Calculates the number of buyers
        self.percentage_high_income = percentage_high_income
        self.num_buyers = np.round((self.percentage_buyers/100)*len(self.land_patches))
        

        # Sets up the number of poor and rich buyers
        self.num_rich_buyers = int(self.num_buyers*self.percentage_high_income/100)
        self.num_poor_buyers = int(self.num_buyers*(100- self.percentage_high_income)/100)

        #Number of Agents
        self.num_sellers = num_sellers
        self.num_buyers = self.num_rich_buyers + self.num_poor_buyers
        self.num_agents = self.num_sellers + self.num_buyers

        self.buyers = set()
        self.sellers = set()

        #To remove
        # At the end of each iteration will remove the sellers who sold
        self.to_remove = []

        # adds the sellers (one for each land patch)
        added_sellers = 0
        for pat in self.land_patches:

            seller = Seller("seller_" + str(added_sellers), self, pat)
            self.schedule.add(seller)

            #Adds the seller
            self.grid.place_agent(seller, pat.pos)
            self.sellers.add(seller)

            added_sellers += 1


        # Adds the buyers
        self.add_rich_buyers(self.num_rich_buyers)
        self.add_poor_buyers(self.num_poor_buyers)

        # The data collector
        # For plotting oprions
        self.current_bids = []

        self.datacollector = DataCollector(
                model_reporters={"Amenities": get_mean_amenities})




    def step(self):
        """
        Method that simulates the step of an epoch
        """

        #Scehdule
        #print('Step ' + str(self.num_epochs))

        #Calculates the sellers that will sell
        market = set()
        for seller in self.sellers:
            if(seller.will_sell()):
                market.add(seller)

        if(len(market) == 0):
            print('Nobody wants to sell')

        #All the buyer make their bids
        for buyer in self.buyers:
            buyer.make_bids(market, self.buyer_mode)


        #Asjust Epsylon
        self.epyslon = (len(self.buyers) - len(self.sellers))/(len(self.buyers) + len(self.sellers))

        #Randomly, buyers and sellers interact
        sellers = random.sample(self.sellers, len(self.sellers))
        for seller in sellers:
            sold = seller.sell()
            if(sold):
                #Removes seller
                self.grid._remove_agent(seller.pos, seller)
                self.sellers.remove(seller)

        self.current_bids = []

        #removes all buyers
        self.remove_all_buyers()

        #Updates the number of buyers for next epoch
        self.num_buyers = np.round((self.percentage_buyers/100)*len(self.land_patches))
        
        

        # Sets up the number of poor and rich buyers
        self.num_rich_buyers = int(self.num_buyers*self.percentage_high_income/100)
        self.num_poor_buyers = int(self.num_buyers*(100- self.percentage_high_income)/100)        
        self.num_buyers = self.num_rich_buyers + self.num_poor_buyers

        #Adds the new generation
        self.add_rich_buyers(self.num_rich_buyers)
        self.add_poor_buyers(self.num_poor_buyers)

        #Collects data
        self.datacollector.collect(self)

        #Adjust progress variables (for batch process)
        self.num_epochs += 1
        if(self.num_epochs == self.max_epochs or self.get_num_patches() == 0):
            self.running = False

        #Stops the process if the maximum urbanization limit is exceeded
        if(len(self.city_patches) >= self.max_urbanization):
            print(self.num_epochs)
            self.running = False



    def get_max_city_distance(self):
        """
        Calculates the max city distance available in the greed (recall there can
        be multiple cities)
        """
        indices = list(itertools.product(range(self.width),range(self.height)))
        positions = np.array(indices)
        centers = np.array(self.city_centers)

        dist_centers = metrics.pairwise.euclidean_distances(positions,centers)
        dist_centers = np.min(dist_centers, axis = 1)

        return(np.max(dist_centers))


    def get_available_pos(self):
        """
        Gets an available position (so agent don't end up in a city patch)
        Was design for when the agents bought around them.
        """

        if(self.land_patches):
            land_patch = random.sample(self.land_patches,1)[0]
            return(land_patch.pos)

        return(None)

    def get_available_positions(self, k, replace = False):

        choices = np.random.choice(list(self.land_patches), size = k, replace = replace)

        return([land_patch.pos for land_patch in choices])
        


    def get_num_patches(self):
        return(len(self.land_patches))



    def remove_all_buyers(self):
        """
        Removes all buyers from the model. At the end of every epoch,
        this method is called
        """
        for agent in self.buyers:
            self.grid._remove_agent(agent.pos, agent)
            self.schedule.remove(agent)

        self.buyers = set()


    def add_rich_buyers(self, num_rich_buyers):
        """
        Add rich buyers to the grid
        """
        indices = self.get_available_positions(num_rich_buyers)

        for i in range(num_rich_buyers):
            income = max(0,(self.base_income + np.abs(np.random.normal(loc = 0, scale = self.rich_poor_std))))
            buyer = Buyer("buyer_rich_" + str(i), self, income = income, market_reach = self.rich_market_reach, type = cons.AGENT_TYPES.RICH)
            self.schedule.add(buyer)

            #Gets an available position
            index = indices[i]

            #Adds the buyer
            self.grid.place_agent(buyer, index)
            self.buyers.add(buyer)


    def add_poor_buyers(self, num_poor_buyers):
        """
        Add poor buyers to the grid
        """
        indices = self.get_available_positions(num_poor_buyers)

        for i in range(num_poor_buyers):
            income = max(0,(self.base_income - np.abs(np.random.normal(loc = 0, scale = self.rich_poor_std))))
            buyer = Buyer("buyer_poor_" + str(i), self, income = income, market_reach = self.poor_market_reach, type = cons.AGENT_TYPES.POOR)
            self.schedule.add(buyer)

            #Gets an available position
            index = indices[i]

            #Adds the buyer
            self.grid.place_agent(buyer, index)

            self.buyers.add(buyer)



    def get_distribution(self, name):
        """
        Gets the corresponding function depending on the distribution
        """

        if("CONSTANT" in str(name).upper()):
            name = name.replace(" ","")
            values = name.split("=")
            if(len(values) != 2):
                raise ValueError("If function is constant, should specify its value")

            constant = float(values[1])
            return(lambda x: constant )        

        if(str(name).upper() == "UNIFORM"):
            return(lambda x: np.random.uniform())

        if(str(name).upper() == "RASTER_AMENITIES"):
            return(CityGenerator.amenities_from_raster(self.grid_shape))


        raise ValueError("No implementation for the distribution: "  + str(name))



    def get_tract_info(self, tract = 4):

        matrix = self.get_sold_type_matrix()
        array = get_tract_structure(matrix, tract)

        n = len(array)
        r = np.apply_along_axis(lambda x: np.sum(x == cons.AGENT_TYPES.RICH), 0, array)
        R = np.sum(matrix == cons.AGENT_TYPES.RICH)
        p = np.apply_along_axis(lambda x: np.sum(x == cons.AGENT_TYPES.POOR), 0, array)
        P = np.sum(matrix == cons.AGENT_TYPES.POOR)

        return(n,r,R,p,P)




    def get_sold_type_matrix(self):

        #Extract the matrix with the values
        matrix = np.array([[ self.patches[i,j].sold_type for j in range(self.patches.shape[1])] for i in range(self.patches.shape[0])])
        return(matrix)
Пример #4
0
class CivModel(Model):

    def __init__(self, N):

        self.nb_agents = N  # Nombre d'agents
        self.schedule = BaseScheduler(self)  # Timeline basic

        # Initializations spatials des agents
        positions = self.spawn_clusters()
        #print(positions, len(positions))

        for i in range(self.nb_agents):
            # positionne aléatoirement l'agent sur la grille
            agent = CivAgent(i, self)
            agent.x, agent.y, agent.z = positions[i]
            self.schedule.add(agent)  # ajoute les agents à la timeline

        # Calcules les distances entre les agents
        self.distances_log = self.calculate_distance()

        # Timeline
        self.timeline = 0
        self.connection_logs = {}  # connections effectuées dict[tour[int] : list[connections]]
        self.removed_agents = {}  # agents enlevés dict[tour[int] : list[agents]]

        # Chaîne de suspicion
        self.suspicions = {} # key : (agent1, agent2), value : suspicion_cooldown

        # Historique
        self.historique = {} # dict[tour[int], list[agents]]
        self.historique[0] = list(self.schedule._agents.values())

### Utilitaires ###############################################################

    def remove_store(self, agent_id):
        """We use this function instead of the mesa remove() implemented method. It allows storing after supression"""
        self.removed_agents[self.timeline] = []
        self.removed_agents[self.timeline].append(
            self.schedule._agents[agent_id])
        self.schedule.remove(self.schedule._agents[agent_id])

    def restitute_agents(self, time):
        """Permet de revenir à l'état du model à l'étape 'time'"""
        old_state = self.schedule._agents
        to_add = [v for k, v in self.removed_agents.items() if k >= time]

        # list[list]->list[int]
        n = []
        for i in to_add:
            n += i
        to_add = n

        # print(to_add)
        for agent in to_add:
            old_state[agent.unique_id] = agent
        # print(old_state.keys())

        return old_state

###############################################################################

### Localisation ##############################################################

    def spawn_clusters(self):
        """Répartis les civilisations en clusters de densité égale 
           dans l'univers (peut être assimiler à des galaxies)"""
        coords = []

        for i in range(nb_clusters):
            clx, cly, clz = random.randint(0, univers_scale), random.randint(
                0, univers_scale), random.randint(0, univers_scale)  # Créer un point de cluster

            # Créé un nombres de groupe d'agent équivalent à celui des clusters
            rd_nb_civ = int(self.nb_agents/nb_clusters)+1
            # Répartis aléatoiremnt les civilisations autour de ce clusters dans un radius donné.
            for j in range(rd_nb_civ):
                r = clusters_scale
                pl_x, pl_y, pl_z = random.randint(max(
                    0, clx-r), min(univers_scale, clx+r)), random.randint(max(0, cly-r), min(univers_scale, cly+r)), random.randint(max(0, clz-r), min(univers_scale, clz+r))
                coords.append((pl_x, pl_y, pl_z))
        return coords

    def sort_dict(self, dic, first_term=False):
        """Tri le dictionnaire de distance de la valeur la plus grande à la plus faible"""
        sorted_dict = {}
        if first_term:
            for i in range(self.nb_agents):
                sorted_dict.update({k: v for k,
                                    v in sorted(dic.items(), key=lambda item: item[1]) if i is k[0]})
        else:
            sorted_dict = {k: v for k, v in sorted(
                dic.items(), key=lambda item: item[1])}
        return sorted_dict

    def calculate_distance(self):
        """Créé un dictionnaire dont les keys sont la pair d'agent en question la la value la distance les séparant"""
        distances_log = {}
        for i in self.schedule._agents:
            #print(distances_log, len(distances_log))
            if i in self.schedule._agents.keys():
                agentA = self.schedule._agents[i]
                for j in range(i+1, len(self.schedule._agents)):
                    if j in self.schedule._agents.keys():
                        agentB = self.schedule._agents[j]
                        d = math.sqrt((agentA.x-agentB.x)**2 +
                                      (agentA.y-agentB.y)**2 + (agentA.z-agentB.z)**2)
                        distances_log[(i, j)] = d
        return distances_log

###############################################################################

### Connection inter-agents ###################################################

    def random_connect(self, methodeTheo=False, seed=0):
        """Renvoie une liste de pair d'agent dans l'orde aléatoire"""
        random_id = random.sample(
            [k for k in range(len(list(self.schedule._agents)))], len(list(self.schedule._agents)))
        n_l = list(range(len(list(self.schedule._agents))))
        connection = list(zip(n_l, random_id))
        # print(connection)
        return connection

    def nn_connect(self):
        """Connect chaque agent avec les autres en partant du plus proches"""
        distances_dict = self.calculate_distance()
        for i in range(self.nb_agents):
            order_of_connection = self.sort_dict(distances_dict)
        # print(order_of_connection)
        return order_of_connection.keys()

###############################################################################

### Detection #################################################################

    def detect_distance_check(self, distance, opacity_factor, threshold):
        """Utilise la fonction exp(-kx) pour simuler la difficulté des civilisations 
            à communiquer par rapport à la distance qui les sépare"""
        d_scaled = distance/univers_scale
        return math.exp(-opacity_factor*d_scaled)

    def detect(self, agentA, agentB, both=True):
        """Renvoie si oui ou non l'agent a detect l'agent b
            Fonctionnement du système émission/réception:
            Plus un agent émet de signaux, plus il est repérable. Le niveau de reception
            définit la capacité d'un agent à détecter des signaux.
            Par conséquent plus le niveau d'emission d'un agent est haut plus il
            est facilement reperable par des agents dont le niveau de reception est bas.
            """

        if agentA.reception == 0:
            return False
            # Cas ou reception = 0, L'agent ne peut rien reperer
            print("Agent", self.schedule._agents, "ne peut rien reperer")
        else:
            a = self.detect_distance_check(self.distances_log[(min(agentA.unique_id, agentB.unique_id), max(
                agentA.unique_id, agentB.unique_id))], opacity_factor, threshold)

            if not a >= threshold:
                print("Trop loin...")
                print(self.distances_log[(min(agentA.unique_id, agentB.unique_id), max(
                    agentA.unique_id, agentB.unique_id))], a, threshold)
                return a >= threshold
            # max(Reception) + 1
            return agentA.reception + agentB.emission >= reception_range+1

###############################################################################

### Logique ###################################################################
    
    def contact(self, a, b):
        """Logique de contact entre deux agents a et b, soit deux agents, cette fonction compare leur
            self.type (0 pour Pacifique (P) et 1 pour aggressif (A)) et leur niveau technologique
            (self.tech_lvl) si besoin"""

        if a in list(self.schedule._agents) and b in list(self.schedule._agents):
            agent_a = self.schedule._agents[a]
            agent_b = self.schedule._agents[b]

            if a == b:
                print("Meme agent")
                return
            # Si A ne detect pas B, vérifie que B ne detect pas A puis passe
            elif not self.detect(agent_a, agent_b):
                print("Agent", a, "ne rentre pas en contact avec Agent",
                      b, ": AR", agent_a.reception, "/ BE", agent_b.emission)
                return

                if not self.detect(agent_b, agent_a):
                    print("Agent", b, "ne rentre pas en contact avec Agent",
                          a, ": BR", agent_b.reception, "/ AE", agent_a.emission)
                    return
                else:
                    print("Mais Agent", b, "rentre en contact avec Agent",
                          a, ": BR", agent_b.reception, "/ AE", agent_a.emission)
        else:
            return

        print("Agents", a, b, "entre en contact !",)
        if agent_a.type < agent_b.type:  # Si b Aggressif et a Pacifist
            self.remove_store(a)
            # self.schedule.remove(agent_a)  # remove a
            print("Agent", a, "destroyed by Agent", b)
        elif agent_a.type > agent_b.type:  # Si b Pacifist et a Aggressif
            self.remove_store(b)
            # self.schedule.remove(agent_b)  # remove b
            print("Agent", b, "destroyed by Agent", a)
        elif agent_a.type == 1 and agent_b.type == 1:  # Si b Aggressif et a Aggressif, regarde le tech_lvl
            print("Agents", a, "and", b, "are both aggresive")
            # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
            if agent_a.tech_lvl == agent_b.tech_lvl:
                print(a, "and", b,
                      "have the same technological level, nothing appends")
                return
            elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                self.remove_store(a)
                # self.schedule.remove(agent_a)
                print("Agent", b, "stronger than Agent", a)
                print("Agent", a, "destroyed by Agent", b)
            else:
                self.remove_store(b)
                # self.schedule.remove(agent_b)  # Same mais inverse
                print("Agent", a, "stronger than Agent", b)
                print("Agent", b, "destroyed by Agent", a)
        else:
            # Cas où les deux agents sont pacifistes et la chaine de suspicion s'engrange, à implémenter
            print("Agent", a, "and", b,
                  "are both pacifists -> chaine de suspicion (implémenté)----------------------")
            if (a,b) not in self.suspicions:
                self.suspicions[(a,b)] = suspicion_cooldown
                print(self.suspicions)
            # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
            if agent_a.tech_lvl == agent_b.tech_lvl:
                print(a, "and", b,
                      "have the same technocontactal level, nothing appends")
                return
            elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                self.remove_store(a)
                # self.schedule.remove(agent_a)
                print("Agent", b, "stronger than Agent", a)
                print("Agent", a, "destroyed by Agent", b)
            else:
                self.remove_store(b)
                # self.schedule.remove(agent_b)  # Same mais inverse
                print("Agent", a, "stronger than Agent", b)
                print("Agent", b, "destroyed by Agent", a)

    def step(self):
        """Agissement du model à chaque étape"""

        # Update historique
        self.historique[self.timeline] = list(self.schedule._agents.values())
        #print("Historique à time =", self.timeline, [i.unique_id for liste in self.historique.values() for i in liste])

        # Compte le nombre de tour
        print("Tour :", self.timeline)
        self.timeline += 1

        # Connecte les agents
        r_l = self.random_connect()
        # Add the ongoing connection to the log (so it can be reused afterwards)
        self.connection_logs[self.timeline] = r_l
        print("Liste des connections", r_l)

        #Logique de contact et de 
        self.resolve_suspicious()
        for a, b in r_l:
            self.contact(a, b)

        # Renvoie la liste des agents ayant survécu
        print("Survivors:")
        # affiche les agents restant
        self.schedule.step()
        print("Nombre d'agents restant", len(self.schedule._agents))

    def resolve_suspicious(self):
        for agentA, agentB in self.suspicions.keys():
            if self.suspicions[(agentA, agentB)] == 0:
                self.contact(agentA, agentB)
                print("Séquence suspicion terminer : ", agentA, agentB)
                continue
            self.suspicions[(agentA, agentB)] -= 1
            print("Les agents", agentA, "et", agentB, "se méfient")
        print(self.suspicions)

        # delete toutes les chaines terminées
        to_del = list(self.suspicions.items())
        for k, v in to_del:
            if v <= 0:
                del self.suspicions[k]
        print(self.suspicions)


###############################################################################

### Indicateurs ###############################################################
    
    def distance_moyenne(self, time):
        agent_ids = self.historique[time]
        sum_dist = 0
        n = 0
        for a, b in self.distances_log.key():
            if a in agent_ids and b in agent_ids:
                sum_dist += self.distances_log[(a, b)]
                n +=1

        return sum_dist/n

    def ratio_P(self, time):
        agent_ids = self.historique[time]
        tot_P = 0
        for i in agent_ids:
            if self.schedule._agents[i] == 0:
                tot_P += 1

        return tot_P/len(agent_ids)

    def ratio_A(self, time):
        return math.abs(1-self.ratio_P(time))

    def ems_moyen(self, time):
        agent_ids = self.historique[time]
        sum_ems = 0
        n = 0
        for i in agent_ids:
            sum_ems += self.schedule._agents[i].emission
            n += 1

        return sum_ems/n
        
    def rec_moyen(self, time):
        agent_ids = self.historique[time]
        sum_ems = 0
        n = 0
        for i in agent_ids:
            sum_ems += self.schedule._agents[i].reception
            n += 1

        return sum_ems/n

    def tech_moyen(self, time):
        agent_ids = self.historique[time]
        sum_ems = 0
        n = 0
        for i in agent_ids:
            sum_ems += self.schedule._agents[i].tech_lvl
            n += 1

        return sum_ems/n

    def nb_contact(self, time):
        return
Пример #5
0
class CivModel(Model):

    def __init__(self, N):

        self.nb_agents = N  # Nombre d'agents
        self.schedule = BaseScheduler(self)  # Timeline basic

        # Initializations spatials des agents
        positions = self.spawn_clusters()
        #print(positions, len(positions))

        for i in range(self.nb_agents):
            # positionne aléatoirement l'agent sur la grille
            agent = CivAgent(i, self)
            agent.x, agent.y, agent.z = positions[i]
            self.schedule.add(agent)  # ajoute les agents à la timeline

        # Calcules les distances entre les agents
        self.distances_log = self.calculate_distance()

    def spawn_clusters(self):
        """Répartis les civilisations en clusters de densité égale 
           dans l'univers (peut être assimiler à des galaxies)"""
        coords = []

        for i in range(nb_clusters):
            clx, cly, clz = random.randint(0, univers_scale), random.randint(
                0, univers_scale), random.randint(0, univers_scale)  # Créer un point de cluster

            # Créé un nombres de groupe d'agent équivalent à celui des clusters
            rd_nb_civ = int(self.nb_agents/nb_clusters)+1
            # Répartis aléatoiremnt les civilisations autour de ce clusters dans un radius donné.
            for j in range(rd_nb_civ):
                r = clusters_scale
                pl_x, pl_y, pl_z = random.randint(max(
                    0, clx-r), min(univers_scale, clx+r)), random.randint(max(0, cly-r), min(univers_scale, cly+r)), random.randint(max(0, clz-r), min(univers_scale, clz+r))
                coords.append((pl_x, pl_y, pl_z))
        return coords

    def random_connect(self, methodeTheo=False, seed=0):
        """Renvoie une liste de pair d'agent dans l'orde aléatoire"""
        # random.seed(0) # Pas bien !
        random_id = random.sample(
            [k for k in range(len(list(self.schedule._agents)))], len(list(self.schedule._agents)))
        n_l = list(range(len(list(self.schedule._agents))))
        connection = list(zip(n_l, random_id))
        # print(connection)
        return connection

    def sort_dict(self, dic, first_term=False):
        sorted_dict = {}
        if first_term:
            for i in range(self.nb_agents):
                sorted_dict.update({k: v for k,
                                    v in sorted(dic.items(), key=lambda item: item[1]) if i is k[0]})
        else:
            sorted_dict = {k: v for k, v in sorted(
                dic.items(), key=lambda item: item[1])}
        return sorted_dict

    def nn_connect(self):
        """Connect chaque agent avec les autres en partant du plus proches"""
        distances_dict = self.calculate_distance()
        for i in range(self.nb_agents):
            order_of_connection = self.sort_dict(distances_dict)
        # print(order_of_connection)
        return order_of_connection.keys()

    def calculate_distance(self):
        """Créé un dictionnaire dont les keys sont la pair d'agent en question la la value la distance les séparant"""
        distances_log = {}
        for i in self.schedule._agents:
            #print(distances_log, len(distances_log))
            if i in self.schedule._agents.keys():
                agentA = self.schedule._agents[i]
                for j in range(i+1, len(self.schedule._agents)):
                    if j in self.schedule._agents.keys():
                        agentB = self.schedule._agents[j]
                        d = math.sqrt((agentA.x-agentB.x)**2 +
                                      (agentA.y-agentB.y)**2 + (agentA.z-agentB.z)**2)
                        distances_log[(i, j)] = d
        return distances_log

    def detect_distance_check(self, distance, opacity_factor, threshold):
        """Utilise la fonction exp(-kx) pour simuler la difficulté des civilisations 
            à communiquer par rapport à la distance qui les sépare"""
        d_scaled = distance/univers_scale
        return math.exp(-opacity_factor*d_scaled)

    def detect(self, agentA, agentB, both=True):
        """Renvoie si oui ou non l'agent a detect l'agent b
            Fonctionnement du système émission/réception:
            Plus un agent émet de signaux, plus il est repérable. Le niveau de reception
            définit la capacité d'un agent à détecter des signaux.
            Par conséquent plus le niveau d'emission d'un agent est haut plus il
            est facilement reperable par des agents dont le niveau de reception est bas.
            """
        if agentA.reception == 0:
            return False
            # Cas ou reception = 0, L'agent ne peut rien reperer
            print("Agent", self.schedule._agents, "ne peut rien reperer")
        else:
            a = self.detect_distance_check(self.distances_log[(min(agentA.unique_id, agentB.unique_id), max(
                agentA.unique_id, agentB.unique_id))], opacity_factor, threshold)
            print(self.distances_log[(min(agentA.unique_id, agentB.unique_id), max(
                agentA.unique_id, agentB.unique_id))], a, threshold)
            if not a >= threshold:
                print("Trop loin...")

            # max(Reception) + 1, merci Théo
            return agentA.reception + agentB.emission >= reception_range+1 and a >= threshold

    def remove_store(self, agent_id, storage):
        storage.append(self.schedule._agents[agent_id])
        self.schedule.remove(agent_id, storage)
        return storage

    def contact(self):
        """Première aspect de la logique utilisé, random_connect crée une
            liste de tuple qui relie deux CivAgent entre eux cette fonction compare leur
            self.type (0 pour Pacifique (P) et 1 pour aggressif (A)) et leur niveau technologique
            (self.tech_lvl) si besoin."""

        # print(self.schedule._agents[2])
        # print(list(self.schedule._agents))
        r_l = self.random_connect()
        # print(r_l)
        for a, b in r_l:
            # print(a)

            # Si l'agent n'appartient déjà plus à self.schedule (qu'il a donc déjà été remove), passe à la prochaine itération
            if a in list(self.schedule._agents) and b in list(self.schedule._agents):
                agent_a = self.schedule._agents[a]
                agent_b = self.schedule._agents[b]

                if a == b:  # Si A est B, passe
                    print("Meme agent")
                    continue
                # Si A ne detect pas B, vérifie que B ne detect pas A puis passe
                elif not self.detect(agent_a, agent_b):
                    print("Agent", a, "ne rentre pas en contact avec Agent",
                          b, ": AR", agent_a.reception, "/ BE", agent_b.emission)
                    continue
                    if not self.detect(agent_b, agent_a):
                        print("Agent", b, "ne rentre pas en contact avec Agent",
                              a, ": BR", agent_b.reception, "/ AE", agent_a.emission)
                        continue
                    else:
                        print("Mais Agent", b, "rentre en contact avec Agent",
                              a, ": BR", agent_b.reception, "/ AE", agent_a.emission)
            else:
                continue

            print("Agents", a, b, "entre en contact !",)
            if agent_a.type < agent_b.type:  # Si b Aggressif et a Pacifist
                self.schedule.remove(agent_a)  # remove a
                print("Agent", a, "destroyed by Agent", b)
            elif agent_a.type > agent_b.type:  # Si b Pacifist et a Aggressif
                self.schedule.remove(agent_b)  # remove b
                print("Agent", b, "destroyed by Agent", a)
            elif agent_a.type == 1 and agent_b.type == 1:  # Si b Aggressif et a Aggressif, regarde le tech_lvl
                print("Agents", a, "and", b, "are both aggresive")
                # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
                if agent_a.tech_lvl == agent_b.tech_lvl:
                    print(a, "and", b,
                          "have the same technological level, nothing appends")
                    continue
                elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                    self.schedule.remove(agent_a)
                    print("Agent", b, "stronger than Agent", a)
                    print("Agent", a, "destroyed by Agent", b)
                else:
                    self.schedule.remove(agent_b)  # Same mais inverse
                    print("Agent", a, "stronger than Agent", b)
                    print("Agent", b, "destroyed by Agent", a)
            else:
                # Cas où les deux agents sont pacifistes et la chaine de suspicion s'engrange, à implémenter
                print("Agent", a, "and", b,
                      "are both pacifists -> chaine de suspicion (a implémenté, ne fait rien pour l'instant)")
                # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
                if agent_a.tech_lvl == agent_b.tech_lvl:
                    print(a, "and", b,
                          "have the same technological level, nothing appends")
                    continue
                elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                    self.schedule.remove(agent_a)
                    print("Agent", b, "stronger than Agent", a)
                    print("Agent", a, "destroyed by Agent", b)
                else:
                    self.schedule.remove(agent_b)  # Same mais inverse
                    print("Agent", a, "stronger than Agent", b)
                    print("Agent", b, "destroyed by Agent", a)

        # Renvoie la liste des agents ayant survécu
        survivors = [index for index in list(self.schedule._agents)]
        print("Survivors:")
        # affiche les agents restant
        self.schedule.step()
        return survivors

    def step(self):
        # self.schedule.step()
        self.calculate_distance()
        self.contact()

############ Plotting Graphs ##################################################

    def plot_agents_positions(self, color):
        fig = plt.figure()
        ax = fig.add_subplot(projection='3d')

        for agent in self.schedule._agents.values():
            ax.scatter(agent.x, agent.y, agent.z, color=color, marker='o')

        plt.show()

    def plot_agents_type(self):
        fig, axs = plt.subplots(1, 1, figsize=(5, 5)) 
        types = [int(a.type) for a in self.schedule._agents.values()]
        
        return axs.hist(types, bins=2)

    def plot_agents_tech(self):
        fig, axs = plt.subplots(1, 1, figsize=(5, 5)) 
        tech = [a.tech_lvl for a in self.schedule._agents.values()]
        
        return axs.hist(tech, bins=technological_range)

    def plot_agents_ems(self):
        fig, axs = plt.subplots(1, 1, figsize=(5, 5)) 
        ems = [a.emission for a in self.schedule._agents.values()]
        
        return axs.hist(ems, bins=emission_range)

    def plot_agents_rec(self):
        fig, axs = plt.subplots(1, 1, figsize=(5, 5)) 
        rec = [a.reception for a in self.schedule._agents.values()]
        
        return axs.hist(rec, bins=reception_range)
Пример #6
0
class CivModel(Model):
    """A model with some number of agents."""
    def __init__(self, N, width=500, height=500):
        self.nb_agents = N
        self.grid = MultiGrid(width, height, True)
        self.schedule = BaseScheduler(self)  # Créer une timeline

        for i in range(self.nb_agents):

            agent = CivAgent(i, self)
            self.schedule.add(agent)  # ajoute N agent à la timeline
            # positionne aléatoirement l'agent sur la grille
            agent.x = self.random.randrange(self.grid.width)
            agent.y = self.random.randrange(self.grid.height)
            agent.pos = agent.x, agent.y
            self.grid.place_agent(agent, agent.pos)

    def random_connect(self, seed=0):
        """Renvoie une liste de pair d'agent dans l'orde aléatoire"""
        #random.seed(0) # Pas bien !
        random_id = random.sample([k for k in range(self.nb_agents)],
                                  self.nb_agents)
        n_l = [k for k in range(self.nb_agents)]
        connection = list(zip(n_l, random_id))
        print(connection)
        return connection

    def detect(self, agentA, agentB, both=True):
        """Renvoie si oui ou non l'agent a detect l'agent b
            Fonctionnement du système émission/réception:
            Plus un agent émet de signaux, plus il est repérable. Le niveau de reception
            définit la capacité d'un agent à détecter des signaux.
            Par conséquent plus le niveau d'emission d'un agent est haut plus il
            est facilement reperable par des agents dont le niveau de reception est bas.
            """
        if agentA.reception == 0:
            return False
            print("Agent", self.schedule._agents, "ne peut rien reperer"
                  )  # Cas ou reception = 0, L'agent ne peut rien reperer
        else:
            # Créé une liste par compréhension dont les élement sont les niveaux d'emissions reperables par l'agent A,
            # si l'agent B a un niveau d'emission appartement à cette liste alors A peut reperer B
            spotable_agents = [
                k for k in range(emission_range - 1, emission_range -
                                 agentA.reception - 1, -1)
            ]
            print("Agent", agentA.unique_id, "R" + str(agentA.reception),
                  "Agent", agentB.unique_id, "E" + str(agentB.emission),
                  "l'agent peut reperer ceux dont l'emission est : ",
                  spotable_agents)
            return agentB.emission in spotable_agents  # renvoie vrai si l'agentB peut etre repere par A ou faux sinon

    def contact(self):
        """Première aspect de la logique utilisé, random_connect crée une 
            liste de tuple qui relie deux CivAgent entre eux cette fonction compare leur 
            self.type (0 pour Pacifique (P) et 1 pour aggressif (A)) et leur niveau technologique
            (self.tech_lvl) si besoin."""

        #print(self.schedule._agents[2])
        #print(list(self.schedule._agents))
        r_l = self.random_connect(0)
        #print(r_l)
        for a, b in r_l:
            #print(a)

            # Si l'agent n'appartient déjà plus à self.schedule (qu'il a donc déjà été remove), passe à la prochaine itération
            if a in list(self.schedule._agents) and b in list(
                    self.schedule._agents):
                agent_a = self.schedule._agents[a]
                agent_b = self.schedule._agents[b]

                if a == b:  # Si A est B, passe
                    print("Meme agent")
                    continue
                elif not self.detect(
                        agent_a, agent_b
                ):  # Si A ne detect pas B, vérifie que B ne detect pas A puis passe
                    print("Agent", a, "ne rentre pas en contact avec Agent", b,
                          ": AR", agent_a.reception, "/ BE", agent_b.emission)
                    continue
                    if not self.detect(agent_b, agent_a):
                        print("Agent", b,
                              "ne rentre pas en contact avec Agent", a, ": BR",
                              agent_b.reception, "/ AE", agent_a.emission)
                        continue
                    else:
                        print("Mais Agent", b, "rentre en contact avec Agent",
                              a, ": BR", agent_b.reception, "/ AE",
                              agent_a.emission)
            else:
                continue

            print("Agents", a, b, "entre en contact !", "Agents restant",
                  list(self.schedule._agents))
            if agent_a.type < agent_b.type:  # Si b Aggressif et a Pacifist
                self.schedule.remove(agent_a)  # remove a
                print("Agent", a, "destroyed by Agent", b)
            elif agent_a.type > agent_b.type:  # Si b Pacifist et a Aggressif
                self.schedule.remove(agent_b)  # remove b
                print("Agent", b, "destroyed by Agent", a)
            elif agent_a.type == 1 and agent_b.type == 1:  # Si b Aggressif et a Aggressif, regarde le tech_lvl
                print("Agents", a, "and", b, "are both aggresive")
                if agent_a.tech_lvl == agent_b.tech_lvl:  # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
                    print(
                        a, "and", b,
                        "have the same technological level, nothing appends")
                    continue
                elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                    self.schedule.remove(agent_a)
                    print("Agent", b, "stronger than Agent", a)
                    print("Agent", a, "destroyed by Agent", b)
                else:
                    self.schedule.remove(agent_b)  # Same mais inverse
                    print("Agent", a, "stronger than Agent", b)
                    print("Agent", b, "destroyed by Agent", a)
            else:
                # Cas où les deux agents sont pacifistes et la chaine de suspicion s'engrange, à implémenter
                print(
                    "Agent", a, "and", b,
                    "are both pacifists -> chaine de suspicion (a implémenté, ne fait rien pour l'instant)"
                )
                if agent_a.tech_lvl == agent_b.tech_lvl:  # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
                    print(
                        a, "and", b,
                        "have the same technological level, nothing appends")
                    continue
                elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                    self.schedule.remove(agent_a)
                    print("Agent", b, "stronger than Agent", a)
                    print("Agent", a, "destroyed by Agent", b)
                else:
                    self.schedule.remove(agent_b)  # Same mais inverse
                    print("Agent", a, "stronger than Agent", b)
                    print("Agent", b, "destroyed by Agent", a)

        # Renvoie la liste des agents ayant survécu
        survivors = [index for index in list(self.schedule._agents)]
        print("Survivors:")
        #affiche les agents restant
        self.schedule.step()
        return survivors

    def step(self):
        #self.schedule.step()
        self.contact()
Пример #7
0
class School(Model):
    def __init__(self,
                 map_path,
                 schedule_path,
                 grade_N,
                 KG_N,
                 preschool_N,
                 special_education_N,
                 faculty_N,
                 seat_dist,
                 init_patient=3,
                 attend_rate=1,
                 mask_prob=0.516,
                 inclass_lunch=False,
                 username="******"):
        # zipcode etc, for access of more realistic population from KG perhaps

        # model param init
        self.__mask_prob = mask_prob
        self.inclass_lunch = inclass_lunch
        self.seat_dist = math.ceil(seat_dist / (attend_rate**(1 / 2)))
        self.idle_teachers = []  # teachers to be assigned without a classroom
        self.init_patient = init_patient

        # mesa model init
        self.running = True
        self.grid = GeoSpace()
        self.schedule = BaseScheduler(self)

        #data collect init
        model_reporters = {
            "day": "day_count",
            "cov_positive": "infected_count"
        }
        agent_reporters = {
            "unique_id": "unique_id",
            "health_status": "health_status",
            "symptoms": "symptoms",
            "x": "x",
            "y": "y",
            "viral_load": "viral_load"
        }
        self.datacollector = datacollection.DataCollector(
            model_reporters=model_reporters, agent_reporters=agent_reporters)

        school_gdf = load_map(map_path)

        # room agent init
        self.room_agents = school_gdf.apply(
            lambda x: Classroom(unique_id=x["Id"],
                                model=self,
                                shape=x["geometry"],
                                room_type=x["room_type"]),
            axis=1).tolist()

        self.grid.add_agents(self.room_agents)

        # stats tracking init
        self.infected_count = 0
        self.step_count = 0
        self.day_count = 0
        self.num_exposed = 0

        # student activity init
        self.schoolday_schedule = pd.read_csv(schedule_path)
        self.activity = None

        # id tracking init
        self.__teacher_id = 0
        self.__student_id = 0
        self.__faculty_N = faculty_N
        self.schedule_ids = self.schoolday_schedule.columns

        self.recess_yards = find_room_type(self.room_agents, 'recess_yard')

        def init_agents(room_type, N, partition=False):
            '''
            batch initialize human agents into input room type rooms with equal partition size
            
            room_type: a valid string of room type: [None, 'restroom_grade_boys', 'lunch_room', 'classroom_grade',
               'restroom_all', 'restroom_grade_girls', 'restroom_KG',
               'classroom_KG', 'community_room', 'library',
               'restroom_special_education', 'restroom_faculty',
               'classroom_special_education', 'health_room', 'faculty_lounge',
               'classroom_preschool', 'restroom_preschool']
            '''

            rooms = find_room_type(self.room_agents, room_type)

            # if student group should be seperated to different day schedules
            # assigning schedule_id to equally partitioned rooms
            # currently only grade 1-5 "grade" students need to be partitioned,
            partition_size = len(rooms)
            if partition:
                partition_size = math.ceil(partition_size /
                                           len(self.schedule_ids))

            class_size = N // len(rooms)
            remaining_size = N % len(rooms)

            for i, classroom in zip(range(len(rooms)), rooms):

                classroom.generate_seats(class_size, self.seat_dist)
                classroom.schedule_id = self.schedule_ids[i // partition_size]

                for idx in range(class_size):
                    pnt = classroom.seats[idx]
                    mask_on = np.random.choice([True, False],
                                               p=[mask_prob, 1 - mask_prob])
                    agent_point = Student(model=self,
                                          shape=pnt,
                                          unique_id="S" +
                                          str(self.__student_id),
                                          room=classroom,
                                          mask_on=mask_on)

                    self.grid.add_agents(agent_point)
                    self.schedule.add(agent_point)
                    self.__student_id += 1

                # spread remaining student into all classrooms
                if remaining_size > 0:
                    pnt = classroom.seats[class_size]
                    mask_on = np.random.choice([True, False],
                                               p=[mask_prob, 1 - mask_prob])
                    agent_point = Student(model=self,
                                          shape=pnt,
                                          unique_id="S" +
                                          str(self.__student_id),
                                          room=classroom,
                                          mask_on=mask_on)

                    self.grid.add_agents(agent_point)
                    self.schedule.add(agent_point)
                    self.__student_id += 1
                    remaining_size -= 1

                #add teacher to class
                pnt = generate_random(classroom.shape)
                agent_point = Teacher(model=self,
                                      shape=pnt,
                                      unique_id="T" + str(self.__teacher_id),
                                      room=classroom)
                self.grid.add_agents(agent_point)
                self.schedule.add(agent_point)
                self.idle_teachers.append(agent_point)
                self.__teacher_id += 1
                self.__faculty_N -= 1

        # initialize all students and teachers in classrooms
        init_agents("classroom_grade",
                    int(grade_N * attend_rate),
                    partition=True)
        # keep track of student types
        #self.grade_students = [a for a in list(self.schedule.agents) if isinstance(a, Student)]
        init_agents("classroom_KG", int(KG_N * attend_rate))
        init_agents("classroom_preschool", int(preschool_N * attend_rate))
        #self.pkg_students = [a for a in list(set(self.schedule.agents).difference(self.grade_students)) if isinstance(a, Student)]
        init_agents("classroom_special_education",
                    int(special_education_N * attend_rate))

        # dump remaining teacher to faculty lounge
        for f_lounge in find_room_type(self.room_agents, "faculty_lounge"):
            f_lounge.schedule_id = self.schedule_ids[0]

            for i in range(self.__faculty_N):

                pnt = generate_random(f_lounge.shape)
                agent_point = Teacher(model=self,
                                      shape=pnt,
                                      unique_id="T" + str(self.__teacher_id),
                                      room=f_lounge)
                self.grid.add_agents(agent_point)
                self.schedule.add(agent_point)
                self.__teacher_id += 1

        #self.people = list(self.schedule.agents)

        # add rooms to scheduler at last
        for room in self.room_agents:
            self.schedule.add(room)

        self.lunchroom = find_room_type(self.room_agents, 'lunch_room')[0]
        self.lunchroom.generate_seats_lunch(3, 12)

    def small_step(self):
        self.schedule.step()
        self.grid._recreate_rtree()

    def add_N_patient(self, N):
        patients = random.sample(
            [a for a in self.schedule.agents if isinstance(a, Student)], N)
        for p in patients:
            p.health_status = "exposed"
            p.asymptomatic = True
            p.infective = True

    def show(self):
        '''
        plot current step visualization
        deprecated since end of model visualization update
        '''

        # UPDATE 10/16: add deprecation warning
        message = "this function is no longer used for performance issues, check output_image.py for end of model visualization"
        warnings.warn(message, DeprecationWarning)

        school_geometry = gpd.GeoSeries([a.shape for a in self.room_agents])
        school_map = gpd.GeoDataFrame(
            {"viral_load": [min(a.viral_load, 5) for a in self.room_agents]})
        school_map.geometry = school_geometry
        basemap = school_map.plot(column="viral_load",
                                  cmap="Reds",
                                  alpha=0.5,
                                  vmin=0,
                                  vmax=5)
        school_map.boundary.plot(ax=basemap, color='k', linewidth=0.2)

        list(
            map(lambda a: a.plot(), [
                a for a in self.schedule.agents if issubclass(type(a), Human)
            ]))

        hour = 9 + self.step_count * 5 // 60  # assume plot start at 9am
        minute = self.step_count * 5 % 60
        plt.title("Iteration: Day {}, ".format(self.day_count + 1) +
                  "%d:%02d" % (hour, minute),
                  fontsize=30)

    def __update_day(self):
        '''
        update incubation time, reset viral_load, remove symptomatic agents, etc for end of day
        '''

        for a in self.schedule.agents[:]:
            if issubclass(type(a), Human):

                if a.symptoms:
                    # remove agent if symptom onset
                    if isinstance(a, Teacher):
                        # assign a new teacher to position
                        new_teacher = self.idle_teachers.pop()
                        new_teacher.shape = a.shape
                        new_teacher.room = a.room
                        new_teacher.classroom = a.classroom
                    self.schedule.remove(a)
                    self.grid.remove_agent(a)

                # UPDATE 10/16: infectious made obsolete, end of day update rework
                elif a.health_status == "exposed":
                    # UPDATE 10/17: update infective delay if agent is not infective by end of day
                    a.infective = True
                    a.symptom_countdown -= 1
                    # calculate when symptoms begin to show using 0-15 density
                    if a.symptom_countdown <= 0:
                        if a.symptom_countdown == 0:
                            self.infected_count += 1
                        # update model stat for total infected
                        # negative countdown means this agent is asymptomatic

                        if not a.asymptomatic:
                            # this is a really small chance, however possible
                            # set symtoms to true
                            # next day this agent will be removed from the model
                            a.symptoms = True

            else:
                # reset viral_load of room agents
                a.viral_load = 0

    def step(self):
        '''
        simulate a day with school day schedule
        '''
        if not self.schedule.steps:
            self.add_N_patient(self.init_patient)

        for i, row in self.schoolday_schedule.iterrows():
            self.activity = row
            self.datacollector.collect(self)
            self.schedule.step()
            self.grid._recreate_rtree()
            self.step_count += 1

        self.__update_day()
        self.grid._recreate_rtree()
        self.day_count += 1
        self.step_count = 0
Пример #8
0
class Labor_Model(Model):
    def __init__(self,num_employee=1000,num_employer=10,num_jobseekers=10,wage_flexibility=(0.5,0.5),p_1=0.01,p_2=0.01,p_3=0.01):
        self.num_employer = num_employer
        self.employer_index = 0
        self.num_employee = num_employee
        self.employee_index = 0
        self.num_jobseekers = num_jobseekers
        self.wage_flexibility = wage_flexibility
        self.p_1 = p_1
        self.p_2 = p_2
        self.p_3 = p_3
        self.p_4 = 1
        self.schedule_employees = BaseScheduler(self)
        self.schedule_employers = BaseScheduler(self)
        self.job_seeker_pool = []
        self.inactive_pool = []
        self.employee_seeker_pool = []
        self.datacollector = Data_Collector(self)
        self.create_employee(self.num_employee)
        self.create_employer(self.num_employer,self.num_employee,wage_flexibility)

        ## INIT ALLOCATING FIRMS TO WORKERS
        while(self.employee_seeker_pool or self.job_seeker_pool):
            employer = random.choice(self.employee_seeker_pool)

            for i in range(employer.firm_size):
                employee = random.choice(self.job_seeker_pool)
                self.change_employer(employee,employer)

        ## ADDING JOB SEEKERS
        for i in range(self.num_jobseekers):
            a = random.choice(self.schedule_employees.agents)
            while(a.employer == None):
                a = random.choice(self.schedule_employees.agents)
            self.change_employer(a,employer=None)

        ##FIND JOBS
        self.job_search()

    def create_employee(self,num):
        wage_list = self.create_wage_list(num)
        age_list = [a / 4.0 for a in range(80, 240)]

        for i in range(self.employee_index,self.employee_index + num):
            age = random.choice(age_list)
            a = Employee_Agent(i, self, wage_list[i-self.employee_index], age)
            self.job_seeker_pool.append(a)
            self.schedule_employees.add(a)
        self.employee_index += num

    def create_employer(self,num_employer,num_employee,wage_flexibility,add_vacancy_wage_list=False):
        firm_size_list = self.create_firm_size_list(num_employer,num_employee)

        for i in range(self.employer_index,self.employer_index + num_employer):
            a = Employer_Agent(i,self,firm_size_list[i-self.employer_index],wage_flexibility)
            self.employee_seeker_pool.append(a)
            self.schedule_employers.add(a)
            if(add_vacancy_wage_list):
                wage_list = self.create_wage_list(num_employee)
                a.vacancy_wage_list.extend(wage_list)
        self.employer_index += num_employer

    def create_wage_list(self,num):
        list = []
        for i in range(num):
            list.append(np.random.lognormal(mean=100,sigma=0.7))
        mean_val = float(sum(list)) / len(list)
        normalized_list = [(100 / mean_val) * list[i] for i in range(num)]

        return np.round(normalized_list).astype(int).tolist()

    def create_firm_size_list(self,num_employer,num_employee):
        list = []
        for i in range(num_employer):
            list.append(np.random.power(1))
        mean_val = float(sum(list)) / len(list)
        new_mean_val = num_employee / num_employer
        normalized_list = [(new_mean_val / mean_val) * list[i] for i in range(num_employer)]
        normalized_list = np.round(normalized_list,decimals=0).astype(int).tolist()
        if(sum(normalized_list) != num_employee):
            diff = num_employee - sum(normalized_list)
            normalized_list[normalized_list.index(max(normalized_list))] += diff

        return normalized_list

    def change_employer(self,employee,employer,change_past_employer=True,leaving_wf = False,employer_closed=False):
        ##If they are changing employers
        if(employer is not None):
            employer.employees.append(employee)
            employer.employee_wage_list.append(employee.wage)
            employee.employer = employer
            self.job_seeker_pool.remove(employee)
            if(len(employer.employees) == employer.firm_size):
                self.employee_seeker_pool.remove(employee.employer)
        ##If they are either leaving the WF or quitting/retrenched
        else:
            ##not leaving the work-fore
            if(not leaving_wf):
                self.job_seeker_pool.append(employee)
                employee.employer.employees.remove(employee)
                employee.employer.employee_wage_list.remove(employee.wage)
                employee.employer.vacancy_wage_list.append(employee.wage)
                if (not employee.employer in self.employee_seeker_pool and not employer_closed):
                    self.employee_seeker_pool.append(employee.employer)
                if (change_past_employer):
                    employee.past_employer = employee.employer
                employee.employer = None

            ##If they are leaving the workforce
            else:

                if(employee in self.job_seeker_pool):
                    self.job_seeker_pool.remove(employee)
                else:
                    employee.employer.employees.remove(employee)
                    employee.employer.employee_wage_list.remove(employee.wage)
                    employee.employer.vacancy_wage_list.append(employee.wage)
                    if (not employee.employer in self.employee_seeker_pool and not employer_closed):
                        self.employee_seeker_pool.append(employee.employer)
                    if (change_past_employer):
                        employee.past_employer = employee.employer
                employee.employer = None
                self.inactive_pool.append(employee)

    def job_search(self):
        list = []
        for e in self.employee_seeker_pool:
            for wage in e.vacancy_wage_list:
                list.append((e,wage))
        sortedlist = sorted(list,key=lambda x : x[1],reverse=True)

        for employer, wage in sortedlist:
            possible_candidates = []
            for a in self.job_seeker_pool:
                allowable_wage = (a.wage * (1 - e.wage_flexibility[0]), a.wage * (1 + e.wage_flexibility[1]))
                if (allowable_wage[0] <= wage <= allowable_wage[1] and a.past_employer != employer):
                    possible_candidates.append(a)
            if (possible_candidates):
                # print([str(x) for x in possible_candidates])
                chosen_candidate = sorted(possible_candidates, key=lambda x: x.wage,reverse=True)[0]
                # print(chosen_candidate)
                chosen_candidate.wage = wage
                self.change_employer(chosen_candidate, employer)
                employer.vacancy_wage_list.remove(wage)


    def step(self):
        ##wipe inactive ppl and add in new peeps
        if(self.inactive_pool):
            for i in self.inactive_pool:
                self.schedule_employees.remove(i)
            self.create_employee(len(self.inactive_pool))
            self.inactive_pool = []

        ##Age everyone
        self.schedule_employees.step()
        retiree = [a for a in self.schedule_employees.agents if a.age >= 60.0]
        for r in retiree:
            self.change_employer(r,employer=None,leaving_wf=True)

        ##Employed & Unemployed peeps leaving WF
        employed_list = [x for x in self.schedule_employees.agents if x not in self.job_seeker_pool and x not in self.inactive_pool]
        for i in range(int(self.p_3 * len(employed_list))):
            a = random.choice(employed_list)
            self.change_employer(a,employer=None,leaving_wf=True)
            employed_list.remove(a)
        unemployed_list = [x for x in self.job_seeker_pool if x not in self.inactive_pool]
        for i in range(int(self.p_2 * len(unemployed_list))):
            a = random.choice(unemployed_list)
            self.change_employer(a, employer=None,leaving_wf=True)
            unemployed_list.remove(a)

        ##Employed peeps quitting (but not leaving the WF)
        employed_list = [x for x in self.schedule_employees.agents if x not in self.job_seeker_pool and x not in self.inactive_pool]
        for i in range(int(self.p_1) * len(employed_list)):
            a = random.choice(employed_list)
            self.change_employer(a,employer=None)
            employed_list.remove(a)

        ##Employers closing down
        firm_size = 0
        for i in range(self.p_4):
            a = random.choice(self.schedule_employers.agents)
            firm_size += a.firm_size
            self.schedule_employers.remove(a)
            if(a in self.employee_seeker_pool):
                self.employee_seeker_pool.remove(a)
            employee_list = a.employees[:]
            for w in employee_list:
                self.change_employer(w,employer=None,employer_closed=True)

        ##Employers entering
        self.create_employer(self.p_4,firm_size,self.wage_flexibility,add_vacancy_wage_list=True)

        ##Job matching occurs
        self.job_search()

        self.datacollector.step()
Пример #9
0
class CivModel(Model):
    """A model with some number of agents."""
    def __init__(self, N):
        self.nb_agents = N
        self.schedule = BaseScheduler(self)  # Créer une timeline

        for i in range(self.nb_agents):
            agent = CivAgent(i, self)
            self.schedule.add(agent)  # ajoute N agent à la timeline
            # positionne aléatoirement l'agent sur la grille

        self.distances_log = self.calculate_distance()

    def random_connect(self, methodeTheo=False, seed=0):
        """Renvoie une liste de pair d'agent dans l'orde aléatoire"""
        #random.seed(0) # Pas bien !
        random_id = random.sample(
            [k for k in range(len(list(self.schedule._agents)))],
            len(list(self.schedule._agents)))
        n_l = list(range(len(list(self.schedule._agents))))
        connection = list(zip(n_l, random_id))
        print(connection)
        return connection

    def calculate_distance(self):
        distances_log = {}
        for i in self.schedule._agents:
            #print(distances_log, len(distances_log))
            if i in self.schedule._agents.keys():
                agentA = self.schedule._agents[i]
                for j in range(i + 1, len(self.schedule._agents)):
                    if j in self.schedule._agents.keys():
                        agentB = self.schedule._agents[j]
                        d = math.sqrt((agentA.x - agentB.x)**2 +
                                      (agentA.y - agentB.y)**2)
                        distances_log[(i, j)] = d
        return distances_log

    def detect_distance_check(self, distance, opacity_factor, threshold):
        d_scaled = distance / univers_scale
        return math.exp(-opacity_factor * d_scaled)

    def detect(self, agentA, agentB, both=True):
        """Renvoie si oui ou non l'agent a detect l'agent b
            Fonctionnement du système émission/réception:
            Plus un agent émet de signaux, plus il est repérable. Le niveau de reception
            définit la capacité d'un agent à détecter des signaux.
            Par conséquent plus le niveau d'emission d'un agent est haut plus il
            est facilement reperable par des agents dont le niveau de reception est bas.
            """
        if agentA.reception == 0:
            return False
            # Cas ou reception = 0, L'agent ne peut rien reperer
            print("Agent", self.schedule._agents, "ne peut rien reperer")
        else:
            a = self.detect_distance_check(
                self.distances_log[(min(agentA.unique_id, agentB.unique_id),
                                    max(agentA.unique_id, agentB.unique_id))],
                opacity_factor, threshold)
            print(
                self.distances_log[(min(agentA.unique_id, agentB.unique_id),
                                    max(agentA.unique_id, agentB.unique_id))],
                a, threshold)
            if not a >= threshold:
                print("Trop loin...")

            return agentA.reception + agentB.emission >= reception_range + 1 and a >= threshold  # max(R) + 1

    def contact(self):
        """Première aspect de la logique utilisé, random_connect crée une
            liste de tuple qui relie deux CivAgent entre eux cette fonction compare leur
            self.type (0 pour Pacifique (P) et 1 pour aggressif (A)) et leur niveau technologique
            (self.tech_lvl) si besoin."""

        # print(self.schedule._agents[2])
        # print(list(self.schedule._agents))
        r_l = self.random_connect()
        # print(r_l)
        for a, b in r_l:
            # print(a)

            # Si l'agent n'appartient déjà plus à self.schedule (qu'il a donc déjà été remove), passe à la prochaine itération
            if a in list(self.schedule._agents) and b in list(
                    self.schedule._agents):
                agent_a = self.schedule._agents[a]
                agent_b = self.schedule._agents[b]

                if a == b:  # Si A est B, passe
                    print("Meme agent")
                    continue
                # Si A ne detect pas B, vérifie que B ne detect pas A puis passe
                elif not self.detect(agent_a, agent_b):
                    print("Agent", a, "ne rentre pas en contact avec Agent", b,
                          ": AR", agent_a.reception, "/ BE", agent_b.emission)
                    continue
                    if not self.detect(agent_b, agent_a):
                        print("Agent", b,
                              "ne rentre pas en contact avec Agent", a, ": BR",
                              agent_b.reception, "/ AE", agent_a.emission)
                        continue
                    else:
                        print("Mais Agent", b, "rentre en contact avec Agent",
                              a, ": BR", agent_b.reception, "/ AE",
                              agent_a.emission)
            else:
                continue

            print("Agents", a, b, "entre en contact !", "Agents restant",
                  list(self.schedule._agents))
            if agent_a.type < agent_b.type:  # Si b Aggressif et a Pacifist
                self.schedule.remove(agent_a)  # remove a
                print("Agent", a, "destroyed by Agent", b)
            elif agent_a.type > agent_b.type:  # Si b Pacifist et a Aggressif
                self.schedule.remove(agent_b)  # remove b
                print("Agent", b, "destroyed by Agent", a)
            elif agent_a.type == 1 and agent_b.type == 1:  # Si b Aggressif et a Aggressif, regarde le tech_lvl
                print("Agents", a, "and", b, "are both aggresive")
                # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
                if agent_a.tech_lvl == agent_b.tech_lvl:
                    print(
                        a, "and", b,
                        "have the same technological level, nothing appends")
                    continue
                elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                    self.schedule.remove(agent_a)
                    print("Agent", b, "stronger than Agent", a)
                    print("Agent", a, "destroyed by Agent", b)
                else:
                    self.schedule.remove(agent_b)  # Same mais inverse
                    print("Agent", a, "stronger than Agent", b)
                    print("Agent", b, "destroyed by Agent", a)
            else:
                # Cas où les deux agents sont pacifistes et la chaine de suspicion s'engrange, à implémenter
                print(
                    "Agent", a, "and", b,
                    "are both pacifists -> chaine de suspicion (a implémenté, ne fait rien pour l'instant)"
                )
                # Niv technologique B == Niv technologique A <=> b Pacifist et a Pacifist, donc passe
                if agent_a.tech_lvl == agent_b.tech_lvl:
                    print(
                        a, "and", b,
                        "have the same technological level, nothing appends")
                    continue
                elif agent_a.tech_lvl < agent_b.tech_lvl:  # Si B a un meilleur NT que A, B détruit A
                    self.schedule.remove(agent_a)
                    print("Agent", b, "stronger than Agent", a)
                    print("Agent", a, "destroyed by Agent", b)
                else:
                    self.schedule.remove(agent_b)  # Same mais inverse
                    print("Agent", a, "stronger than Agent", b)
                    print("Agent", b, "destroyed by Agent", a)

        # Renvoie la liste des agents ayant survécu
        survivors = [index for index in list(self.schedule._agents)]
        print("Survivors:")
        # affiche les agents restant
        # self.schedule.step()
        return survivors

    def step(self):
        #self.schedule.step()
        self.calculate_distance()
        self.contact()