def move(self): ''' The random move function for the fish schools. ''' neighbourhood = MultiGrid.get_neighborhood(self.model.grid, self.pos, True, False, 1) new_pos = random.choice(neighbourhood) MultiGrid.move_agent(self.model.grid, self, new_pos)
def fisherman_move(self): ''' The random move function for the fisherman. ''' neighbourhood = MultiGrid.get_neighborhood(self.model.grid, self.pos, True, False, 1) new_pos = random.choice(neighbourhood) while (new_pos[0] < self.model.no_fish_size) and (new_pos[1] < self.model.no_fish_size): new_pos = random.choice(neighbourhood) MultiGrid.move_agent(self.model.grid, self, new_pos)
class Neighborhood(Model): """A model of a neighborhood with some number of agents.""" def __init__(self, N=10, width=None, height=None): """ Neighborhood: a neighborhood containing people Parameters ---------- N: number of people in the neighborhood width: width of the (rectangular) neighborhood area height: height of the (rectangular) neighborhood area """ super().__init__() self.num_agents = N self.width = width or min(N, 100) self.height = height or min(N, 100) self.grid = MultiGrid(self.width, self.height, True) self.schedule = RandomActivation(self) # Create agents for i in range(self.num_agents): rand = random.random() infection = rand >= (N-N**.5)/N print(i, rand, (N-N**.5)/N) a = Person(i, self, level_of_infection=int(infection)) print(a, a.level_of_infection) self.schedule.add(a) # adding the agent to a random position in the neighborhood (x, y) = random.random() * self.width, random.random() * self.height self.grid.place_agent(a, (int(x), int(y))) def step(self): """Advance the model by one step.""" self.schedule.step() def get_neighbors(self, person, radius=1): """ get neighbors of person """ neighbor_objects = self.grid.get_cell_list_contents([person.pos]) return [*filter(lambda x: type(x) is Person and x is not person, neighbor_objects)] def move_agent(self, *args, **kwargs): return self.grid.move_agent(*args, **kwargs)
class PitchModel(Model): def __init__(self, N, width, height): '''Initiate the model''' self.num_agents = 2 * N self.grid = MultiGrid(width, height, False) self.schedule = SimultaneousActivation(self) self.running = True self.justConceded = 0 self.score1 = 0 self.score2 = 0 self.i = 0 self.newPossession = -1 #Initialise potential fields for each state self.movePotentialGK1 = np.zeros((width, height)) self.movePotentialGK2 = np.zeros((width, height)) self.movePotentialGKP1 = np.zeros((width, height)) self.movePotentialGKP2 = np.zeros((width, height)) self.movePotentialDF1 = np.zeros((width, height)) self.movePotentialDF2 = np.zeros((width, height)) self.movePotentialPO1 = np.zeros((width, height)) self.movePotentialPO2 = np.zeros((width, height)) self.movePotentialBP1 = np.zeros((width, height)) self.movePotentialBP2 = np.zeros((width, height)) #Set initial potential field due to goals self.goalPotentialGK1 = np.zeros((width, height)) self.goalPotentialGK2 = np.zeros((width, height)) self.goalPotentialGKP1 = np.zeros((width, height)) self.goalPotentialGKP2 = np.zeros((width, height)) self.goalPotentialDF1 = np.zeros((width, height)) self.goalPotentialDF2 = np.zeros((width, height)) self.goalPotentialPO1 = np.zeros((width, height)) self.goalPotentialPO2 = np.zeros((width, height)) self.goalPotentialBP1 = np.zeros((width, height)) self.goalPotentialBP2 = np.zeros((width, height)) for x in range(8): for y in range(height): widthVal = ((width / 2) - 4) + x self.goalPotentialGK1[int(widthVal)][ y] = self.goalPotentialGK1[int(widthVal)][y] + (y + 1) self.goalPotentialGK1[int(widthVal)][ height - (y + 1)] = self.goalPotentialGK1[int(widthVal)][ height - (y + 1)] - np.log2(height - (y + 1)) self.goalPotentialGK2[int( widthVal)][y] = self.goalPotentialGK2[int( widthVal)][y] - np.log2(height - (y + 1)) self.goalPotentialGK2[int(widthVal)][height - ( y + 1)] = self.goalPotentialGK2[int(widthVal)][height - (y + 1)] + ( y + 1) self.goalPotentialGKP1[int(widthVal)][ y] = self.goalPotentialGKP1[int(widthVal)][y] + (y + 1) self.goalPotentialGKP1[int(widthVal)][ height - (y + 1)] = self.goalPotentialGKP1[int(widthVal)][ height - (y + 1)] - np.log2(height - (y + 1)) self.goalPotentialGKP2[int( widthVal)][y] = self.goalPotentialGKP2[int( widthVal)][y] - np.log2(height - (y + 1)) self.goalPotentialGKP2[int(widthVal)][height - ( y + 1 )] = self.goalPotentialGKP2[int(widthVal)][height - (y + 1)] + (y + 1) self.goalPotentialDF1[int(widthVal)][ y] = self.goalPotentialDF1[int(widthVal)][y] + (y + 1) self.goalPotentialDF1[int(widthVal)][ height - (y + 1)] = self.goalPotentialDF1[int(widthVal)][ height - (y + 1)] - np.log2(height - (y + 1)) self.goalPotentialDF2[int( widthVal)][y] = self.goalPotentialDF2[int( widthVal)][y] - np.log2(height - (y + 1)) self.goalPotentialDF2[int(widthVal)][height - ( y + 1)] = self.goalPotentialDF2[int(widthVal)][height - (y + 1)] + ( y + 1) self.goalPotentialPO1[int( widthVal)][y] = self.goalPotentialPO1[int( widthVal)][y] - np.log2(height - (y + 1)) self.goalPotentialPO1[int(widthVal)][height - ( y + 1)] = self.goalPotentialPO1[int(widthVal)][height - (y + 1)] + ( y + 1) self.goalPotentialPO2[int(widthVal)][ y] = self.goalPotentialPO2[int(widthVal)][y] + (y + 1) self.goalPotentialPO2[int(widthVal)][ height - (y + 1)] = self.goalPotentialPO2[int(widthVal)][ height - (y + 1)] - np.log2(height - (y + 1)) self.goalPotentialBP1[int( widthVal)][y] = self.goalPotentialBP1[int( widthVal)][y] - np.log2(height - (y + 1)) self.goalPotentialBP1[int(widthVal)][height - ( y + 1)] = self.goalPotentialBP1[int(widthVal)][height - (y + 1)] + ( y + 1) self.goalPotentialBP2[int(widthVal)][ y] = self.goalPotentialBP2[int(widthVal)][y] + (y + 1) self.goalPotentialBP2[int(widthVal)][ height - (y + 1)] = self.goalPotentialBP2[int(widthVal)][ height - (y + 1)] - np.log2(height - (y + 1)) for x in range(int((width / 2) - 4)): for y in range(height): r1 = (((x + 1)**2) + ((y + 1)**2))**0.5 r2 = (((x + 1)**2) + ((height - (y + 1))**2))**0.5 goalStart = ((width / 2) - 5) - x goalEnd = ((width / 2) + 4) + x self.goalPotentialGK1[int(goalStart)][ y] = self.goalPotentialGK1[int(goalStart)][y] + (r1) self.goalPotentialGK1[int(goalEnd)][y] = self.goalPotentialGK1[ int(goalEnd)][y] + (r1) self.goalPotentialGK1[int(goalStart)][ height - (y + 1)] = self.goalPotentialGK1[int(goalStart)][ height - (y + 1)] - np.log2(r2) self.goalPotentialGK1[int(goalEnd)][height - ( y + 1 )] = self.goalPotentialGK1[int(goalEnd)][height - (y + 1)] - np.log2(r2) self.goalPotentialGK2[int(goalStart)][ y] = self.goalPotentialGK2[int(goalStart)][y] - np.log2(r2) self.goalPotentialGK2[int(goalEnd)][y] = self.goalPotentialGK2[ int(goalEnd)][y] - np.log2(r2) self.goalPotentialGK2[int(goalStart)][height - ( y + 1)] = self.goalPotentialGK2[int(goalStart)][height - (y + 1)] + (r1) self.goalPotentialGK2[int(goalEnd)][height - ( y + 1)] = self.goalPotentialGK2[int(goalEnd)][height - (y + 1)] + (r1) self.goalPotentialGKP1[int(goalStart)][ y] = self.goalPotentialGKP1[int(goalStart)][y] + (r1) self.goalPotentialGKP1[int(goalEnd)][ y] = self.goalPotentialGKP1[int(goalEnd)][y] + (r1) self.goalPotentialGKP1[int(goalStart)][ height - (y + 1)] = self.goalPotentialGKP1[int(goalStart)][ height - (y + 1)] - np.log2(r2) self.goalPotentialGKP1[int(goalEnd)][ height - (y + 1)] = self.goalPotentialGKP1[int(goalEnd)][ height - (y + 1)] - np.log2(r2) self.goalPotentialGKP2[int( goalStart )][y] = self.goalPotentialGKP2[int(goalStart)][y] - np.log2(r2) self.goalPotentialGKP2[int(goalEnd)][ y] = self.goalPotentialGKP2[int(goalEnd)][y] - np.log2(r2) self.goalPotentialGKP2[int(goalStart)][height - ( y + 1 )] = self.goalPotentialGKP2[int(goalStart)][height - (y + 1)] + (r1) self.goalPotentialGKP2[int(goalEnd)][height - ( y + 1)] = self.goalPotentialGKP2[int(goalEnd)][height - (y + 1)] + (r1) self.goalPotentialDF1[int(goalStart)][ y] = self.goalPotentialDF1[int(goalStart)][y] + (r1) self.goalPotentialDF1[int(goalEnd)][y] = self.goalPotentialDF1[ int(goalEnd)][y] + (r1) self.goalPotentialDF1[int(goalStart)][ height - (y + 1)] = self.goalPotentialDF1[int(goalStart)][ height - (y + 1)] - np.log2(r2) self.goalPotentialDF1[int(goalEnd)][height - ( y + 1 )] = self.goalPotentialDF1[int(goalEnd)][height - (y + 1)] - np.log2(r2) self.goalPotentialDF2[int(goalStart)][ y] = self.goalPotentialDF2[int(goalStart)][y] - np.log2(r2) self.goalPotentialDF2[int(goalEnd)][y] = self.goalPotentialDF2[ int(goalEnd)][y] - np.log2(r2) self.goalPotentialDF2[int(goalStart)][height - ( y + 1)] = self.goalPotentialDF2[int(goalStart)][height - (y + 1)] + (r1) self.goalPotentialDF2[int(goalEnd)][height - ( y + 1)] = self.goalPotentialDF2[int(goalEnd)][height - (y + 1)] + (r1) self.goalPotentialPO1[int(goalStart)][ y] = self.goalPotentialPO1[int(goalStart)][y] - np.log2(r2) self.goalPotentialPO1[int(goalEnd)][y] = self.goalPotentialPO1[ int(goalEnd)][y] - np.log2(r2) self.goalPotentialPO1[int(goalStart)][height - ( y + 1)] = self.goalPotentialPO1[int(goalStart)][height - (y + 1)] + (r1) self.goalPotentialPO1[int(goalEnd)][height - ( y + 1)] = self.goalPotentialPO1[int(goalEnd)][height - (y + 1)] + (r1) self.goalPotentialPO2[int(goalStart)][ y] = self.goalPotentialPO2[int(goalStart)][y] + (r1) self.goalPotentialPO2[int(goalEnd)][y] = self.goalPotentialPO2[ int(goalEnd)][y] + (r1) self.goalPotentialPO2[int(goalStart)][ height - (y + 1)] = self.goalPotentialPO2[int(goalStart)][ height - (y + 1)] - np.log2(r2) self.goalPotentialPO2[int(goalEnd)][height - ( y + 1 )] = self.goalPotentialPO2[int(goalEnd)][height - (y + 1)] - np.log2(r2) self.goalPotentialBP1[int(goalStart)][ y] = self.goalPotentialBP1[int(goalStart)][y] - np.log2(r2) self.goalPotentialBP1[int(goalEnd)][y] = self.goalPotentialBP1[ int(goalEnd)][y] - np.log2(r2) self.goalPotentialBP1[int(goalStart)][height - ( y + 1)] = self.goalPotentialBP1[int(goalStart)][height - (y + 1)] + (r1) self.goalPotentialBP1[int(goalEnd)][height - ( y + 1)] = self.goalPotentialBP1[int(goalEnd)][height - (y + 1)] + (r1) self.goalPotentialBP2[int(goalStart)][ y] = self.goalPotentialBP2[int(goalStart)][y] + (r1) self.goalPotentialBP2[int(goalEnd)][y] = self.goalPotentialBP2[ int(goalEnd)][y] + (r1) self.goalPotentialBP2[int(goalStart)][ height - (y + 1)] = self.goalPotentialBP2[int(goalStart)][ height - (y + 1)] - np.log2(r2) self.goalPotentialBP2[int(goalEnd)][height - ( y + 1 )] = self.goalPotentialBP2[int(goalEnd)][height - (y + 1)] - np.log2(r2) #Create Agents for i in range(self.num_agents): if i > ((2 * N) - 3): a = PlayerAgent(i, self, True) else: a = PlayerAgent(i, self) self.schedule.add(a) x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(a, (x, y)) #Set Up Kickoff self.kickoff() #Set Up DataCollector self.datacollector = DataCollector(model_reporters={ "Score 1": "score1", "Score 2": "score2" }, agent_reporters={ "Avg. Displacement": "avgDisp", "Max Displacement": "maxDisp" }) def kickoff(self): posBoy = -1 newPositions = {} if self.justConceded == 0: posTeam = self.random.randint(1, 2) else: posTeam = self.justConceded for cellContents, x, y in self.grid.coord_iter(): if len(cellContents) == 0: pass else: for i in cellContents: if posBoy == -1: if i.teamID == posTeam: if i.goalkeeper == True: pass else: i.possession = True posBoy = i.unique_id newPositions[i] = ((self.grid.width / 2) - 1, (self.grid.height / 2) - 1) if i.unique_id != posBoy: if i.teamID == 1: if i.goalkeeper == True: x = self.random.randint( (self.grid.width / 2) - 5, (self.grid.width / 2) + 3) y = self.random.randint(0, 17) newPositions[i] = (x, y) else: x = self.random.randrange(self.grid.width) y = self.random.randint( 0, (self.grid.height / 2) - 1) newPositions[i] = (x, y) else: if i.goalkeeper == True: x = self.random.randint( (self.grid.width / 2) - 5, (self.grid.width / 2) + 3) y = self.random.randint( self.grid.height - 18, self.grid.height - 1) newPositions[i] = (x, y) else: x = self.random.randrange(self.grid.width) y = self.random.randint( (self.grid.height / 2) - 1, self.grid.height - 1) newPositions[i] = (x, y) for key in newPositions.keys(): (x, y) = newPositions[key] x = int(x) y = int(y) self.grid.move_agent(key, (x, y)) self.justConceded = 0 def calcPotential(self): for x in range(self.grid.width): for y in range(self.grid.height): self.movePotentialGK1[x][y] = self.goalPotentialGK1[x][y] self.movePotentialGK2[x][y] = self.goalPotentialGK2[x][y] self.movePotentialGKP1[x][y] = self.goalPotentialGKP1[x][y] self.movePotentialGKP2[x][y] = self.goalPotentialGKP2[x][y] self.movePotentialDF1[x][y] = self.goalPotentialDF1[x][y] self.movePotentialDF2[x][y] = self.goalPotentialDF2[x][y] self.movePotentialPO1[x][y] = self.goalPotentialPO1[x][y] self.movePotentialPO2[x][y] = self.goalPotentialPO2[x][y] self.movePotentialBP1[x][y] = self.goalPotentialBP1[x][y] self.movePotentialBP2[x][y] = self.goalPotentialBP2[x][y] playerPos = {} for agent, x, y in self.grid.coord_iter(): if len(agent) == 0: pass else: for i in agent: playerPos[i.unique_id] = {"x": x, "y": y, "state": i.state} if i.state == "": i.checkState() playerPos[i.unique_id]['state'] = i.state for key in playerPos.keys(): agent = playerPos[key] for i in range(self.grid.width): for j in range(self.grid.height): r = ((agent['x'] - i)**2 + (agent['y'] - j)**2)**(0.5) if r != 0: if agent['state'] == "GK": self.movePotentialGK1[i][ j] = self.movePotentialGK1[i][j] + (20 / (r**2)) self.movePotentialGK2[i][ j] = self.movePotentialGK2[i][j] + (20 / (r**2)) self.movePotentialGKP1[i][ j] = self.movePotentialGKP1[i][j] + (20 / (r**2)) self.movePotentialGKP2[i][ j] = self.movePotentialGKP2[i][j] + (20 / (r**2)) self.movePotentialDF1[i][ j] = self.movePotentialDF1[i][j] + 40 * ( (5 * (2**(-1 / 6)) / r)**12 - (5 * (2**(-1 / 6)) / r)**6) self.movePotentialDF2[i][ j] = self.movePotentialDF2[i][j] + 40 * ( (5 * (2**(-1 / 6)) / r)**12 - (5 * (2**(-1 / 6)) / r)**6) self.movePotentialPO1[i][ j] = self.movePotentialPO1[i][j] + (20 / (r**2)) self.movePotentialPO2[i][ j] = self.movePotentialPO2[i][j] + (20 / (r**2)) self.movePotentialBP1[i][ j] = self.movePotentialBP1[i][j] + (20 / (r**2)) self.movePotentialBP2[i][ j] = self.movePotentialBP2[i][j] + (20 / (r**2)) elif agent['state'] == "GKP": self.movePotentialGK1[i][ j] = self.movePotentialGK1[i][j] + (20 / (r**2)) self.movePotentialGK2[i][ j] = self.movePotentialGK2[i][j] + (20 / (r**2)) self.movePotentialGKP1[i][ j] = self.movePotentialGKP1[i][j] self.movePotentialGKP2[i][ j] = self.movePotentialGKP2[i][j] self.movePotentialDF1[i][ j] = self.movePotentialDF1[i][j] + (20 / (r**2)) self.movePotentialDF2[i][ j] = self.movePotentialDF2[i][j] + (20 / (r**2)) self.movePotentialPO1[i][ j] = self.movePotentialPO1[i][j] + (20 / (r**2)) self.movePotentialPO2[i][ j] = self.movePotentialPO2[i][j] + (20 / (r**2)) self.movePotentialBP1[i][ j] = self.movePotentialBP1[i][j] self.movePotentialBP2[i][ j] = self.movePotentialBP2[i][j] elif agent['state'] == "DF": self.movePotentialGK1[i][ j] = self.movePotentialGK1[i][j] + (20 / (r**2)) self.movePotentialGK2[i][ j] = self.movePotentialGK2[i][j] + (20 / (r**2)) self.movePotentialGKP1[i][ j] = self.movePotentialGKP1[i][j] + (20 / (r**2)) self.movePotentialGKP2[i][ j] = self.movePotentialGKP2[i][j] + (20 / (r**2)) self.movePotentialDF1[i][ j] = self.movePotentialDF1[i][j] + (20 / (r**2)) self.movePotentialDF2[i][ j] = self.movePotentialDF2[i][j] + (20 / (r**2)) self.movePotentialPO1[i][ j] = self.movePotentialPO1[i][j] + (20 / (r**2)) self.movePotentialPO2[i][ j] = self.movePotentialPO2[i][j] + (20 / (r**2)) self.movePotentialBP1[i][ j] = self.movePotentialBP1[i][j] + (20 / (r**2)) self.movePotentialBP2[i][ j] = self.movePotentialBP2[i][j] + (20 / (r**2)) elif agent['state'] == "PO": self.movePotentialGK1[i][ j] = self.movePotentialGK1[i][j] - (20 / (r**2)) self.movePotentialGK2[i][ j] = self.movePotentialGK2[i][j] - (20 / (r**2)) self.movePotentialGKP1[i][ j] = self.movePotentialGKP1[i][j] - (20 / (r**2)) self.movePotentialGKP2[i][ j] = self.movePotentialGKP2[i][j] - (20 / (r**2)) self.movePotentialDF1[i][ j] = self.movePotentialDF1[i][j] + 40 * ( (2.5 * (2**(-1 / 6)) / r)**12 - (2.5 * (2**(-1 / 6)) / r)**6) self.movePotentialDF2[i][ j] = self.movePotentialDF2[i][j] + 40 * ( (2.5 * (2**(-1 / 6)) / r)**12 - (2.5 * (2**(-1 / 6)) / r)**6) self.movePotentialPO1[i][ j] = self.movePotentialPO1[i][j] + (20 / (r**2)) self.movePotentialPO2[i][ j] = self.movePotentialPO2[i][j] + (20 / (r**2)) self.movePotentialBP1[i][ j] = self.movePotentialBP1[i][j] + (20 / (r**2)) self.movePotentialBP2[i][ j] = self.movePotentialBP2[i][j] + (20 / (r**2)) elif agent['state'] == "BP": self.movePotentialGK1[i][ j] = self.movePotentialGK1[i][j] - (20 / (r**2)) self.movePotentialGK2[i][ j] = self.movePotentialGK2[i][j] - (20 / (r**2)) self.movePotentialGKP1[i][ j] = self.movePotentialGKP1[i][j] self.movePotentialGKP2[i][ j] = self.movePotentialGKP2[i][j] self.movePotentialDF1[i][ j] = self.movePotentialDF1[i][j] - (20 / (r**2)) self.movePotentialDF2[i][ j] = self.movePotentialDF2[i][j] - (20 / (r**2)) self.movePotentialPO1[i][ j] = self.movePotentialPO1[i][j] + 40 * ( (5 * (2**(-1 / 6)) / r)**12 - (5 * (2**(-1 / 6)) / r)**6) self.movePotentialPO2[i][ j] = self.movePotentialPO2[i][j] + 40 * ( (5 * (2**(-1 / 6)) / r)**12 - (5 * (2**(-1 / 6)) / r)**6) self.movePotentialBP1[i][ j] = self.movePotentialBP1[i][j] self.movePotentialBP2[i][ j] = self.movePotentialBP2[i][j] else: print( "Error in CalcPotential: Player has no state") def scoreCheck(self): '''Checks if any player agent has successfully scored and increments the team's score by 1''' if self.justConceded == 0: pass else: if self.justConceded == 1: self.score2 = self.score2 + 1 self.kickoff() else: self.score1 = self.score1 + 1 self.kickoff() def gridVisual(self): grid = np.zeros((self.grid.width, self.grid.height)) for agent, x, y in self.grid.coord_iter(): if len(agent) != 0: for k in agent: grid[x][y] = k.teamID name = "Visualisation\Latest Test\Figure_" + str(self.i) + ".jpg" plt.imsave(name, grid) def bugTest(self): self.calcPotential() plt.figure(1) plt.clf() plt.imshow(self.movePotentialBP1, interpolation="nearest") plt.figure(2) plt.clf() plt.imshow(self.movePotentialBP2, interpolation="nearest") plt.figure(3) plt.clf() plt.imshow(self.movePotentialDF1, interpolation="nearest") plt.figure(4) plt.clf() plt.imshow(self.movePotentialDF2, interpolation="nearest") plt.figure(5) plt.clf() plt.imshow(self.movePotentialGK1, interpolation="nearest") plt.figure(6) plt.clf() plt.imshow(self.movePotentialGK2, interpolation="nearest") plt.figure(7) plt.clf() plt.imshow(self.movePotentialGKP1, interpolation="nearest") plt.figure(8) plt.clf() plt.imshow(self.movePotentialGKP2, interpolation="nearest") plt.figure(9) plt.clf() plt.imshow(self.movePotentialPO1, interpolation="nearest") plt.figure(10) plt.clf() plt.imshow(self.movePotentialPO2, interpolation="nearest") def step(self): '''Advance the model by one step.''' self.calcPotential() self.scoreCheck() self.datacollector.collect(self) self.schedule.step() self.i = self.i + 1 self.gridVisual() print("Step: " + str(self.i)) print(str(self.score1) + " - " + str(self.score2))
class Environment(Model): """ A model which contains a number of ant colonies. """ def __init__(self, width, height, n_colonies, n_ants, n_obstacles, decay=0.2, sigma=0.1, moore=False, birth=True, death=True): """ :param width: int, width of the system :param height: int, height of the system :param n_colonies: int, number of colonies :param n_ants: int, number of ants per colony :param decay: float, the rate in which the pheromone decays :param sigma: float, sigma of the Gaussian convolution :param moore: boolean, True/False whether Moore/vonNeumann is used """ super().__init__() # Agent variables self.birth = birth self.death = death self.pheromone_level = 1 # Environment variables self.width = width self.height = height self.grid = MultiGrid(width, height, False) self.moore = moore self.sigma = sigma self.decay = decay # Environment attributes self.schedule = RandomActivation(self) self.colonies = [Colony(self, i, (width // 2, height // 2), n_ants, birth=self.birth, death=self.death) for i in range(n_colonies)] self.pheromones = np.zeros((width, height), dtype=np.float) self.pheromone_updates = [] self.food = FoodGrid(self) self.food.add_food() self.obstacles = [] for _ in range(n_obstacles): self.obstacles.append(Obstacle(self)) # Metric + data collection self.min_distance = distance.cityblock(self.colonies[0].pos, self.food.get_food_pos()) self.datacollector = DataCollector( model_reporters={"Minimum path length": metrics.min_path_length, "Mean minimum path length": metrics.mean_min_path_length}, agent_reporters={"Agent minimum path length": lambda x: min(x.path_lengths), "Encounters": Ant.count_encounters}) # Animation attributes self.pheromone_im = None self.ax = None def step(self): """ Do a single time-step using freeze-dry states, colonies are updated each time-step in random orders, and ants are updated per colony in random order. """ self.food.step() self.datacollector.collect(self) # Update all colonies for col in random.sample(self.colonies, len(self.colonies)): col.step() self.schedule.step() self.update_pheromones() def move_agent(self, ant, pos): """ Move an agent across the map. :param ant: class Ant :param pos: tuple (x, y) """ if self.moore: assert np.sum(np.subtract(pos, ant.pos) ** 2) in [1, 2], \ "the ant can't move from its original position {} to the new position {}, because the distance " \ "is too large".format(ant.pos, pos) else: assert np.sum(np.subtract(pos, ant.pos) ** 2) == 1, \ "the ant can't move from its original position {} to the new position {}, because the distance " \ "is too large, loc_food {}".format(ant.pos, pos, self.food.get_food_pos()) self.grid.move_agent(ant, pos) def get_random_position(self): return (np.random.randint(0, self.width), np.random.randint(0, self.height)) def position_taken(self, pos): if pos in self.food.get_food_pos(): return True for colony in self.colonies: if colony.on_colony(pos): return True for obstacle in self.obstacles: if obstacle.on_obstacle(pos): return True return False def add_food(self): """ Add food somewhere on the map, which is not occupied by a colony yet """ self.food.add_food() def place_pheromones(self, pos): """ Add pheromone somewhere on the map :param pos: tuple (x, y) """ self.pheromone_updates.append((pos, self.pheromone_level)) def get_neighbor_pheromones(self, pos, id): """ Get the passable neighboring positions and their respective pheromone levels for the pheromone id :param pos: :param id: :return: """ indices = self.grid.get_neighborhood(pos, self.moore) indices = [x for x in indices if not any([isinstance(x, Obstacle) for x in self.grid[x[0]][x[1]]])] pheromones = [self.pheromones[x, y] for x, y in indices] return indices, pheromones def update_pheromones(self): """ Place the pheromones at the end of a timestep on the grid. This is necessary for freeze-dry time-steps """ for (pos, level) in self.pheromone_updates: # self.pheromones[pos] += level self.pheromones[pos] += 1 self.pheromone_updates = [] # gaussian convolution using self.sigma self.pheromones = gaussian_filter(self.pheromones, self.sigma) * self.decay def animate(self, ax): """ :param ax: :return: """ self.ax = ax self.animate_pheromones() self.animate_colonies() self.animate_ants() self.animate_food() self.animate_obstacles() def animate_pheromones(self): """ Update the visualization part of the Pheromones. :param ax: """ pheromones = np.rot90(self.pheromones.astype(np.float64).reshape(self.width, self.height)) if not self.pheromone_im: self.pheromone_im = self.ax.imshow(pheromones, vmin=0, vmax=50, interpolation='None', cmap="Purples") else: self.pheromone_im.set_array(pheromones) def animate_colonies(self): """ Update the visualization part of the Colonies. :return: """ for colony in self.colonies: colony.update_vis() def animate_food(self): """ Update the visualization part of the FoodGrid. :return: """ self.food.update_vis() def animate_ants(self): """ Update the visualization part of the Ants. """ for ant in self.schedule.agents: ant.update_vis() def animate_obstacles(self): """ Update the visualization part of the Obstacles. :return: """ for obstacle in self.obstacles: obstacle.update_vis() def grid_to_array(self, pos): """ Convert the position/indices on self.grid to imshow array. :param pos: tuple (int: x, int: y) :return: tuple (float: x, float: y) """ return pos[0] - 0.5, self.height - pos[1] - 1.5 def pheromone_threshold(self, threshold): """ Returns an array of the positions in the grid in which the pheromone levels are above the given threshold""" pher_above_thres = np.where(self.pheromones >= threshold) return list(zip(pher_above_thres[0],pher_above_thres[1])) def find_path(self, pher_above_thres): """ Returns the shortest paths from all the colonies to all the food sources. A path can only use the positions in the given array. Therefore, this function checks whether there is a possible path for a certain pheremone level. Essentially a breadth first search""" space_searched = False all_paths = [] food_sources = self.food.get_food_pos() # Search the paths for a colony to all food sources for colony in self.colonies: colony_paths = [] pos_list = {colony.pos} # Prooning possible_paths = [[colony.pos]] # Continue expanding search area until all food sources found # or until the entire space is searched while food_sources != [] and not space_searched: space_searched = True temp = [] for path in possible_paths: for neighbor in self.grid.get_neighborhood(include_center=False, radius=1, pos=path[-1], moore=self.moore): if neighbor in food_sources: food_path = copy(path) food_path.append(neighbor) colony_paths.append(food_path) food_sources.remove(neighbor) # Add epanded paths to the possible paths if neighbor in pher_above_thres and neighbor not in pos_list: space_searched = False temp_path = copy(path) temp_path.append(neighbor) temp.append(temp_path) pos_list.add(neighbor) possible_paths.remove(path) possible_paths += temp all_paths.append(colony_paths) return all_paths
class SamplePSO(PSO): def __init__(self, population: int, dimension: int, attraction_best_global: float, attraction_best_personal: float, lim_vel_particles: float, inertia_particle: float, max_iterations: int, width: int, height: int, num_max_locales: int, suavizar_espacio: int): super().__init__(population, dimension, attraction_best_global, attraction_best_personal, lim_vel_particles, inertia_particle, max_iterations) self.width = width self.height = height self.grid = MultiGrid(self.width, self.height, torus=False) # Variables para el espacio de busqueda self.num_max_locales = num_max_locales self.suavizar_espacio = suavizar_espacio # Crear espacio de busqueda self.setup_search_space() # Crear particulas # Lo hace la clase padre # Colocar particulas # Hay que adaptar pos interno al espacio de busqueda self.place_particles(True) # Captura de datos para grafica self.datacollector = DataCollector({ "Best": lambda m: m.global_best_value, "Average": lambda m: m.average() }) def average(self): sum = 0 for agent in self.schedule.agents: if isinstance(agent, Particle): sum += agent.personal_best_value return sum / self.population # Se modifica step del padre para añadir el collector def step(self): super().step() # Collect data self.datacollector.collect(self) # Stop si llega al máximo if self.global_best_value == 1: self.running = False def place_particles(self, initial=False): for particle in self.particles: pos = self.pos_particle_to_pos(particle) if initial: self.grid.place_agent(particle, pos) else: self.grid.move_agent(particle, pos) def pos_particle_to_pos(self, particle: Particle): # Convierte posiciones de particula [0 1] en posiciones de grid 2D min_xcor = 0 max_xcor = self.width - 1 min_ycor = 0 max_ycor = self.height - 1 x_cor = self.convert(particle.pos_particle[0], min_xcor, max_xcor) y_cor = self.convert(particle.pos_particle[1], min_ycor, max_ycor) return (x_cor, y_cor) @staticmethod def convert(x: float, a: float, b: float) -> int: # Bijection from [0, 1] to [a, b] return int(a + x * (b - a)) def setup_search_space(self): # Preparar un espacio de busqueda con colinas y valles if self.num_max_locales == 0: for agent, x, y in self.grid.coord_iter(): val = random.random() patch = Patch(self.unique_id, self, (x, y), val) self.unique_id += 1 self.grid.place_agent(patch, (x, y)) else: n_elements = (self.width - 1) * (self.height - 1) selected_elements = random.sample(range(n_elements), self.num_max_locales) element = 0 for (agentSet, x, y) in self.grid.coord_iter(): val = 10 * random.random( ) if element in selected_elements else 0 patch = Patch(self.unique_id, self, (x, y), val) self.unique_id += 1 self.grid.place_agent(patch, (x, y)) element += 1 # Suavizado del espacio for _ in range(self.suavizar_espacio): for (agentSet, x, y) in self.grid.coord_iter(): for agent in agentSet: if isinstance(agent, Patch): agent.diffuse_val(1) # Normalizacion del espacio 0 y 0.99999 min_val = 0 max_val = 0 for (agentSet, x, y) in self.grid.coord_iter(): for agent in agentSet: if isinstance(agent, Patch): if agent.val < min_val: min_val = agent.val if agent.val > max_val: max_val = agent.val for (agentSet, x, y) in self.grid.coord_iter(): for agent in agentSet: if isinstance(agent, Patch): agent.val = 0.99999 * (agent.val - min_val) / (max_val - min_val) # Marcar a 1 el máximo max_val = 0 max_patch = None for (agentSet, x, y) in self.grid.coord_iter(): for agent in agentSet: if isinstance(agent, Patch): if agent.val > max_val: max_patch = agent if isinstance(max_patch, Particle): max_patch.val = 1 # Colorear patches for (agentSet, x, y) in self.grid.coord_iter(): for agent in agentSet: if isinstance(agent, Patch): agent.set_color() # Se han de definir los métodos evaluation y psoexternalUpdate def evaluation(self, particle: Particle): # Se podría usar particle.pos si se ejecutara primero pso_external_update # Pero se ejecuta despues # Hay que revisar la primera evaluación al crear particulas if self.grid is not None: pos = self.pos_particle_to_pos(particle) for patch in self.grid.get_cell_list_contents(pos): if isinstance(patch, Patch): return patch.val else: return 0 def pso_external_update(self): self.place_particles()
class Kmedias(Model): def __init__(self, height, width, initial_topics, agrupados, dispersion, tam_dispersion, num_cluster, tolerancia, representar_areas): super().__init__() self.height = height self.width = width # Numero de topics a clasificar self.initial_topics = initial_topics self.agrupados = agrupados self.dispersion = dispersion self.tam_dispersion = tam_dispersion self.num_cluster = num_cluster self.tolerancia = tolerancia self.representar_areas = representar_areas self.unique_id=0 # Creación del planificador y del grid self.schedule = RandomActivation(self) self.grid = MultiGrid(self.width, self.height, torus=False) self.topics = [] self.clusters = [] self.colors = {0: "lime", 1: "yellow", 2: "green", 3: "blue", 4: "fuchsia", 5: "brown"} self.setup() self.running = True def setup(self): if self.agrupados==True: self.setup_topics2() else: self.setup_topics() self.setup_cluster() def setup_topics(self): self.setup_patches("grey0") for _ in range(self.initial_topics): pos = [random.randint(0, self.width-1), random.randint(0, random.randint(0, self.height-1))] topic = Topic(self.unique_id, self, pos, "black") self.unique_id +=1 self.grid.place_agent(topic, pos) self.topics.append(topic) def setup_topics2(self): self.setup_patches("grey0") bolsas = random.randint(1, self.dispersion) for _ in range(bolsas): pos = [random.randint(0, self.width - 1), random.randint(0, random.randint(0, self.height - 1))] topic = Topic(self.unique_id, self, pos, "black") self.unique_id += 1 self.grid.place_agent(topic, pos) self.topics.append(topic) for _ in range(self.initial_topics - bolsas): # Clonar uno de los topics darle orientacion random (ya la tienen) # y hacer que avance 0-5 posiciones posiciones ram = random.randint(0, len(self.topics)-1) topic_father = self.topics[ram] pos = topic_father.pos topic = Topic(self.unique_id, self, pos, "black", random.randint(0, 359)) self.unique_id += 1 self.grid.place_agent(topic, pos) self.topics.append(topic) for _ in range(random.randint(0, self.tam_dispersion)): if topic.can_move(): topic.forward() def setup_patches(self, color): for agent, x, y in self.grid.coord_iter(): pos = [x,y] cell = Cell(self.unique_id,self,pos,color) self.unique_id +=1 self.grid.place_agent(cell,pos) def setup_cluster(self): # 1. Generar centros aleatorios for i in range(self.num_cluster): topic = self.topics[random.randint(0, len(self.topics)-1)] pos = topic.pos color = "red" cluster = Cluster(self.unique_id, self, pos, color) self.unique_id += 1 self.grid.place_agent(cluster, pos) self.clusters.append(cluster) cluster.clase_color = self.colors[i] def step(self): # print("step turulu") # 4. Mientras algún centro de mueva if self.any_cluster_movido(): # 2. Asignar un grupo a cada elemento for topic in self.topics: topic.clase = self.get_clase(topic) topic.color = self.colors[topic.clase] # Contar los elementos asignados a cada cluster i = 0 for cluster in self.clusters: topicClase = [] for topic in self.topics: if topic.clase == i: topicClase.append(topic) if len(topicClase) > 0: centroide = self.calcular_centroide(topicClase) if self.distance(centroide, cluster.pos) > 0.01: cluster.movido = True else: cluster.movido = False self.grid.move_agent(cluster, centroide) else: x_pos = random.randint(0, self.width-1) y_pos = random.randint(0, self.height-1) self.grid.move_agent(cluster, [x_pos, y_pos]) cluster.movido = True i += 1 else: # No se moveran más los cluster if self.representar_areas: self.areas() self.representar_areas = False else: self.running = False def areas(self): # Poner todos los topics en negro for topic in self.topics: topic.color = "black" # Colorear con color al centroide más cercano for (agentset, x, y) in self.grid.coord_iter(): for agent in agentset: if isinstance(agent, Cell): clase = self.get_clase(agent) agent.color = self.colors[clase] def calcular_centroide(self, topicClase): sum_x = 0 sum_y = 0 for topic in topicClase: sum_x += topic.pos[0] sum_y += topic.pos[1] x = int(sum_x / len(topicClase)) y = int(sum_y / len(topicClase)) return [x,y] def any_cluster_movido(self): for c in self.clusters: if c.movido == True: return True return False def get_clase(self, topic): clase = 0 distance = self.distance(topic.pos, self.clusters[0].pos) for i in range(1,len(self.clusters)): new_distance = self.distance(topic.pos, self.clusters[i].pos) if new_distance < distance: distance = new_distance clase = i return clase @staticmethod def distance(pos1, pos2): return math.sqrt((pos1[0]-pos2[0])**2+(pos1[1]-pos2[1])**2)
class MarketModel(Model): def __init__(self, buff, plot_buff, max_agents_number, market, checkout_slider, width=50, height=50, steps=3000): self.steps = steps self.plot_buff = plot_buff self.running = True self.market = market self.checkout_slider = checkout_slider self.num_agents = max_agents_number self.schedule = RandomActivation(self) self.grid = MultiGrid(width, height, True) self.grid_mutex = Lock() self.agents_number = 1 self.regal_agents = [] self.checkout_agents = [] self.opened_checkouts = [] self.closed_checkouts = [] self.space_graph = np.zeros((width, height)) self.place_checkouts() self.place_regals() self.thread_pool = ThreadPool(20) self.customer_list = buff self.total_income = 0.0 self.agent_counts = [[0 for x in range(self.grid.width)] for y in range(self.grid.height)] self.plot_buff.append(self.agent_counts) self.plot_buff.append(self.grid.width) self.plot_buff.append(self.grid.height) self.income_data_collector = DataCollector( model_reporters={"total_income": get_income}) self.queue_length_data_collector = DataCollector( model_reporters={ "average_queue_length": compute_average_queue_size }) self.open_checkouts() def add_agent(self): i = random.randint(0, 1) if i == 0: a = CommonCustomer(self.agents_number, self, self.market.articles) else: a = LazyCustomer(self.agents_number, self, self.market.articles) # a = CommonCustomer(self.agents_number, self, self.market.articles) self.agents_number += 1 self.schedule.add(a) self.grid.place_agent(a, (a.x, a.y)) self.customer_list.append(a) def place_checkouts(self): for checkout_location in self.market.cashRegisters: checkout_agent = Checkout(self.agents_number, self, checkout_location) self.agents_number += 1 self.grid.place_agent(checkout_agent, checkout_location) self.checkout_agents.append(checkout_agent) self.space_graph[checkout_location[0], checkout_location[1]] = 1 self.closed_checkouts = self.checkout_agents def place_regals(self): for regal in self.market.regals: self.place_regal(regal) def place_regal(self, regal): for shelf in regal.shelf_list: self.place_shelf(shelf) def place_shelf(self, shelf): shelf_agent = ShelfAgent(self.agents_number, self, shelf) pos = shelf_agent.get_location() self.agents_number += 1 self.grid.place_agent(shelf_agent, pos) self.regal_agents.append(shelf_agent) self.space_graph[pos[0], pos[1]] = 1 def open_checkouts(self): for i in range(0, len(self.checkout_agents), len(self.checkout_agents) // self.checkout_slider): checkout = self.closed_checkouts.pop( random.randint(0, len(self.closed_checkouts) - 1)) checkout.open() self.opened_checkouts.append(checkout) self.schedule.add(checkout) def open_random_checkout(self): if len(self.closed_checkouts) != 0: checkout = self.closed_checkouts.pop( random.randint(0, len(self.closed_checkouts) - 1)) checkout.open() self.opened_checkouts.append(checkout) self.schedule.add(checkout) def close_random_checkout(self): if len(self.opened_checkouts) > 1: checkout = self.opened_checkouts.pop( random.randint(0, len(self.opened_checkouts) - 1)) checkout.close() self.closed_checkouts.append(checkout) # self.schedule.add(checkout) def find_nearest_checkouts(self, location, n): new_list = self.opened_checkouts.copy() ordered_list = sorted(new_list, key=(lambda x: ((x.location[0] - location[0])**2) + ( (x.location[1] - location[1])**2))) return ordered_list[0:] def generate_random_starting_pos(self): pos_list = [(self.grid.width // 2 + 1, 0), (self.grid.width - 1, 1), (self.grid.width - 1, self.grid.height - 2)] i = random.randint(0, len(pos_list) - 1) pos = pos_list[i] if i == 0: pos = (pos_list[0][0] + random.randint(-2, 2), pos_list[0][1]) return pos def step(self): print(self.checkout_slider) self.income_data_collector.collect(self) self.queue_length_data_collector.collect(self) if compute_average_queue_size(self) > 3: self.open_random_checkout() if compute_average_queue_size(self) < 3: self.close_random_checkout() sigma = 1 cycle_steps = 1500 n = self.schedule.steps // cycle_steps + 1 gauss = gaussian( self.schedule.steps * (6 * sigma / cycle_steps) - 3 * n * sigma, 0, sigma) * self.num_agents print(gauss) while len(self.schedule.agents) - len( self.checkout_agents) < np.ceil(gauss): self.add_agent() self.schedule.step() def move_agent(self, agent, new_pos): # self.grid_mutex.acquire() self.agent_counts[new_pos[0]][new_pos[1]] += 1 self.plot_buff[0] = self.agent_counts self.grid.move_agent(agent, new_pos) # self.grid_mutex.release() def remove_agent(self, agent): # self.grid_mutex.acquire() self.grid.remove_agent(agent) self.schedule.remove(agent) if type(agent) is CommonCustomer: self.customer_list.remove(agent) # self.grid_mutex.release() def get_customers(self): return self.customer_list
class HumanitarianLogistics(Model): """A model with: number of azc rate of newcomer arrival dimensions width and height""" def __init__(self, shock_period, shock_duration, shock_rate, N_cities, N_a, nc_rate, width, height): #canvas info self.width = width self.height = height #sim boilerplate self.grid = MultiGrid(width, height, True) self.schedule = RandomActivation(self) self.running = True self.num_nc = 0 #counts number of applicants self.num_azc = N_a #number of AZC in sim self.nc_rate = nc_rate #rate of inflow of newcomers self.num_cities = N_cities #number of cities in sim self.num_buildings = 3 self.num_activity_centers = 2 self.num_activities_per_center = 2 self.num_per_step = 10 self.num_activity_centers = 2 self.num_activities_per_center = 2 #initialize shock values self.shock_period = shock_period #how often does shock occur self.shock_duration = shock_duration #how long does shock last self._shock_duration = shock_duration #current position in shock self.shock_rate = shock_rate #amt of increase during shock self.shock = False #shock flag self.number_added = 1 #base rate of influx self.number_shocks = 4 self.shock_growth = 2 #dict of probabilities of first/second decision success rates by country self.specs = {} # list of multinomial probabilities for countries self.country_multinomial = [] # list of shock distributions for countries related to adding newcomers self.country_shock_dist = [] # list of countries self.country_list = [] with open("country-input.csv") as csvfile: reader = csv.DictReader(csvfile) for row in reader: decisionList = [] decisionList.append(float(row['DecisionA'])) decisionList.append(float(row['DecisionB'])) self.specs[row['Country']] = decisionList self.country_shock_dist.append(row['ShockDist']) self.country_list.append(row['Country']) self.country_multinomial.append(row['Multinomial']) self.country_count = np.zeros( len(self.country_list )) #keeps track of how many applicants from each country self.country_success = np.zeros(len(self.country_list)) self.current_country_index = -1 #records capacitiy of each AZC type self.datacollector = DataCollector(model_reporters={ 'Cap - Extended-AS': calc_extended_as, 'Cap - AS': calc_as }) #records success rates of each country of origin using current_country_index #which is manipulated in sr_country sr_functions = {} for i in range(0, len(self.country_list)): self.current_country_index = i sr_functions[self.country_list[ self.current_country_index]] = sr_country self.sr = DataCollector(model_reporters=sr_functions) self.capacity_dc = DataCollector(model_reporters={ 'Current Capacity': coa_occ, 'Projected Capacity': coa_proj }) #Ter apel ta_pos = (int(self.width / 2), int(self.height / 6 * 5)) ta_id = self.num_cities + 1 ter_apel = City(self.num_cities + 1, self, ta_pos) ta_coa = COA(ta_id, self, ter_apel) ta_coa.ta = True self.schedule.add(ta_coa) ta_ind = IND(ta_id, self, ter_apel) self.schedule.add(ta_ind) ta_azc = AZC(ta_id, self, 'edp', ta_pos, ta_coa) ta_azc.ta = True ta_coa.azcs.add(ta_azc) ta_coa.capacities[ta_azc] = ta_azc.occupancy self.schedule.add(ta_azc) self.grid.place_agent(ta_azc, ta_pos) self.ter_apel = ta_azc #add activities self.test_activity = Football(0, self, 5) self.schedule.add(self.test_activity) #generate cities for city in range(self.num_cities): space_per_city = int(self.width / self.num_cities) orientation_x = int( space_per_city / 2 + city * space_per_city + int(space_per_city / self.num_azc / 2)) #center point for city pos = (orientation_x, int(self.height / 2)) #placeholder position city_size = np.random.uniform(low=0, high=1) city_is_big = False if city_size > 0.70: city_is_big = True current_city = City(city, self, pos, city_is_big) #instantiates city #add COA current_coa = COA(city, self, current_city) current_city.coa = current_coa self.schedule.add(current_coa) self.grid.place_agent(current_coa, (pos[0], int(self.height / 3 * 2))) current_ind = IND(city, self, current_city) self.schedule.add(current_ind) current_coa.IND = current_ind current_ind.coa = current_coa #adds city to schedule n grid self.schedule.add(current_city) self.grid.place_agent(current_city, (current_city.pos)) #azc location essentials space_per_azc = int(space_per_city / self.num_azc) azc_starting_point = orientation_x - (.5 * space_per_city) num_activity_centers_added = 0 # Create AZCs for i in range(self.num_azc): ''' if i == 0: occupant_type = 'edp' # ter apel ''' if i < self.num_azc - 2: occupant_type = 'as' # standard AZC elif i == self.num_azc - 2: occupant_type = 'as_ext' # extended procedure AZC else: occupant_type = 'tr' # 'Housing' for those with #place evenly x = int(azc_starting_point + i * space_per_azc) y = int(self.height * .5) a = AZC(i, self, occupant_type, (x, y), current_coa) #instantiate self.schedule.add(a) #add in time self.grid.place_agent(a, (x, y)) #add in spaace current_city.buildings.add(a) if a.occupant_type != 'tr': current_coa.azcs.add(a) current_coa.capacities[a] = a.occupancy if a.occupant_type == 'tr': current_city.social_housing = a #add viz v = AZC_Viz(self, a) self.schedule.add(v) self.grid.place_agent(v, v.pos) #create civilian buildings y = int(self.height / 5) space_per_building = space_per_city / self.num_buildings row_size = 15 if city == 0: x = int(azc_starting_point + .5 * space_per_building) current = Hotel(self.num_buildings + 1, self, (x, y), 1000) current_city.buildings.add(current) current.city = current_city self.grid.place_agent(current, (x, y)) self.schedule.add(current) empty = Empty(self.num_buildings + 1, self, (int(x + space_per_building), y), 100) current_city.buildings.add(empty) empty.city = current_city self.grid.place_agent(empty, (int(x + space_per_building), y)) self.schedule.add(empty) for bdg in range(city * self.num_buildings): x = int(azc_starting_point + (bdg % 3) * space_per_building) if bdg == 0: current = Hotel(bdg, self, (x, y), 1000) current_city.buildings.add(current) current.city = current_city self.grid.place_agent(current, (x, y)) self.schedule.add(current) else: empty = Empty(bdg, self, (x, y - row_size * int(bdg / 3)), 100 * bdg) current_city.buildings.add(empty) empty.city = current_city self.grid.place_agent(empty, (x, y - row_size * int(bdg / 3))) self.schedule.add(empty) def house(self, newcomer): #find building for newcomers legal status eligible_buildings = [ x for x in self.schedule.agents if type(x) is AZC and x.occupant_type == newcomer.ls ] #take first one, in future, evaluate buildings on some criteria destination = eligible_buildings[0] house_loc = destination.pos #where is it if newcomer.ls is not 'edp': newcomer.loc.occupancy -= 1 #reduce occupance of prev building #add noise so agents don't overlap x = house_loc[0] + np.random.randint(-20, 20) y = house_loc[1] + np.random.randint(-20, 20) self.grid.move_agent(newcomer, (x, y)) #place destination.occupants.add(newcomer) #add agent to building roster newcomer.loc = destination #update agent location destination.occupancy += 1 #update occupancy def Remove(self, agent): agent.loc.occupancy -= 1 #reduce occupancy of building agent.loc.occupants.remove(agent) #remove from time n space self.schedule.remove(agent) self.grid.remove_agent(agent) def shock_distribution(self): #draws a random discrete number from multinomial distribution country = np.random.multinomial(1, self.country_shock_dist, size=1) # turns that distribution into a number country = np.where(country == 1)[1][0] # assigns that number to a country country_of_origin = self.country_list[country] return country_of_origin def country_distribution(self): #draws a random discrete number from multinomial distribution country = np.random.multinomial(1, self.country_multinomial, size=1) # turns that distribution into a number country = np.where(country == 1)[1][0] # updates country count self.country_count[country] += 1 # assigns that number to a country country_of_origin = self.country_list[country] return country_of_origin def addNewcomer(self, shock, country_of_origin): #increase count self.num_nc += 1 if not shock: country_of_origin = self.country_distribution() else: self.country_count[self.country_list.index(country_of_origin)] += 1 x = np.random.randint(0, 10, dtype='int') y = np.random.randint(0, 10, dtype='int') #define newcomer r = Newcomer(self.num_nc, self, country_of_origin, (x, y)) self.schedule.add(r) self.grid.place_agent(r, r.pos) #find coa coa = [x for x in self.schedule.agents if type(x) is COA][0] coa.intake(r) #place n ter apel coa.newcomers.add(r) #adds NC to coa's list of residents r.coa = coa #likewise for the newcomer def step(self): self.schedule.step() self.datacollector.collect(self) #collects occupancy data self.sr.collect(self) #collects success rate data self.capacity_dc.collect(self) if self.schedule.steps % self.shock_period == 0: self.shock = True self.shock_counter = 0 if self.shock: #if self._shock_duration > (self._shock_duration / 2): # self.number_added += self.shock_rate #else: # self.number_added -= self.shock_rate self.number_added += self.shock_rate for i in range(int(self.number_added)): shock_country = self.shock_distribution() self.addNewcomer( True, shock_country ) # currently in data file all shocks come from Syria self.shock_counter += 1 self._shock_duration -= 1 if self._shock_duration == 0: self.shock = False self._shock_duration = self.shock_duration self.number_added = 1 self.shock_counter = 0 self.shock_rate = self.shock_rate * self.shock_growth else: #adds newcomers to simuluation at a given rate if uniform(0, 1) < self.nc_rate: for i in range(self.num_per_step): self.addNewcomer(False, None)
class Environment(Model): """ A model which contains ants with specified roles. """ def __init__(self, N=10, g=1, size=10, p_uf=0.5, p_pu=0.1, p_up=0.5, p_fl=0.8, p_lu=0.05, ratio=0.5, moore=False, grow=False): """ Args: N (int): number of ants g (float): the max group size of an Ant relative to N size(int): the size of the system (size X size) p_uf (float): the probability that Unassigned changes to Follower p_pu (float): the probability that Pheromone changes to Unassigned p_up (float): the probability that Unassigned changes to Pheromone p_fl (float): the probability that Follower changes to Leader p_lu (float): the probability that Leader changes to Unassigned ratio (float): the start ratio of leaders (1 - ratio is the start nr of pheromone) moore (bool): True/False whether Moore/vonNeumann is used grow (bool): True/False whether the system grows over time or not """ super().__init__() # Environment variables size = int(size) self.width = size self.height = size self.moore = moore self.grow = grow self.grid = MultiGrid(size, size, torus=True) self.interaction_probs = { Unassigned: (-1, None), Follower: (-1, None), Leader: (p_uf, Follower), Pheromone: (p_up, Pheromone), "success": (p_fl, Leader), "failure": (p_lu, Unassigned), "scent_lost": (p_pu, Unassigned) } self.ant_counter = 0 # Environment attributes self.schedule = RandomActivation(self) # Ant variables N = int(N) self.N = N self.g = g self.max_group_size = np.round(g * N) if np.round(g * N) >= 1 else 1 role_division = { Unassigned: np.round(N // 2), Follower: 0, Leader: int((N // 2) * ratio), Pheromone: N - np.round(N // 2) - int((N // 2) * ratio) } self.role_division = role_division for role, number in role_division.items(): self.add_ants(number, role) model_reporters = { "unassigned": lambda m: sum( [1 if a.role == Unassigned else 0 for a in m.schedule.agents]), "followers": lambda m: sum( [1 if a.role == Follower else 0 for a in m.schedule.agents]), "leaders": lambda m: sum( [1 if a.role == Leader else 0 for a in m.schedule.agents]), "pheromone": lambda m: sum( [1 if a.role == Pheromone else 0 for a in m.schedule.agents]) } self.dc = DataCollector(model_reporters=model_reporters) def get_torus_coordinates(self, x, y): """ Gives correct coordinates if the coordinates are out of bounds. Args: x (int): current x position y (int): current y position Returns: Tuple of (x, y) that is in ([0, width], [0, height]) """ return x % self.width, y % self.height def get_torus_neighborhood(self, pos, moore, radius=1, include_center=False): """ Faster alternative to the mesa built-in grid.get_neighbourhood(). Args: pos (tuple): tuple of position (int x, int y) moore (bool): if True, uses Moore's neighborhood if False, uses Neumann's neighborhood radius (int): decides the radius of the neighborhood (default 1) include_center (bool): if True, include the center if False, do not include the center (default False) Returns: An iterator that gives all coordinates that are connected to pos through the given neighborhood """ x, y = pos coordinates = set() # Loop over Moore's neighborhood for dy in range(-radius, radius + 1): for dx in range(-radius, radius + 1): if dx == 0 and dy == 0 and not include_center: continue # Skip anything outside the manhattan distance for Neumann if not moore and abs(dx) + abs(dy) > radius: continue px, py = x + dx, y + dy px, py = self.get_torus_coordinates(px, py) coords = (px, py) if coords not in coordinates: coordinates.add(coords) yield coords def get_random_position(self): """ Gets a random position in the grid, samples from a uniform distribution. Returns: Tuple position (int x, int y) """ return (np.random.randint(0, self.width), np.random.randint(0, self.height)) def add_ants(self, N, role): """ Adds N ants of with role role to this colony. Args: N (int): integer value which specifies the nr of ants to add role (Role): one of {Unassigned, Follower, Leader, Pheromone} """ for _ in range(N): a = Ant(self.ant_counter, model=self, pos=None, role=role) self.grid.place_agent(a, a.pos) self.schedule.add(a) self.ant_counter += 1 def move_agent(self, ant, pos): """ Move an agent across the map. Args: ant (Ant): what agent to move pos (tuple): (int x, int y) to move the agent to """ self.grid.move_agent(ant, pos) def step(self): """ Do a single time-step using freeze-dry states, colonies are updated each time-step in random orders, and ants are updated per colony in random order. """ self.schedule.step() self.dc.collect(self) if self.grow: self.add_ants(1, Unassigned) self.N += 1 def animate(self, ax): """ Update the visualization part of the Ants. Args: ax (Axes): axes binding of matplotlib to animate on """ self.ax = ax self.animate_ants() def animate_ants(self): """ Ask the ants to update themselfs in the animation. """ for ant in self.schedule.agents: ant.update_vis() def grid_to_array(self, pos): """ Convert the position/indices on self.grid to imshow array. Args: pos (tuple): (int x, int y) Returns: tuple (int: x, int: y), that contains the converted position """ return pos[0], self.height - pos[1] - 1
class GeneticNQueens(Genetic): def __init__(self, population, num_iters, crossover_ratio, mutation_ratio, n_queens): self.n_queens = n_queens super().__init__(population, num_iters, crossover_ratio, mutation_ratio) self.grid = MultiGrid(self.n_queens, self.n_queens, False) self.queens = [] self.best: Individual = None self.create_board() self.running = True # Captura de datos para grafica self.datacollector = DataCollector({ "Best": lambda m: m.best.fitness, "Average": lambda m: m.average(), "Worst": lambda m: m.worst(), "Diversity": lambda m: m.diversity() }) def average(self): sum = 0 for individual in self.individuals: sum += individual.fitness return sum / len(self.individuals) def worst(self): worst = self.individuals[0].fitness for individual in self.individuals[1:len(self.individuals)]: if worst > individual.fitness: worst = individual.fitness return worst def create_board(self): for i in range(self.n_queens): cell_queen = CellQueen(self.unique_id, self, (i, 0)) self.unique_id += 1 self.grid.place_agent(cell_queen, (i, 0)) self.queens.append(cell_queen) for j in range(self.n_queens): color = "white" if divmod(i + j, 2)[1] == 1 else "black" cell = Cell(self.unique_id, self, (i, j), color) self.unique_id += 1 self.grid.place_agent(cell, (i, j)) self.update_best() def update_board(self): i = 0 for queen in self.queens: self.grid.move_agent(queen, (i, self.best.content[i])) i += 1 def update_best(self): best = self.individuals[0] for individual in self.individuals[1:len(self.individuals)]: if individual.fitness > best.fitness: best = individual self.best = best # Metodos de la clase padre def initial_population(self): for _ in range(self.population): content = [ random.randint(0, self.n_queens - 1) for _ in range(self.n_queens) ] individual = Individual(self.unique_id, self, 0, content) self.unique_id += 1 self.compute_fitness(individual) self.individuals.append(individual) def compute_fitness(self, individual): res = 0 lis = [i for i in range(len(individual.content))] for i in lis: for j in lis[i:len(lis)]: if j > i: res += self.threat(i, j, individual.content) individual.fitness = self.n_queens - res def threat(self, i, j, content): eli = content[i] elj = content[j] if (eli == elj) or\ ((elj - eli) == (j - i)) or\ ((elj - eli) == (i - j)): return 1 return 0 def crossover(self, content1, content2): cut_point = 1 + random.randint(0, len(content1) - 1) c1 = content1[0:cut_point] + content2[cut_point:len(content2)] c2 = content2[0:cut_point] + content1[cut_point:len(content1)] return [c1, c2] def mutate(self, individual): for i in range(len(individual.content)): if random.random() * 100 < self.mutation_ratio: individual.content[i] = random.randint(0, self.n_queens - 1) def external_update(self): self.update_best() self.update_board() # Recoger datos para plot self.datacollector.collect(self) # Parada de simulacion si se encuentra solucion # O si se acaban las iteraciones if self.best.fitness == self.n_queens: self.running = False