Tabu Search
Tabu search, created by Fred W. Glover in 1986 and formalized in 1989 is a meta-heuristic search method employing local search methods used for mathematical optimization. Tabu search is the enhanced version of local searches by relaxing its basic rules. Local searches always refuse any solution that is no better than the history best one, so local search algorithm can easily get trapped in the local optimal solution. Instead, tabu search can accept the worsening moves at each step if no improving move is available. In addition, prohibitions are introduced to discourage the search from coming back to previously-visited solutions.
# -*- coding: utf-8 -*-
"""
Created on 2017/3/15 12:15 2017
@author: Randolph.Lee
"""
import numpy as np
import random
import copy
class TabuSearch:
def __init__(self, max_len, graph, total_nodes):
self.max_len = max_len
self.graph_mat = graph
self.node_num = total_nodes
self.current_solution = range(total_nodes)
random.shuffle(self.current_solution)
self.best_solution = []
self.aspiration = 0.0
self.candidates = []
self.fit_list = []
self.tabu_record = []
self.tabu_list = []
def cal_aspiration(self, solution):
current_aspiration = 0.0
for i in solution[:-1]:
for j in solution[1:]:
current_aspiration += self.graph_mat[i, j]
return current_aspiration
def initialize_aspiration(self):
self.aspiration = self.cal_aspiration(self.current_solution)
self.best_solution = copy.deepcopy(self.current_solution)
# generate candidate set based on the current solution
def generate_candidates(self):
random_num = random.randint(0, self.node_num - 1)
neighbor_base = copy.deepcopy(self.current_solution)
element = self.current_solution[random_num]
del neighbor_base[random_num]
temp_candidates = [neighbor_base[:i] + [element] + neighbor_base[i:] for i in range(self.node_num)]
self.candidates = filter(lambda x: x != self.current_solution, temp_candidates)
self.tabu_record = [(item[item.index(element)-1], element) if item.index(element) == self.node_num-1 else (element, item[item.index(element)+1]) for item in self.candidates]
self.fit_list = [self.cal_aspiration(item) for item in self.candidates]
def update_tabulist(self, selected_record):
if len(self.tabu_list) == self.max_len:
del self.tabu_list[0]
self.tabu_list.append(selected_record)
def relieve_ban(self, fitness):
if fitness < self.aspiration:
sign = True
self.aspiration = fitness
else:
sign = False
return sign
if __name__ == "__main__":
max_len = 4
max_iteration = 20
total_nodes = 8
graph_mat = abs(np.random.randn(8, 8))
tabu_search = TabuSearch(max_len, graph_mat, total_nodes)
tabu_search.initialize_aspiration()
res = []
i = 0
while i < max_iteration:
# produce the candidates
tabu_search.generate_candidates()
# rank the fitness
fit_rank = np.array(tabu_search.fit_list).argsort().tolist()
move_times = 0
if tabu_search.relieve_ban(tabu_search.fit_list[fit_rank[0]]):
tabu_search.update_tabulist(tabu_search.candidates[fit_rank[0]])
tabu_search.best_solution = copy.deepcopy(tabu_search.candidates[fit_rank[0]])
else:
while tabu_search.tabu_record[fit_rank[move_times]] in tabu_search.tabu_list:
move_times += 1
if move_times > len(tabu_search.candidates):
break
else:
tabu_move = tabu_search.tabu_record[fit_rank[move_times]]
tabu_search.update_tabulist(tabu_move)
res.append((i, tabu_search.aspiration))
print "iteration ", i
i += 1
print tabu_search.best_solution