diff options
| author | Mitsuo Tokumori <[email protected]> | 2022-05-05 22:39:23 -0500 |
|---|---|---|
| committer | Mitsuo Tokumori <[email protected]> | 2022-05-05 22:39:23 -0500 |
| commit | 76292bcc75723ad0e31be0c066800d792de8d720 (patch) | |
| tree | 50474de940b540f526f1c5fafd2460d59c872be7 /test/mitsuo.ipynb | |
| parent | 400b19e25d10443d802bcf2355c8dfd392297894 (diff) | |
| download | DP1_project-76292bcc75723ad0e31be0c066800d792de8d720.tar.gz DP1_project-76292bcc75723ad0e31be0c066800d792de8d720.tar.bz2 DP1_project-76292bcc75723ad0e31be0c066800d792de8d720.zip | |
Clear clutter. No more test/data/ directory
Diffstat (limited to 'test/mitsuo.ipynb')
| -rw-r--r-- | test/mitsuo.ipynb | 771 |
1 files changed, 771 insertions, 0 deletions
diff --git a/test/mitsuo.ipynb b/test/mitsuo.ipynb new file mode 100644 index 0000000..653663c --- /dev/null +++ b/test/mitsuo.ipynb @@ -0,0 +1,771 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "956275e8-e4e6-4a03-afe5-31eca1c3272b", + "metadata": {}, + "source": [ + "# Testing possible algorithms to solve MDHVRPTW" + ] + }, + { + "cell_type": "markdown", + "id": "234feb6e-4c52-443c-a3d6-6da8e903dd5c", + "metadata": { + "tags": [] + }, + "source": [ + "Travelling salesman problem\n", + "\n", + "TSP es *casi* MDHVRPTW (*Multi-Depot Heterogeneous VRP with Time Windows) *del profe* pero:\n", + "- Solo 1 camion\n", + "- Todos los ciudades (aka. almacenes pequeños) tienen al menos 1 pedido\n", + "- Capacidad infinita (1 solo tipo de vehiculo)\n", + "- Sin ventanas de tiempo (aka. plazos de entrega)\n", + "- Solo 1 deposito\n", + "- No hay entregas parciales\n", + " - Relajar la restriccion de que la demanda de los \"customers\" debe ser satisfecha al 100% por\n", + " un solo camion. Entonces, si un \"customer\" requiere 8 paquetes, se le puede entregar solo 5,\n", + " y quedan pendientes 3. **Esto modifica la solucion, ahora es una lista donde los nodos a visitar\n", + " ya no son unicos**. Se debe terminar la solucion cuando ya no hayan pedidos pendientes (paquetes por entregar > 0).\n", + "- No hay \"trasvaces\"\n", + " - F\n", + "\n", + "Cambios identificados, necesarios para adaptar el TSP a nuestro caso:\n", + "- Tramos no conectados -> distancia grande entre ellos\n", + "- Distancias no son euclidianas, usar \"geodistance\"\n", + "- [...]" + ] + }, + { + "cell_type": "markdown", + "id": "6ce403ac-eb32-4f74-ae8d-41cb70fe4a20", + "metadata": { + "tags": [] + }, + "source": [ + "## Posibilidades\n", + "\n", + "Una manera de implementar \n", + "\n", + "- [scikit-opt](https://github.com/guofei9987/scikit-opt)" + ] + }, + { + "cell_type": "markdown", + "id": "98fe5cbb-4fb3-478b-b22f-c14a0408e638", + "metadata": { + "tags": [] + }, + "source": [ + "## NetworkX to find all_pairs_shortest_path" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b854709-fe5c-4c5a-8a05-b2e438c92a1a", + "metadata": {}, + "outputs": [], + "source": [ + "import networkx as nx\n", + "G = nx.Graph()\n", + "G.add_edge(1, 2) # default edge data=1\n", + "G.add_edge(2, 3, weight=0.9) # specify edge data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44bf2120-1e55-4c1d-b806-3e66227483a3", + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "G.add_edge('y', 'x', function=math.cos)\n", + "G.add_node(math.cos) # any hashable can be a node" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ed6d6e2-921a-4376-8f8e-c6731385d561", + "metadata": {}, + "outputs": [], + "source": [ + "elist = [(1, 2), (2, 3), (1, 4), (4, 2)]\n", + "G.add_edges_from(elist)\n", + "elist = [('a', 'b', 5.0), ('b', 'c', 3.0), ('a', 'c', 1.0), ('c', 'd', 7.3)]\n", + "G.add_weighted_edges_from(elist)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16aad098-3702-4d81-889b-3dc8b3e46ca7", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "#G = nx.cubical_graph()\n", + "subax1 = plt.subplot(121)\n", + "nx.draw(G) # default spring_layout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1cc6e56b-3dcf-45fe-9127-0cd63f01ccec", + "metadata": {}, + "outputs": [], + "source": [ + "print(G.adj)" + ] + }, + { + "cell_type": "markdown", + "id": "bad6e2e8-cff5-4a7d-9e3f-f37bae5dff2d", + "metadata": {}, + "source": [ + "## Pre-processing" + ] + }, + { + "cell_type": "markdown", + "id": "22af16ef-7df6-49c8-8e55-157069c03830", + "metadata": {}, + "source": [ + "La data del profe es muy tedioso de leer. Formato raro. Pasar primero a csv.\n", + "\n", + "Distancia entre nodos:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "db46bd0b-46c7-4125-bfff-33205c578e27", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/home/mitsuo/docs/courses/2022-1/INF226_DP1/project/code/DP_project/test'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b87961d0-f9b4-417e-9138-3db1b0a36d2f", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "import csv\n", + "import math\n", + "import random\n", + "\n", + "import networkx as nx\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "aeca1be3-1394-4ae1-b488-6abe8bd1e808", + "metadata": {}, + "outputs": [], + "source": [ + "def degreesToRadians(degrees):\n", + " return degrees * math.pi / 180\n", + "\n", + "def distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2):\n", + " earthRadiusKm = 6371 # Avg. radius\n", + "\n", + " dLat = degreesToRadians(lat2-lat1)\n", + " dLon = degreesToRadians(lon2-lon1)\n", + "\n", + " lat1 = degreesToRadians(lat1)\n", + " lat2 = degreesToRadians(lat2)\n", + "\n", + " a = math.sin(dLat/2) * math.sin(dLat/2) \\\n", + " + math.sin(dLon/2) * math.sin(dLon/2) * math.cos(lat1) * math.cos(lat2)\n", + " c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a));\n", + " return earthRadiusKm * c\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "80a0fef2-ae25-40e3-94ab-e3d07b9b60c0", + "metadata": {}, + "outputs": [], + "source": [ + "class Node:\n", + " \"\"\"\n", + " \n", + " Attributes\n", + " ----------\n", + " lat : float\n", + " Latitud (angulo de los Paralelos) en grados sexagesimales\n", + " lon : float\n", + " Longitud (angulo de los Meridianos) en grados sexagesimales\n", + " x : float\n", + " Aproximacion local, en Km respecto (\"Lima\": -12.04591952,-77.03049615 (lat, long))\n", + " x = (longitud - (-77.03049615)) * (pi / 180) * earthRadiusKm\n", + " y : float\n", + " Aproximacion local, en Km respecto (\"Lima\")\n", + " y = (latitud - (-12.04591952)) * (pi / 180) * earthRadiusKm\n", + " demand : float\n", + " Cantidad de paquetes (facil cambiar a int)\n", + " *_time : float\n", + " Cantidades de tiempo en minutos\n", + " \n", + " Notes\n", + " -----\n", + " Web Mercator projection (BAD):\n", + " \n", + " x = floor(256 / (2 * math.pi) * 2**(zoom_level) * (lon + math.pi))\n", + " y = floor(265 / (2 * math.pi) * 2**(zoom_level) * (math.pi - math.ln(math.tan( math.pi / 4 + lat / 2 ))))\n", + " \n", + " x = R * lon\n", + " y = R * ln(tan(pi/4 + lat/2)\n", + " \n", + " Both `lon` and `lat` in radians.\n", + " \n", + " \"Lima\": -12.04591952,-77.03049615 (lat, long)\n", + " \"\"\"\n", + " def __init__(self, id: int, ubigeo, lat, lon, is_depot,\n", + " demand, ready_time, due_time, service_time):\n", + " super()\n", + " self.id = id\n", + " self.ubigeo = ubigeo\n", + "\n", + " if is_depot:\n", + " self.is_depot = True\n", + " else:\n", + " self.is_depot = False\n", + " \n", + " earthRadiusKm = 6371 # Avg. radius\n", + " zoom_level = 1\n", + " lima_lat = (-12.04591952)\n", + " lima_lon = (-77.03049615)\n", + " \n", + " self.lat = lat\n", + " self.lon = lon\n", + " self.x = (lon - lima_lon) * (math.pi / 180) * earthRadiusKm\n", + " self.y = (lat - lima_lat) * (math.pi / 180) * earthRadiusKm\n", + " #self.lat *= (math.pi / 180)\n", + " #self.lon *= (math.pi / 180)\n", + " #self.x = 256 / (2 * math.pi) * 2**(zoom_level) * (self.lon + math.pi)\n", + " #self.y = 256 / (2 * math.pi) * 2**(zoom_level) * (math.pi - math.log(math.tan( math.pi / 4 + self.lat / 2 )))\n", + " self.x = round(self.x, 3)\n", + " self.y = round(self.y, 3)\n", + " self.demand = demand\n", + " self.ready_time = 0 #ready_time\n", + " self.due_time = due_time\n", + " self.service_time = service_time" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fd72a504-3538-4b43-9e90-bef4299ca83d", + "metadata": {}, + "outputs": [], + "source": [ + "nodes = []\n", + "\n", + "with open('data/VRPTW_python/inf226.oficinas_mod.csv', newline='') as csvfile:\n", + " orders = csv.reader(csvfile)\n", + " count = 1\n", + " id = 0\n", + " for row in orders:\n", + " if count >= 2:\n", + " ubigeo, dept, prov, latitud, longitud, region_natural, is_depot = row[:7]\n", + " demand, ready_time, due_time, service_time = row[7:]\n", + " nodes.append(Node(\n", + " id, ubigeo, float(latitud), float(longitud), int(is_depot),\n", + " #int(100 * random.random()), 0, int(5000 + 500 * (1.5 - random.random())), service_time=60\n", + " demand=float(demand), ready_time=0, due_time=float(due_time), service_time=60\n", + " ))\n", + " id += 1\n", + " count += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8a9cb3eb-d434-44de-a179-01464ba7bbf8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 34, 'ubigeo': '040101', 'is_depot': True, 'lat': -16.39881421, 'lon': -71.537019649, 'x': 610.847, 'y': -484.02, 'demand': 0.0, 'ready_time': 0, 'due_time': 8000.0, 'service_time': 60}\n", + "{'id': 122, 'ubigeo': '130101', 'is_depot': True, 'lat': -8.11176389, 'lon': -79.02868652, 'x': -222.189, 'y': 437.458, 'demand': 0.0, 'ready_time': 0, 'due_time': 8000.0, 'service_time': 60}\n", + "{'id': 134, 'ubigeo': '150101', 'is_depot': True, 'lat': -12.04591952, 'lon': -77.03049615, 'x': 0.0, 'y': 0.0, 'demand': 0.0, 'ready_time': 0, 'due_time': 8000.0, 'service_time': 60}\n" + ] + } + ], + "source": [ + "for node in nodes:\n", + " if node.is_depot:\n", + " print(node.__dict__)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "79fcde2d-d0df-4cca-8334-3ffd7a0da997", + "metadata": {}, + "outputs": [], + "source": [ + "node_num = len(nodes)\n", + "\n", + "tramos = []\n", + "with open('../data/inf226.tramos.v.2.0.csv', newline='') as f:\n", + " rows = csv.reader(f)\n", + " count = 1\n", + " for row in rows:\n", + " if count >= 2:\n", + " tramos.append([row[0], row[1]])\n", + " count += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "945de058-6fc3-44c1-8d59-227064323bae", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7008\n" + ] + }, + { + "data": { + "text/plain": [ + "[['010201', '010301'],\n", + " ['010301', '010201'],\n", + " ['010201', '010401'],\n", + " ['010401', '010201'],\n", + " ['010201', '010501']]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(len(tramos))\n", + "tramos[:5]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "e6895a35-ff22-48a1-88a8-ceb8344f36cb", + "metadata": {}, + "outputs": [], + "source": [ + "node_dist_mat = np.zeros((node_num, node_num))\n", + "\n", + "nodes_d = dict(zip([n.ubigeo for n in nodes], nodes))\n", + "for ubigeo1, ubigeo2 in tramos:\n", + " #if ubigeo1 in nodes_d.keys() and ubigeo2 in nodes_d.keys():\n", + " id1 = nodes_d[ubigeo1].id\n", + " id2 = nodes_d[ubigeo2].id\n", + " n1 = nodes[id1]\n", + " n2 = nodes[id2]\n", + " node_dist_mat[id1][id2] = round(distanceInKmBetweenEarthCoordinates(n1.lat, n1.lon, n2.lat, n2.lon), 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "b971e3b3-cea5-43b8-9c57-5bbb83180ee6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(196, 196)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "node_dist_mat.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "abc75da4-fed7-493e-ae9d-f5daba33c693", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0. , 86.349, 0. , 137.864],\n", + " [ 86.349, 0. , 0. , 146.07 ],\n", + " [ 0. , 0. , 0. , 0. ],\n", + " [137.864, 146.07 , 0. , 0. ]])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "node_dist_mat[:4, :4]" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "e818c9bb-28cb-475d-b8b5-98dfe4d11f91", + "metadata": {}, + "outputs": [], + "source": [ + "# depots are '040101', '130101', '150101'\n", + "\n", + "depots = []\n", + "customers = []\n", + "for n in nodes:\n", + " if n.is_depot:\n", + " depots.append(n)\n", + " else:\n", + " customers.append(n)\n", + "depots_customers = depots + customers\n", + "\n", + "with open('data/VRPTW_python/pedidosperu195.txt', 'w', newline='') as csvfile:\n", + " spamwriter = csv.writer(csvfile, delimiter=' ', quoting=csv.QUOTE_MINIMAL)\n", + " i = 0\n", + " for node in depots_customers:\n", + " spamwriter.writerow([\n", + " #node.id,\n", + " i,\n", + " node.x, node.y,\n", + " node.demand, node.ready_time, node.due_time, node.service_time\n", + " ])\n", + " i += 1" + ] + }, + { + "cell_type": "markdown", + "id": "4cf94976-9003-4b9a-a600-ad9b48d3e60e", + "metadata": {}, + "source": [ + "### Transformar a matriz conexa de nodos \"customer\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac9f4ce7-7f54-4d26-9bbf-75252f083046", + "metadata": {}, + "outputs": [], + "source": [ + "for n in nodes[:5]:\n", + " print(n.__dict__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3f18eaf-a962-454f-99d4-67bf71067e39", + "metadata": {}, + "outputs": [], + "source": [ + "count = 0\n", + "for n in nodes:\n", + " if n.demand:\n", + " print(n.__dict__)\n", + " count += 1\n", + "count" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4308a3df-27ca-4910-bff3-1302c8fb589d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14d8d583-7766-421b-96cc-ec95ad9604e6", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f85c9cab", + "metadata": {}, + "outputs": [], + "source": [ + "#node_dist_mat = np.zeros((node_num, node_num))\n", + "elist = []\n", + "\n", + "nodes_d = dict(zip([n.ubigeo for n in nodes], nodes))\n", + "for ubigeo1, ubigeo2 in tramos:\n", + " #if ubigeo1 in nodes_d.keys() and ubigeo2 in nodes_d.keys():\n", + " id1 = nodes_d[ubigeo1].id\n", + " id2 = nodes_d[ubigeo2].id\n", + " n1 = nodes[id1]\n", + " n2 = nodes[id2]\n", + " #node_dist_mat[id1][id2] = round(distanceInKmBetweenEarthCoordinates(n1.lat, n1.lon, n2.lat, n2.lon), 3)\n", + " dist = round(distanceInKmBetweenEarthCoordinates(n1.lat, n1.lon, n2.lat, n2.lon), 3)\n", + " elist.append((ubigeo1, ubigeo2, dist))\n", + " \n", + "G = nx.Graph()\n", + "G.add_weighted_edges_from(elist)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3c522d4", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "print(len(list(nodes_d)))\n", + "print(len(list(G.nodes)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86771f42", + "metadata": {}, + "outputs": [], + "source": [ + "G['010201']['010301']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "001a04b8", + "metadata": {}, + "outputs": [], + "source": [ + "node_dist_mat[nodes_d['010201'].id, nodes_d['010301'].id]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71e54f4d", + "metadata": {}, + "outputs": [], + "source": [ + "G['010201']['250301']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ebe3cdc", + "metadata": {}, + "outputs": [], + "source": [ + "path1 = nx.shortest_path(G, source='010201', target='250301', weight='weight')\n", + "path1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cca62d40", + "metadata": {}, + "outputs": [], + "source": [ + "path2 = nx.shortest_path(G, source='010201', target='250301')\n", + "path2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "756f1845", + "metadata": {}, + "outputs": [], + "source": [ + "l1, l2 = 0, 0\n", + "for i in range(len(path1)):\n", + " if i == 0:\n", + " continue\n", + " l1 += G[path1[i-1]][path1[i]]['weight']\n", + " l2 += G[path2[i-1]][path2[i]]['weight']\n", + "print(l1, l2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e124757", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# https://stackoverflow.com/a/63169428/7498073\n", + "H = nx.subgraph(G, path1)\n", + "nx.draw(H, with_labels=True, font_weight='bold', node_color='lightblue', node_size=500)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5ded33b", + "metadata": {}, + "outputs": [], + "source": [ + "len_path = dict(nx.all_pairs_dijkstra(G, weight='weight'))\n", + "#for node, (dist, path) in len_path:\n", + "# print(f\"{node}: {dist} [{path}]\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3361d460", + "metadata": {}, + "outputs": [], + "source": [ + "print(len_path['010201'][0]['250301'])\n", + "print(len_path['010201'][1]['250301'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba3d4ae7-c6b5-484a-a1b4-0f6ffe1890b6", + "metadata": {}, + "outputs": [], + "source": [ + "help(G)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "596bf42a-3600-4446-a904-a4e9080d2f2b", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "132bea6b-c50c-4406-8e2f-2279a87e9cbf", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf5cac1d-9ae4-4423-ab96-48728c14fa01", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00f4cd39-c093-4397-ae96-cb3ae2a433c6", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "ff3f7473-6418-4f4a-828f-172f2996ba54", + "metadata": {}, + "source": [ + "## Pruebitas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6956f235-0401-4a67-8ed2-d2b3fd07b3bf", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ab3843c-faba-46a0-9f7b-97897430ba67", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e45dd91b-fc32-4da3-a340-d3dc888b1335", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fdfcaa8-9000-48d7-b3ab-4d2f2efc2bcc", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} |
