[fix] error handling

This commit is contained in:
Wu Han 2021-01-07 22:52:00 +00:00
parent 0a10febfd7
commit ff8de454a6
18 changed files with 4581 additions and 4939 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,954 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Make sure you run this at the begining**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"import math\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Append template path to sys path\n",
"sys.path.append(os.getcwd() + \"/template\") "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from utils.load_data import load_data\n",
"from utils.load_data import log\n",
"from utils.visualize_tsp import plotTSP\n",
"from utils.tsp import TSP\n",
"from utils.tsp import TSP_Bench\n",
"from utils.tsp import TSP_Bench_ALL"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Workshop Starts Here"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/tsp.jpg\" alt=\"TSP\" style=\"width: 900px;\"/>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/solutions.png\" alt=\"solutions\" style=\"width: 900px;\"/>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Get familiar with your dataset"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are problems at different levels. **3 simple, 2 medium, 1 hard**."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"for root, _, files in os.walk('./template/data'):\n",
" if(files):\n",
" for f in files:\n",
" print(str(root) + \"/\" + f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ulysses16 = np.array(load_data(\"./template/data/simple/ulysses16.tsp\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ulysses16[:]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"plt.scatter(ulysses16[:, 0], ulysses16[:, 1])\n",
"for i in range(0, 16):\n",
" plt.annotate(i, (ulysses16[i, 0], ulysses16[i, 1]+0.5))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Solution: In Order"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simple_sequence = list(range(0, 16))\n",
"print(simple_sequence)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plotTSP([simple_sequence], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Solution: Random Permutation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"random_permutation = np.random.permutation(16).tolist()\n",
"print(random_permutation)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plotTSP([random_permutation], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Best Solution"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"best_ulysses16 = [0, 13, 12, 11, 6, 5, 14, 4, 10, 8, 9, 15, 2, 1, 3, 7]\n",
"plotTSP([best_ulysses16], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Calculate Fitness (Sum of all Distances)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def dist(node_0, node_1, coords):\n",
" \"\"\"\n",
" Euclidean distance between two nodes.\n",
" \"\"\"\n",
" coord_0, coord_1 = coords[node_0], coords[node_1]\n",
" return math.sqrt((coord_0[0] - coord_1[0]) ** 2 + (coord_0[1] - coord_1[1]) ** 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Coordinate of City 0:\", ulysses16[0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Coordinate of City 1:\", ulysses16[1])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"print(\"Distance Between\", dist(0, 1, ulysses16))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def fitness(solution, coords):\n",
" N = len(coords)\n",
" cur_fit = 0\n",
" if(len(solution) != N):\n",
" return math.inf\n",
" for i in range(len(solution)):\n",
" cur_fit += dist(solution[i % N], solution[(i + 1) % N], coords)\n",
" return cur_fit"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"print (\"Order Fitness:\\t\", fitness(simple_sequence, ulysses16))\n",
"print (\"Random Fitness:\\t\", fitness(random_permutation, ulysses16))\n",
"print (\"Best Fitness:\\t\", fitness(best_ulysses16, ulysses16))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Random Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"import numpy as np\n",
"from model.base_model import Model\n",
"\n",
"class MyRandomModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
" random_solutions = []\n",
" for i in range(0, max_it):\n",
" solution = np.random.permutation(self.N).tolist()\n",
" random_solutions.append(solution)\n",
" self.fitness_list.append(self.fitness(solution))\n",
" self.best_solution = random_solutions[self.fitness_list.index(min(self.fitness_list))]\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"tsp_file = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyRandomModel, max_it=100)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(fitness_list, 'o-')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Uniform Cost Search"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"\n",
"class MyUCSModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
"\n",
" def getMST(self, node):\n",
" MST = []\n",
" distances = []\n",
" for i in range(0, self.N):\n",
" if i != node:\n",
" MST.append(i)\n",
" distances.append(self.dist(node, i))\n",
" return [x for _,x in sorted(zip(distances, MST))]\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
"\n",
" UCS_solutions = []\n",
" UCS_losses = []\n",
" \n",
" for i in range(0, self.N):\n",
" solution = [i]\n",
" UCS_solutions.append(solution)\n",
" UCS_losses.append(math.inf)\n",
" \n",
" MSTs = []\n",
" for i in range(0, self.N):\n",
" MSTs.append([-1] * self.N)\n",
"\n",
" # Breadth First: Set each city as starting point, then go to next city simultaneously\n",
" min_loss = math.inf\n",
" while(len(UCS_solutions[ UCS_losses.index(min(UCS_losses)) ]) != self.N):\n",
" unvisited_list = list(range(0, self.N))\n",
" min_loss = min(UCS_losses)\n",
" # For each search path\n",
" for i in range(0, self.N):\n",
" if UCS_losses[i] == min_loss:\n",
" cur_city = UCS_solutions[i][-1]\n",
" unvisited_list = list( set(range(0, self.N)) - set(UCS_solutions[i]) )\n",
" if MSTs[cur_city][0] == -1:\n",
" MST = self.getMST(cur_city)\n",
" MSTs[cur_city] = MST\n",
"\n",
" for j in MSTs[cur_city]:\n",
" if(j in unvisited_list):\n",
" UCS_solutions[i].append(j)\n",
"\n",
" N = len(UCS_solutions[i])\n",
" cur_fit = 0\n",
" for k in range(len(UCS_solutions[i])):\n",
" coord_0, coord_1 = self.coords[UCS_solutions[i][k % N]], self.coords[UCS_solutions[i][(k + 1) % N]]\n",
" cur_fit += math.sqrt((coord_0[0] - coord_1[0]) ** 2 + (coord_0[1] - coord_1[1]) ** 2)\n",
" UCS_losses[i] = cur_fit\n",
"# if(UCS_losses[i] < min_loss):\n",
"# min_loss = UCS_losses[i]\n",
" break\n",
" self.best_solution = UCS_solutions[ UCS_losses.index(min(UCS_losses)) ]\n",
" self.fitness_list.append(self.fitness(self.best_solution))\n",
"\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_file = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyUCSModel)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A star"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Heuristic"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"\n",
"class MyASModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
"\n",
" def getMST(self, node):\n",
" MST = []\n",
" distances = []\n",
" for i in range(0, self.N):\n",
" if i != node:\n",
" MST.append(i)\n",
" distances.append(self.dist(node, i))\n",
" return [x for _,x in sorted(zip(distances, MST))]\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
"\n",
" MST_solutions = []\n",
" \n",
" for i in range(0, self.N):\n",
" solution = [i]\n",
" MST_solutions.append(solution)\n",
" \n",
" # Breadth First: Set each city as starting point, then go to next city simultaneously\n",
" for step in range(0, self.N - 1):\n",
"# print(\"[step]\", step)\n",
" unvisited_list = list(range(0, self.N))\n",
" # For each search path\n",
" for i in range(0, self.N):\n",
" cur_city = MST_solutions[i][-1]\n",
" unvisited_list = list( set(range(0, self.N)) - set(MST_solutions[i]) )\n",
" closest_neighbour = -1\n",
" min_f = math.inf\n",
" \n",
" for j in unvisited_list:\n",
" g = self.dist(cur_city, j)\n",
" sub_unvisited_list = unvisited_list.copy()\n",
" sub_unvisited_list.remove(j)\n",
"\n",
" sub_cur_city = self.getMST(j)[0]\n",
" h = 0\n",
" while len(sub_unvisited_list) > 0:\n",
" if(len(unvisited_list) == 2):\n",
" break\n",
" else:\n",
" for k in self.getMST(sub_cur_city):\n",
" if k in sub_unvisited_list:\n",
" h = h + self.dist(sub_cur_city, k)\n",
" sub_cur_city = k\n",
" sub_unvisited_list.remove(k)\n",
" break\n",
" # Get f(x) = g(x) + h(x)\n",
"\n",
" f = g + h\n",
" if(f < min_f):\n",
" closest_neighbour = j\n",
" min_f = f\n",
" MST_solutions[i].append(closest_neighbour)\n",
"\n",
" for i in range(0, self.N):\n",
" self.fitness_list.append(self.fitness(MST_solutions[i]))\n",
" \n",
" self.best_solution = MST_solutions[ self.fitness_list.index(min(self.fitness_list)) ]\n",
"\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_file = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyASModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"plt.plot(fitness_list, 'o-')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Hill Climbing"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Heuristic Iteration"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"import numpy as np\n",
"from model.base_model import Model\n",
"\n",
"class MyHillClimbModel(Model):\n",
"\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
"\n",
" def random_tour(self):\n",
" return np.random.permutation(self.N).tolist()\n",
"\n",
" def all_pairs(self, size, shuffle=random.shuffle):\n",
" r1 = list(range(size))\n",
" r2 = list(range(size))\n",
" if shuffle:\n",
" shuffle(r1)\n",
" shuffle(r2)\n",
" for i in r1:\n",
" for j in r2:\n",
" yield (i,j)\n",
"\n",
" def move_operator(self, tour):\n",
" '''generator to return all possible variations\n",
" where the section between two cities are swapped'''\n",
" for i,j in self.all_pairs(len(tour)):\n",
" if i != j:\n",
" copy=tour[:]\n",
" if i < j:\n",
" copy[i:j+1]=reversed(tour[i:j+1])\n",
" else:\n",
" copy[i+1:]=reversed(tour[:j])\n",
" copy[:j]=reversed(tour[i+1:])\n",
" if copy != tour: # no point returning the same tour\n",
" yield copy\n",
"\n",
" def fit(self, max_it=100):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
"\n",
" self.best_solution = self.random_tour()\n",
" best_score = -self.fitness(self.best_solution)\n",
"\n",
" num_evaluations = 0\n",
"\n",
" while num_evaluations < max_it:\n",
" # examine moves around our current position\n",
" move_made = False\n",
" for next_solution in self.move_operator(self.best_solution):\n",
" if num_evaluations >= max_it:\n",
" print(\"Max iteration reached:\", max_it)\n",
" break\n",
"\n",
" # see if this move is better than the current\n",
" next_score = -self.fitness(next_solution)\n",
" num_evaluations += 1\n",
" if next_score > best_score:\n",
" self.best_solution = next_solution\n",
" self.fitness_list.append(self.fitness(self.best_solution))\n",
" best_score=next_score\n",
" move_made=True\n",
" break # depth first search\n",
"\n",
" if not move_made:\n",
" break # we couldn't find a better move (must be at a local maximum)\n",
"\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_file = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyHillClimbModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(fitness_list)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Your Smart Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"import numpy as np\n",
"\n",
"class MyModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
" self.log(\"Nothing to initialize in your model now\")\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
" self.best_solution = np.random.permutation(self.N).tolist()\n",
" self.fitness_list.append(self.fitness(self.best_solution))\n",
"\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test your Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_problem = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyModel)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test All Dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for root, _, files in os.walk('./template/data'):\n",
" if(files):\n",
" for f in files:\n",
" print(str(root) + \"/\" + f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_path = './template/data'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def plot_results(best_solutions, times, title):\n",
" fig = plt.figure()\n",
" nodes = [len(s) for s in best_solutions]\n",
" data = np.array([[node, time] for node, time in sorted(zip(nodes, times))])\n",
" plt.plot(data[:, 0], data[:, 1], 'o-')\n",
" fig.suptitle(title, fontsize=20)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"print(\"Random Search\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyRandomModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"Random Model\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"print(\"Uniform Cost Search\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyUCSModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"Uniform Cost Search\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"A Star Search\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyASModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"A Star Search\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"print(\"Hill-Climbing Search\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyHillClimbModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"Hill-Climbing Search\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Conclusions"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Simple\n",
"# ulysses16: 77.12 (UCS-BFS), 77.02 (A-Star)\n",
"# att48: 39236 (UCS-BFS), 47853 (A-Star)\n",
"# st70: 761 (UCS-BFS), time-out (A-Star)\n",
"\n",
"# Medium\n",
"# a280: 3088 (UCS-BFS), time-out (A-Star)\n",
"# pcb442: 58952 (UCS-BFS), time-out (A-Star)\n",
"\n",
"# Hard\n",
"# dsj1000: time-out (UCS-BFS), 542,620,572 (Hill-Climbing)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<p style=\"font-size: 18px\"> 1. UCS is the slowest one, and gets the same result as BFS, DFS, DP </p>\n",
"<p style=\"font-size: 18px\"> 1. A-Star can only solve problems with number of cities < 50. </p>\n",
"<p style=\"font-size: 18px\"> 2. Hill-Climbing gets different results every time (Heuristic). </p>\n",
"<p style=\"font-size: 18px\"> 3. Hill-Climbing is the fastest one till now. (faster than Dynamic Programming, but worse results). </p>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

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

View File

@ -0,0 +1,717 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Make sure you run this at the begining**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"import math\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Append template path to sys path\n",
"sys.path.append(os.getcwd() + \"/template\") "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from utils.load_data import load_data\n",
"from utils.load_data import log\n",
"from utils.visualize_tsp import plotTSP\n",
"from utils.tsp import TSP\n",
"from utils.tsp import TSP_Bench\n",
"from utils.tsp import TSP_Bench_ALL"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Workshop Starts Here"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/tsp.jpg\" alt=\"TSP\" style=\"width: 900px;\"/>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/solutions.png\" alt=\"solutions\" style=\"width: 900px;\"/>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Get familiar with your dataset"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are problems at different levels. **3 simple, 2 medium, 1 hard**."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"for root, _, files in os.walk('./template/data'):\n",
" if(files):\n",
" for f in files:\n",
" print(str(root) + \"/\" + f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ulysses16 = np.array(load_data(\"./template/data/simple/ulysses16.tsp\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ulysses16[:]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"plt.scatter(ulysses16[:, 0], ulysses16[:, 1])\n",
"for i in range(0, 16):\n",
" plt.annotate(i, (ulysses16[i, 0], ulysses16[i, 1]+0.5))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Solution: In Order"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simple_sequence = list(range(0, 16))\n",
"print(simple_sequence)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plotTSP([simple_sequence], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Solution: Random Permutation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"random_permutation = np.random.permutation(16).tolist()\n",
"print(random_permutation)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plotTSP([random_permutation], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Best Solution"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"best_ulysses16 = [0, 13, 12, 11, 6, 5, 14, 4, 10, 8, 9, 15, 2, 1, 3, 7]\n",
"plotTSP([best_ulysses16], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Calculate Fitness (Sum of all Distances)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def dist(node_0, node_1, coords):\n",
" \"\"\"\n",
" Euclidean distance between two nodes.\n",
" \"\"\"\n",
" coord_0, coord_1 = coords[node_0], coords[node_1]\n",
" return math.sqrt((coord_0[0] - coord_1[0]) ** 2 + (coord_0[1] - coord_1[1]) ** 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Coordinate of City 0:\", ulysses16[0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Coordinate of City 1:\", ulysses16[1])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"print(\"Distance Between\", dist(0, 1, ulysses16))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def fitness(solution, coords):\n",
" N = len(coords)\n",
" cur_fit = 0\n",
" for i in range(len(solution)):\n",
" cur_fit += dist(solution[i % N], solution[(i + 1) % N], coords)\n",
" return cur_fit"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print (\"Order Fitness:\\t\", fitness(simple_sequence, ulysses16))\n",
"print (\"Random Fitness:\\t\", fitness(random_permutation, ulysses16))\n",
"print (\"Best Fitness:\\t\", fitness(best_ulysses16, ulysses16))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Random Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"import numpy as np\n",
"\n",
"class MyRandomModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
" random_solutions = []\n",
" for i in range(0, max_it):\n",
" solution = np.random.permutation(self.N).tolist()\n",
" random_solutions.append(solution)\n",
" self.fitness_list.append(self.fitness(solution))\n",
"\n",
" self.best_solution = random_solutions[self.fitness_list.index(min(self.fitness_list))]\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"tsp_file = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyRandomModel, max_it=100)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(fitness_list, 'o-')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ant Colony Optimization"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"https://github.com/rochakgupta/aco-tsp"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"\n",
"class MyACOModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" class Edge:\n",
" def __init__(self, a, b, weight, initial_pheromone):\n",
" self.a = a\n",
" self.b = b\n",
" self.weight = weight\n",
" self.pheromone = initial_pheromone\n",
"\n",
" class Ant:\n",
" def __init__(self, alpha, beta, num_nodes, edges):\n",
" self.alpha = alpha\n",
" self.beta = beta\n",
" self.num_nodes = num_nodes\n",
" self.edges = edges\n",
" self.tour = None\n",
" self.distance = 0.0\n",
"\n",
" def _select_node(self):\n",
" roulette_wheel = 0.0\n",
" unvisited_nodes = [node for node in range(self.num_nodes) if node not in self.tour]\n",
" heuristic_total = 0.0\n",
" for unvisited_node in unvisited_nodes:\n",
" heuristic_total += self.edges[self.tour[-1]][unvisited_node].weight\n",
" for unvisited_node in unvisited_nodes:\n",
" roulette_wheel += pow(self.edges[self.tour[-1]][unvisited_node].pheromone, self.alpha) * \\\n",
" pow((heuristic_total / self.edges[self.tour[-1]][unvisited_node].weight), self.beta)\n",
" random_value = random.uniform(0.0, roulette_wheel)\n",
" wheel_position = 0.0\n",
" for unvisited_node in unvisited_nodes:\n",
" wheel_position += pow(self.edges[self.tour[-1]][unvisited_node].pheromone, self.alpha) * \\\n",
" pow((heuristic_total / self.edges[self.tour[-1]][unvisited_node].weight), self.beta)\n",
" if wheel_position >= random_value:\n",
" return unvisited_node\n",
"\n",
" def find_tour(self):\n",
" self.tour = [random.randint(0, self.num_nodes - 1)]\n",
" while len(self.tour) < self.num_nodes:\n",
" self.tour.append(self._select_node())\n",
" return self.tour\n",
"\n",
" def get_distance(self):\n",
" self.distance = 0.0\n",
" for i in range(self.num_nodes):\n",
" self.distance += self.edges[self.tour[i]][self.tour[(i + 1) % self.num_nodes]].weight\n",
" return self.distance\n",
"\n",
" def init(self, nodes, *args):\n",
" super().init(nodes)\n",
" mode, colony_size, elitist_weight, min_scaling_factor, alpha, beta, rho, pheromone_deposit_weight, initial_pheromone, labels = args\n",
"\n",
" self.mode = mode[0]\n",
" self.colony_size = colony_size\n",
" self.elitist_weight = elitist_weight\n",
" self.min_scaling_factor = min_scaling_factor\n",
" self.rho = rho\n",
" self.pheromone_deposit_weight = pheromone_deposit_weight\n",
" self.num_nodes = len(nodes)\n",
" self.nodes = nodes\n",
"\n",
" if labels is not None:\n",
" self.labels = labels\n",
" else:\n",
" self.labels = range(1, self.num_nodes + 1)\n",
" self.edges = [[None] * self.num_nodes for _ in range(self.num_nodes)]\n",
" for i in range(self.num_nodes):\n",
" for j in range(i + 1, self.num_nodes):\n",
" self.edges[i][j] = self.edges[j][i] = self.Edge(i, j, math.sqrt(\n",
" pow(self.nodes[i][0] - self.nodes[j][0], 2.0) + pow(self.nodes[i][1] - self.nodes[j][1], 2.0)),\n",
" initial_pheromone)\n",
" self.ants = [self.Ant(alpha, beta, self.num_nodes, self.edges) for _ in range(self.colony_size)]\n",
" self.global_best_tour = None\n",
" self.global_best_distance = float(\"inf\")\n",
"\n",
" def _add_pheromone(self, tour, distance, weight=1.0):\n",
" pheromone_to_add = self.pheromone_deposit_weight / distance\n",
" for i in range(self.num_nodes):\n",
" self.edges[tour[i]][tour[(i + 1) % self.num_nodes]].pheromone += weight * pheromone_to_add\n",
"\n",
" def _acs(self, max_it):\n",
" for step in range(0, max_it):\n",
"# print('[step]', step)\n",
" for ant in self.ants:\n",
" self._add_pheromone(ant.find_tour(), ant.get_distance())\n",
" if ant.distance < self.global_best_distance:\n",
" self.global_best_tour = ant.tour\n",
" self.global_best_distance = ant.distance\n",
" self.fitness_list.append(ant.distance)\n",
" for i in range(self.num_nodes):\n",
" for j in range(i + 1, self.num_nodes):\n",
" self.edges[i][j].pheromone *= (1.0 - self.rho)\n",
"\n",
" def _elitist(self, max_it):\n",
" for step in range(0, max_it):\n",
"# print('[step]', step)\n",
" for ant in self.ants:\n",
" self._add_pheromone(ant.find_tour(), ant.get_distance())\n",
" if ant.distance < self.global_best_distance:\n",
" self.global_best_tour = ant.tour\n",
" self.global_best_distance = ant.distance\n",
" self.fitness_list.append(ant.distance)\n",
" self._add_pheromone(self.global_best_tour, self.global_best_distance, weight=self.elitist_weight)\n",
" for i in range(self.num_nodes):\n",
" for j in range(i + 1, self.num_nodes):\n",
" self.edges[i][j].pheromone *= (1.0 - self.rho)\n",
"\n",
" def fit(self, max_it=1000):\n",
" \"\"\"\n",
" Execute simulated annealing algorithm.\n",
" \"\"\"\n",
" # Initialize with the greedy solution.\n",
" if self.mode == 'ACS':\n",
" self._acs(max_it)\n",
" elif self.mode == 'Elitist':\n",
" self._elitist(max_it)\n",
" else:\n",
" print(\"Un supported\")\n",
"# print('Sequence : <- {0} ->'.format(' - '.join(str(self.labels[i]) for i in self.global_best_tour)))\n",
"# print('Total distance travelled to complete the tour : {0}\\n'.format(round(self.global_best_distance, 2)))\n",
"\n",
" return self.global_best_tour, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_file = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Set hypter-parameters\n",
"mode='ACS', \n",
"colony_size=10\n",
"elitist_weight=1.0\n",
"min_scaling_factor=0.001\n",
"alpha=1.0\n",
"beta=3.0\n",
"rho=0.1\n",
"pheromone_deposit_weight=1.0\n",
"initial_pheromone=1.0\n",
"labels = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyACOModel, mode, colony_size, elitist_weight, min_scaling_factor, alpha, beta, rho, pheromone_deposit_weight, initial_pheromone, labels, max_it=1000, timeout=300)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Your Smart Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"\n",
"class MyModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
" self.log(\"Nothing to initialize in your model now\")\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
" self.log(\"Naive Random Solution\")\n",
" self.best_solution = np.random.permutation(self.N).tolist()\n",
" self.fitness_list.append(self.fitness(self.best_solution))\n",
"\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test your Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_problem = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyModel)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Test All Dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for root, _, files in os.walk('./template/data'):\n",
" if(files):\n",
" for f in files:\n",
" print(str(root) + \"/\" + f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def plot_results(best_solutions, times, title):\n",
" fig = plt.figure()\n",
" nodes = [len(s) for s in best_solutions]\n",
" data = np.array([[node, time] for node, time in sorted(zip(nodes, times))])\n",
" plt.plot(data[:, 0], data[:, 1], 'o-')\n",
" fig.suptitle(title, fontsize=20)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_path = './template/data'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Random Search\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyRandomModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"Random Model\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Set hypter-parameters\n",
"mode='ACS', \n",
"colony_size=10\n",
"elitist_weight=1.0\n",
"min_scaling_factor=0.001\n",
"alpha=1.0\n",
"beta=3.0\n",
"rho=0.1\n",
"pheromone_deposit_weight=1.0\n",
"initial_pheromone=1.0\n",
"labels = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Ant Colony Optimization\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyACOModel, mode, colony_size, elitist_weight, min_scaling_factor, alpha, beta, rho, pheromone_deposit_weight, initial_pheromone, labels, max_it=100, timeout=600)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"Ant Colony Optimization\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,763 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Make sure you run this at the begining**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"import math\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Append template path to sys path\n",
"sys.path.append(os.getcwd() + \"/template\") "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from utils.load_data import load_data\n",
"from utils.load_data import log\n",
"from utils.visualize_tsp import plotTSP\n",
"from utils.tsp import TSP\n",
"from utils.tsp import TSP_Bench\n",
"from utils.tsp import TSP_Bench_ALL"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Workshop Starts Here"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/tsp.jpg\" alt=\"TSP\" style=\"width: 900px;\"/>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/solutions.png\" alt=\"solutions\" style=\"width: 900px;\"/>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Get familiar with your dataset"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are problems at different levels. **3 simple, 2 medium, 1 hard**."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"for root, _, files in os.walk('./template/data'):\n",
" if(files):\n",
" for f in files:\n",
" print(str(root) + \"/\" + f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ulysses16 = np.array(load_data(\"./template/data/simple/ulysses16.tsp\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ulysses16[:]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"plt.scatter(ulysses16[:, 0], ulysses16[:, 1])\n",
"for i in range(0, 16):\n",
" plt.annotate(i, (ulysses16[i, 0], ulysses16[i, 1]+0.5))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Solution: In Order"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simple_sequence = list(range(0, 16))\n",
"print(simple_sequence)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plotTSP([simple_sequence], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Solution: Random Permutation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"random_permutation = np.random.permutation(16).tolist()\n",
"print(random_permutation)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plotTSP([random_permutation], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Best Solution"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"best_ulysses16 = [0, 13, 12, 11, 6, 5, 14, 4, 10, 8, 9, 15, 2, 1, 3, 7]\n",
"plotTSP([best_ulysses16], ulysses16, num_iters=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Calculate Fitness (Sum of all Distances)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def dist(node_0, node_1, coords):\n",
" \"\"\"\n",
" Euclidean distance between two nodes.\n",
" \"\"\"\n",
" coord_0, coord_1 = coords[node_0], coords[node_1]\n",
" return math.sqrt((coord_0[0] - coord_1[0]) ** 2 + (coord_0[1] - coord_1[1]) ** 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Coordinate of City 0:\", ulysses16[0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Coordinate of City 1:\", ulysses16[1])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"print(\"Distance Between\", dist(0, 1, ulysses16))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def fitness(solution, coords):\n",
" N = len(coords)\n",
" cur_fit = 0\n",
" for i in range(len(solution)):\n",
" cur_fit += dist(solution[i % N], solution[(i + 1) % N], coords)\n",
" return cur_fit"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print (\"Order Fitness:\\t\", fitness(simple_sequence, ulysses16))\n",
"print (\"Random Fitness:\\t\", fitness(random_permutation, ulysses16))\n",
"print (\"Best Fitness:\\t\", fitness(best_ulysses16, ulysses16))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Naive Random Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"import numpy as np\n",
"\n",
"class MyRandomModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
" random_solutions = []\n",
" for i in range(0, max_it):\n",
" solution = np.random.permutation(self.N).tolist()\n",
" random_solutions.append(solution)\n",
" self.fitness_list.append(self.fitness(solution))\n",
"\n",
" self.best_solution = random_solutions[self.fitness_list.index(min(self.fitness_list))]\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_file = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyRandomModel, max_it=100)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(fitness_list, 'o-')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Genetic Algorithm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Gene: # City\n",
" def __init__(self, name, lat, lng):\n",
" self.name = name\n",
" self.lat = lat\n",
" self.lng = lng\n",
"\n",
" def get_distance_to(self, dest):\n",
" return math.sqrt( (self.lng - dest.lng) ** 2 + (self.lat - dest.lat) ** 2 )\n",
"\n",
"class Individual: # Route: possible solution to TSP\n",
" def __init__(self, genes):\n",
" assert(len(genes) > 3)\n",
" self.genes = genes\n",
" self.__reset_params()\n",
"\n",
" def swap(self, gene_1, gene_2):\n",
" self.genes[0]\n",
" a, b = self.genes.index(gene_1), self.genes.index(gene_2)\n",
" self.genes[b], self.genes[a] = self.genes[a], self.genes[b]\n",
" self.__reset_params()\n",
"\n",
" def add(self, gene):\n",
" self.genes.append(gene)\n",
" self.__reset_params()\n",
"\n",
" @property\n",
" def fitness(self):\n",
" if self.__fitness == 0:\n",
" self.__fitness = 1 / self.travel_cost # Normalize travel cost\n",
" return self.__fitness\n",
"\n",
" @property\n",
" def travel_cost(self): # Get total travelling cost\n",
" if self.__travel_cost == 0:\n",
" for i in range(len(self.genes)):\n",
" origin = self.genes[i]\n",
" if i == len(self.genes) - 1:\n",
" dest = self.genes[0]\n",
" else:\n",
" dest = self.genes[i+1]\n",
"\n",
" self.__travel_cost += origin.get_distance_to(dest)\n",
"\n",
" return self.__travel_cost\n",
"\n",
" def __reset_params(self):\n",
" self.__travel_cost = 0\n",
" self.__fitness = 0\n",
"\n",
"class Population: # Population of individuals\n",
" def __init__(self, individuals):\n",
" self.individuals = individuals\n",
"\n",
" @staticmethod\n",
" def gen_individuals(sz, genes):\n",
" individuals = []\n",
" for _ in range(sz):\n",
" individuals.append(Individual(sample(genes, len(genes))))\n",
" return Population(individuals)\n",
"\n",
" def add(self, route):\n",
" self.individuals.append(route)\n",
"\n",
" def rmv(self, route):\n",
" self.individuals.remove(route)\n",
"\n",
" def get_fittest(self):\n",
" fittest = self.individuals[0]\n",
" for route in self.individuals:\n",
" if route.fitness > fittest.fitness:\n",
" fittest = route\n",
"\n",
" return fittest"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"from random import randint, sample\n",
"\n",
"class MyGAModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
" self.iteration = 0\n",
"\n",
" def init(self, nodes):\n",
" super().init(nodes)\n",
"\n",
" def evolve(self, pop, tourn_size, mut_rate):\n",
" new_generation = Population([])\n",
" pop_size = len(pop.individuals)\n",
" elitism_num = pop_size // 4\n",
"\n",
" # Elitism\n",
" for _ in range(elitism_num):\n",
" fittest = pop.get_fittest()\n",
" new_generation.add(fittest)\n",
" pop.rmv(fittest)\n",
"\n",
" # Crossover\n",
" for _ in range(elitism_num, pop_size):\n",
" parent_1 = self.selection(new_generation, tourn_size)\n",
" parent_2 = self.selection(new_generation, tourn_size)\n",
" child = self.crossover(parent_1, parent_2)\n",
" new_generation.add(child)\n",
"\n",
" # Mutation\n",
" for i in range(elitism_num, pop_size):\n",
" self.mutate(new_generation.individuals[i], mut_rate)\n",
"\n",
" return new_generation\n",
"\n",
" def crossover(self, parent_1, parent_2):\n",
" def fill_with_parent1_genes(child, parent, genes_n):\n",
" start_at = randint(0, len(parent.genes)-genes_n-1)\n",
" finish_at = start_at + genes_n\n",
" for i in range(start_at, finish_at):\n",
" child.genes[i] = parent_1.genes[i]\n",
"\n",
" def fill_with_parent2_genes(child, parent):\n",
" j = 0\n",
" for i in range(0, len(parent.genes)):\n",
" if child.genes[i] == None:\n",
" while parent.genes[j] in child.genes:\n",
" j += 1\n",
" child.genes[i] = parent.genes[j]\n",
" j += 1\n",
"\n",
" genes_n = len(parent_1.genes)\n",
" child = Individual([None for _ in range(genes_n)])\n",
" fill_with_parent1_genes(child, parent_1, genes_n // 2)\n",
" fill_with_parent2_genes(child, parent_2)\n",
"\n",
" return child\n",
"\n",
" def mutate(self, individual, rate):\n",
" for _ in range(len(individual.genes)):\n",
" if random.random() < rate:\n",
" sel_genes = sample(individual.genes, 2)\n",
" individual.swap(sel_genes[0], sel_genes[1])\n",
"\n",
" def selection(self, population, competitors_n):\n",
" return Population(sample(population.individuals, competitors_n)).get_fittest()\n",
"\n",
" def fit(self, max_it=20):\n",
" \"\"\"\n",
" Execute simulated annealing algorithm.\n",
" \"\"\"\n",
" pop_size = 1000\n",
" mut_rate = 0.9\n",
" tourn_size = 100\n",
"\n",
" genes = [Gene(num, city[0], city[1]) for num, city in enumerate(self.coords)]\n",
" self.genes = genes\n",
"\n",
" population = Population.gen_individuals(pop_size, genes)\n",
" \n",
"\n",
" for it in range(0, max_it):\n",
" mut_rate = mut_rate * 0.95\n",
" if mut_rate < 0.05:\n",
" mut_rate = 0.05\n",
" population = self.evolve(population, tourn_size, mut_rate)\n",
" cost = population.get_fittest().travel_cost\n",
"\n",
" it += 1\n",
" self.fitness_list.append(cost)\n",
" print(\"[step] \", it, \" [mut] \", mut_rate, \" [best] \", self.fitness_list[self.fitness_list.index(min(self.fitness_list))])\n",
"\n",
" self.best_solution = [gene.name for gene in population.get_fittest().genes]\n",
"\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_problem = \"./template/data/simple/ulysses16.tsp\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"print(\"Genetic Algorithm\")\n",
"best_solution, fitness_list, time = TSP_Bench(tsp_problem, MyGAModel, max_it=200)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"plt.plot(fitness_list, 'o-')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plotTSP([best_solution], load_data(tsp_problem), num_iters=1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print (\"Best Fitness:\\t\", fitness(best_solution, ulysses16))\n",
"print (\"Best Fitness:\\t\", fitness(best_ulysses16, ulysses16))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Your Smart Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"import random\n",
"from model.base_model import Model\n",
"\n",
"class MyModel(Model):\n",
" def __init__(self):\n",
" super().__init__()\n",
"\n",
" def init(self, nodes):\n",
" \"\"\"\n",
" Put your initialization here.\n",
" \"\"\"\n",
" super().init(nodes)\n",
" self.log(\"Nothing to initialize in your model now\")\n",
"\n",
" def fit(self, max_it):\n",
" \"\"\"\n",
" Put your iteration process here.\n",
" \"\"\"\n",
" self.log(\"Naive Random Solution\")\n",
" self.best_solution = np.random.permutation(self.N).tolist()\n",
" self.fitness_list.append(self.fitness(self.best_solution))\n",
"\n",
" return self.best_solution, self.fitness_list"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test your Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_problem = './template/data/simple/ulysses16.tsp'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"best_solution, fitness_list, time = TSP_Bench(tsp_file, MyModel)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Test All Dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for root, _, files in os.walk('./template/data'):\n",
" if(files):\n",
" for f in files:\n",
" print(str(root) + \"/\" + f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def plot_results(best_solutions, times, title):\n",
" fig = plt.figure()\n",
" nodes = [len(s) for s in best_solutions]\n",
" data = np.array([[node, time] for node, time in sorted(zip(nodes, times))])\n",
" plt.plot(data[:, 0], data[:, 1], 'o-')\n",
" fig.suptitle(title, fontsize=20)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tsp_path = './template/data/medium'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Random Search\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyRandomModel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"Random Model\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Genetic Algorithm\")\n",
"best_solutions, fitness_lists, times = TSP_Bench_ALL(tsp_path, MyGAModel, max_it=100, timeout=600)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_results(best_solutions, times, \"Genetic Algorithm\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

1
template/.gitignore vendored
View File

@ -1,2 +1,3 @@
.vscode/
__pycache__/
.ipynb_checkpoints/

View File

@ -4,4 +4,5 @@ ADD ./ /tsp
WORKDIR /tsp
CMD ["/bin/bash", "-c", "pip install -r requirements.txt && python main.py; mkdir -p /output && cp -r output/* /output"]
RUN pip install -r requirements.txt
CMD ["/bin/bash", "-c", "python main.py; mkdir -p /output && cp -r output/* /output"]

View File

@ -7,5 +7,4 @@ from utils.tsp import TSP_Bench_ALL
from model.my_model import MyModel
if __name__ == "__main__":
model = MyModel()
TSP_Bench_ALL("./data", model)
TSP_Bench_ALL("./data", MyModel)

View File

@ -23,6 +23,8 @@ class Model:
"""
Total distance of the current solution path.
"""
if(len(solution) != self.N):
return math.inf
cur_fit = 0
for i in range(self.N):
cur_fit += self.dist(solution[i % self.N], solution[(i + 1) % self.N])

View File

@ -1,22 +1,27 @@
import math
import random
from model.base_model import Model
import numpy as np
class MyModel(Model):
def __init__(self):
super().__init__()
def init(self, coords):
def init(self, nodes):
"""
Put your initialization here.
"""
super().init(coords)
self.log("Nothing to initialize in your model now")
super().init(nodes)
def fit(self, max_it=1000, visualize=False):
def fit(self, max_it):
"""
Put your iteration process here.
"""
self.log("Nothing happens in your model now")
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))
return self.best_solution, self.fitness_list
self.best_solution = random_solutions[self.fitness_list.index(min(self.fitness_list))]
return self.best_solution, self.fitness_list

View File

@ -0,0 +1 @@
numpy

View File

@ -19,6 +19,8 @@ def dist(node_0, node_1, coords):
def fitness(solution, coords):
N = len(coords)
if(len(solution) != N):
return math.inf
cur_fit = 0
for i in range(len(solution)):
cur_fit += dist(solution[i % N], solution[(i + 1) % N], coords)
@ -64,6 +66,7 @@ def TSP(tsp_file, model, *args, max_it=1000, timeout=60):
nodes = load_data(tsp_file)
model = model()
# Set timeout
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(timeout)
@ -80,27 +83,32 @@ def TSP(tsp_file, model, *args, max_it=1000, timeout=60):
log("Timeout -3")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-3")
best_solution = [-1] * len(nodes)
elif (len(best_solution) == 0):
print(exec)
log("No Answer -1")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-1")
else:
print(exc)
log("Unkown -4")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-4")
best_solution = [-1] * len(nodes)
return best_solution, fitness_list
signal.alarm(0)
# Collect results
if(len(fitness_list) > 0):
log("[Node] " + str(len(best_solution)) + ", [Best] " + str(fitness_list[fitness_list.index(min(fitness_list))]))
if (len(best_solution) == 0):
log("No Answer -1")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-1")
elif (len(best_solution) != len(nodes)):
if (len(best_solution) != len(nodes)):
print(len(best_solution))
log("Invalid -2")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-2")
best_solution = [-1] * len(nodes)
else:
# log("Writing the best solution to file" )
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile: