OpenJij/OpenJij

View on GitHub
docs/tutorial/en/003-jijmodeling_openjij_tsp.ipynb

Summary

Maintainability
Test Coverage
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Mathematical Model Formulation using JijModeling and Optimization with OpenJij\n",
    "In this tutorial, we explain the process of formulating a mathematical model using [JijModeling](https://www.ref.documentation.jijzept.com/jijmodeling/), converting the mathematical model to QUBO, and solving it with OpenJij."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, install the required packages.\n",
    "Install JijModeling, a module to easily build mathematical models, and [jijmodeling-transpiler](https://www.ref.documentation.jijzept.com/jijmodeling-transpiler/), a module for converting mathematical models using JijModeling to QUBO.\n",
    "These can be installed using `pip`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# !pip install jijmodeling\n",
    "# !pip install jijmodeling-transpiler"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import jijmodeling as jm\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Traveling Salesman Problem (TSP)\n",
    "We discuss the traveling salesman problem (TSP) as an example of a constrained optimization problem.\n",
    "Suppose a salesman travels once to each of the  cities to sell a product and then returns to the city he started from.\n",
    "The problem is to find the route with the shortest distance to reduce the cost of travel.\n",
    "\n",
    "### Constraints\n",
    "In this problem, there are two constraints: a location constraint, which states that a salesman can only visit each point once, and a time constraint, which states that since there is only one salesman, he can only be in one city at a given time.\n",
    "\n",
    "Using a binary variable with $x_{t,i}=1$ when visiting the $i$th city at time $t$ and $x_{t,i}=0$ otherwise, the above two constraints are:\n",
    "\n",
    "\n",
    "$$\\text{Location constraint : }\\sum_{t=1}^N x_{t,i}=1 \\quad \\forall i$$\n",
    "\n",
    "$$\\text{Time constraint : }\\sum_{i=1}^N x_{t,i}=1 \\quad \\forall t$$\n",
    "\n",
    "A one-hot constraint is a type of constraint in which one of the above variables is 1.\n",
    "\n",
    "### Objective Function\n",
    "TSP is a problem of finding the shortest route.\n",
    "Therefore, if $d_{ij}$ is the distance between cities $i$ and $j$, the distance traveled when visiting city $i$ at time $t$ and city $j$ at time $t+1$ is:\n",
    "\n",
    "$$d_{ij}x_{t,i}x_{t+1,j}$$\n",
    "\n",
    "The sum of the above is:\n",
    "\n",
    "$$\\sum_{t=1}^N\\sum_{i=1}^N \\sum_{j=1}^N d_{ij}x_{t,i}x_{t+1,j}$$\n",
    "\n",
    "This is the total distance traveled, which is the objective function we wish to minimize."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To perform Ising optimization as described in the previous tutorials, a mathematical model with such constraints must be converted to an Ising Hamiltonian or QUBO Hamiltonian.\n",
    "Doing such work by hand is tedious and may cause bugs between the actual mathematical model and QUBO.\n",
    "JijModeling can do all this work automatically.\n",
    "In other words, it can code the mathematical model constructed as described above and automatically convert it to QUBO.\n",
    "In this section, we explain how to use JijModeling to solve TSP."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Building a Mathematical Model of the TSP using JijModeling\n",
    "First, we use JijModeling to describe the mathematical model of the problem.\n",
    "Unlike common modelers for mathematical optimization calculations, JijModeling builds the mathematical model independently from the data of the problem instance.\n",
    "By constructing the mathematical model this way, the generality of the mathematical model can be ensured.\n",
    "Moreover, mathematical equations can be described intuitively, just like writing mathematical equations on paper.\n",
    "Furthermore, the mathematical model described in JijModeling can be checked in LaTeX on the notebook.\n",
    "\n",
    "In this section, we construct mathematical models one by one with JijModeling."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, let us define the variables and the constants of the problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "dist = jm.Placeholder(\"dist\", dim=2)\n",
    "N = jm.Placeholder(\"N\")\n",
    "x = jm.Binary(\"x\", shape=(N, N))\n",
    "i = jm.Element(\"i\", (0,N))\n",
    "j = jm.Element(\"j\", (0,N))\n",
    "t = jm.Element(\"t\", (0,N))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, `jm.Placeholder` represents a constant, which is the distance matrix and the number of cities.\n",
    "By varying the distance matrix and number of cities data, we represent various sizes of TSP.\n",
    "\n",
    "Binary variables are represented by `jm.Binary`.\n",
    "Here we define a binary variable of $N\\times N$.\n",
    "Then, we use `jm.Element` to define the subscripts `i`,`j`,`t`.\n",
    "These are used to represent the range of sums.\n",
    "\n",
    "In JijModeling, we create a `jm.Problem` instance and add objective functions and constraints to it.\n",
    "Next, we will define the objective function using the variables we have defined."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$\\begin{alignat*}{4}\\text{Problem} & \\text{: TSP} \\\\\\min & \\quad \\sum_{ t = 0 }^{ N - 1 } \\sum_{ i = 0 }^{ N - 1 } \\sum_{ j = 0 }^{ N - 1 } dist_{i,j} \\cdot x_{t,i} \\cdot x_{\\left( t + 1 \\right) \\mod N,j} \\\\& x_{i_{0},i_{1}} \\in \\{0, 1\\}\\end{alignat*}$$"
      ],
      "text/plain": [
       "<jijmodeling.problem.problem.Problem at 0x11b3e4b20>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "problem = jm.Problem(\"TSP\")\n",
    "obj = jm.Sum([t, i, j], dist[i, j] * x[t, i] * x[(t + 1) % N, j])\n",
    "problem += obj\n",
    "problem"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The sum can be expressed with `jm.Sum`.\n",
    "The first argument of `jm.Sum` is the indices to be summed, and since the objective function of TSP takes sums for three indices, we pass those indices (`jm.element`) in a list.\n",
    "\n",
    "Then, we add the constraint conditions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Constraint 1 : one-hot position constraint\n",
    "problem += jm.Constraint(\n",
    "            \"one-hot location\",\n",
    "            jm.Sum(t,x[t,i]) == 1,\n",
    "            forall=i,\n",
    "        )\n",
    "\n",
    "# Constraint 2 : one-hot time constraint\n",
    "problem += jm.Constraint(\n",
    "            \"one-hot time\",\n",
    "            x[t, :] == 1,\n",
    "            forall=t,\n",
    "        )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Constraints can be expressed using `jm.Constraint`.\n",
    "The first argument is the name of the constraint condition, and the second argument is a mathematical expression of the constraint condition.\n",
    "\n",
    "This constraint has an optional argument, `forall`.\n",
    "This is a JijModeling argument that expresses what is expressed in a mathematical model as \"for any $i$\" or \"$\\forall i$\".\n",
    "\n",
    "Finally, let us check the mathematical model we have just described."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$$\\begin{alignat*}{4}\\text{Problem} & \\text{: TSP} \\\\\\min & \\quad \\sum_{ t = 0 }^{ N - 1 } \\sum_{ i = 0 }^{ N - 1 } \\sum_{ j = 0 }^{ N - 1 } dist_{i,j} \\cdot x_{t,i} \\cdot x_{\\left( t + 1 \\right) \\mod N,j} \\\\\\text{s.t.} & \\\\& \\text{one-hot location} :\\\\ &\\quad \\quad \\sum_{ t = 0 }^{ N - 1 } x_{t,i} = 1,\\ \\forall i \\in \\left\\{ 0 ,\\ldots , N - 1 \\right\\} \\\\[8pt]& \\text{one-hot time} :\\\\ &\\quad \\quad \\sum_{ \\bar{i}_{1} = 0 }^{ N - 1 } x_{t,\\bar{i}_{1}} = 1,\\ \\forall t \\in \\left\\{ 0 ,\\ldots , N - 1 \\right\\} \\\\[8pt]& x_{i_{0},i_{1}} \\in \\{0, 1\\}\\end{alignat*}$$"
      ],
      "text/plain": [
       "<jijmodeling.problem.problem.Problem at 0x11b3e4b20>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "problem"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We see the same mathematical expression displayed as in the mathematical model used in the explanation.\n",
    "\n",
    "This completes the construction of the mathematical model.\n",
    "As above, JijModeling allows you to code mathematical models by comparing them with mathematical formulas."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating the Problem Data\n",
    "Now that we have a mathematical model of the problem, the next step is to create data for the problem.\n",
    "Here we will solve a simple problem with 5 cities and random distances between cities."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.0, 1.0)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "N = 5\n",
    "np.random.seed(3)\n",
    "\n",
    "x_pos = np.random.rand(N) \n",
    "y_pos = np.random.rand(N) \n",
    "\n",
    "plt.plot(x_pos, y_pos, 'o')\n",
    "plt.xlim(0, 1)\n",
    "plt.ylim(0, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since we assign the data to the `jm.Placeholder` to create the mathematical model, we need to pass the data in a dictionary type with the Placeholder's name as the key.\n",
    "In this problem, we need to pass values for `N` and `dist`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'N': 5,\n",
       " 'dist': array([[0.        , 0.7866063 , 0.73643374, 0.84577089, 0.56967619],\n",
       "        [0.7866063 , 0.        , 0.4251585 , 0.21078131, 0.36540009],\n",
       "        [0.73643374, 0.4251585 , 0.        , 0.26950348, 0.64576184],\n",
       "        [0.84577089, 0.21078131, 0.26950348, 0.        , 0.54552992],\n",
       "        [0.56967619, 0.36540009, 0.64576184, 0.54552992, 0.        ]])}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "XX, XX_T = np.meshgrid(x_pos, x_pos)\n",
    "YY, YY_T = np.meshgrid(y_pos, y_pos)\n",
    "distance = np.sqrt((XX - XX_T)**2 + (YY - YY_T)**2)\n",
    "instance_data = {\n",
    "    \"N\":N,\"dist\": distance\n",
    "}\n",
    "instance_data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Convert Mathematical Models to QUBO using JijModeling-Transpiler\n",
    "Now that the mathematical model and data are ready, we convert the mathematical model and data to QUBO using JijModeling-Transpiler.\n",
    "\n",
    "First, import `to_pyqubo`, a function to convert to QUBO."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from jijmodeling.transpiler.pyqubo import to_pyqubo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We create a pyqubo object by giving this `to_pyqubo` a mathematical model and the data of the problem.\n",
    "Note that, if we want to fix some of the variables to a certain value, we can give them as the third variable in a dictionary type."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "model,cache = to_pyqubo(problem,instance_data,{})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To generate QUBO, we pass the magnitude of the coefficients of the constraints to the pyqubo object  and then use the `to_qubo` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "multipliers = {\"one-hot location\":1.0,\"one-hot time\":1.0}\n",
    "Q,offset = model.compile().to_qubo(feed_dict = multipliers)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have successfully generated QUBO."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Performing Optimization using OpenJij\n",
    "Since QUBO has been obtained, optimization calculations can be performed as before using this QUBO."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openjij as oj"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "sampler = oj.SASampler(num_reads=100)\n",
    "res = sampler.sample_qubo(Q=Q)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The JijModeling-Transpiler function will format the results obtained by optimization into a more readable form which is the [SampleSet](https://www.ref.documentation.jijzept.com/jijmodeling/reference/jijmodeling/#jijmodeling.SampleSet) class.\n",
    "Let us use the `decode` function.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "SampleSet(record=Record(solution={'x': [(([1, 0, 2, 3, 4], [3, 2, 1, 4, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 2, 3, 1, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 2, 3, 1, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 1, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 2, 1, 4, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 3, 2, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 1, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 0, 4, 1]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 2, 3, 1, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 1, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 1, 3]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 2, 3, 1, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 2, 3, 1, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 3, 2, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 3, 2, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 1, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 3, 2, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 2, 1, 4, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 0, 4, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 3, 2, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 0, 4, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 3, 2, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 0, 4, 1]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 0, 4, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 1, 0, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 4, 2, 3, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 1, 2, 0, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 1, 0, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 1, 0, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 1, 2, 0, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 4, 2, 3, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 2, 3, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 4, 3, 2, 1]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 4, 3, 2, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 4, 2, 3, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 1, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 1, 4, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 3, 4, 1, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 1, 4, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 0, 4, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 2, 1, 0, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 2, 1, 0, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 0, 4, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 0, 4, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 3, 0, 4, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 2, 1, 0, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 1, 3, 2, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 4, 1, 3, 2]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [1, 0, 4, 2, 3]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [1, 0, 4, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 4, 3, 1, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 1, 2, 4, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [1, 0, 4, 2, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 4, 0, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 1, 4, 0, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 3, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 4, 2, 1, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 2, 3, 4, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 3, 1, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 4, 2, 1, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 1, 0, 4, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 3, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 4, 3, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 1, 3, 4, 0]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 3, 2, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 1, 0, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 4, 3, 2, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 1, 0, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 1, 2, 3, 4]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 1, 2, 3, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 3, 0, 1, 2]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [1, 0, 4, 3, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 1, 0, 4, 2]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [1, 2, 3, 0, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 1, 3, 2, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 2, 1, 4, 3]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [3, 2, 4, 1, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [2, 3, 0, 1, 4]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 2, 1, 3, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [0, 3, 2, 4, 1]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 2, 1, 3, 0]), [1, 1, 1, 1, 1], ()), (([1, 0, 2, 3, 4], [4, 2, 1, 0, 3]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 1, 4, 2, 3]), [1, 1, 1, 1, 1], ()), (([0, 1, 2, 3, 4], [0, 1, 3, 4, 2]), [1, 1, 1, 1, 1], ())]}, num_occurrences=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]), evaluation=Evaluation(energy=[-7.848205186671935, -7.512420345981557, -7.512420345981557, -7.517670867792821, -7.5176708677928215, -7.195852125954437, -7.848205186671935, -7.848205186671935, -7.403525608627656, -7.517670867792821, -7.848205186671935, -7.517670867792821, -7.512420345981557, -7.848205186671935, -7.403525608627656, -7.848205186671935, -7.848205186671935, -7.5176708677928215, -7.848205186671935, -7.403525608627657, -7.403525608627657, -7.848205186671935, -7.403525608627657, -7.848205186671934, -7.848205186671934, -7.517670867792821, -7.848205186671935, -7.5176708677928215, -7.848205186671935, -7.5176708677928215, -7.848205186671935, -7.512420345981557, -7.524490846313727, -7.403525608627657, -7.848205186671934, -7.848205186671935, -7.403525608627657, -7.29652646979358, -7.524490846313728, -7.848205186671935, -7.403525608627657, -7.848205186671935, -7.848205186671935, -7.848205186671935, -7.296526469793579, -7.195852125954437, -7.195852125954437, -7.5176708677928215, -7.512420345981557, -7.848205186671934, -7.524490846313728, -7.848205186671935, -7.848205186671935, -7.524490846313727, -7.524490846313727, -7.848205186671935, -7.848205186671935, -7.517670867792821, -7.848205186671935, -7.848205186671935, -7.074886888268367, -7.848205186671935, -7.296526469793579, -7.5176708677928215, -7.848205186671935, -7.302851264788513, -7.512420345981557, -7.512420345981557, -7.524490846313728, -7.296526469793579, -7.302851264788514, -7.848205186671935, -7.524490846313728, -7.5176708677928215, -7.524490846313728, -7.086957388600537, -7.512420345981557, -7.848205186671935, -7.848205186671935, -7.086957388600536, -7.517670867792821, -7.524490846313728, -7.848205186671935, -7.5176708677928215, -7.848205186671935, -7.848205186671935, -7.848205186671934, -7.524490846313728, -7.848205186671935, -7.512420345981558, -7.848205186671935, -7.848205186671935, -7.848205186671934, -7.848205186671934, -7.517670867792821, -7.403525608627657, -7.848205186671935, -7.848205186671935, -7.848205186671935, -7.848205186671935], objective=[2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.151794813328065, 2.1517948133280655, 2.151794813328065, 2.151794813328065, 2.1517948133280655, 2.151794813328065, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4755091536862723, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.48232913220718, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.4823291322071794, 2.487579654018443, 2.487579654018443, 2.487579654018443, 2.487579654018443, 2.487579654018443, 2.487579654018443, 2.487579654018443, 2.487579654018443, 2.487579654018443, 2.596474391372343, 2.596474391372343, 2.596474391372343, 2.596474391372343, 2.596474391372343, 2.596474391372343, 2.596474391372343, 2.596474391372343, 2.596474391372343, 2.6971487352114867, 2.6971487352114862, 2.703473530206421, 2.703473530206421, 2.703473530206421, 2.703473530206421, 2.8041478740455634, 2.8041478740455634, 2.8041478740455634, 2.913042611399464, 2.913042611399464, 2.9251131117316342], constraint_violations={'one-hot location': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'one-hot time': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}, penalty={}), measuring_time=MeasuringTime(solve=SolvingTime(preprocess=None, solve=None, postprocess=None), system=SystemTime(post_problem_and_instance_data=None, request_queue=None, fetch_problem_and_instance_data=None, fetch_result=None, deserialize_solution=None), total=None))"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result = cache.decode(res)\n",
    "result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`SampleSet.Record` mainly stores the solutions and the occurrences of the solutions.\n",
    "The obtained solution is contained in the `solution` which is in the `result.record` as a sparse matrix.\n",
    "The first two elements are critical: the first is the index in the matrix, and the second is the value of that index.\n",
    "In the case of a binary variable, only the value that is 1 is stored, so the value usually contains only 1.\n",
    "`SampleSet.lowest()` method extracts the solutions taking the minimum value of the objective functions among the feasible solutions.\n",
    "If there are multiple minimum values, `lowest()` method returns all these solutions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([1, 0, 2, 3, 4], [3, 2, 1, 4, 0])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sparse_index,value,_ = result.lowest().record.solution['x'][0]\n",
    "sparse_index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In `result.evaluation`, there is energy, objective function, and constraint violation.\n",
    "These represent the evaluation values obtained by optimization.\n",
    "Here, we check whether the solution satisfies the constraints."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'one-hot location': [0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0],\n",
       " 'one-hot time': [0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0,\n",
       "  0.0]}"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result.evaluation.constraint_violations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This shows that we have obtained a solution that satisfies the constraints.\n",
    "\n",
    "Let us visualize this solution.\n",
    "When plotting the route, we can get the order in which to move around the cities by sorting the city indices using the time-related indices."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((0, 1, 2, 3, 4), (2, 3, 1, 4, 0))"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time_indices, city_indices = zip(*sorted(zip(*sparse_index)))\n",
    "time_indices, city_indices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x11ffc2d00>]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi4AAAGiCAYAAADA0E3hAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABOxklEQVR4nO3deVzUdeLH8dfMAAOi4Ake4UWaZZllipStR5Zddm1lWea6WVtZv9IOM28tLbPW3bLczMqy1Go7dtPsQN228ijNstRMPLfk8AIF5Zj5/v74BEiBMjjwneP9fDx47JdxBt7sBLz5zOdwWJZlISIiIhIEnHYHEBEREakqFRcREREJGiouIiIiEjRUXERERCRoqLiIiIhI0FBxERERkaCh4iIiIiJBQ8VFREREgoaKi4iIiAQNFRcREREJGj4Xl88++4z+/fvTvHlzHA4H77333nEfs3z5cs4++2zcbjcnn3wyr7zySjWiioiISLjzubjk5eVx5plnMnPmzCrdf9u2bVx22WX07t2bdevWcd999zF06FA++ugjn8OKiIhIeHOcyCGLDoeDd999l6uuuqrS+4wcOZJFixbx/fffl952ww03cODAAZYsWVLdTy0iIiJhKKKmP8GKFSvo27dvudv69evHfffdV+ljCgoKKCgoKH3f6/Wyb98+GjVqhMPhqKmoIiIi4keWZXHw4EGaN2+O0+mfabU1XlwyMjJITEwsd1tiYiK5ubkcPnyYmJiY3z1m6tSpTJw4saajiYiISC3YtWsXJ510kl8+Vo0Xl+oYNWoUI0aMKH0/JyeHli1bsmvXLuLi4mxMJiIiIlWVm5tLUlIS9erV89vHrPHi0rRpUzIzM8vdlpmZSVxcXIWjLQButxu32/272+Pi4lRcREREgow/p3nU+D4uqamppKWllbvtk08+ITU1taY/tYiIiIQYn4vLoUOHWLduHevWrQPMcud169axc+dOwLzMc8stt5Te/4477mDr1q089NBDbNq0ieeee44333yT4cOH++crEBERkbDhc3H5+uuvOeusszjrrLMAGDFiBGeddRbjxo0DYPfu3aUlBqBNmzYsWrSITz75hDPPPJOnnnqKF198kX79+vnpSxAREZFwcUL7uNSW3Nxc4uPjycnJ0RwXERGRIFETv791VpGIiIgEDRUXERERCRoqLiIiIhI0VFxEREQk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Bh3FJRIaZs6EefPMHyQLF8JJJ9mdKHypuIj40RdfwMcfQ0QEjBljdxoR8YfPP4fhw831tGnQq5etccKeiouIH5WMtgwZAm3a2JtFRE7c7t1m1+viYrMfU0mBEfuouIj4yWefQVoaREbC6NF2pxGRE1VYaEpLRobZQPLFF3XicyBQcRHxk5LRlltvhVat7M0iIifugQfMy79xcfDuu1C3rt2JBFRcRPxi2TJYvhyiouCRR+xOIyInat48eOaZsut27ezNI2VUXEROkGXBuHHm+rbbICnJ3jwicmK+/RZuv91cjxkD/fvbm0fKU3EROUFpaWbVgdttjrUXkeC1f7/ZZO7wYbj44rKjOyRwqLiInICjR1vuuANatLA3j4hUn9cLN91ktvVv0wZef10nPgciFReRE/Dxx7BiBURHw8iRdqcRkRMxcaLZ9To62pz43LCh3YmkIiouItV09GjLXXdBs2b25hGR6vvgA5g0yVy/8AJ07mxrHDkGFReRavrwQ1i9GmJi4KGH7E4jItW1ZQvcfLO5HjbMHI4qgUvFRaQajh5tuftuSEy0N4+IVE9eHlx9NeTkwLnnwtNP251IjkfFRaQa/v1vWLMGYmPhwQftTiMi1WFZZguD77+Hpk3hrbfMXkwS2FRcRHxkWWW75N5zDzRpYm8eEamev/0N5s83h6K++SY0b253IqkKFRcRH733HqxbZ7b/fuABu9OISHX85z9l379PPQXnn29vHqk6FRcRH3i9ZRtS3XsvNGpkaxwRqYaff4brrwePBwYONCOnEjxUXER88M478N135tC1ESPsTiMivioshGuvhaws6NTJLH3Wic/BRcVFpIqOHm257z5tTiUSjIYPh5UroX5984dIbKzdicRXKi4iVfTWW/DDDxAfb374iUhwmTsXnnvOjLC8/jokJ9udSKpDxUWkCjyestGWESPMX2siEjzWrjXniYFZFXjppfbmkepTcRGpgoULYdMmaNDATMoVkeCxd6858fnIEbjsMhg71u5EciJUXESOo7jYHL4GZvlkfLy9eUSk6kpWDu3YYV4aeu01cOo3X1DT0ydyHPPnw+bNZumzlk2KBJfx480p7jExZjJugwZ2J5ITpeIicgxHj7Y8+CDUq2dvHhGpuvffh8ceM9cvvmiWP0vwU3EROYbXXoP0dGjc2JwaKyLB4ccfy055vvde83KR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27cvK1asqPAxK1asYMSIEeVu69evH++9916ln2fq1KlMnDjxd7cnJSX5EldEREQCwN69e+0pLnv27MHj8ZCYmFju9sTERDZt2lThYzIyMiq8f0ZGRqWfZ9SoUeXKzoEDB2jVqhU7d+702xcu1VPSnjX6ZT89F4FDz0Vg0fMROEpeMWnYsKHfPmZAbvnvdrtxu92/uz0+Pl7/EQaIuLg4PRcBQs9F4NBzEVj0fAQOp9N/i5h9+kiNGzfG5XKRmZlZ7vbMzEyaNq34fJGmTZv6dH8RERGRyvhUXKKioujSpQtpaWmlt3m9XtLS0khNTa3wMampqeXuD/DJJ59Uen8RERGRyvj8UtGIESMYPHgw55xzDt26dWPGjBnk5eUxZMgQAG655RZatGjB1KlTAbj33nvp2bMnTz31FJdddhkLFizg66+/5oUXXqjy53S73YwfP77Cl4+kdum5CBx6LgKHnovAoucjcNTEc+HzcmiAZ599lieffJKMjAw6d+7M3//+d1JSUgDo1asXrVu35pVXXim9/1tvvcWYMWPYvn077dq1Y9q0aVx66aV++yJEREQkPFSruIiIiIjYQWcViYiISNBQcREREZGgoeIiIiIiQUPFRURERIJGwBSXmTNn0rp1a6Kjo0lJSWH16tXHvP9bb71Fhw4diI6O5owzzmDx4sW1lDT0+fJczJ49m/PPP58GDRrQoEED+vbte9znTqrO1++LEgsWLMDhcHDVVVfVbMAw4utzceDAAYYNG0azZs1wu920b99eP6f8xNfnYsaMGZxyyinExMSQlJTE8OHDOXLkSC2lDV2fffYZ/fv3p3nz5jgcjmOeQVhi+fLlnH322bjdbk4++eRyK5CrzAoACxYssKKioqyXXnrJ+uGHH6zbbrvNql+/vpWZmVnh/b/44gvL5XJZ06ZNszZs2GCNGTPGioyMtNavX1/LyUOPr8/FwIEDrZkzZ1rffPONtXHjRutPf/qTFR8fb/3vf/+r5eShx9fnosS2bdusFi1aWOeff7515ZVX1k7YEOfrc1FQUGCdc8451qWXXmp9/vnn1rZt26zly5db69atq+XkocfX5+L111+33G639frrr1vbtm2zPvroI6tZs2bW8OHDazl56Fm8eLE1evRo65133rEA69133z3m/bdu3WrVqVPHGjFihLVhwwbrmWeesVwul7VkyRKfPm9AFJdu3bpZw4YNK33f4/FYzZs3t6ZOnVrh/a+//nrrsssuK3dbSkqK9Ze//KVGc4YDX5+L3youLrbq1atnzZ07t6Yiho3qPBfFxcXWueeea7344ovW4MGDVVz8xNfn4vnnn7fatm1rFRYW1lbEsOHrczFs2DCrT58+5W4bMWKEdd5559VoznBTleLy0EMPWR07dix324ABA6x+/fr59Llsf6mosLCQNWvW0Ldv39LbnE4nffv2ZcWKFRU+ZsWKFeXuD9CvX79K7y9VU53n4rfy8/MpKiry60mg4ai6z8WkSZNISEjg1ltvrY2YYaE6z8W//vUvUlNTGTZsGImJiZx++ulMmTIFj8dTW7FDUnWei3PPPZc1a9aUvpy0detWFi9erE1QbeCv3922nw69Z88ePB4PiYmJ5W5PTExk06ZNFT4mIyOjwvtnZGTUWM5wUJ3n4rdGjhxJ8+bNf/cfp/imOs/F559/zpw5c1i3bl0tJAwf1Xkutm7dytKlS7nppptYvHgxW7Zs4a677qKoqIjx48fXRuyQVJ3nYuDAgezZs4cePXpgWRbFxcXccccdPPLII7URWY5S2e/u3NxcDh8+TExMTJU+ju0jLhI6Hn/8cRYsWMC7775LdHS03XHCysGDBxk0aBCzZ8+mcePGdscJe16vl4SEBF544QW6dOnCgAEDGD16NLNmzbI7WthZvnw5U6ZM4bnnnmPt2rW88847LFq0iMmTJ9sdTarJ9hGXxo0b43K5yMzMLHd7ZmYmTZs2rfAxTZs29en+UjXVeS5KTJ8+nccff5xPP/2UTp061WTMsODrc5Gens727dvp379/6W1erxeAiIgIfvzxR5KTk2s2dIiqzvdFs2bNiIyMxOVyld526qmnkpGRQWFhIVFRUTWaOVRV57kYO3YsgwYNYujQoQCcccYZ5OXlcfvttzN69GicTv39Xlsq+90dFxdX5dEWCIARl6ioKLp06UJaWlrpbV6vl7S0NFJTUyt8TGpqarn7A3zyySeV3l+qpjrPBcC0adOYPHkyS5Ys4ZxzzqmNqCHP1+eiQ4cOrF+/nnXr1pW+XXHFFfTu3Zt169aRlJRUm/FDSnW+L8477zy2bNlSWh4BNm/eTLNmzVRaTkB1nov8/PzflZOSQmnpqL5a5bff3b7NG64ZCxYssNxut/XKK69YGzZssG6//Xarfv36VkZGhmVZljVo0CDr4YcfLr3/F198YUVERFjTp0+3Nm7caI0fP17Lof3E1+fi8ccft6Kioqy3337b2r17d+nbwYMH7foSQoavz8VvaVWR//j6XOzcudOqV6+edffdd1s//vij9cEHH1gJCQnWo48+ateXEDJ8fS7Gjx9v1atXz5o/f761detW6+OPP7aSk5Ot66+/3q4vIWQcPHjQ+uabb6xvvvnGAqynn37a+uabb6wdO3ZYlmVZDz/8sDVo0KDS+5csh37wwQetjRs3WjNnzgze5dCWZVnPPPOM1bJlSysqKsrq1q2btXLlytJ/69mzpzV48OBy93/zzTet9u3bW1FRUVbHjh2tRYsW1XLi0OXLc9GqVSsL+N3b+PHjaz94CPL1++JoKi7+5etz8eWXX1opKSmW2+222rZtaz322GNWcXFxLacOTb48F0VFRdaECROs5ORkKzo62kpKSrLuuusua//+/bUfPMQsW7aswp//Jf//Dx482OrZs+fvHtO5c2crKirKatu2rfXyyy/7/HkdlqWxMhEREQkOts9xEREREakqFRcREREJGiouIiIiEjRUXERERCRoqLiIiIhI0FBxERERkaCh4iIiIiJBQ8VFREREgoaKi4iIiAQNFRcREREJGiouIiIiEjT+HxyaGa7JuG1pAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(x_pos, y_pos, 'o',markersize=12)\n",
    "plt.xlim(0, 1)\n",
    "plt.ylim(0, 1)\n",
    "\n",
    "for i, city_index in enumerate(city_indices[:-1]):\n",
    "    next_city_index = city_indices[i+1]\n",
    "    plt.plot([x_pos[city_index],x_pos[next_city_index ]],[y_pos[city_index],y_pos[next_city_index ]],c = \"blue\")\n",
    "    \n",
    "plt.plot([x_pos[city_indices[-1]],x_pos[city_indices[0]]],[y_pos[city_indices[-1]],y_pos[city_indices[0]]],c = \"blue\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.9.15"
  },
  "vscode": {
   "interpreter": {
    "hash": "2e8d7574d7ec71e14cb1575cf43673432d6fae464c836a7b3733d4f6c20243fb"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}