From c4ee305256d1630b89064c1775c76eebd44c9e97 Mon Sep 17 00:00:00 2001 From: AlexBocken Date: Wed, 28 Jun 2023 14:57:34 +0200 Subject: [PATCH] further plotting experiments --- agent.py | 18 ++++--- hexplot.py | 4 +- main.py | 145 ++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 146 insertions(+), 21 deletions(-) diff --git a/agent.py b/agent.py index 2be08df..5a05ab3 100644 --- a/agent.py +++ b/agent.py @@ -9,7 +9,7 @@ License: AGPL 3 (see end of file) """ TO DISCUSS: -Is the separation of energy and sensitivity useful? +Is the separation of energy and sensitivity useful? -> only if we have the disconnect via resistance """ import numpy as np @@ -22,7 +22,7 @@ class RandomWalkerAnt(Agent): def __init__(self, unique_id, model, look_for_pheromone=None, drop_pheromone=None, - sensitivity_max = 30000, + sensitivity_max = 10000, ) -> None: super().__init__(unique_id=unique_id, model=model) @@ -81,9 +81,11 @@ class RandomWalkerAnt(Agent): # bit round-about but self.model.grid.fields['res'][positions] # gets interpreted as slices, not multiple singular positions resistance = np.array([ self.model.grid.fields['res'][x,y] for x,y in positions ]) - easiness = np.max(self.model.grid.fields['res']) - resistance + 1e-15 # + epsilon to not divide by zero + easiness = np.max(self.model.grid.fields['res']) - resistance + np.min(self.model.grid.fields['res']) + 1e-15 # + epsilon to not divide by zero weights = easiness/ np.sum(easiness) - + #inv_weights = resistance/ np.sum(resistance) + #weights = 1 - inv_weights + #weights /= np.sum(weights) return weights def _choose_next_pos(self): @@ -103,7 +105,7 @@ class RandomWalkerAnt(Agent): """ combined = res_weights * walk_weights normalized = combined / np.sum(combined) - return list(normalized) + return normalized def _pick_from_remaining_five(remaining_five): """ @@ -213,8 +215,6 @@ class RandomWalkerAnt(Agent): self._prev_pos = self.pos def step(self): - self.sensitivity -= self.model.d_s - self.energy -= self.model.grid.fields['res'][self.pos] * self.model.d_e # Die and get removed if no energy if self.energy < self.model.e_min: self.model.schedule.remove(self) @@ -222,6 +222,10 @@ class RandomWalkerAnt(Agent): self._choose_next_pos() self._adjust_pheromone_drop_rate() + self.sensitivity -= self.model.d_s + self.energy -= self.model.grid.fields['res'][self.pos] * self.model.d_e + + def _adjust_pheromone_drop_rate(self): if(self.drop_pheromone is not None): self.pheromone_drop_rate -= self.pheromone_drop_rate * self.model.beta diff --git a/hexplot.py b/hexplot.py index 62eb3ca..0ec91cb 100755 --- a/hexplot.py +++ b/hexplot.py @@ -2,7 +2,7 @@ import numpy as np import matplotlib.pyplot as plt -def plot_hexagon(A, title=None): +def plot_hexagon(A, title=None, block=True): X, Y = np.meshgrid(range(A.shape[0]), range(A.shape[-1])) X, Y = X*2, Y*2 @@ -28,4 +28,4 @@ def plot_hexagon(A, title=None): if(title is not None): plt.title(title) - plt.show(block=False) + plt.show(block=block) diff --git a/main.py b/main.py index db82f3c..5d1e33c 100755 --- a/main.py +++ b/main.py @@ -226,24 +226,145 @@ def viviane_bfs_example_run(): print(f"{xv=}") -from model import kwargs_paper_setup1 as kwargs -if __name__ == "__main__": - print("Test") - kwargs["resistance_map_type"] = "perlin" - print(kwargs) - model = ActiveWalkerModel(**kwargs) +def fixed_distance_tests(): + """ + position a target food source a known distance away from nest + check for no. successful ants for n runs + """ + + from tqdm import tqdm + runs = 10 + from model import kwargs_paper_setup1 as kwargs + kwargs["N_f"] = 0 + kwargs["gamma"] /= 2 # field decays three times slower + kwargs["beta"] /= 2 # drop rates decays three times slower + kwargs["d_s"] /= 2 # drop rates decays three times slower + kwargs["d_e"] /= 2 # drop rates decays three times slower + successful_walkers = {} + for distance in tqdm(range(5,30), position=0, desc="dis"): + successful_walkers[distance] = [] + for _ in tqdm(range(runs), position=1, desc="run", leave=False): + model = ActiveWalkerModel(**kwargs) + nest_location = kwargs["nest_position"] + food_location = (nest_location[0] - distance, nest_location[1]) + model.grid.add_food(size=100, pos=food_location) + for _ in tqdm(range(model.max_steps), position=2, desc="step", leave=False): + model.step() + successful_walkers[distance].append(model.datacollector.get_model_vars_dataframe().reset_index()["successful_walkers"][kwargs["max_steps"]]) + return successful_walkers + +def fixed_distance_object_between(): + """ + diameter of object: floor(50% of distance) + """ + + from tqdm import tqdm + runs = 10 + from model import kwargs_paper_setup1 as kwargs + kwargs["N_f"] = 0 + kwargs["gamma"] /= 2 # field decays slower + kwargs["beta"] /= 2 # drop rates decays slower + kwargs["d_e"] /= 2 # live longer, search longer + kwargs["d_s"] /= 2 # live longer, search longer + successful_walkers = {} + for distance in tqdm(range(5,30), position=0, desc="dis"): + successful_walkers[distance] = [] + for _ in tqdm(range(runs), position=1, desc="run", leave=False): + model = ActiveWalkerModel(**kwargs) + nest_location = kwargs["nest_position"] + food_location = (nest_location[0] - distance, nest_location[1]) + object_location = (nest_location[0] - distance//2, nest_location[1]) + place_blocking_object(object_location, radius=distance//4, model=model) + model.grid.add_food(size=100, pos=food_location) + for _ in tqdm(range(model.max_steps), position=2, desc="step", leave=False): + model.step() + successful_walkers[distance].append(model.datacollector.get_model_vars_dataframe().reset_index()["successful_walkers"][kwargs["max_steps"]]) + return successful_walkers + +def place_blocking_object(center, radius, model): + positions = [center] + next_outside = [center] + # We grow from the center and add all neighbours of the outer edge of our blocking object + # Add all neighbours of next_outside that aren't in positions to the object + # by doing this radius times we should get an object of diameter 2 * radius + 1 + # positions: accumulator for all positions inside the object of radius radius + # next_outside: keep track what we added in the last go-around. These will be used in the next step. + for _ in range(radius): + outside = next_outside + next_oustide = [] + + #otherwise interprets the tuple as something stupid + for i in range(len(outside)): + cell = outside[i] + neighbours = model.grid.get_neighborhood(cell) + for n in neighbours: + if n not in positions: + positions.append(n) + next_outside.append(n) + + # some large number in comparison to the rest of the resistance field + # such that the probability of stepping on these grid spots tend towards zero + infinity = 1e20 + for pos in positions: + model.grid.fields['res'][pos] = infinity + + +def plot_heatmap(): from hexplot import plot_hexagon + from tqdm import tqdm + # nests rather far away but also partially clumped. + np.random.seed(6) + + from model import kwargs_paper_setup1 as kwargs + kwargs["gamma"] /= 3 # field decays slower + kwargs["beta"] /= 3 # drop rates decays slower + kwargs["d_e"] /= 3 # live longer, search longer + kwargs["d_s"] /= 3 # live longer, search longer + + model = ActiveWalkerModel(**kwargs) a = np.zeros_like(model.grid.fields['food']) a[np.nonzero(model.grid.fields['food'])] = 1 - plot_hexagon(a, title="Nest locations") - plot_hexagon(model.grid.fields['res'], title="Resistance Map") - - - from tqdm import tqdm as progress_bar - for _ in progress_bar(range(model.max_steps)): + a[np.nonzero(model.grid.fields['nests'])] = -1 + plot_hexagon(a, title="food locations", block=False) + for _ in tqdm(range(model.max_steps)): model.step() + for time in np.arange(0, model.max_steps + 1, 1000): + pheromone_concentration = model.datacollector.get_model_vars_dataframe()["pheromone_a"][time] + a = pheromone_concentration + #plot_hexagon(a) + pheromone_concentration = model.datacollector.get_model_vars_dataframe()["pheromone_b"][time] + b = pheromone_concentration + #plot_hexagon(b) + c = np.max([a,b], axis=0) + c = a + b + c = np.clip(c, 0, 200) + plot_hexagon(c) + + +#if __name__ == "__main__": +plot_heatmap() +#print("DISTANCE TEST VS SUCCESSFUL ANTS OBJECT INBETWEEN") +#res = fixed_distance_tests() +#res = fixed_distance_object_between() + # print("Test") +#from model import kwargs_paper_setup1 as kwargs +#kwargs["resistance_map_type"] = "perlin" + # print(kwargs) +#model = ActiveWalkerModel(**kwargs) +#model.step() + + # a = np.zeros_like(model.grid.fields['food']) + # a[np.nonzero(model.grid.fields['food'])] = 1 + # plot_hexagon(a, title="Nest locations") + # plot_hexagon(model.grid.fields['res'], title="Resistance Map") + + + # from tqdm import tqdm as progress_bar + # for _ in progress_bar(range(model.max_steps)): + # model.step() + # Access the DataCollector