{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Solving TSP with Genetic Algorithm (GA)\n", "\n", "Understanding the principles of genes and mutation as the driving mechanism\n", "for evolution is common today. Less common is the availability of a minimal\n", "viable [example](example.py), that showcases the method. \n", "So here's an example I've used to enlighten friends, where I deliberately\n", "deviate from pep-8 to introduce imports only when they're needed.\n", "\n", "To solve the Traveling Salesmans Problem (TSP), we need cities to travel to, \n", "and to keep the world simple, we have only `x` and `y` to worry about, and\n", "use a straight line distance:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from collections import namedtuple\n", "\n", "City = namedtuple(\"City\", [\"x\", \"y\", \"id\"])\n", "\n", "def distance(a, b):\n", " return ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** (1 / 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With this out of the way, the next element is a map: \n", "\n", "1. We want to keep the cities in a dictionary, for easy of lookup.\n", "2. We want the cities to be on the map, so we set a max `x` and a max `y` value.\n", "2. We want to be able to generate the cities somewhat random." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import random\n", "random.seed(43) # set the seed for repeatability.\n", "\n", "def make_map(n_cities, x_max=1200, y_max=600):\n", " cities = {}\n", " for city in range(n_cities):\n", " x, y = random.randint(0, x_max), random.randint(0, y_max)\n", " c = City(x, y, id=f\"{x},{y}\")\n", " cities[c.id] = c\n", " return cities" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now make with any number of cities in a single line:\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "city_map = make_map(n_cities=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Making a random route visiting all cities, should also be easy, as we can choose\n", "any random sequence that contains all towns:\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def make_random_route(city_map):\n", " \"\"\" creates a random route. \"\"\"\n", " cities = list(city_map)\n", " random.shuffle(cities)\n", " return cities " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To determine which of two routes is the shorter, it is nice to have a function \n", "that does the work for us. Just remember one thing: \n", "The TSP returns to start after traveling through all cities, so the distance\n", "must include the consideration that it returns to start after all cities have\n", "been visited." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def route_length(citymap, route):\n", " dist = 0.0\n", " a = route[0]\n", " for b in route[1:] + route[:1]:\n", " city_a, city_b = citymap[a], citymap[b]\n", " dist += distance(city_a, city_b)\n", " a = b\n", " return int(dist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's make a helper to look at it:\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from matplotlib import pyplot as plt\n", "from itertools import count\n", "map_no = count() \n", "\n", "def plot(citymap, route):\n", " plt.figure()\n", " xs = [c.x for c in citymap.values()]\n", " ys = [c.y for c in citymap.values()]\n", "\n", " plt.plot(xs, ys, 'o')\n", "\n", " a = route[0]\n", " for b in route[1:] + route[:1]:\n", " city_a, city_b = citymap[a], citymap[b]\n", " plt.plot([city_a.x, city_b.x], [city_a.y, city_b.y], 'bo-', clip_on=False)\n", " a = b\n", "\n", " plt.title(\"({}) length: {:,}\".format(next(map_no), route_length(citymap, route)))\n", " plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then plot it:\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "first_route = make_random_route(city_map)\n", "plot(city_map, first_route)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From this point we can **_mutate_** our `first_route` simply by changing the order\n", "in which we visit the different cities. It would work this way:\n", "\n", "If we have 9 cities as a list like this:\n", "\n", " [1,2,3,4,5,6,7,8,9]\n", " \n", "We can select a random index point in the list and swap the numbers in the position \n", "before and after the index point \n", "\n", " [1,2,3,4,5,6,7,8,9]\n", " ^--- here.\n", "\n", "The position with the one after:\n", "\n", "before \\[1,2,3,4,_**5,6**_,7,8,9]\n", "after \\[1,2,3,4,_**6,5**_,7,8,9]\n", "\n", "We can express this change as a very simple function:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def mutate(route):\n", " new_route = route[:] # copy the route\n", " cut = random.randint(1, len(route)-2) # select the index point.\n", " new_route[cut], new_route[cut+1] = route[cut+1], route[cut] # swap the values.\n", " return new_route" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The one thing that remains to be discussed is the relationship between fitness\n", "and evolution. We want the \"fittest\" to be the shortest path. \n", "\n", "Lets' try it out and check if the new route is better. Spoiler alert: It won't be." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "new_route = mutate(first_route)\n", "plot(city_map, new_route)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "distance before: 2701 , distance after: 3480\n" ] } ], "source": [ "before = route_length(city_map, first_route)\n", "after = route_length(city_map, new_route)\n", "print(\"distance before:\", before, \", distance after:\", after)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you observe, the mutation is not better than the first randomly created \n", "route. This leads us to acknowledge that randomised evolution is quite wasteful, \n", "despite that it can find a good solution. To overcome this we require retention\n", "of the _fittest_ solution:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "shortest distance after 30 : 2285\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "generations = 30 # number of generations to explore\n", "shortest_distance = float('inf')\n", "\n", "for _ in range(generations):\n", " new_route = mutate(first_route) # make mutation\n", " dist = route_length(city_map, new_route) # measure fitness.\n", " if dist < shortest_distance: # retain fittest solution.\n", " first_route = new_route\n", " shortest_distance = dist\n", "\n", "print(\"shortest distance after\", generations, \":\", shortest_distance)\n", "plot(city_map, first_route)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The for loop will now generate solutions, test their fitness and retain the better. \n", "Each iteration will look like this:\n", "\n", "![ga_tsp](artwork/ga_tsp.gif) \n", "\n", "\n", "And the winner is:\n", "\n", "![3](artwork/myplot3.png)" ] } ], "metadata": { "interpreter": { "hash": "c4df837ac4477c7435bbd736fb9ba2c8df232961013baf2c3c9d338fc856bbbf" }, "kernelspec": { "display_name": "Python 3.6.7 64-bit ('python36': conda)", "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.6.7" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }