Combine resistance and sensitivity/alpha
This commit is contained in:
parent
7c19031ca2
commit
fb1c8f5797
68
agent.py
68
agent.py
@ -87,6 +87,24 @@ class RandomWalkerAnt(Agent):
|
|||||||
return weights
|
return weights
|
||||||
|
|
||||||
def _choose_next_pos(self):
|
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):
|
def _pick_from_remaining_five(remaining_five):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
@ -96,7 +114,10 @@ class RandomWalkerAnt(Agent):
|
|||||||
self._prev_pos = self.pos
|
self._prev_pos = self.pos
|
||||||
|
|
||||||
if self._prev_pos is None:
|
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)
|
i = np.random.choice(range(6),p=weights)
|
||||||
assert(self.pos is not self.neighbors()[i])
|
assert(self.pos is not self.neighbors()[i])
|
||||||
self._next_pos = self.neighbors()[i]
|
self._next_pos = self.neighbors()[i]
|
||||||
@ -155,28 +176,37 @@ class RandomWalkerAnt(Agent):
|
|||||||
|
|
||||||
index = np.argmax(gradient)
|
index = np.argmax(gradient)
|
||||||
if gradient[index] > 0:
|
if gradient[index] > 0:
|
||||||
# follow positive gradient with likelihood self.sensitivity
|
# follow positive gradient with likelihood self.sensitivity * resistance_weight (re-normalized)
|
||||||
p = np.random.uniform()
|
|
||||||
if p < self.sensitivity:
|
all_neighbors_cells = self.neighbors()
|
||||||
self._next_pos = self.front_neighbors[index]
|
highest_gradient_cell = self.front_neighbors[index]
|
||||||
self._prev_pos = self.pos
|
highest_gradient_index_arr = np.where(all_neighbors_cells == highest_gradient_cell)
|
||||||
else:
|
assert(len(highest_gradient_index_arr) == 1)
|
||||||
other_neighbors = self.neighbors().copy()
|
|
||||||
other_neighbors.remove(self.front_neighbors[index])
|
all_neighbors_index = highest_gradient_index_arr[0]
|
||||||
_pick_from_remaining_five(other_neighbors)
|
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
|
return
|
||||||
|
|
||||||
# do biased random walk
|
# do biased random walk
|
||||||
p = np.random.uniform()
|
all_neighbors_cells = self.neighbors()
|
||||||
# TODO: This completely neglects resistance, relevant?
|
front_index_arr = np.where(all_neighbors_cells == self.front_neighbor)
|
||||||
if p < self.model.alpha:
|
assert(len(front_index_arr) == 1 )
|
||||||
self._next_pos = self.front_neighbor
|
front_index = front_index_arr[0]
|
||||||
self._prev_pos = self.pos
|
|
||||||
else:
|
|
||||||
other_neighbors = self.neighbors().copy()
|
|
||||||
other_neighbors.remove(self.front_neighbor)
|
|
||||||
_pick_from_remaining_five(other_neighbors)
|
|
||||||
|
|
||||||
|
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):
|
def step(self):
|
||||||
self.sensitivity -= self.model.d_s
|
self.sensitivity -= self.model.d_s
|
||||||
|
196
main.py
196
main.py
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#!/bin/python
|
#!/bin/python
|
||||||
"""
|
"""
|
||||||
main.py - Part of ants project
|
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)
|
License: AGPL 3 (see end of file)
|
||||||
(C) Alexander Bocken, Viviane Fahrni, Grace Kagho
|
(C) Alexander Bocken, Viviane Fahrni, Grace Kagho
|
||||||
"""
|
"""
|
||||||
import array
|
|
||||||
from model import ActiveWalkerModel
|
from model import ActiveWalkerModel
|
||||||
from agent import RandomWalkerAnt
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from mesa.space import Coordinate
|
from mesa.space import Coordinate
|
||||||
@ -17,13 +14,6 @@ from mesa.datacollection import DataCollector
|
|||||||
|
|
||||||
#from multihex import MultiHexGrid
|
#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():
|
def check_pheromone_exponential_decay():
|
||||||
"""
|
"""
|
||||||
Check whether wanted exponential decay of pheromones on grid is done correctly
|
Check whether wanted exponential decay of pheromones on grid is done correctly
|
||||||
@ -183,126 +173,88 @@ def check_ants_follow_gradient():
|
|||||||
model.step()
|
model.step()
|
||||||
|
|
||||||
|
|
||||||
# if __name__ == "__main__":
|
|
||||||
# main()
|
|
||||||
|
|
||||||
from model import kwargs_paper_setup1 as kwargs
|
from model import kwargs_paper_setup1 as kwargs
|
||||||
# kwargs["N_m"] = 10000
|
if __name__ == "__main__":
|
||||||
model = ActiveWalkerModel(**kwargs)
|
print("Test")
|
||||||
|
kwargs["resistance_map_type"] = "perlin"
|
||||||
|
print(kwargs)
|
||||||
|
model = ActiveWalkerModel(**kwargs)
|
||||||
|
|
||||||
from hexplot import plot_hexagon
|
# from hexplot import plot_hexagon
|
||||||
# a = np.zeros_like(model.grid.fields['food'])
|
# a = np.zeros_like(model.grid.fields['food'])
|
||||||
# a[np.nonzero(model.grid.fields['food'])] = 1
|
# a[np.nonzero(model.grid.fields['food'])] = 1
|
||||||
# plot_hexagon(a, title="Nest locations")
|
# plot_hexagon(a, title="Nest locations")
|
||||||
# plot_hexagon(model.grid.fields['res'], title="Resistance Map")
|
# plot_hexagon(model.grid.fields['res'], title="Resistance Map")
|
||||||
|
|
||||||
|
|
||||||
from tqdm import tqdm as progress_bar
|
# from tqdm import tqdm as progress_bar
|
||||||
for _ in progress_bar(range(model.max_steps)):
|
#for _ in progress_bar(range(model.max_steps)):
|
||||||
model.step()
|
# model.step()
|
||||||
# agent_densities = model.datacollector.get_model_vars_dataframe()["agent_dens"]
|
# agent_densities = model.datacollector.get_model_vars_dataframe()["agent_dens"]
|
||||||
# mean_dens = np.mean(agent_densities)
|
# mean_dens = np.mean(agent_densities)
|
||||||
# norm_dens = mean_dens/np.max(mean_dens)
|
# norm_dens = mean_dens/np.max(mean_dens)
|
||||||
# plot_hexagon(norm_dens, title="Ant density overall")
|
# plot_hexagon(norm_dens, title="Ant density overall")
|
||||||
# plt.show()
|
# 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)
|
self.grid = MultiHexGridScalarFields(width=width, height=height, torus=True, fields=fields)
|
||||||
|
|
||||||
if resistance_map_type is None:
|
if resistance_map_type is None:
|
||||||
|
print("No resistance field")
|
||||||
self.grid.fields["res"] = np.ones((width, height)).astype(float)
|
self.grid.fields["res"] = np.ones((width, height)).astype(float)
|
||||||
elif resistance_map_type == "perlin":
|
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
|
# pip3 install git+https://github.com/pvigier/perlin-numpy
|
||||||
from perlin_numpy import (
|
from perlin_numpy import (
|
||||||
generate_fractal_noise_2d,
|
generate_fractal_noise_2d,
|
||||||
generate_perlin_noise_2d,
|
generate_perlin_noise_2d,
|
||||||
)
|
)
|
||||||
noise = generate_perlin_noise_2d(shape=(width,height), res=((10,10)))
|
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
|
self.grid.fields["res"] = normalized_noise
|
||||||
else:
|
else:
|
||||||
# possible other noise types: simplex or value
|
# possible other noise types: simplex or value
|
||||||
|
Loading…
Reference in New Issue
Block a user