199 lines
6.8 KiB
Plaintext
199 lines
6.8 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "google",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Copyright 2025 Google LLC."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "apache",
|
|
"metadata": {},
|
|
"source": [
|
|
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
|
"you may not use this file except in compliance with the License.\n",
|
|
"You may obtain a copy of the License at\n",
|
|
"\n",
|
|
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
|
"\n",
|
|
"Unless required by applicable law or agreed to in writing, software\n",
|
|
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
|
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
|
"See the License for the specific language governing permissions and\n",
|
|
"limitations under the License.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "basename",
|
|
"metadata": {},
|
|
"source": [
|
|
"# vrp_nodes_indices"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "link",
|
|
"metadata": {},
|
|
"source": [
|
|
"<table align=\"left\">\n",
|
|
"<td>\n",
|
|
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
|
"</td>\n",
|
|
"<td>\n",
|
|
"<a href=\"https://github.com/google/or-tools/blob/main/ortools/constraint_solver/samples/vrp_nodes_indices.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
|
"</td>\n",
|
|
"</table>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "doc",
|
|
"metadata": {},
|
|
"source": [
|
|
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "install",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"%pip install ortools"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "description",
|
|
"metadata": {},
|
|
"source": [
|
|
"Sample to better understand Node/Index relation.\n",
|
|
"\n",
|
|
"This script generate few markdown tables to better understand\n",
|
|
"the relation between nodes and indices.\n",
|
|
"\n",
|
|
"Things to notice:\n",
|
|
"* Since we have two duplicates (node 5 and node 4) solver need 2 extra indices\n",
|
|
"to have an unique index for each vehicle start/stop and locations.\n",
|
|
"* Solver needs to \"create\" an index for a vehicle 1 start since solver need an\n",
|
|
"unique start index per vehicle.\n",
|
|
"* All end nodes are moved to the end of the index list aka [15, 16, 17, 18].\n",
|
|
"* routing.Size() return the number of node which are not end nodes (here 15 aka\n",
|
|
"[0-14])\n",
|
|
"note: using the two properties above, we know that any index in\n",
|
|
"range(routing.Size()) is not a vehicle end node.\n",
|
|
"\n",
|
|
"* Since end nodes are moved to the end, their respective \"empty\" node index are\n",
|
|
"reused so all locations indices are \"shifted\"\n",
|
|
"e.g. node 9 is mapped to index 6\n",
|
|
"* Same for start nodes which are moved to \"empty\" space\n",
|
|
"e.g. start node 7 mapped to index 4\n",
|
|
"\n",
|
|
"Takeaway:\n",
|
|
"* Allways use routing.Start(), routing.End(), manager.IndexToNode() or\n",
|
|
"manager.NodeToIndex().\n",
|
|
"* Location node is not necessarily equal to its index.\n",
|
|
"* To loop through ALL indices use manager.GetNumberOfIndices() (Python) or\n",
|
|
"manager::num_indices() (C++)\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "code",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from ortools.constraint_solver import routing_enums_pb2\n",
|
|
"from ortools.constraint_solver import pywrapcp\n",
|
|
"\n",
|
|
"\n",
|
|
"def main():\n",
|
|
" \"\"\"Entry point of the program.\"\"\"\n",
|
|
" locations = 17\n",
|
|
" starts = [5, 5, 7, 8]\n",
|
|
" ends = [1, 2, 4, 4]\n",
|
|
" vehicles = len(starts)\n",
|
|
" assert len(starts) == len(ends)\n",
|
|
"\n",
|
|
" manager = pywrapcp.RoutingIndexManager(locations, vehicles, starts, ends)\n",
|
|
" routing = pywrapcp.RoutingModel(manager)\n",
|
|
"\n",
|
|
" print(\"Starts/Ends:\")\n",
|
|
" header = \"| |\"\n",
|
|
" separator = \"|---|\"\n",
|
|
" v_starts = \"| start |\"\n",
|
|
" v_ends = \"| end |\"\n",
|
|
" for v in range(manager.GetNumberOfVehicles()):\n",
|
|
" header += f\" vehicle {v} |\"\n",
|
|
" separator += \"---|\"\n",
|
|
" v_starts += f\" {starts[v]} |\"\n",
|
|
" v_ends += f\" {ends[v]} |\"\n",
|
|
" print(header)\n",
|
|
" print(separator)\n",
|
|
" print(v_starts)\n",
|
|
" print(v_ends)\n",
|
|
"\n",
|
|
" print(\"\\nNodes:\")\n",
|
|
" print(\n",
|
|
" \"| locations | manager.GetNumberOfNodes | manager.GetNumberOfIndices |\"\n",
|
|
" \" routing.nodes | routing.Size |\"\n",
|
|
" )\n",
|
|
" print(\"|---|---|---|---|---|\")\n",
|
|
" print(\n",
|
|
" f\"| {locations} | {manager.GetNumberOfNodes()} |\"\n",
|
|
" f\" {manager.GetNumberOfIndices()} | {routing.nodes()} |\"\n",
|
|
" f\" {routing.Size()} |\"\n",
|
|
" )\n",
|
|
"\n",
|
|
" print(\"\\nLocations:\")\n",
|
|
" print(\"| node | index | routing.IsStart | routing.IsEnd |\")\n",
|
|
" print(\"|---|---|---|---|\")\n",
|
|
" for node in range(manager.GetNumberOfNodes()):\n",
|
|
" if node in starts or node in ends:\n",
|
|
" continue\n",
|
|
" index = manager.NodeToIndex(node)\n",
|
|
" print(\n",
|
|
" f\"| {node} | {index} | {routing.IsStart(index)} |\"\n",
|
|
" f\" {routing.IsEnd(index)} |\"\n",
|
|
" )\n",
|
|
"\n",
|
|
" print(\"\\nStart/End:\")\n",
|
|
" print(\"| vehicle | Start/end | node | index | routing.IsStart | routing.IsEnd |\")\n",
|
|
" print(\"|---|---|---|---|---|---|\")\n",
|
|
" for v in range(manager.GetNumberOfVehicles()):\n",
|
|
" start_index = routing.Start(v)\n",
|
|
" start_node = manager.IndexToNode(start_index)\n",
|
|
" print(\n",
|
|
" f\"| {v} | start | {start_node} | {start_index} |\"\n",
|
|
" f\" {routing.IsStart(start_index)} | {routing.IsEnd(start_index)} |\"\n",
|
|
" )\n",
|
|
" for v in range(manager.GetNumberOfVehicles()):\n",
|
|
" end_index = routing.End(v)\n",
|
|
" end_node = manager.IndexToNode(end_index)\n",
|
|
" print(\n",
|
|
" f\"| {v} | end | {end_node} | {end_index} |\"\n",
|
|
" f\" {routing.IsStart(end_index)} | {routing.IsEnd(end_index)} |\"\n",
|
|
" )\n",
|
|
"\n",
|
|
"\n",
|
|
"main()\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"language_info": {
|
|
"name": "python"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|