[fix] error handling
This commit is contained in:
parent
0a10febfd7
commit
ff8de454a6
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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,2 +1,3 @@
|
|||
.vscode/
|
||||
__pycache__/
|
||||
.ipynb_checkpoints/
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
numpy
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue