add test ant pheromone decay, rename chemicals to pheromone

This commit is contained in:
Alexander Bocken 2023-05-17 19:32:08 +02:00
parent 11821b6138
commit a8cb347e4a
Signed by: Alexander
GPG Key ID: 1D237BE83F9B05E8
3 changed files with 71 additions and 25 deletions

View File

@ -12,11 +12,11 @@ from mesa.agent import Agent
from mesa.space import Coordinate
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,
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,
alpha=0.6, drop_chemical=None,
alpha=0.6, drop_pheromone=None,
betas : dict[str, float]={"A": 0.0512, "B": 0.0512},
sensitivity_decay_rate=0.01,
sensitivity_max = 1
@ -27,12 +27,12 @@ class RandomWalkerAnt(Agent):
self._next_pos : None | Coordinate = None
self.prev_pos : None | Coordinate = None
self.look_for_chemical = look_for_chemical
self.drop_chemical = drop_chemical
self.look_for_pheromone = look_for_pheromone
self.drop_pheromone = drop_pheromone
self.energy = energy_0 #TODO: use
self.sensitivity_0 = 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.sensitivity_max = sensitivity_max
self.sensitivity_decay_rate = sensitivity_decay_rate
@ -87,7 +87,7 @@ class RandomWalkerAnt(Agent):
if self.searching_food:
for neighbor in self.front_neighbors:
if self.model.grid.is_food(neighbor):
self.drop_chemical = "B"
self.drop_pheromone = "B"
self.sensitivity = self.sensitivity_0
self.prev_pos = neighbor
@ -96,8 +96,8 @@ class RandomWalkerAnt(Agent):
elif self.searching_nest:
for neighbor in self.front_neighbors:
if self.model.grid.is_nest(neighbor):
self.look_for_chemical = "A" # Is this a correct interpretation?
self.drop_chemical = "A"
self.look_for_pheromone = "A" # Is this a correct interpretation?
self.drop_pheromone = "A"
self.sensitivity = self.sensitivity_0
#TODO: Do we flip the ant here or reset prev pos?
@ -107,16 +107,16 @@ class RandomWalkerAnt(Agent):
# recruit new ants
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
self.model.schedule.add(agent)
self.model.grid.place_agent(agent, pos=neighbor)
# follow positive gradient
if self.look_for_chemical is not None:
front_concentration = [self.model.grid.fields[self.look_for_chemical][cell] for cell in self.front_neighbors ]
front_concentration = self.sens_adj(front_concentration, self.look_for_chemical)
current_pos_concentration = self.sens_adj(self.model.grid.fields[self.look_for_chemical][self.pos], self.look_for_chemical)
if self.look_for_pheromone is not None:
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_pheromone)
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)
index = np.argmax(gradient)
if gradient[index] > 0:
@ -138,19 +138,19 @@ class RandomWalkerAnt(Agent):
def step(self):
self.sensitivity -= self.sensitivity_decay_rate
self._choose_next_pos()
self._adjust_chemical_drop_rate()
self._adjust_pheromone_drop_rate()
def _adjust_chemical_drop_rate(self):
if(self.drop_chemical is not None):
self.chemical_drop_rate[self.drop_chemical] -= self.chemical_drop_rate[self.drop_chemical] * self.betas[self.drop_chemical]
def _adjust_pheromone_drop_rate(self):
if(self.drop_pheromone is not None):
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
if self.drop_chemical is not None:
self.model.grid.fields[self.drop_chemical][self.pos] += self.chemical_drop_rate[self.drop_chemical]
if self.drop_pheromone is not None:
self.model.grid.fields[self.drop_pheromone][self.pos] += self.pheromone_drop_rate[self.drop_pheromone]
def advance(self) -> None:
self.drop_chemicals()
self.drop_pheromones()
self.prev_pos = self.pos
self.model.grid.move_agent(self, self._next_pos)
@ -162,11 +162,11 @@ class RandomWalkerAnt(Agent):
@property
def searching_nest(self) -> bool:
return self.drop_chemical == "B"
return self.drop_pheromone == "B"
@property
def searching_food(self) -> bool:
return self.drop_chemical == "A"
return self.drop_pheromone == "A"
@property
def front_neighbors(self):

46
main.py
View File

@ -15,6 +15,7 @@ from mesa.space import Coordinate
def main():
check_pheromone_exponential_decay()
check_ant_sensitivity_linear_decay()
check_ant_pheromone_exponential_decay()
def check_pheromone_exponential_decay():
"""
@ -103,6 +104,51 @@ def check_ant_sensitivity_linear_decay():
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__":
main()

View File

@ -39,7 +39,7 @@ class ActiveWalkerModel(Model):
}
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.grid.place_agent(agent, pos=nest_position)