add viviane's bfs implementation

This commit is contained in:
Alexander Bocken 2023-06-27 22:24:40 +02:00
parent 9fae37347b
commit ef7646f556
Signed by: Alexander
GPG Key ID: 1D237BE83F9B05E8
2 changed files with 83 additions and 27 deletions

53
main.py
View File

@ -172,6 +172,59 @@ def check_ants_follow_gradient():
print(20*"#") print(20*"#")
model.step() model.step()
def viviane_bfs_example_run():
# Breadth-first-search algorithm for connectivity
def bfs(graph, start_node, threshold): #graph=grid, start_node=nest, threshold=TBD?
from collections import deque
visited = set()
queue = deque([(start_node, [])])
paths = {}
connected_food_sources = set()
while queue:
current_node, path = queue.popleft()
#current_node = tuple(current_node)
visited.add(current_node)
if current_node in graph:
for neighbor, m.grid.fields["A"] in graph[current_node].items():
if neighbor not in visited and m.grid.fields["A"] >= threshold:
new_path = path + [neighbor]
queue.append((neighbor, new_path))
# Check if the neighbor is a food source
if neighbor in self.grid_food:
if neighbor not in paths:
paths[neighbor] = new_path
connected_food_sources.add(neighbor)
connectivity = len(connected_food_sources)
return connectivity
# Calculate connectivity through BFS
current_paths = bfs(self.grid, self.grid.fields["nests"], 0.000001)
import numpy as np
N = 121
N_X = int(np.sqrt(N))
N_Y = N // N_X
# fancy way of saying absolutely nothing but 11
xv, yv = np.meshgrid(np.arange(N_X), np.arange(N_Y), sparse=False, indexing='xy')
print(f"{N_X=}")
print(f"{N_Y=}")
print(f"{(xv, yv)=}")
print(f"{xv=}")
from model import kwargs_paper_setup1 as kwargs from model import kwargs_paper_setup1 as kwargs
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -15,7 +15,6 @@ from multihex import MultiHexGridScalarFields
from mesa.time import SimultaneousActivation from mesa.time import SimultaneousActivation
from mesa.datacollection import DataCollector from mesa.datacollection import DataCollector
from agent import RandomWalkerAnt from agent import RandomWalkerAnt
from collections import deque
kwargs_paper_setup1 = { kwargs_paper_setup1 = {
"width": 100, "width": 100,
@ -101,6 +100,7 @@ class ActiveWalkerModel(Model):
self.e_min : float = e_min # energy at which walker dies self.e_min : float = e_min # energy at which walker dies
self.N_f : int = N_f #num food sources self.N_f : int = N_f #num food sources
self.successful_ants = 0 # for viviane's graph self.successful_ants = 0 # for viviane's graph
self.connectivity = 0 # for viviane's persistence
fields=["A", "B", "nests", "food", "res"] fields=["A", "B", "nests", "food", "res"]
self.schedule = SimultaneousActivation(self) self.schedule = SimultaneousActivation(self)
@ -141,39 +141,42 @@ class ActiveWalkerModel(Model):
# Breadth-first-search algorithm for connectivity # Breadth-first-search algorithm for connectivity
#def bfs(graph, start_node, threshold): #graph=grid, start_node=nest, threshold=TBD? # TODO: Implement pheromone B (take max of the two or sum?)
# visited = set() # alex: what's to say against max?
# queue = deque([(start_node, [])]) def bfs(self):
# paths = {} threshold = 0.0000001 #the value of A
# connected_food_sources = set() connectivity = 0 #initial value of connectivity
connected_food_sources = list() #empty list of connected food sources
visited = list() #empty list of visited (by the algorithm) nodes
# while queue: nest = np.argwhere(self.grid.fields["nests"] == 1) #get nest location
# current_node, path = queue.popleft() nest = nest[0].tolist() #transforming not to have type errors
#current_node = tuple(current_node) nest = tuple(nest) #transforming not to have type errors
# visited.add(current_node) start_node = nest #rename
# if current_node in graph: neighbours_to_check = list([start_node]) #start node gets checked first
# for neighbor, m.grid.fields["A"] in graph[current_node].items(): neighbours_to_check = neighbours_to_check + self.grid.get_neighborhood(start_node) #start node neighbours get added to the to check list
# if neighbor not in visited and m.grid.fields["A"] >= threshold:
# new_path = path + [neighbor]
# queue.append((neighbor, new_path))
# Check if the neighbor is a food source while neighbours_to_check: #as long as there is something on the to check list
# if neighbor in self.grid_food: current_node = neighbours_to_check[0] #the first list entry is taken
# if neighbor not in paths: del neighbours_to_check[0] #and deleted on the to check list
# paths[neighbor] = new_path
# connected_food_sources.add(neighbor)
# connectivity = len(connected_food_sources) if current_node not in visited: #if it has not previously been checked
if self.grid.fields["A"][current_node] >= threshold: #and its A value is above our threshold
new_neighbors = self.grid.get_neighborhood(current_node) #then we get its neighbours
if new_neighbors not in visited: #if they have not yet been visited
neighbours_to_check = neighbours_to_check + new_neighbors #then they are also added to our to check list
visited = visited + list([current_node]) #and the current node has now been checked
# return connectivity neighbours_to_check = list(dict.fromkeys(neighbours_to_check)) #only check nodes once (unique values)
if self.grid.fields["food"][current_node] > 0: #in case the node we check is food
connectivity += 1 #then we have found a connected path to a food source
connected_food_sources = connected_food_sources + list([current_node]) #and it is added to the list of connected food sources
# Calculate connectivity through BFS return connectivity #we want the connectivity (0-5)
# current_paths = bfs(self.grid, self.grid.fields["nests"], 0.000001)
self.connectivity = bfs(self)
self.datacollector = DataCollector( self.datacollector = DataCollector(
@ -182,7 +185,7 @@ class ActiveWalkerModel(Model):
"pheromone_b": lambda m: m.grid.fields["B"], "pheromone_b": lambda m: m.grid.fields["B"],
"alive_ants": lambda m: m.schedule.get_agent_count(), "alive_ants": lambda m: m.schedule.get_agent_count(),
"sucessful_walkers": lambda m: m.successful_ants, "sucessful_walkers": lambda m: m.successful_ants,
#"connectivity": lambda m: check_food_source_connectivity(self.grid_food,current_paths), "connectivity": lambda m: m.connectivity,
}, },
agent_reporters={} agent_reporters={}
) )