-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathworld.py
80 lines (66 loc) · 2.81 KB
/
world.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from agent import Agent
from ant import Ant
import settings
class World(Agent):
def __init__(self, graph, source_node, terminal_node):
super(World, self).__init__()
# World population
self.ants = []
# World geography
self.graph = graph
self.SOURCE_NODE = source_node
self.TERMINAL_NODE = terminal_node
self.arcs = []
for start, ends in self.graph.iteritems():
for end in ends:
if start | end not in self.arcs:
self.arcs.append(start | end)
# World pheromone levels
self.base = { arc:0 for arc in self.arcs } # initial pheromone levels
self.current = self.base.copy() # pheromone changes for the period
self.history = [] # history of pheromone settings for each period
self.memo = { arc:1 for arc in self.arcs } # running tally of pheromones on nodes
self.memo_history = [] # history of running tally for each period
self.path_lengths = {} # history of path lengths found by the ants
def advance(self):
"""Advance to the next time period"""
for arc, level in self.current.iteritems():
# add the new level
self.memo[arc] += level
# evaporate some pheromone
self.memo[arc] = (1 - settings.rho) * self.memo[arc]
self.memo_history.append(self.memo.copy())
self.history.append(self.current)
self.current = self.base.copy()
def get_ant(self, i):
"""Get the ith ant"""
return self.ants[i]
def get_pheromones(self, node):
"""Get the pheromones on all arcs proceeding from a given node"""
pheromones = {}
for destination in self.graph[node]:
pheromones[destination] = self.memo[node | destination]
return pheromones
def populate(self, ant):
"""Add an ant to the world population"""
self.ants.append(ant)
ant.attach(self)
return len(self.ants)
def update(self, ant):
"""Observer pattern update method
Update pheromone levels when an ant moves across an arc, and, after the ant
completes the journey to the destination (FOOD), store the length of the
path they found.
"""
# Only want to update pheromone on the return journey
if ant.direction == ant.BACKWARDS:
# Check if we want the amount of pheromone to inversely correspond to path length
level = settings.deposit / ant.return_length if settings.autocatalysis else settings.deposit
self.current[ant.trip[-1] | ant.trip[-2]] += level
# Save the path length if the ant just left the TERMINAL_NODE
# (i.e. trip[-1] is the first node the ant went to after leaving the
# TERMINAL_NODE, so trip[-2] would be the TERMINAL_NODE)
if ant.trip[-2] == self.TERMINAL_NODE:
if ant.return_length not in self.path_lengths:
self.path_lengths[ant.return_length] = 0
self.path_lengths[ant.return_length] += 1