Combine resistance and sensitivity/alpha
This commit is contained in:
parent
7c19031ca2
commit
fb1c8f5797
66
agent.py
66
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]
|
||||
# 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
|
||||
else:
|
||||
other_neighbors = self.neighbors().copy()
|
||||
other_neighbors.remove(self.front_neighbors[index])
|
||||
_pick_from_remaining_five(other_neighbors)
|
||||
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
|
||||
|
196
main.py
196
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 <https://www.gnu.org/licenses/>
|
||||
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
"""
|
||||
|
||||
|
||||
|
||||
# |%%--%%| <Z5Ra4Us5kN|y6CRYNrY9x>
|
||||
|
||||
# Access the DataCollector
|
||||
datacollector = model.datacollector
|
||||
|
||||
|
||||
# |%%--%%| <y6CRYNrY9x|v2PfrSWbzG>
|
||||
|
||||
# Get the data from the DataCollector
|
||||
model_data = datacollector.get_model_vars_dataframe()
|
||||
|
||||
# |%%--%%| <v2PfrSWbzG|74OaeOltqi>
|
||||
|
||||
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()
|
||||
|
||||
# |%%--%%| <WpQLCA0RuP|UufL3yaROS>
|
||||
|
||||
# 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()
|
||||
|
||||
# |%%--%%| <UufL3yaROS|mgJWQ0bqG1>
|
||||
|
||||
# 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
|
||||
|
||||
# |%%--%%| <mgJWQ0bqG1|64kmoHYvCD>
|
||||
|
||||
# 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>
|
||||
|
||||
|
||||
|
||||
# |%%--%%| <JEzmDy4wuX|U9vmSFZUyD>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# |%%--%%| <U9vmSFZUyD|r0xVXEqlAh>
|
||||
|
||||
|
||||
|
||||
# |%%--%%| <r0xVXEqlAh|6K80EwwmVN>
|
||||
|
6
model.py
6
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
|
||||
|
Loading…
Reference in New Issue
Block a user