ACO algorithm is originally inspired by social behavior of ant colonies, which is a branch of newly developed form of artificial intelligence called Swarm Intelligence (SI). Although ants have no sight, they are capable of finding the shortest route between a food source and their nest by chemical materials called pheromone that they leave when moving. ACO algorithm was firstly used to solve Traveling Salesman Problem (TSP) and then has been successfully applied in many difficult problems like the Quadratic Assignment Problem (QAP), routing in telecommunication networks, feature selection,scheduling, clustering, etc.
The basic idea of ACO is to model the problem as the search for a minimum cost path in a graph, and to use artificial ants to search for good paths. Ants can lay pheromone on edges at each move.Moreover, the ants can always sense the pheromone and decide choose the side with more pheromone to search at a very large probability. The probability can be calculated by both pheromone and visibility information on the path. The pheromone will progressively evaporate after a short time. The more ants on the path, the more the pheromone. Finally, only the shortest path will have the largest pheromone. The shortest path is then the optimal solution of our problem.
# -*- coding: utf-8 -*-
"""
Created on 2017/3/20 8:54 2017
@author: Randolph.Lee
"""
from __future__ import division
import numpy as np
import random
import copy
import sys
class Ant:
def __init__(self, ID, city_list, position):
self.ID = ID
self.current_path = 0.0
self.current_node = position
self.tabu_list = [position]
self.tabu_set = set(self.tabu_list)
self.allowed_set = set(city_list) - self.tabu_set
def update_delat_pheromone(self, nodes):
# always define the ant with ID=0 to update the pheromone
path_0 = self.tabu_list[:-1]
path_1 = self.tabu_list[1:]
delta_pheromone = np.zeros((nodes, nodes))
for i in path_0:
for j in path_1:
delta_pheromone[i, j] = 1 / self.current_path
return delta_pheromone
def visit_next_city(self, alpha, beta, pheromone_mat, heuristic_mat):
if len(self.allowed_set) == 0:
return -1
prob_list = []
# calculate the transition probability
for node in self.allowed_set:
prob_list.append((node, np.power(pheromone_mat[self.current_node, node], alpha) * np.power(heuristic_mat[self.current_node, node], beta)))
prob_list.sort(cmp=lambda x, y:cmp(x[1], y[1]))
node_list = map(lambda x: x[0], prob_list)
prob_arr = np.array(map(lambda x: x[1], prob_list))
prob_arr = prob_arr / prob_arr.sum()
# determine next city to visit based on the Roulette strategy
cum_prob_arr = prob_arr.cumsum()
index = np.where(cum_prob_arr > np.random.rand())[0][0]
return node_list[index]
def update_property(self, next_node, graph):
if next_node >= 0:
self.tabu_list.append(next_node)
self.tabu_set.add(next_node)
self.allowed_set -= self.tabu_set
self.current_path += graph[self.current_node, next_node]
self.current_node = next_node
def stop_sign(self):
if len(self.allowed_set) > 0:
non_stop = True
else:
non_stop = False
return non_stop
'''
def clear_tabu(self, city_list):
self.tabu_list = []
self.tabu_set.clear()
self.allowed_set = set(city_list) - self.tabu_set
'''
if __name__ == "__main__":
# set best record
best_path = []
best_distance = sys.maxint
# set basic parameters
alpha = 0.5
beta = 2
phro = 0.1
num_ant = 5
max_iteration = 100
distance_mat = abs(np.random.randn(10, 10)*10 + np.random.rand())
nodes = distance_mat.shape[0]
pheromone_mat = np.ones((nodes, nodes)) * 0.1
city_list = range(nodes)
delta_pheromone = np.zeros((nodes, nodes))
start = 0
while start < max_iteration:
# create the ant colony
ant_list = [Ant(g, city_list, random.randint(0, nodes-1)) for g in range(num_ant)]
for ant in ant_list:
while ant.stop_sign():
next_node = ant.visit_next_city(alpha, beta, pheromone_mat, distance_mat)
ant.update_property(next_node, distance_mat)
delta_pheromone += ant.update_delat_pheromone(nodes)
# update the global solution
for ant in ant_list:
if ant.current_path < best_distance:
best_distance = ant.current_path
best_path = copy.deepcopy(ant.tabu_list)
# ant.clear_tabu(city_list)
# update the pheromone information
pheromone_mat *= (1- phro)
pheromone_mat += delta_pheromone
start += 1
print best_distance
print best_path