add test ant pheromone decay, rename chemicals to pheromone
This commit is contained in:
		
							
								
								
									
										48
									
								
								agent.py
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								agent.py
									
									
									
									
									
								
							| @@ -12,11 +12,11 @@ from mesa.agent import Agent | |||||||
| from mesa.space import Coordinate | from mesa.space import Coordinate | ||||||
|  |  | ||||||
| class RandomWalkerAnt(Agent): | class RandomWalkerAnt(Agent): | ||||||
|     def __init__(self, unique_id, model, look_for_chemical=None, |     def __init__(self, unique_id, model, look_for_pheromone=None, | ||||||
|                  energy_0=1, |                  energy_0=1, | ||||||
|                  chemical_drop_rate_0 : dict[str, float]={"A": 80, "B": 80}, |                  pheromone_drop_rate_0 : dict[str, float]={"A": 80, "B": 80}, | ||||||
|                  sensitivity_0=0.99, |                  sensitivity_0=0.99, | ||||||
|                  alpha=0.6, drop_chemical=None, |                  alpha=0.6, drop_pheromone=None, | ||||||
|                  betas : dict[str, float]={"A": 0.0512, "B": 0.0512}, |                  betas : dict[str, float]={"A": 0.0512, "B": 0.0512}, | ||||||
|                  sensitivity_decay_rate=0.01, |                  sensitivity_decay_rate=0.01, | ||||||
|                  sensitivity_max = 1 |                  sensitivity_max = 1 | ||||||
| @@ -27,12 +27,12 @@ class RandomWalkerAnt(Agent): | |||||||
|         self._next_pos : None | Coordinate = None |         self._next_pos : None | Coordinate = None | ||||||
|         self.prev_pos : None | Coordinate = None |         self.prev_pos : None | Coordinate = None | ||||||
|  |  | ||||||
|         self.look_for_chemical = look_for_chemical |         self.look_for_pheromone = look_for_pheromone | ||||||
|         self.drop_chemical = drop_chemical |         self.drop_pheromone = drop_pheromone | ||||||
|         self.energy = energy_0 #TODO: use |         self.energy = energy_0 #TODO: use | ||||||
|         self.sensitivity_0 = sensitivity_0 |         self.sensitivity_0 = sensitivity_0 | ||||||
|         self.sensitivity = self.sensitivity_0 |         self.sensitivity = self.sensitivity_0 | ||||||
|         self.chemical_drop_rate = chemical_drop_rate_0 |         self.pheromone_drop_rate = pheromone_drop_rate_0 | ||||||
|         self.alpha = alpha |         self.alpha = alpha | ||||||
|         self.sensitivity_max = sensitivity_max |         self.sensitivity_max = sensitivity_max | ||||||
|         self.sensitivity_decay_rate = sensitivity_decay_rate |         self.sensitivity_decay_rate = sensitivity_decay_rate | ||||||
| @@ -87,7 +87,7 @@ class RandomWalkerAnt(Agent): | |||||||
|         if self.searching_food: |         if self.searching_food: | ||||||
|             for neighbor in self.front_neighbors: |             for neighbor in self.front_neighbors: | ||||||
|                 if self.model.grid.is_food(neighbor): |                 if self.model.grid.is_food(neighbor): | ||||||
|                     self.drop_chemical = "B" |                     self.drop_pheromone = "B" | ||||||
|                     self.sensitivity = self.sensitivity_0 |                     self.sensitivity = self.sensitivity_0 | ||||||
|  |  | ||||||
|                     self.prev_pos = neighbor |                     self.prev_pos = neighbor | ||||||
| @@ -96,8 +96,8 @@ class RandomWalkerAnt(Agent): | |||||||
|         elif self.searching_nest: |         elif self.searching_nest: | ||||||
|             for neighbor in self.front_neighbors: |             for neighbor in self.front_neighbors: | ||||||
|                 if self.model.grid.is_nest(neighbor): |                 if self.model.grid.is_nest(neighbor): | ||||||
|                     self.look_for_chemical = "A" # Is this a correct interpretation? |                     self.look_for_pheromone = "A" # Is this a correct interpretation? | ||||||
|                     self.drop_chemical = "A" |                     self.drop_pheromone = "A" | ||||||
|                     self.sensitivity = self.sensitivity_0 |                     self.sensitivity = self.sensitivity_0 | ||||||
|  |  | ||||||
|                     #TODO: Do we flip the ant here or reset prev pos? |                     #TODO: Do we flip the ant here or reset prev pos? | ||||||
| @@ -107,16 +107,16 @@ class RandomWalkerAnt(Agent): | |||||||
|  |  | ||||||
|                     # recruit new ants |                     # recruit new ants | ||||||
|                     for agent_id in self.model.get_unique_ids(self.model.num_new_recruits): |                     for agent_id in self.model.get_unique_ids(self.model.num_new_recruits): | ||||||
|                         agent = RandomWalkerAnt(unique_id=agent_id, model=self.model, look_for_chemical="B", drop_chemical="A") |                         agent = RandomWalkerAnt(unique_id=agent_id, model=self.model, look_for_pheromone="B", drop_pheromone="A") | ||||||
|                         agent._next_pos = self.pos |                         agent._next_pos = self.pos | ||||||
|                         self.model.schedule.add(agent) |                         self.model.schedule.add(agent) | ||||||
|                         self.model.grid.place_agent(agent, pos=neighbor) |                         self.model.grid.place_agent(agent, pos=neighbor) | ||||||
|  |  | ||||||
|         # follow positive gradient |         # follow positive gradient | ||||||
|         if self.look_for_chemical is not None: |         if self.look_for_pheromone is not None: | ||||||
|             front_concentration = [self.model.grid.fields[self.look_for_chemical][cell] for cell in self.front_neighbors ] |             front_concentration = [self.model.grid.fields[self.look_for_pheromone][cell] for cell in self.front_neighbors ] | ||||||
|             front_concentration = self.sens_adj(front_concentration, self.look_for_chemical) |             front_concentration = self.sens_adj(front_concentration, self.look_for_pheromone) | ||||||
|             current_pos_concentration = self.sens_adj(self.model.grid.fields[self.look_for_chemical][self.pos], self.look_for_chemical) |             current_pos_concentration = self.sens_adj(self.model.grid.fields[self.look_for_pheromone][self.pos], self.look_for_pheromone) | ||||||
|             gradient = front_concentration - np.repeat(current_pos_concentration, 3) |             gradient = front_concentration - np.repeat(current_pos_concentration, 3) | ||||||
|             index = np.argmax(gradient) |             index = np.argmax(gradient) | ||||||
|             if gradient[index] > 0: |             if gradient[index] > 0: | ||||||
| @@ -138,19 +138,19 @@ class RandomWalkerAnt(Agent): | |||||||
|     def step(self): |     def step(self): | ||||||
|         self.sensitivity -= self.sensitivity_decay_rate |         self.sensitivity -= self.sensitivity_decay_rate | ||||||
|         self._choose_next_pos() |         self._choose_next_pos() | ||||||
|         self._adjust_chemical_drop_rate() |         self._adjust_pheromone_drop_rate() | ||||||
|  |  | ||||||
|     def _adjust_chemical_drop_rate(self): |     def _adjust_pheromone_drop_rate(self): | ||||||
|         if(self.drop_chemical is not None): |         if(self.drop_pheromone is not None): | ||||||
|             self.chemical_drop_rate[self.drop_chemical] -= self.chemical_drop_rate[self.drop_chemical] * self.betas[self.drop_chemical] |             self.pheromone_drop_rate[self.drop_pheromone] -= self.pheromone_drop_rate[self.drop_pheromone] * self.betas[self.drop_pheromone] | ||||||
|  |  | ||||||
|     def drop_chemicals(self) -> None: |     def drop_pheromones(self) -> None: | ||||||
|         # should only be called in advance() as we do not use hidden fields |         # should only be called in advance() as we do not use hidden fields | ||||||
|         if self.drop_chemical is not None: |         if self.drop_pheromone is not None: | ||||||
|             self.model.grid.fields[self.drop_chemical][self.pos] += self.chemical_drop_rate[self.drop_chemical] |             self.model.grid.fields[self.drop_pheromone][self.pos] += self.pheromone_drop_rate[self.drop_pheromone] | ||||||
|  |  | ||||||
|     def advance(self) -> None: |     def advance(self) -> None: | ||||||
|         self.drop_chemicals() |         self.drop_pheromones() | ||||||
|         self.prev_pos = self.pos |         self.prev_pos = self.pos | ||||||
|         self.model.grid.move_agent(self, self._next_pos) |         self.model.grid.move_agent(self, self._next_pos) | ||||||
|  |  | ||||||
| @@ -162,11 +162,11 @@ class RandomWalkerAnt(Agent): | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def searching_nest(self) -> bool: |     def searching_nest(self) -> bool: | ||||||
|         return self.drop_chemical == "B" |         return self.drop_pheromone == "B" | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def searching_food(self) -> bool: |     def searching_food(self) -> bool: | ||||||
|         return self.drop_chemical == "A" |         return self.drop_pheromone == "A" | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def front_neighbors(self): |     def front_neighbors(self): | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								main.py
									
									
									
									
									
								
							| @@ -15,6 +15,7 @@ from mesa.space import Coordinate | |||||||
| def main(): | def main(): | ||||||
|     check_pheromone_exponential_decay() |     check_pheromone_exponential_decay() | ||||||
|     check_ant_sensitivity_linear_decay() |     check_ant_sensitivity_linear_decay() | ||||||
|  |     check_ant_pheromone_exponential_decay() | ||||||
|  |  | ||||||
| def check_pheromone_exponential_decay(): | def check_pheromone_exponential_decay(): | ||||||
|     """ |     """ | ||||||
| @@ -103,6 +104,51 @@ def check_ant_sensitivity_linear_decay(): | |||||||
|  |  | ||||||
|     plt.show() |     plt.show() | ||||||
|  |  | ||||||
|  | def check_ant_pheromone_exponential_decay(): | ||||||
|  |     """ | ||||||
|  |     Check whether wanted exponential decay of pheromone drop rate for ants is correctly modeled | ||||||
|  |     shows plot of pheromone placed on grid vs. equivalent exponential decay function | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     from mesa.datacollection import DataCollector | ||||||
|  |  | ||||||
|  |     width = 50 | ||||||
|  |     height = width | ||||||
|  |     num_initial_roamers = 1 | ||||||
|  |     num_max_agents = 100 | ||||||
|  |     nest_position : Coordinate = (width //2, height //2) | ||||||
|  |     max_steps = 1000 | ||||||
|  |  | ||||||
|  |     model = ActiveWalkerModel(width=width, height=height, | ||||||
|  |                               num_initial_roamers=num_initial_roamers, | ||||||
|  |                               nest_position=nest_position, | ||||||
|  |                               num_max_agents=num_max_agents, | ||||||
|  |                               max_steps=max_steps) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     model.datacollector = DataCollector( | ||||||
|  |             model_reporters={}, | ||||||
|  |             agent_reporters={"pheromone_drop_rate": lambda a: a.pheromone_drop_rate["A"]} | ||||||
|  |                 ) | ||||||
|  |     start = model.schedule.agents[0].pheromone_drop_rate["A"] | ||||||
|  |     model.run_model() | ||||||
|  |     a_test = model.datacollector.get_agent_vars_dataframe().reset_index()["pheromone_drop_rate"] | ||||||
|  |  | ||||||
|  |     import matplotlib.pyplot as plt | ||||||
|  |     import numpy as np | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     plt.figure() | ||||||
|  |     xx = np.linspace(0,1000, 10000) | ||||||
|  |     yy = a_test[0]*np.exp(-model.schedule.agents[0].betas["A"]*xx) | ||||||
|  |     plt.plot(xx, yy, label="correct exponential function") | ||||||
|  |     plt.scatter(range(len(a_test)), a_test, label="modeled decay", marker='o') | ||||||
|  |     plt.title("Exponential pheromone drop rate decay test") | ||||||
|  |     plt.legend(loc='best') | ||||||
|  |  | ||||||
|  |     plt.show() | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     main() |     main() | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								model.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								model.py
									
									
									
									
									
								
							| @@ -39,7 +39,7 @@ class ActiveWalkerModel(Model): | |||||||
|                                                } |                                                } | ||||||
|  |  | ||||||
|         for agent_id in self.get_unique_ids(num_initial_roamers): |         for agent_id in self.get_unique_ids(num_initial_roamers): | ||||||
|             agent = RandomWalkerAnt(unique_id=agent_id, model=self, look_for_chemical="A", drop_chemical="A") |             agent = RandomWalkerAnt(unique_id=agent_id, model=self, look_for_pheromone="A", drop_pheromone="A") | ||||||
|             self.schedule.add(agent) |             self.schedule.add(agent) | ||||||
|             self.grid.place_agent(agent, pos=nest_position) |             self.grid.place_agent(agent, pos=nest_position) | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user