diff --git a/agent.py b/agent.py
index 105fcae..c76ebf2 100644
--- a/agent.py
+++ b/agent.py
@@ -87,6 +87,24 @@ class RandomWalkerAnt(Agent):
return weights
def _choose_next_pos(self):
+ def _combine_weights(res_weights, walk_weights):
+ """
+ If we have a resistance -> Infinity we want to have a likelihood -> 0 for this direction
+ Therefore we should multiply our two probabilities.
+ For the case of no resistance field this will return the normal walk_weights
+ res_weights : resistance weights: based on resistance field of neighbours
+ see _get_resistance_weights for more info
+ walk weights: In case of biased random walk (no positive pheromone gradient):
+ forward: alpha,
+ everywhere else: (1- alpaha)/5)
+ In case of positive pheromone gradient present in front:
+ max. positive gradient: self.sensitivity
+ everyhwere else: (1-self.sensitivity)/5
+ """
+ combined = res_weights * walk_weights
+ normalized = combined / np.sum(combined)
+ return normalized
+
def _pick_from_remaining_five(remaining_five):
"""
"""
@@ -96,7 +114,10 @@ class RandomWalkerAnt(Agent):
self._prev_pos = self.pos
if self._prev_pos is None:
- weights = self._get_resistance_weights()
+ res_weights = self._get_resistance_weights()
+ walk_weights = np.ones(6)
+ weights = _combine_weights(res_weights, walk_weights)
+
i = np.random.choice(range(6),p=weights)
assert(self.pos is not self.neighbors()[i])
self._next_pos = self.neighbors()[i]
@@ -155,28 +176,37 @@ class RandomWalkerAnt(Agent):
index = np.argmax(gradient)
if gradient[index] > 0:
- # follow positive gradient with likelihood self.sensitivity
- p = np.random.uniform()
- if p < self.sensitivity:
- self._next_pos = self.front_neighbors[index]
- self._prev_pos = self.pos
- else:
- other_neighbors = self.neighbors().copy()
- other_neighbors.remove(self.front_neighbors[index])
- _pick_from_remaining_five(other_neighbors)
+ # follow positive gradient with likelihood self.sensitivity * resistance_weight (re-normalized)
+
+ all_neighbors_cells = self.neighbors()
+ highest_gradient_cell = self.front_neighbors[index]
+ highest_gradient_index_arr = np.where(all_neighbors_cells == highest_gradient_cell)
+ assert(len(highest_gradient_index_arr) == 1)
+
+ all_neighbors_index = highest_gradient_index_arr[0]
+ sens_weights = np.ones(6) * (1-self.sensitivity)/5
+ sens_weights[all_neighbors_index] = self.sensitivity
+
+ res_weights = self._get_resistance_weights()
+ weights = _combine_weights(res_weights, sens_weights)
+
+ self._next_pos = np.random.choice(all_neighbors_cells, p=weights)
+ self._prev_pos = self.pos
return
# do biased random walk
- p = np.random.uniform()
- # TODO: This completely neglects resistance, relevant?
- if p < self.model.alpha:
- self._next_pos = self.front_neighbor
- self._prev_pos = self.pos
- else:
- other_neighbors = self.neighbors().copy()
- other_neighbors.remove(self.front_neighbor)
- _pick_from_remaining_five(other_neighbors)
+ all_neighbors_cells = self.neighbors()
+ front_index_arr = np.where(all_neighbors_cells == self.front_neighbor)
+ assert(len(front_index_arr) == 1 )
+ front_index = front_index_arr[0]
+ res_weights = self._get_resistance_weights()
+ walk_weights = np.ones(6) * (1-self.model.alpha) / 5
+ walk_weights[front_index] = self.model.alpha
+
+ weights = _combine_weights(res_weights, walk_weights)
+ self._nex_pos = np.random.choice(all_neighbors_cells, p=weights)
+ self._prev_pos = self.pos
def step(self):
self.sensitivity -= self.model.d_s
diff --git a/main.py b/main.py
index 1d91e90..870155c 100755
--- a/main.py
+++ b/main.py
@@ -1,4 +1,3 @@
-
#!/bin/python
"""
main.py - Part of ants project
@@ -7,9 +6,7 @@ execute via `python main.py` in terminal or only UNIX: `./main.py`
License: AGPL 3 (see end of file)
(C) Alexander Bocken, Viviane Fahrni, Grace Kagho
"""
-import array
from model import ActiveWalkerModel
-from agent import RandomWalkerAnt
import numpy as np
import matplotlib.pyplot as plt
from mesa.space import Coordinate
@@ -17,13 +14,6 @@ from mesa.datacollection import DataCollector
#from multihex import MultiHexGrid
-def main():
- pass
- # check_pheromone_exponential_decay()
- # check_ant_sensitivity_linear_decay()
- # check_ant_pheromone_exponential_decay()
- # check_ants_follow_gradient()
-
def check_pheromone_exponential_decay():
"""
Check whether wanted exponential decay of pheromones on grid is done correctly
@@ -183,126 +173,88 @@ def check_ants_follow_gradient():
model.step()
-# if __name__ == "__main__":
-# main()
-
from model import kwargs_paper_setup1 as kwargs
-# kwargs["N_m"] = 10000
-model = ActiveWalkerModel(**kwargs)
+if __name__ == "__main__":
+ print("Test")
+ kwargs["resistance_map_type"] = "perlin"
+ print(kwargs)
+ model = ActiveWalkerModel(**kwargs)
-from hexplot import plot_hexagon
-# 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 hexplot import plot_hexagon
+ # 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()
-# agent_densities = model.datacollector.get_model_vars_dataframe()["agent_dens"]
-# mean_dens = np.mean(agent_densities)
-# norm_dens = mean_dens/np.max(mean_dens)
-# plot_hexagon(norm_dens, title="Ant density overall")
-# plt.show()
+ # from tqdm import tqdm as progress_bar
+ #for _ in progress_bar(range(model.max_steps)):
+ # model.step()
+ # agent_densities = model.datacollector.get_model_vars_dataframe()["agent_dens"]
+ # mean_dens = np.mean(agent_densities)
+ # norm_dens = mean_dens/np.max(mean_dens)
+ # plot_hexagon(norm_dens, title="Ant density overall")
+ # plt.show()
+ # Access the DataCollector
+ #datacollector = model.datacollector
+ ## Get the data from the DataCollector
+ #model_data = datacollector.get_model_vars_dataframe()
+ #print(model_data.columns)
+
+ ## Plot the number of alive ants over time
+ #plt.plot(model_data.index, model_data['alive_ants'])
+ #plt.xlabel('Time')
+ #plt.ylabel('Number of Alive Ants') #this should probably be "active" ants, since it is not considering those in the nest
+ #plt.title('Number of Alive Ants Over Time')
+ #plt.grid(True)
+ #plt.show()
+
+ ## Plot the number of sucessful walkers over time
+ #plt.plot(model_data.index, model_data['sucessful_walkers'])
+ #plt.xlabel('Time')
+ #plt.ylabel('Number of Sucessful Walkers')
+ #plt.title('Number of Sucessful Walkers Over Time')
+ #plt.grid(True)
+ #plt.show()
+
+
+ ## Calculate the cumulative sum
+ #model_data['cumulative_sucessful_walkers'] = model_data['sucessful_walkers'].cumsum()
+
+ ## Plot the cumulative sum of sucessful walkers over time
+ #plt.plot(model_data.index, model_data['cumulative_sucessful_walkers'])
+ #plt.xlabel('Time')
+ #plt.ylabel('Cumulative Sucessful Walkers')
+ #plt.title('Cumulative Sucessful Walkers Over Time')
+ #plt.grid(True)
+ #plt.show()
+
+ ## Values over 100 are to be interpreted as walkers being sucessfull several times since the total max number of ants is 100
+
+ # # Connectivity measure
+ #def check_food_source_connectivity(food_sources, paths): #food_sources = nodes.is_nest, paths=result from BFS
+ # connected_food_sources = set()
+
+ # for source in food_sources:
+ # if source in paths:
+ # connected_food_sources.add(source)
+
+ # connectivity = len(connected_food_sources)
+
+
+ # return connectivity
+
+
+ # # Calculate connectivity through BFS
+
+ # current_paths = bfs(self.grid, self.grid.fields["nests"], 0.000001)
"""
-This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License along with this program. If not, see
+ You should have received a copy of the GNU Affero General Public License along with this program. If not, see
"""
-
-
-
-# |%%--%%|
-
-# Access the DataCollector
-datacollector = model.datacollector
-
-
-# |%%--%%|
-
-# Get the data from the DataCollector
-model_data = datacollector.get_model_vars_dataframe()
-
-# |%%--%%|
-
-print(model_data.columns)
-
-# |%%--%%| <74OaeOltqi|WpQLCA0RuP>
-
-# Plot the number of alive ants over time
-plt.plot(model_data.index, model_data['alive_ants'])
-plt.xlabel('Time')
-plt.ylabel('Number of Alive Ants') #this should probably be "active" ants, since it is not considering those in the nest
-plt.title('Number of Alive Ants Over Time')
-plt.grid(True)
-plt.show()
-
-# |%%--%%|
-
-# Plot the number of sucessful walkers over time
-plt.plot(model_data.index, model_data['sucessful_walkers'])
-plt.xlabel('Time')
-plt.ylabel('Number of Sucessful Walkers')
-plt.title('Number of Sucessful Walkers Over Time')
-plt.grid(True)
-plt.show()
-
-# |%%--%%|
-
-# Calculate the cumulative sum
-model_data['cumulative_sucessful_walkers'] = model_data['sucessful_walkers'].cumsum()
-
-# Plot the cumulative sum of sucessful walkers over time
-plt.plot(model_data.index, model_data['cumulative_sucessful_walkers'])
-plt.xlabel('Time')
-plt.ylabel('Cumulative Sucessful Walkers')
-plt.title('Cumulative Sucessful Walkers Over Time')
-plt.grid(True)
-plt.show()
-
-# Values over 100 are to be interpreted as walkers being sucessfull several times since the total max number of ants is 100
-
-# |%%--%%|
-
- # Connectivity measure
-def check_food_source_connectivity(food_sources, paths): #food_sources = nodes.is_nest, paths=result from BFS
- connected_food_sources = set()
-
- for source in food_sources:
- if source in paths:
- connected_food_sources.add(source)
-
- connectivity = len(connected_food_sources)
-
-
- return connectivity
-
-
- # Calculate connectivity through BFS
-
- current_paths = bfs(self.grid, self.grid.fields["nests"], 0.000001)
-
-
-# |%%--%%| <64kmoHYvCD|JEzmDy4wuX>
-
-
-
-# |%%--%%|
-
-
-
-
-
-
-
-# |%%--%%|
-
-
-
-# |%%--%%|
diff --git a/model.py b/model.py
index 357d95b..c858b1c 100644
--- a/model.py
+++ b/model.py
@@ -107,16 +107,18 @@ class ActiveWalkerModel(Model):
self.grid = MultiHexGridScalarFields(width=width, height=height, torus=True, fields=fields)
if resistance_map_type is None:
+ print("No resistance field")
self.grid.fields["res"] = np.ones((width, height)).astype(float)
elif resistance_map_type == "perlin":
- # perlin generates isotropic noise which may or may not be a good choice
+ # perlin generates anisotropic noise which may or may not be a good choice
# pip3 install git+https://github.com/pvigier/perlin-numpy
from perlin_numpy import (
generate_fractal_noise_2d,
generate_perlin_noise_2d,
)
noise = generate_perlin_noise_2d(shape=(width,height), res=((10,10)))
- normalized_noise = (noise - np.min(noise))/(np.max(noise) - np.min(noise))
+ # normalized to mean=1, min=0, and max=2
+ normalized_noise = (noise - np.min(noise))/(np.max(noise) - np.min(noise)) * 2
self.grid.fields["res"] = normalized_noise
else:
# possible other noise types: simplex or value