diff --git a/makefiles/Makefile.cpp.mk b/makefiles/Makefile.cpp.mk index 8e3d2fcd8b..fc0d74061e 100755 --- a/makefiles/Makefile.cpp.mk +++ b/makefiles/Makefile.cpp.mk @@ -370,6 +370,8 @@ test_cc_constraint_solver_samples: \ rcc_simple_ls_program \ rcc_simple_routing_program \ rcc_tsp \ + rcc_tsp_cities \ + rcc_tsp_circuit_board \ rcc_tsp_distance_matrix \ rcc_vrp \ rcc_vrp_capacity \ diff --git a/makefiles/Makefile.dotnet.mk b/makefiles/Makefile.dotnet.mk index 09e8b345e3..c29bd4df66 100644 --- a/makefiles/Makefile.dotnet.mk +++ b/makefiles/Makefile.dotnet.mk @@ -442,6 +442,8 @@ test_dotnet_algorithms_samples: ; test_dotnet_constraint_solver_samples: $(MAKE) run SOURCE=ortools/constraint_solver/samples/SimpleRoutingProgram.cs $(MAKE) run SOURCE=ortools/constraint_solver/samples/Tsp.cs + $(MAKE) run SOURCE=ortools/constraint_solver/samples/TspCities.cs + $(MAKE) run SOURCE=ortools/constraint_solver/samples/TspCircuitBoard.cs $(MAKE) run SOURCE=ortools/constraint_solver/samples/TspDistanceMatrix.cs $(MAKE) run SOURCE=ortools/constraint_solver/samples/Vrp.cs $(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpCapacity.cs diff --git a/makefiles/Makefile.java.mk b/makefiles/Makefile.java.mk index d6a78ca577..90dcff1d48 100755 --- a/makefiles/Makefile.java.mk +++ b/makefiles/Makefile.java.mk @@ -375,6 +375,8 @@ test_java_algorithms_samples: \ test_java_constraint_solver_samples: \ rjava_SimpleRoutingProgram \ rjava_Tsp \ + rjava_TspCities \ + rjava_TspCircuitBoard \ rjava_TspDistanceMatrix \ rjava_Vrp \ rjava_VrpCapacity \ diff --git a/makefiles/Makefile.python.mk b/makefiles/Makefile.python.mk index 80695d8d17..a64c28f157 100755 --- a/makefiles/Makefile.python.mk +++ b/makefiles/Makefile.python.mk @@ -501,6 +501,8 @@ test_python_constraint_solver_samples: \ rpy_simple_cp_program \ rpy_simple_routing_program \ rpy_tsp \ + rpy_tsp_cities \ + rpy_tsp_circuit_board \ rpy_tsp_distance_matrix \ rpy_vrp \ rpy_vrp_capacity \ diff --git a/ortools/constraint_solver/samples/TspCircuitBoard.cs b/ortools/constraint_solver/samples/TspCircuitBoard.cs new file mode 100644 index 0000000000..d515720173 --- /dev/null +++ b/ortools/constraint_solver/samples/TspCircuitBoard.cs @@ -0,0 +1,187 @@ +// Copyright 2010-2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START program] +// [START import] +using System; +using System.Collections.Generic; +using Google.OrTools.ConstraintSolver; +// [END import] + +/// +/// Minimal TSP. +/// A description of the problem can be found here: +/// http://en.wikipedia.org/wiki/Travelling_salesman_problem. +/// +public class TspCircuitBoard { + // [START data_model] + class DataModel { + public int[,] Locations = { + {288, 149}, {288, 129}, {270, 133}, {256, 141}, {256, 157}, {246, 157}, + {236, 169}, {228, 169}, {228, 161}, {220, 169}, {212, 169}, {204, 169}, + {196, 169}, {188, 169}, {196, 161}, {188, 145}, {172, 145}, {164, 145}, + {156, 145}, {148, 145}, {140, 145}, {148, 169}, {164, 169}, {172, 169}, + {156, 169}, {140, 169}, {132, 169}, {124, 169}, {116, 161}, {104, 153}, + {104, 161}, {104, 169}, {90, 165}, {80, 157}, {64, 157}, {64, 165}, + {56, 169}, {56, 161}, {56, 153}, {56, 145}, {56, 137}, {56, 129}, + {56, 121}, {40, 121}, {40, 129}, {40, 137}, {40, 145}, {40, 153}, + {40, 161}, {40, 169}, {32, 169}, {32, 161}, {32, 153}, {32, 145}, + {32, 137}, {32, 129}, {32, 121}, {32, 113}, {40, 113}, {56, 113}, + {56, 105}, {48, 99}, {40, 99}, {32, 97}, {32, 89}, {24, 89}, {16, 97}, + {16, 109}, {8, 109}, {8, 97}, {8, 89}, {8, 81}, {8, 73}, {8, 65}, + {8, 57}, {16, 57}, {8, 49}, {8, 41}, {24, 45}, {32, 41}, {32, 49}, + {32, 57}, {32, 65}, {32, 73}, {32, 81}, {40, 83}, {40, 73}, {40, 63}, + {40, 51}, {44, 43}, {44, 35}, {44, 27}, {32, 25}, {24, 25}, {16, 25}, + {16, 17}, {24, 17}, {32, 17}, {44, 11}, {56, 9}, {56, 17}, {56, 25}, + {56, 33}, {56, 41}, {64, 41}, {72, 41}, {72, 49}, {56, 49}, {48, 51}, + {56, 57}, {56, 65}, {48, 63}, {48, 73}, {56, 73}, {56, 81}, {48, 83}, + {56, 89}, {56, 97}, {104, 97}, {104, 105}, {104, 113}, {104, 121}, + {104, 129}, {104, 137}, {104, 145}, {116, 145}, {124, 145}, {132, 145}, + {132, 137}, {140, 137}, {148, 137}, {156, 137}, {164, 137}, {172, 125}, + {172, 117}, {172, 109}, {172, 101}, {172, 93}, {172, 85}, {180, 85}, + {180, 77}, {180, 69}, {180, 61}, {180, 53}, {172, 53}, {172, 61}, + {172, 69}, {172, 77}, {164, 81}, {148, 85}, {124, 85}, {124, 93}, + {124, 109}, {124, 125}, {124, 117}, {124, 101}, {104, 89}, {104, 81}, + {104, 73}, {104, 65}, {104, 49}, {104, 41}, {104, 33}, {104, 25}, + {104, 17}, {92, 9}, {80, 9}, {72, 9}, {64, 21}, {72, 25}, {80, 25}, + {80, 25}, {80, 41}, {88, 49}, {104, 57}, {124, 69}, {124, 77}, {132, 81}, + {140, 65}, {132, 61}, {124, 61}, {124, 53}, {124, 45}, {124, 37}, + {124, 29}, {132, 21}, {124, 21}, {120, 9}, {128, 9}, {136, 9}, {148, 9}, + {162, 9}, {156, 25}, {172, 21}, {180, 21}, {180, 29}, {172, 29}, + {172, 37}, {172, 45}, {180, 45}, {180, 37}, {188, 41}, {196, 49}, + {204, 57}, {212, 65}, {220, 73}, {228, 69}, {228, 77}, {236, 77}, + {236, 69}, {236, 61}, {228, 61}, {228, 53}, {236, 53}, {236, 45}, + {228, 45}, {228, 37}, {236, 37}, {236, 29}, {228, 29}, {228, 21}, + {236, 21}, {252, 21}, {260, 29}, {260, 37}, {260, 45}, {260, 53}, + {260, 61}, {260, 69}, {260, 77}, {276, 77}, {276, 69}, {276, 61}, + {276, 53}, {284, 53}, {284, 61}, {284, 69}, {284, 77}, {284, 85}, + {284, 93}, {284, 101}, {288, 109}, {280, 109}, {276, 101}, {276, 93}, + {276, 85}, {268, 97}, {260, 109}, {252, 101}, {260, 93}, {260, 85}, + {236, 85}, {228, 85}, {228, 93}, {236, 93}, {236, 101}, {228, 101}, + {228, 109}, {228, 117}, {228, 125}, {220, 125}, {212, 117}, {204, 109}, + {196, 101}, {188, 93}, {180, 93}, {180, 101}, {180, 109}, {180, 117}, + {180, 125}, {196, 145}, {204, 145}, {212, 145}, {220, 145}, {228, 145}, + {236, 145}, {246, 141}, {252, 125}, {260, 129}, {280, 133}, + }; + public int VehicleNumber = 1; + public int Depot = 0; + }; + // [END data_model] + + // [START euclidean_distance] + /// + /// Euclidean distance implemented as a callback. It uses an array of + /// positions and computes the Euclidean distance between the two + /// positions of two different indices. + /// + static long[,] ComputeEuclideanDistanceMatrix(in int[,] locations) { + // Calculate the distance matrix using Euclidean distance. + int locationNumber = locations.GetLength(0); + long[,] distanceMatrix = new long[locationNumber, locationNumber]; + for (int fromNode = 0; fromNode < locationNumber; fromNode++) { + for (int toNode = 0; toNode < locationNumber; toNode++) { + if (fromNode == toNode) + distanceMatrix[fromNode, toNode] = 0; + else + distanceMatrix[fromNode, toNode] = + (long)Math.Sqrt( + Math.Pow(locations[toNode, 0] - + locations[fromNode, 0], 2) + + Math.Pow(locations[toNode, 1] - + locations[fromNode, 1], 2) + ); + } + } + return distanceMatrix; + } + // [END euclidean_distance] + + // [START solution_printer] + /// + /// Print the solution. + /// + static void PrintSolution( + in RoutingModel routing, + in RoutingIndexManager manager, + in Assignment solution) { + Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); + // Inspect solution. + Console.WriteLine("Route:"); + long routeDistance = 0; + var index = routing.Start(0); + while (routing.IsEnd(index) == false) { + Console.Write("{0} -> ", manager.IndexToNode((int)index)); + var previousIndex = index; + index = solution.Value(routing.NextVar(index)); + routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); + } + Console.WriteLine("{0}", manager.IndexToNode((int)index)); + Console.WriteLine("Route distance: {0}m", routeDistance); + } + // [END solution_printer] + + public static void Main(String[] args) { + // Instantiate the data problem. + // [START data] + DataModel data = new DataModel(); + // [END data] + + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager = new RoutingIndexManager( + data.Locations.GetLength(0), + data.VehicleNumber, + data.Depot); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START transit_callback] + long[,] distanceMatrix = ComputeEuclideanDistanceMatrix(data.Locations); + int transitCallbackIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + // Convert from routing variable Index to distance matrix NodeIndex. + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return distanceMatrix[fromNode, toNode]; } + ); + // [END transit_callback] + + // [START arc_cost + routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); + // [END arc_cost] + + // Setting first solution heuristic. + // [START parameters] + RoutingSearchParameters searchParameters = + operations_research_constraint_solver.DefaultRoutingSearchParameters(); + searchParameters.FirstSolutionStrategy = + FirstSolutionStrategy.Types.Value.PathCheapestArc; + // [END parameters] + + // Solve the problem. + // [START solve] + Assignment solution = routing.SolveWithParameters(searchParameters); + // [END solve] + + // Print solution on console. + // [START print_solution] + PrintSolution(routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/TspCircuitBoard.csproj b/ortools/constraint_solver/samples/TspCircuitBoard.csproj new file mode 100644 index 0000000000..a5beab7657 --- /dev/null +++ b/ortools/constraint_solver/samples/TspCircuitBoard.csproj @@ -0,0 +1,20 @@ + + + Exe + 7.2 + netcoreapp2.1 + false + ../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json + + + + full + true + true + + + + + + + diff --git a/ortools/constraint_solver/samples/TspCircuitBoard.java b/ortools/constraint_solver/samples/TspCircuitBoard.java new file mode 100644 index 0000000000..7ecb4d46e1 --- /dev/null +++ b/ortools/constraint_solver/samples/TspCircuitBoard.java @@ -0,0 +1,177 @@ +// Copyright 2010-2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START program] +// [START import] + +import com.google.ortools.constraintsolver.Assignment; +import com.google.ortools.constraintsolver.FirstSolutionStrategy; +import com.google.ortools.constraintsolver.RoutingIndexManager; +import com.google.ortools.constraintsolver.RoutingModel; +import com.google.ortools.constraintsolver.RoutingSearchParameters; +import com.google.ortools.constraintsolver.main; +import java.util.logging.Logger; + +// [END import] + +/** Minimal TSP. */ +public class TspCircuitBoard { + static { + System.loadLibrary("jniortools"); + } + + private static final Logger logger = Logger.getLogger(TspCircuitBoard.class.getName()); + + // [START data_model] + static class DataModel { + public final int[][] locations = {{288, 149}, {288, 129}, {270, 133}, {256, 141}, {256, 157}, + {246, 157}, {236, 169}, {228, 169}, {228, 161}, {220, 169}, {212, 169}, {204, 169}, + {196, 169}, {188, 169}, {196, 161}, {188, 145}, {172, 145}, {164, 145}, {156, 145}, + {148, 145}, {140, 145}, {148, 169}, {164, 169}, {172, 169}, {156, 169}, {140, 169}, + {132, 169}, {124, 169}, {116, 161}, {104, 153}, {104, 161}, {104, 169}, {90, 165}, + {80, 157}, {64, 157}, {64, 165}, {56, 169}, {56, 161}, {56, 153}, {56, 145}, {56, 137}, + {56, 129}, {56, 121}, {40, 121}, {40, 129}, {40, 137}, {40, 145}, {40, 153}, {40, 161}, + {40, 169}, {32, 169}, {32, 161}, {32, 153}, {32, 145}, {32, 137}, {32, 129}, {32, 121}, + {32, 113}, {40, 113}, {56, 113}, {56, 105}, {48, 99}, {40, 99}, {32, 97}, {32, 89}, + {24, 89}, {16, 97}, {16, 109}, {8, 109}, {8, 97}, {8, 89}, {8, 81}, {8, 73}, {8, 65}, + {8, 57}, {16, 57}, {8, 49}, {8, 41}, {24, 45}, {32, 41}, {32, 49}, {32, 57}, {32, 65}, + {32, 73}, {32, 81}, {40, 83}, {40, 73}, {40, 63}, {40, 51}, {44, 43}, {44, 35}, {44, 27}, + {32, 25}, {24, 25}, {16, 25}, {16, 17}, {24, 17}, {32, 17}, {44, 11}, {56, 9}, {56, 17}, + {56, 25}, {56, 33}, {56, 41}, {64, 41}, {72, 41}, {72, 49}, {56, 49}, {48, 51}, {56, 57}, + {56, 65}, {48, 63}, {48, 73}, {56, 73}, {56, 81}, {48, 83}, {56, 89}, {56, 97}, {104, 97}, + {104, 105}, {104, 113}, {104, 121}, {104, 129}, {104, 137}, {104, 145}, {116, 145}, + {124, 145}, {132, 145}, {132, 137}, {140, 137}, {148, 137}, {156, 137}, {164, 137}, + {172, 125}, {172, 117}, {172, 109}, {172, 101}, {172, 93}, {172, 85}, {180, 85}, {180, 77}, + {180, 69}, {180, 61}, {180, 53}, {172, 53}, {172, 61}, {172, 69}, {172, 77}, {164, 81}, + {148, 85}, {124, 85}, {124, 93}, {124, 109}, {124, 125}, {124, 117}, {124, 101}, {104, 89}, + {104, 81}, {104, 73}, {104, 65}, {104, 49}, {104, 41}, {104, 33}, {104, 25}, {104, 17}, + {92, 9}, {80, 9}, {72, 9}, {64, 21}, {72, 25}, {80, 25}, {80, 25}, {80, 41}, {88, 49}, + {104, 57}, {124, 69}, {124, 77}, {132, 81}, {140, 65}, {132, 61}, {124, 61}, {124, 53}, + {124, 45}, {124, 37}, {124, 29}, {132, 21}, {124, 21}, {120, 9}, {128, 9}, {136, 9}, + {148, 9}, {162, 9}, {156, 25}, {172, 21}, {180, 21}, {180, 29}, {172, 29}, {172, 37}, + {172, 45}, {180, 45}, {180, 37}, {188, 41}, {196, 49}, {204, 57}, {212, 65}, {220, 73}, + {228, 69}, {228, 77}, {236, 77}, {236, 69}, {236, 61}, {228, 61}, {228, 53}, {236, 53}, + {236, 45}, {228, 45}, {228, 37}, {236, 37}, {236, 29}, {228, 29}, {228, 21}, {236, 21}, + {252, 21}, {260, 29}, {260, 37}, {260, 45}, {260, 53}, {260, 61}, {260, 69}, {260, 77}, + {276, 77}, {276, 69}, {276, 61}, {276, 53}, {284, 53}, {284, 61}, {284, 69}, {284, 77}, + {284, 85}, {284, 93}, {284, 101}, {288, 109}, {280, 109}, {276, 101}, {276, 93}, {276, 85}, + {268, 97}, {260, 109}, {252, 101}, {260, 93}, {260, 85}, {236, 85}, {228, 85}, {228, 93}, + {236, 93}, {236, 101}, {228, 101}, {228, 109}, {228, 117}, {228, 125}, {220, 125}, + {212, 117}, {204, 109}, {196, 101}, {188, 93}, {180, 93}, {180, 101}, {180, 109}, + {180, 117}, {180, 125}, {196, 145}, {204, 145}, {212, 145}, {220, 145}, {228, 145}, + {236, 145}, {246, 141}, {252, 125}, {260, 129}, {280, 133}}; + public final int vehicleNumber = 1; + public final int depot = 0; + } + // [END data_model] + + // [START euclidean_distance] + /// @brief Compute Euclidean distance matrix from locations array. + /// @details It uses an array of locations and computes + /// the Euclidean distance between any two locations. + private static long[][] computeEuclideanDistanceMatrix(int[][] locations) { + // Calculate distance matrix using Euclidean distance. + long[][] distanceMatrix = new long[locations.length][locations.length]; + for (int fromNode = 0; fromNode < locations.length; ++fromNode) { + for (int toNode = 0; toNode < locations.length; ++toNode) { + if (fromNode == toNode) { + distanceMatrix[fromNode][toNode] = 0; + } else { + distanceMatrix[fromNode][toNode] = + (long) Math.hypot(locations[toNode][0] - locations[fromNode][0], + locations[toNode][1] - locations[fromNode][1]); + } + } + } + return distanceMatrix; + } + // [END euclidean_distance] + + // [START solution_printer] + /// @brief Print the solution. + static void printSolution( + DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) { + // Solution cost. + logger.info("Objective: " + solution.objectiveValue()); + // Inspect solution. + logger.info("Route:"); + long routeDistance = 0; + String route = ""; + long index = routing.start(0); + while (!routing.isEnd(index)) { + route += manager.indexToNode(index) + " -> "; + long previousIndex = index; + index = solution.value(routing.nextVar(index)); + routing.getArcCostForVehicle(previousIndex, index, 0); + } + route += manager.indexToNode(routing.end(0)); + logger.info(route); + logger.info("Route distance: " + routeDistance); + } + // [END solution_printer] + + public static void main(String[] args) throws Exception { + // Instantiate the data problem. + // [START data] + final DataModel data = new DataModel(); + // [END data] + + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager = + new RoutingIndexManager(data.locations.length, data.vehicleNumber, data.depot); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Create and register a transit callback. + // [START transit_callback] + final long[][] distanceMatrix = computeEuclideanDistanceMatrix(data.locations); + final int transitCallbackIndex = + routing.registerTransitCallback((long fromIndex, long toIndex) -> { + // Convert from routing variable Index to user NodeIndex. + int fromNode = manager.indexToNode(fromIndex); + int toNode = manager.indexToNode(toIndex); + return distanceMatrix[fromNode][toNode]; + }); + // [END transit_callback] + + // Define cost of each arc. + // [START arc_cost] + routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex); + // [END arc_cost] + + // Setting first solution heuristic. + // [START parameters] + RoutingSearchParameters searchParameters = + main.defaultRoutingSearchParameters() + .toBuilder() + .setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC) + .build(); + // [END parameters] + + // Solve the problem. + // [START solve] + Assignment solution = routing.solveWithParameters(searchParameters); + // [END solve] + + // Print solution on console. + // [START print_solution] + printSolution(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/TspCities.cs b/ortools/constraint_solver/samples/TspCities.cs new file mode 100644 index 0000000000..48a2a5bc3b --- /dev/null +++ b/ortools/constraint_solver/samples/TspCities.cs @@ -0,0 +1,124 @@ +// Copyright 2010-2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START program] +// [START import] +using System; +using System.Collections.Generic; +using Google.OrTools.ConstraintSolver; +// [END import] + +/// +/// Minimal TSP using distance matrix. +/// +public class TspCities { + // [START data_model] + class DataModel { + public long[,] DistanceMatrix = { + {0, 2451, 713, 1018, 1631, 1374, 2408, 213, 2571, 875, 1420, 2145, 1972}, + {2451, 0, 1745, 1524, 831, 1240, 959, 2596, 403, 1589, 1374, 357, 579}, + {713, 1745, 0, 355, 920, 803, 1737, 851, 1858, 262, 940, 1453, 1260}, + {1018, 1524, 355, 0, 700, 862, 1395, 1123, 1584, 466, 1056, 1280, 987}, + {1631, 831, 920, 700, 0, 663, 1021, 1769, 949, 796, 879, 586, 371}, + {1374, 1240, 803, 862, 663, 0, 1681, 1551, 1765, 547, 225, 887, 999}, + {2408, 959, 1737, 1395, 1021, 1681, 0, 2493, 678, 1724, 1891, 1114, 701}, + {213, 2596, 851, 1123, 1769, 1551, 2493, 0, 2699, 1038, 1605, 2300, 2099}, + {2571, 403, 1858, 1584, 949, 1765, 678, 2699, 0, 1744, 1645, 653, 600}, + {875, 1589, 262, 466, 796, 547, 1724, 1038, 1744, 0, 679, 1272, 1162}, + {1420, 1374, 940, 1056, 879, 225, 1891, 1605, 1645, 679, 0, 1017, 1200}, + {2145, 357, 1453, 1280, 586, 887, 1114, 2300, 653, 1272, 1017, 0, 504}, + {1972, 579, 1260, 987, 371, 999, 701, 2099, 600, 1162, 1200, 504, 0}, + }; + public int VehicleNumber = 1; + public int Depot = 0; + }; + // [END data_model] + + // [START solution_printer] + /// + /// Print the solution. + /// + static void PrintSolution( + in RoutingModel routing, + in RoutingIndexManager manager, + in Assignment solution) { + Console.WriteLine("Objective: {0} miles", solution.ObjectiveValue()); + // Inspect solution. + Console.WriteLine("Route:"); + long routeDistance = 0; + var index = routing.Start(0); + while (routing.IsEnd(index) == false) { + Console.Write("{0} -> ", manager.IndexToNode((int)index)); + var previousIndex = index; + index = solution.Value(routing.NextVar(index)); + routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); + } + Console.WriteLine("{0}", manager.IndexToNode((int)index)); + Console.WriteLine("Route distance: {0}miles", routeDistance); + } + // [END solution_printer] + + public static void Main(String[] args) { + // Instantiate the data problem. + // [START data] + DataModel data = new DataModel(); + // [END data] + + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager = new RoutingIndexManager( + data.DistanceMatrix.GetLength(0), + data.VehicleNumber, + data.Depot); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // [START transit_callback] + int transitCallbackIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + // Convert from routing variable Index to distance matrix NodeIndex. + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.DistanceMatrix[fromNode, toNode]; } + ); + // [END transit_callback] + + // Define cost of each arc. + // [START arc_cost] + routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); + // [END arc_cost] + + // Setting first solution heuristic. + // [START parameters] + RoutingSearchParameters searchParameters = + operations_research_constraint_solver.DefaultRoutingSearchParameters(); + searchParameters.FirstSolutionStrategy = + FirstSolutionStrategy.Types.Value.PathCheapestArc; + // [END parameters] + + // Solve the problem. + // [START solve] + Assignment solution = routing.SolveWithParameters(searchParameters); + // [END solve] + + // Print solution on console. + // [START print_solution] + PrintSolution(routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/TspCities.csproj b/ortools/constraint_solver/samples/TspCities.csproj new file mode 100644 index 0000000000..696d466ad0 --- /dev/null +++ b/ortools/constraint_solver/samples/TspCities.csproj @@ -0,0 +1,20 @@ + + + Exe + 7.2 + netcoreapp2.1 + false + ../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json + + + + full + true + true + + + + + + + diff --git a/ortools/constraint_solver/samples/TspCities.java b/ortools/constraint_solver/samples/TspCities.java new file mode 100644 index 0000000000..ca36c7a88a --- /dev/null +++ b/ortools/constraint_solver/samples/TspCities.java @@ -0,0 +1,132 @@ +// Copyright 2010-2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START program] +// [START import] +import com.google.ortools.constraintsolver.Assignment; +import com.google.ortools.constraintsolver.FirstSolutionStrategy; +import com.google.ortools.constraintsolver.RoutingIndexManager; +import com.google.ortools.constraintsolver.RoutingModel; +import com.google.ortools.constraintsolver.RoutingSearchParameters; +import com.google.ortools.constraintsolver.main; +import java.util.logging.Logger; + +// [END import] + +/** Minimal TSP using distance matrix. */ +public class TspCities { + static { + System.loadLibrary("jniortools"); + } + + private static final Logger logger = Logger.getLogger(TspCities.class.getName()); + + // [START data_model] + static class DataModel { + public final long[][] distanceMatrix = { + {0, 2451, 713, 1018, 1631, 1374, 2408, 213, 2571, 875, 1420, 2145, 1972}, + {2451, 0, 1745, 1524, 831, 1240, 959, 2596, 403, 1589, 1374, 357, 579}, + {713, 1745, 0, 355, 920, 803, 1737, 851, 1858, 262, 940, 1453, 1260}, + {1018, 1524, 355, 0, 700, 862, 1395, 1123, 1584, 466, 1056, 1280, 987}, + {1631, 831, 920, 700, 0, 663, 1021, 1769, 949, 796, 879, 586, 371}, + {1374, 1240, 803, 862, 663, 0, 1681, 1551, 1765, 547, 225, 887, 999}, + {2408, 959, 1737, 1395, 1021, 1681, 0, 2493, 678, 1724, 1891, 1114, 701}, + {213, 2596, 851, 1123, 1769, 1551, 2493, 0, 2699, 1038, 1605, 2300, 2099}, + {2571, 403, 1858, 1584, 949, 1765, 678, 2699, 0, 1744, 1645, 653, 600}, + {875, 1589, 262, 466, 796, 547, 1724, 1038, 1744, 0, 679, 1272, 1162}, + {1420, 1374, 940, 1056, 879, 225, 1891, 1605, 1645, 679, 0, 1017, 1200}, + {2145, 357, 1453, 1280, 586, 887, 1114, 2300, 653, 1272, 1017, 0, 504}, + {1972, 579, 1260, 987, 371, 999, 701, 2099, 600, 1162, 1200, 504, 0}, + }; + public final int vehicleNumber = 1; + public final int depot = 0; + } + // [END data_model] + + // [START solution_printer] + /// @brief Print the solution. + static void printSolution( + DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) { + // Solution cost. + logger.info("Objective: " + solution.objectiveValue() + "miles"); + // Inspect solution. + logger.info("Route:"); + long routeDistance = 0; + String route = ""; + long index = routing.start(0); + while (!routing.isEnd(index)) { + route += manager.indexToNode(index) + " -> "; + long previousIndex = index; + index = solution.value(routing.nextVar(index)); + routeDistance += routing.getArcCostForVehicle(previousIndex, index, 0); + } + route += manager.indexToNode(routing.end(0)); + logger.info(route); + logger.info("Route distance: " + routeDistance + "miles"); + } + // [END solution_printer] + + public static void main(String[] args) throws Exception { + // Instantiate the data problem. + // [START data] + final DataModel data = new DataModel(); + // [END data] + + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager = + new RoutingIndexManager(data.distanceMatrix.length, data.vehicleNumber, data.depot); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Create and register a transit callback. + // [START transit_callback] + final int transitCallbackIndex = + routing.registerTransitCallback((long fromIndex, long toIndex) -> { + // Convert from routing variable Index to user NodeIndex. + int fromNode = manager.indexToNode(fromIndex); + int toNode = manager.indexToNode(toIndex); + return data.distanceMatrix[fromNode][toNode]; + }); + // [END transit_callback] + + // Define cost of each arc. + // [START arc_cost] + routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex); + // [END arc_cost] + + // Setting first solution heuristic. + // [START parameters] + RoutingSearchParameters searchParameters = + main.defaultRoutingSearchParameters() + .toBuilder() + .setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC) + .build(); + // [END parameters] + + // Solve the problem. + // [START solve] + Assignment solution = routing.solveWithParameters(searchParameters); + // [END solve] + + // Print solution on console. + // [START print_solution] + printSolution(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/tsp_circuit_board.cc b/ortools/constraint_solver/samples/tsp_circuit_board.cc new file mode 100644 index 0000000000..174c89a9d8 --- /dev/null +++ b/ortools/constraint_solver/samples/tsp_circuit_board.cc @@ -0,0 +1,175 @@ +// Copyright 2010-2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START program] +// [START import] +#include +#include +#include "ortools/constraint_solver/routing.h" +#include "ortools/constraint_solver/routing_enums.pb.h" +#include "ortools/constraint_solver/routing_index_manager.h" +#include "ortools/constraint_solver/routing_parameters.h" +// [END import] + +namespace operations_research { +// [START distance_matrix] +// @brief Generate distance matrix. +std::vector> GenerateDistanceMatrix( + const std::vector>& locations) { + std::vector> distances = std::vector>( + locations.size(), std::vector(locations.size(), int64{0})); + for (int fromNode = 0; fromNode < locations.size(); fromNode++) { + for (int toNode = 0; toNode < locations.size(); toNode++) { + if (fromNode != toNode) + distances[fromNode][toNode] = static_cast( + std::hypot((locations[toNode][0] - locations[fromNode][0]), + (locations[toNode][1] - locations[fromNode][1]))); + } + } + return distances; +} +// [END distance_matrix] + +// [START solution_printer] +//! @brief Print the solution +//! @param[in] manager Index manager used. +//! @param[in] routing Routing solver used. +//! @param[in] solution Solution found by the solver. +void PrintSolution(const RoutingIndexManager& manager, + const RoutingModel& routing, const Assignment& solution) { + LOG(INFO) << "Objective: " << solution.ObjectiveValue(); + // Inspect solution. + int64 index = routing.Start(0); + LOG(INFO) << "Route:"; + int64 distance{0}; + std::stringstream route; + while (routing.IsEnd(index) == false) { + route << manager.IndexToNode(index).value() << " -> "; + int64 previous_index = index; + index = solution.Value(routing.NextVar(index)); + distance += const_cast(routing).GetArcCostForVehicle( + previous_index, index, int64{0}); + } + LOG(INFO) << route.str() << manager.IndexToNode(index).value(); + LOG(INFO) << "Route distance: " << distance << "miles"; + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << routing.solver()->wall_time() << "ms"; +} +// [END solution_printer] + +void Tsp() { + // Instantiate the data problem. + // [START data] + const std::vector> locations = { + {288, 149}, {288, 129}, {270, 133}, {256, 141}, {256, 157}, {246, 157}, + {236, 169}, {228, 169}, {228, 161}, {220, 169}, {212, 169}, {204, 169}, + {196, 169}, {188, 169}, {196, 161}, {188, 145}, {172, 145}, {164, 145}, + {156, 145}, {148, 145}, {140, 145}, {148, 169}, {164, 169}, {172, 169}, + {156, 169}, {140, 169}, {132, 169}, {124, 169}, {116, 161}, {104, 153}, + {104, 161}, {104, 169}, {90, 165}, {80, 157}, {64, 157}, {64, 165}, + {56, 169}, {56, 161}, {56, 153}, {56, 145}, {56, 137}, {56, 129}, + {56, 121}, {40, 121}, {40, 129}, {40, 137}, {40, 145}, {40, 153}, + {40, 161}, {40, 169}, {32, 169}, {32, 161}, {32, 153}, {32, 145}, + {32, 137}, {32, 129}, {32, 121}, {32, 113}, {40, 113}, {56, 113}, + {56, 105}, {48, 99}, {40, 99}, {32, 97}, {32, 89}, {24, 89}, + {16, 97}, {16, 109}, {8, 109}, {8, 97}, {8, 89}, {8, 81}, + {8, 73}, {8, 65}, {8, 57}, {16, 57}, {8, 49}, {8, 41}, + {24, 45}, {32, 41}, {32, 49}, {32, 57}, {32, 65}, {32, 73}, + {32, 81}, {40, 83}, {40, 73}, {40, 63}, {40, 51}, {44, 43}, + {44, 35}, {44, 27}, {32, 25}, {24, 25}, {16, 25}, {16, 17}, + {24, 17}, {32, 17}, {44, 11}, {56, 9}, {56, 17}, {56, 25}, + {56, 33}, {56, 41}, {64, 41}, {72, 41}, {72, 49}, {56, 49}, + {48, 51}, {56, 57}, {56, 65}, {48, 63}, {48, 73}, {56, 73}, + {56, 81}, {48, 83}, {56, 89}, {56, 97}, {104, 97}, {104, 105}, + {104, 113}, {104, 121}, {104, 129}, {104, 137}, {104, 145}, {116, 145}, + {124, 145}, {132, 145}, {132, 137}, {140, 137}, {148, 137}, {156, 137}, + {164, 137}, {172, 125}, {172, 117}, {172, 109}, {172, 101}, {172, 93}, + {172, 85}, {180, 85}, {180, 77}, {180, 69}, {180, 61}, {180, 53}, + {172, 53}, {172, 61}, {172, 69}, {172, 77}, {164, 81}, {148, 85}, + {124, 85}, {124, 93}, {124, 109}, {124, 125}, {124, 117}, {124, 101}, + {104, 89}, {104, 81}, {104, 73}, {104, 65}, {104, 49}, {104, 41}, + {104, 33}, {104, 25}, {104, 17}, {92, 9}, {80, 9}, {72, 9}, + {64, 21}, {72, 25}, {80, 25}, {80, 25}, {80, 41}, {88, 49}, + {104, 57}, {124, 69}, {124, 77}, {132, 81}, {140, 65}, {132, 61}, + {124, 61}, {124, 53}, {124, 45}, {124, 37}, {124, 29}, {132, 21}, + {124, 21}, {120, 9}, {128, 9}, {136, 9}, {148, 9}, {162, 9}, + {156, 25}, {172, 21}, {180, 21}, {180, 29}, {172, 29}, {172, 37}, + {172, 45}, {180, 45}, {180, 37}, {188, 41}, {196, 49}, {204, 57}, + {212, 65}, {220, 73}, {228, 69}, {228, 77}, {236, 77}, {236, 69}, + {236, 61}, {228, 61}, {228, 53}, {236, 53}, {236, 45}, {228, 45}, + {228, 37}, {236, 37}, {236, 29}, {228, 29}, {228, 21}, {236, 21}, + {252, 21}, {260, 29}, {260, 37}, {260, 45}, {260, 53}, {260, 61}, + {260, 69}, {260, 77}, {276, 77}, {276, 69}, {276, 61}, {276, 53}, + {284, 53}, {284, 61}, {284, 69}, {284, 77}, {284, 85}, {284, 93}, + {284, 101}, {288, 109}, {280, 109}, {276, 101}, {276, 93}, {276, 85}, + {268, 97}, {260, 109}, {252, 101}, {260, 93}, {260, 85}, {236, 85}, + {228, 85}, {228, 93}, {236, 93}, {236, 101}, {228, 101}, {228, 109}, + {228, 117}, {228, 125}, {220, 125}, {212, 117}, {204, 109}, {196, 101}, + {188, 93}, {180, 93}, {180, 101}, {180, 109}, {180, 117}, {180, 125}, + {196, 145}, {204, 145}, {212, 145}, {220, 145}, {228, 145}, {236, 145}, + {246, 141}, {252, 125}, {260, 129}, {280, 133}, + }; + const int num_vehicles(1); + const RoutingIndexManager::NodeIndex depot(0); + // [END data] + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager(locations.size(), num_vehicles, depot); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing(manager); + // [END routing_model] + + // [START transit_callback] + const auto distance_matrix = GenerateDistanceMatrix(locations); + const int transit_callback_index = routing.RegisterTransitCallback( + [&distance_matrix, &manager](int64 from_index, int64 to_index) -> int64 { + // Convert from routing variable Index to distance matrix NodeIndex. + auto from_node = manager.IndexToNode(from_index).value(); + auto to_node = manager.IndexToNode(to_index).value(); + return distance_matrix[from_node][to_node]; + }); + // [End transit_callback] + + // Define cost of each arc. + // [START arc_cost] + routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index); + // [END arc_cost] + + // Setting first solution heuristic. + // [START parameters] + RoutingSearchParameters searchParameters = DefaultRoutingSearchParameters(); + searchParameters.set_first_solution_strategy( + FirstSolutionStrategy::PATH_CHEAPEST_ARC); + // [END parameters] + + // Solve the problem. + // [START solve] + const Assignment* solution = routing.SolveWithParameters(searchParameters); + // [END solve] + + // Print solution on console. + // [START print_solution] + PrintSolution(manager, routing, *solution); + // [END print_solution] +} +} // namespace operations_research + +int main(int argc, char** argv) { + operations_research::Tsp(); + return EXIT_SUCCESS; +} +// [END program] diff --git a/ortools/constraint_solver/samples/tsp_circuit_board.py b/ortools/constraint_solver/samples/tsp_circuit_board.py new file mode 100644 index 0000000000..ae766b1d66 --- /dev/null +++ b/ortools/constraint_solver/samples/tsp_circuit_board.py @@ -0,0 +1,410 @@ +# Copyright 2010-2018 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# [START program] +"""Simple travelling salesman problem on a circuit board.""" + +# [START import] +from __future__ import print_function +import math +from ortools.constraint_solver import routing_enums_pb2 +from ortools.constraint_solver import pywrapcp +# [END import] + + +# [START data_model] +def create_data_model(): + """Stores the data for the problem.""" + data = {} + # Locations in block units + data['locations'] = [ + [288, 149], + [288, 129], + [270, 133], + [256, 141], + [256, 157], + [246, 157], + [236, 169], + [228, 169], + [228, 161], + [220, 169], + [212, 169], + [204, 169], + [196, 169], + [188, 169], + [196, 161], + [188, 145], + [172, 145], + [164, 145], + [156, 145], + [148, 145], + [140, 145], + [148, 169], + [164, 169], + [172, 169], + [156, 169], + [140, 169], + [132, 169], + [124, 169], + [116, 161], + [104, 153], + [104, 161], + [104, 169], + [90, 165], + [80, 157], + [64, 157], + [64, 165], + [56, 169], + [56, 161], + [56, 153], + [56, 145], + [56, 137], + [56, 129], + [56, 121], + [40, 121], + [40, 129], + [40, 137], + [40, 145], + [40, 153], + [40, 161], + [40, 169], + [32, 169], + [32, 161], + [32, 153], + [32, 145], + [32, 137], + [32, 129], + [32, 121], + [32, 113], + [40, 113], + [56, 113], + [56, 105], + [48, 99], + [40, 99], + [32, 97], + [32, 89], + [24, 89], + [16, 97], + [16, 109], + [8, 109], + [8, 97], + [8, 89], + [8, 81], + [8, 73], + [8, 65], + [8, 57], + [16, 57], + [8, 49], + [8, 41], + [24, 45], + [32, 41], + [32, 49], + [32, 57], + [32, 65], + [32, 73], + [32, 81], + [40, 83], + [40, 73], + [40, 63], + [40, 51], + [44, 43], + [44, 35], + [44, 27], + [32, 25], + [24, 25], + [16, 25], + [16, 17], + [24, 17], + [32, 17], + [44, 11], + [56, 9], + [56, 17], + [56, 25], + [56, 33], + [56, 41], + [64, 41], + [72, 41], + [72, 49], + [56, 49], + [48, 51], + [56, 57], + [56, 65], + [48, 63], + [48, 73], + [56, 73], + [56, 81], + [48, 83], + [56, 89], + [56, 97], + [104, 97], + [104, 105], + [104, 113], + [104, 121], + [104, 129], + [104, 137], + [104, 145], + [116, 145], + [124, 145], + [132, 145], + [132, 137], + [140, 137], + [148, 137], + [156, 137], + [164, 137], + [172, 125], + [172, 117], + [172, 109], + [172, 101], + [172, 93], + [172, 85], + [180, 85], + [180, 77], + [180, 69], + [180, 61], + [180, 53], + [172, 53], + [172, 61], + [172, 69], + [172, 77], + [164, 81], + [148, 85], + [124, 85], + [124, 93], + [124, 109], + [124, 125], + [124, 117], + [124, 101], + [104, 89], + [104, 81], + [104, 73], + [104, 65], + [104, 49], + [104, 41], + [104, 33], + [104, 25], + [104, 17], + [92, 9], + [80, 9], + [72, 9], + [64, 21], + [72, 25], + [80, 25], + [80, 25], + [80, 41], + [88, 49], + [104, 57], + [124, 69], + [124, 77], + [132, 81], + [140, 65], + [132, 61], + [124, 61], + [124, 53], + [124, 45], + [124, 37], + [124, 29], + [132, 21], + [124, 21], + [120, 9], + [128, 9], + [136, 9], + [148, 9], + [162, 9], + [156, 25], + [172, 21], + [180, 21], + [180, 29], + [172, 29], + [172, 37], + [172, 45], + [180, 45], + [180, 37], + [188, 41], + [196, 49], + [204, 57], + [212, 65], + [220, 73], + [228, 69], + [228, 77], + [236, 77], + [236, 69], + [236, 61], + [228, 61], + [228, 53], + [236, 53], + [236, 45], + [228, 45], + [228, 37], + [236, 37], + [236, 29], + [228, 29], + [228, 21], + [236, 21], + [252, 21], + [260, 29], + [260, 37], + [260, 45], + [260, 53], + [260, 61], + [260, 69], + [260, 77], + [276, 77], + [276, 69], + [276, 61], + [276, 53], + [284, 53], + [284, 61], + [284, 69], + [284, 77], + [284, 85], + [284, 93], + [284, 101], + [288, 109], + [280, 109], + [276, 101], + [276, 93], + [276, 85], + [268, 97], + [260, 109], + [252, 101], + [260, 93], + [260, 85], + [236, 85], + [228, 85], + [228, 93], + [236, 93], + [236, 101], + [228, 101], + [228, 109], + [228, 117], + [228, 125], + [220, 125], + [212, 117], + [204, 109], + [196, 101], + [188, 93], + [180, 93], + [180, 101], + [180, 109], + [180, 117], + [180, 125], + [196, 145], + [204, 145], + [212, 145], + [220, 145], + [228, 145], + [236, 145], + [246, 141], + [252, 125], + [260, 129], + [280, 133], + ] + data['num_vehicles'] = 1 + data['depot'] = 0 + return data + # [END data_model] + + +# [START distance_callback] +def compute_euclidean_distance_matrix(data): + """Creates callback to return distance between points.""" + distances = {} + for from_counter, from_node in enumerate(data['locations']): + distances[from_counter] = {} + for to_counter, to_node in enumerate(data['locations']): + if from_counter == to_counter: + distances[from_counter][to_counter] = 0 + else: + # Euclidean distance + distances[from_counter][to_counter] = (int( + math.hypot((from_node[0] - to_node[0]), + (from_node[1] - to_node[1])))) + return distances + # [END distance_callback] + + +# [START solution_printer] +def print_solution(manager, routing, assignment): + """Prints assignment on console.""" + print('Objective: {}'.format(assignment.ObjectiveValue())) + index = routing.Start(0) + plan_output = 'Route:\n' + route_distance = 0 + while not routing.IsEnd(index): + plan_output += ' {} ->'.format(manager.IndexToNode(index)) + previous_index = index + index = assignment.Value(routing.NextVar(index)) + route_distance += routing.GetArcCostForVehicle(previous_index, index, 0) + plan_output += ' {}\n'.format(manager.IndexToNode(index)) + print(plan_output) + plan_output += 'Objective: {}m\n'.format(route_distance) + # [END solution_printer] + + +def main(): + """Entry point of the program.""" + # Instantiate the data problem. + # [START data] + data = create_data_model() + # [END data] + + # Create the routing index manager. + # [START index_manager] + manager = pywrapcp.RoutingIndexManager( + len(data['locations']), data['num_vehicles'], data['depot']) + # [END index_manager] + + # Create Routing Model. + # [START routing_model] + routing = pywrapcp.RoutingModel(manager) + # [END routing_model] + + # [START transit_callback] + distance_matrix = compute_euclidean_distance_matrix(data) + + def distance_callback(from_index, to_index): + """Returns the distance between the two nodes.""" + # Convert from routing variable Index to distance matrix NodeIndex. + from_node = manager.IndexToNode(from_index) + to_node = manager.IndexToNode(to_index) + return distance_matrix[from_node][to_node] + + transit_callback_index = routing.RegisterTransitCallback(distance_callback) + # [END transit_callback] + + # Define cost of each arc. + # [START arc_cost] + routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index) + # [END arc_cost] + + # Setting first solution heuristic. + # [START parameters] + search_parameters = pywrapcp.DefaultRoutingSearchParameters() + search_parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) + # [END parameters] + + # Solve the problem. + # [START solve] + assignment = routing.SolveWithParameters(search_parameters) + # [END solve] + + # Print solution on console. + # [START print_solution] + if assignment: + print_solution(manager, routing, assignment) + # [END print_solution] + + +if __name__ == '__main__': + main() +# [END program] diff --git a/ortools/constraint_solver/samples/tsp_cities.cc b/ortools/constraint_solver/samples/tsp_cities.cc new file mode 100644 index 0000000000..a43a7e18ee --- /dev/null +++ b/ortools/constraint_solver/samples/tsp_cities.cc @@ -0,0 +1,124 @@ +// Copyright 2010-2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START program] +// [START import] +#include +#include +#include "ortools/constraint_solver/routing.h" +#include "ortools/constraint_solver/routing_enums.pb.h" +#include "ortools/constraint_solver/routing_index_manager.h" +#include "ortools/constraint_solver/routing_parameters.h" +// [END import] + +namespace operations_research { +// [START solution_printer] +//! @brief Print the solution. +//! @param[in] manager Index manager used. +//! @param[in] routing Routing solver used. +//! @param[in] solution Solution found by the solver. +void PrintSolution(const RoutingIndexManager& manager, + const RoutingModel& routing, const Assignment& solution) { + // Inspect solution. + LOG(INFO) << "Objective: " << solution.ObjectiveValue() << " miles"; + int64 index = routing.Start(0); + LOG(INFO) << "Route:"; + int64 distance{0}; + std::stringstream route; + while (routing.IsEnd(index) == false) { + route << manager.IndexToNode(index).value() << " -> "; + int64 previous_index = index; + index = solution.Value(routing.NextVar(index)); + distance += const_cast(routing).GetArcCostForVehicle( + previous_index, index, 0LL); + } + LOG(INFO) << route.str() << manager.IndexToNode(index).value(); + LOG(INFO) << "Route distance: " << distance << "miles"; + LOG(INFO) << ""; + LOG(INFO) << "Advanced usage:"; + LOG(INFO) << "Problem solved in " << routing.solver()->wall_time() << "ms"; +} +// [END solution_printer] + +void Tsp() { + // Instantiate the data problem. + // [START data] + const std::vector> distance_matrix = { + {0, 2451, 713, 1018, 1631, 1374, 2408, 213, 2571, 875, 1420, 2145, 1972}, + {2451, 0, 1745, 1524, 831, 1240, 959, 2596, 403, 1589, 1374, 357, 579}, + {713, 1745, 0, 355, 920, 803, 1737, 851, 1858, 262, 940, 1453, 1260}, + {1018, 1524, 355, 0, 700, 862, 1395, 1123, 1584, 466, 1056, 1280, 987}, + {1631, 831, 920, 700, 0, 663, 1021, 1769, 949, 796, 879, 586, 371}, + {1374, 1240, 803, 862, 663, 0, 1681, 1551, 1765, 547, 225, 887, 999}, + {2408, 959, 1737, 1395, 1021, 1681, 0, 2493, 678, 1724, 1891, 1114, 701}, + {213, 2596, 851, 1123, 1769, 1551, 2493, 0, 2699, 1038, 1605, 2300, 2099}, + {2571, 403, 1858, 1584, 949, 1765, 678, 2699, 0, 1744, 1645, 653, 600}, + {875, 1589, 262, 466, 796, 547, 1724, 1038, 1744, 0, 679, 1272, 1162}, + {1420, 1374, 940, 1056, 879, 225, 1891, 1605, 1645, 679, 0, 1017, 1200}, + {2145, 357, 1453, 1280, 586, 887, 1114, 2300, 653, 1272, 1017, 0, 504}, + {1972, 579, 1260, 987, 371, 999, 701, 2099, 600, 1162, 1200, 504, 0}, + }; + const int num_vehicles(1); + const RoutingIndexManager::NodeIndex depot(0); + // [END data] + + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager(distance_matrix.size(), num_vehicles, depot); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing(manager); + // [END routing_model] + + // [START transit_callback] + const int transit_callback_index = routing.RegisterTransitCallback( + [&distance_matrix, &manager](int64 from_index, int64 to_index) -> int64 { + // Convert from routing variable Index to distance matrix NodeIndex. + auto from_node = manager.IndexToNode(from_index).value(); + auto to_node = manager.IndexToNode(to_index).value(); + return distance_matrix[from_node][to_node]; + }); + // [END transit_callback] + + // Define cost of each arc. + // [START arc_cost] + routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index); + // [END arc_cost] + + // Setting first solution heuristic. + // [START parameters] + RoutingSearchParameters searchParameters = DefaultRoutingSearchParameters(); + searchParameters.set_first_solution_strategy( + FirstSolutionStrategy::PATH_CHEAPEST_ARC); + // [END parameters] + + // Solve the problem. + // [START solve] + const Assignment* solution = routing.SolveWithParameters(searchParameters); + // [END solve] + + // Print solution on console. + // [START print_solution] + PrintSolution(manager, routing, *solution); + // [END print_solution] +} + +} // namespace operations_research + +int main(int argc, char** argv) { + operations_research::Tsp(); + return EXIT_SUCCESS; +} +// [END program] diff --git a/ortools/constraint_solver/samples/tsp_cities.py b/ortools/constraint_solver/samples/tsp_cities.py new file mode 100644 index 0000000000..33c8a145c0 --- /dev/null +++ b/ortools/constraint_solver/samples/tsp_cities.py @@ -0,0 +1,131 @@ +# Copyright 2010-2018 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# [START program] +"""Simple travelling salesman problem between cities.""" + +# [START import] +from __future__ import print_function +from ortools.constraint_solver import routing_enums_pb2 +from ortools.constraint_solver import pywrapcp +# [END import] + + +# [START data_model] +def create_data_model(): + """Stores the data for the problem.""" + data = {} + data['distance_matrix'] = [ + [ + 0, 2451, 713, 1018, 1631, 1374, 2408, 213, 2571, 875, 1420, 2145, + 1972 + ], + [2451, 0, 1745, 1524, 831, 1240, 959, 2596, 403, 1589, 1374, 357, 579], + [713, 1745, 0, 355, 920, 803, 1737, 851, 1858, 262, 940, 1453, 1260], + [1018, 1524, 355, 0, 700, 862, 1395, 1123, 1584, 466, 1056, 1280, 987], + [1631, 831, 920, 700, 0, 663, 1021, 1769, 949, 796, 879, 586, 371], + [1374, 1240, 803, 862, 663, 0, 1681, 1551, 1765, 547, 225, 887, 999], + [ + 2408, 959, 1737, 1395, 1021, 1681, 0, 2493, 678, 1724, 1891, 1114, + 701 + ], + [ + 213, 2596, 851, 1123, 1769, 1551, 2493, 0, 2699, 1038, 1605, 2300, + 2099 + ], + [2571, 403, 1858, 1584, 949, 1765, 678, 2699, 0, 1744, 1645, 653, 600], + [875, 1589, 262, 466, 796, 547, 1724, 1038, 1744, 0, 679, 1272, 1162], + [1420, 1374, 940, 1056, 879, 225, 1891, 1605, 1645, 679, 0, 1017, 1200], + [2145, 357, 1453, 1280, 586, 887, 1114, 2300, 653, 1272, 1017, 0, 504], + [1972, 579, 1260, 987, 371, 999, 701, 2099, 600, 1162, 1200, 504, 0] + ] + data['num_vehicles'] = 1 + data['depot'] = 0 + return data + # [END data_model] + + +# [START solution_printer] +def print_solution(manager, routing, assignment): + """Prints assignment on console.""" + print('Objective: {} miles'.format(assignment.ObjectiveValue())) + index = routing.Start(0) + plan_output = 'Route for vehicle 0:\n' + route_distance = 0 + while not routing.IsEnd(index): + plan_output += ' {} ->'.format(manager.IndexToNode(index)) + previous_index = index + index = assignment.Value(routing.NextVar(index)) + route_distance += routing.GetArcCostForVehicle(previous_index, index, 0) + plan_output += ' {}\n'.format(manager.IndexToNode(index)) + print(plan_output) + plan_output += 'Route distance: {}miles\n'.format(route_distance) + # [END solution_printer] + + +def main(): + """Entry point of the program.""" + # Instantiate the data problem. + # [START data] + data = create_data_model() + # [END data] + + # Create the routing index manager. + # [START index_manager] + manager = pywrapcp.RoutingIndexManager( + len(data['distance_matrix']), data['num_vehicles'], data['depot']) + # [END index_manager] + + # Create Routing Model. + # [START routing_model] + routing = pywrapcp.RoutingModel(manager) + + # [END routing_model] + + # [START transit_callback] + def distance_callback(from_index, to_index): + """Returns the distance between the two nodes.""" + # Convert from routing variable Index to distance matrix NodeIndex. + from_node = manager.IndexToNode(from_index) + to_node = manager.IndexToNode(to_index) + return data['distance_matrix'][from_node][to_node] + + transit_callback_index = routing.RegisterTransitCallback(distance_callback) + # [END transit_callback] + + # Define cost of each arc. + # [START arc_cost] + routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index) + # [END arc_cost] + + # Setting first solution heuristic. + # [START parameters] + search_parameters = pywrapcp.DefaultRoutingSearchParameters() + search_parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) + # [END parameters] + + # Solve the problem. + # [START solve] + assignment = routing.SolveWithParameters(search_parameters) + # [END solve] + + # Print solution on console. + # [START print_solution] + if assignment: + print_solution(manager, routing, assignment) + # [END print_solution] + + +if __name__ == '__main__': + main() +# [END program]