-
Notifications
You must be signed in to change notification settings - Fork 1
/
AntColonySolver.py
134 lines (95 loc) · 4.49 KB
/
AntColonySolver.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import numpy as np
from CommonRouteMethods import separation, circular_route_length
def init_pheramone_matrix(n):
matrix = np.ones((n,n))
#np.fill_diagonal(matrix, 0)
return matrix
def quality_factor(node_map, current_node, destination_node):
sep = separation(node_map[current_node], node_map[destination_node])
if sep == 0.0:
return 0.0
else:
return 1.0/separation(node_map[current_node], node_map[destination_node])
def probability_vector(node_map, pheramone_matrix, visited_nodes):
# Make a vector of destinations that are disallowed
forbiddon_destinations = visited_nodes
# Now make a vector with 0s at locations of forbiddon destinations
permitted_destination_vector = np.ones(len(pheramone_matrix))
permitted_destination_vector[forbiddon_destinations] = 0.0
# Get a pheramone path vector based on permitted destinations
# and the pheramone matrix
pheramone_path_vector = permitted_destination_vector*pheramone_matrix[visited_nodes[-1]]
# Generate a vector of heuristic factors that are inversely proportional to
# the distances to each destination
quality_vector = [quality_factor(node_map, visited_nodes[-1], x) for x in xrange(len(node_map))]
# Get un-normalisesed probability vector
probability_vector = quality_vector*pheramone_path_vector
norm = sum(probability_vector)
return probability_vector/norm
def sort_destinations(probability_vector):
return sorted(zip(probability_vector, range(len(probability_vector))), reverse = True)
def get_next_node(node_map, pheramone_matrix, visited_nodes):
# Get vector of probabilities
prob_vec = probability_vector(node_map, pheramone_matrix, visited_nodes)
# Sort destinations according to probability
sorted_destinations = sort_destinations(prob_vec)
# Select a destination based on probabilities
rand = np.random.random()
accFit = 0.0
for destination in sorted_destinations:
accFit += destination[0] # sorted_destinations = [[probability,destination],...]
if accFit > rand:
return destination[1]
def generate_route(node_map, pheramone_matrix):
# Start on node 0
node = 0
route = [node]
# Calculate and store number of nodes in route
nodes = len(pheramone_matrix)
while len(route) < nodes:
# Generate next node that is not currently in the route
next_node = get_next_node(node_map, pheramone_matrix, route)
route.append(next_node)
return route
def partition(l, partition_length):
return [l[i:i+partition_length] for i in xrange(0, len(l)-partition_length+1,1)]
def pheramone_matrix_update(route, route_length):
partitioned_route = partition(route, 2)
update_matrix = np.zeros((len(route),len(route)))
for pair in partitioned_route:
update_matrix[pair[0],pair[1]] = 1.0/route_length
return update_matrix
def evaporate_pheramone_matrix(matrix, evaporation_factor):
return (1-evaporation_factor)*matrix
def find_shortest_route(node_map, ant_count, evaporation_factor=0.05, convergence_percentage = 0.75, time_out_steps = 1000):
route_lengths=[]
# Initialize pheramone matrix
pheramone_matrix = init_pheramone_matrix(len(node_map))
unique_fraction = 1.0
step_count = 0
while unique_fraction > (1-convergence_percentage):
# Initialize set of routes
routes=[]
# Evaporate pheramone matrix
pheramone_matrix = evaporate_pheramone_matrix(pheramone_matrix, evaporation_factor)
# Set ants roaming
for ant in xrange(ant_count):
route = generate_route(node_map, pheramone_matrix)
routes.append(route)
# Update pheramone matrix
for route in routes:
route_length = circular_route_length(node_map, route)
pheramone_matrix += pheramone_matrix_update(route, route_length)
# Track an ant in the colony
route_lengths.append(circular_route_length(node_map, routes[0]))
# Check for convergence
unique_routes = []
for route in routes:
if route not in unique_routes:
unique_routes.append(route)
unique_fraction = float(len(unique_routes))/float(len(routes))
# Check for timeout
step_count += 1
if (step_count > time_out_steps):
break
return route_lengths, routes[0]