16 KiB
16 KiB
None
<html>
<head>
</head>
</html>
Make sure you run this at the begining
In [ ]:
import os
import sys
import math
import numpy as np
import matplotlib.pyplot as plt
# Append template path to sys path
sys.path.append(os.getcwd() + "/template")
In [ ]:
from utils.load_data import load_data
from utils.visualize_tsp import plotTSP
from tsp import TSP_Bench_ONE
from tsp import TSP_Bench_PATH
from tsp import TSP_Bench_ALL
Workshop Starts Here¶
Get familiar with your dataset¶
There are problems at different levels. 3 simple, 2 medium, 1 difficult.
In [ ]:
for root, _, files in os.walk('./template/data'):
if(files):
for f in files:
print(str(root) + "/" + f)
In [ ]:
ulysses16 = np.array(load_data("./template/data/simple/ulysses16.tsp"))
In [ ]:
ulysses16[:]
In [ ]:
plt.scatter(ulysses16[:, 0], ulysses16[:, 1])
for i in range(0, 16):
plt.annotate(i, (ulysses16[i, 0], ulysses16[i, 1]+0.5))
Naive Solution: In Order¶
In [ ]:
simple_sequence = list(range(0, 16))
print(simple_sequence)
In [ ]:
plotTSP([simple_sequence], ulysses16, num_iters=1)
Naive Solution: Random Permutation¶
In [ ]:
random_permutation = np.random.permutation(16).tolist()
print(random_permutation)
In [ ]:
plotTSP([random_permutation], ulysses16, num_iters=1)
Best Solution¶
In [ ]:
best_ulysses16 = [0, 13, 12, 11, 6, 5, 14, 4, 10, 8, 9, 15, 2, 1, 3, 7]
plotTSP([best_ulysses16], ulysses16, num_iters=1)
Calculate Fitness (Sum of all Distances)¶
In [ ]:
def dist(node_0, node_1, coords):
"""
Euclidean distance between two nodes.
"""
coord_0, coord_1 = coords[node_0], coords[node_1]
return math.sqrt((coord_0[0] - coord_1[0]) ** 2 + (coord_0[1] - coord_1[1]) ** 2)
In [ ]:
print("Coordinate of City 0:", ulysses16[0])
In [ ]:
print("Coordinate of City 1:", ulysses16[1])
In [ ]:
print("Distance Between", dist(0, 1, ulysses16))
In [ ]:
def fitness(solution, coords):
N = len(coords)
cur_fit = 0
for i in range(len(solution)):
cur_fit += dist(solution[i % N], solution[(i + 1) % N], coords)
return cur_fit
In [ ]:
print ("Order Fitness:\t", fitness(simple_sequence, ulysses16))
print ("Random Fitness:\t", fitness(random_permutation, ulysses16))
print ("Best Fitness:\t", fitness(best_ulysses16, ulysses16))
Naive Random Model¶
In [ ]:
import math
import random
from model.base_model import Model
import numpy as np
class MyRandomModel(Model):
def __init__(self):
super().__init__()
def init(self, nodes):
"""
Put your initialization here.
"""
super().init(nodes)
def fit(self, max_it=1000):
"""
Put your iteration process here.
"""
random_solutions = []
for i in range(0, max_it):
solution = np.random.permutation(self.N).tolist()
random_solutions.append(solution)
self.fitness_list.append(self.fitness(solution))
self.best_solution = random_solutions[self.fitness_list.index(min(self.fitness_list))]
return self.best_solution, self.fitness_list
In [ ]:
tsp_file = './template/data/simple/ulysses16.tsp'
In [ ]:
best_solution, fitness_list, time = TSP_Bench_ONE(tsp_file, MyRandomModel)
In [ ]:
plt.plot(fitness_list, 'o-')
Simulated Annealing¶
In [ ]:
import math
import random
from model.base_model import Model
class MySAModel(Model):
def __init__(self):
super().__init__()
self.iteration = 0
def init(self, nodes):
super().init(nodes)
# Set hyper-parameters
T = -1
stopping_temperature = -1
alpha = 0.99
self.T = math.sqrt(self.N) if T == -1 else T
self.alpha = 0.995 if alpha == -1 else alpha
self.stopping_temperature = 1e-8 if stopping_temperature == -1 else stopping_temperature
self.T_save = self.T # save inital T to reset if batch annealing is used
def initial_solution(self):
"""
Greedy algorithm to get an initial solution (closest-neighbour).
"""
cur_node = random.choice(self.nodes) # start from a random node
solution = [cur_node]
free_nodes = set(self.nodes)
free_nodes.remove(cur_node)
while free_nodes:
next_node = min(free_nodes, key=lambda x: self.dist(cur_node, x)) # nearest neighbour
free_nodes.remove(next_node)
solution.append(next_node)
cur_node = next_node
cur_fit = self.fitness(solution)
if cur_fit < self.best_fitness: # If best found so far, update best fitness
self.best_fitness = cur_fit
self.best_solution = solution
self.fitness_list.append(cur_fit)
return solution, cur_fit
def p_accept(self, candidate_fitness):
"""
Probability of accepting if the candidate is worse than current.
Depends on the current temperature and difference between candidate and current.
"""
return math.exp(-abs(candidate_fitness - self.cur_fitness) / self.T)
def accept(self, candidate):
"""
Accept with probability 1 if candidate is better than current.
Accept with probabilty p_accept(..) if candidate is worse.
"""
candidate_fitness = self.fitness(candidate)
if candidate_fitness < self.cur_fitness:
self.cur_fitness, self.cur_solution = candidate_fitness, candidate
if candidate_fitness < self.best_fitness:
self.best_fitness, self.best_solution = candidate_fitness, candidate
else:
if random.random() < self.p_accept(candidate_fitness):
self.cur_fitness, self.cur_solution = candidate_fitness, candidate
def fit(self, max_it=1000):
"""
Execute simulated annealing algorithm.
"""
# Initialize with the greedy solution.
self.cur_solution, self.cur_fitness = self.initial_solution()
self.log("Starting annealing.")
while self.T >= self.stopping_temperature and self.iteration < max_it:
candidate = list(self.cur_solution)
l = random.randint(1, self.N - 1)
i = random.randint(0, self.N - l)
candidate[i : (i + l)] = reversed(candidate[i : (i + l)])
self.accept(candidate)
self.T *= self.alpha
self.iteration += 1
self.fitness_list.append(self.cur_fitness)
self.log(f"Best fitness obtained: {self.best_fitness}")
improvement = 100 * (self.fitness_list[0] - self.best_fitness) / (self.fitness_list[0])
self.log(f"Improvement over greedy heuristic: {improvement : .2f}%")
return self.best_solution, self.fitness_list
In [ ]:
tsp_file = './template/data/simple/ulysses16.tsp'
In [ ]:
best_solution, fitness_list, time = TSP_Bench_ONE(tsp_file, MySAModel)
In [ ]:
plt.plot(fitness_list, 'o-')
Your Smart Model¶
In [ ]:
import math
import random
from model.base_model import Model
class MyModel(Model):
def __init__(self):
super().__init__()
def init(self, nodes):
"""
Put your initialization here.
"""
super().init(nodes)
self.log("Nothing to initialize in your model now")
def fit(self, max_it=1000):
"""
Put your iteration process here.
"""
self.best_solution = np.random.permutation(self.N).tolist()
self.fitness_list.append(self.fitness(self.best_solution))
return self.best_solution, self.fitness_list
Test your Model¶
In [ ]:
tsp_file = './template/data/simple/ulysses16.tsp'
In [ ]:
best_solution, fitness_list, time = TSP_Bench_ONE(tsp_file, MyModel)
Test All Dataset¶
In [ ]:
tsp_path = './template'
for root, _, files in os.walk(tsp_path + '/data'):
if(files):
for f in files:
print(str(root) + "/" + f)
In [ ]:
def plot_results(best_solutions, times, title):
fig = plt.figure()
nodes = [len(s) for s in best_solutions]
data = np.array([[node, time] for node, time in sorted(zip(nodes, times))])
plt.plot(data[:, 0], data[:, 1], 'o-')
fig.suptitle(title, fontsize=20)
In [ ]:
print("Random Search")
best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyRandomModel)
In [ ]:
plot_results(best_solutions, times, "Random Model")
In [ ]:
print("Simulated Annealing")
best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MySAModel)
In [ ]:
plot_results(best_solutions, times, "Simulated Annealing Model")
Conclusions¶
In [ ]: