From cd59b90650412103eefcd3b9b1486057192a42e6 Mon Sep 17 00:00:00 2001 From: Corentin Le Molgat Date: Wed, 9 Jan 2019 13:16:32 +0100 Subject: [PATCH] Add .Net routing samples --- makefiles/Makefile.dotnet.mk | 6 + .../samples/SimpleRoutingProgram.cs | 10 +- ortools/constraint_solver/samples/Tsp.cs | 114 +++++---- ortools/constraint_solver/samples/Tsp.csproj | 2 +- .../samples/TspDistanceMatrix.cs | 130 +++++++++++ .../samples/TspDistanceMatrix.csproj | 20 ++ ortools/constraint_solver/samples/Vrp.cs | 221 +++++++----------- ortools/constraint_solver/samples/Vrp.csproj | 2 +- .../constraint_solver/samples/VrpCapacity.cs | 162 +++++++++++++ .../samples/VrpCapacity.csproj | 20 ++ .../constraint_solver/samples/VrpDropNodes.cs | 180 ++++++++++++++ .../samples/VrpDropNodes.csproj | 20 ++ .../samples/VrpGlobalSpan.cs | 146 ++++++++++++ .../samples/VrpGlobalSpan.csproj | 20 ++ .../samples/VrpStartsEnds.cs | 152 ++++++++++++ .../samples/VrpStartsEnds.csproj | 20 ++ .../samples/VrpTimeWindows.cs | 200 ++++++++++++++++ .../samples/VrpTimeWindows.csproj | 20 ++ 18 files changed, 1253 insertions(+), 192 deletions(-) create mode 100644 ortools/constraint_solver/samples/TspDistanceMatrix.cs create mode 100644 ortools/constraint_solver/samples/TspDistanceMatrix.csproj create mode 100644 ortools/constraint_solver/samples/VrpCapacity.cs create mode 100644 ortools/constraint_solver/samples/VrpCapacity.csproj create mode 100644 ortools/constraint_solver/samples/VrpDropNodes.cs create mode 100644 ortools/constraint_solver/samples/VrpDropNodes.csproj create mode 100644 ortools/constraint_solver/samples/VrpGlobalSpan.cs create mode 100644 ortools/constraint_solver/samples/VrpGlobalSpan.csproj create mode 100644 ortools/constraint_solver/samples/VrpStartsEnds.cs create mode 100644 ortools/constraint_solver/samples/VrpStartsEnds.csproj create mode 100644 ortools/constraint_solver/samples/VrpTimeWindows.cs create mode 100644 ortools/constraint_solver/samples/VrpTimeWindows.csproj diff --git a/makefiles/Makefile.dotnet.mk b/makefiles/Makefile.dotnet.mk index d3a6fc4b46..ab98885cd2 100644 --- a/makefiles/Makefile.dotnet.mk +++ b/makefiles/Makefile.dotnet.mk @@ -522,7 +522,13 @@ 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/TspDistanceMatrix.cs $(MAKE) run SOURCE=ortools/constraint_solver/samples/Vrp.cs + $(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpCapacity.cs + $(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpDropNodes.cs + $(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpGlobalSpan.cs + $(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpStartsEnds.cs + $(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpTimeWindows.cs .PHONY: test_dotnet_graph_samples # Build and Run all .Net LP Samples (located in ortools/graph/samples) test_dotnet_graph_samples: ; diff --git a/ortools/constraint_solver/samples/SimpleRoutingProgram.cs b/ortools/constraint_solver/samples/SimpleRoutingProgram.cs index 89bd35629a..7973eaba7a 100644 --- a/ortools/constraint_solver/samples/SimpleRoutingProgram.cs +++ b/ortools/constraint_solver/samples/SimpleRoutingProgram.cs @@ -21,10 +21,7 @@ using Google.OrTools.ConstraintSolver; /// This is a sample using the routing library .Net wrapper. /// public class SimpleRoutingProgram { - /// - /// Solves the current routing problem. - /// - static void Solve() { + public static void Main(String[] args) { // Instantiate the data problem. // [START data] const int num_location = 5; @@ -81,8 +78,5 @@ public class SimpleRoutingProgram { Console.WriteLine("Distance of the route: {0}m", route_distance); // [END print_solution] } - - public static void Main(String[] args) { - Solve(); - } } +// [END program] diff --git a/ortools/constraint_solver/samples/Tsp.cs b/ortools/constraint_solver/samples/Tsp.cs index 8f9087fe6d..ac311dfe02 100644 --- a/ortools/constraint_solver/samples/Tsp.cs +++ b/ortools/constraint_solver/samples/Tsp.cs @@ -1,4 +1,4 @@ -// Copyright 2018 Google +// Copyright 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 @@ -11,22 +11,23 @@ // 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] /// -/// This is a sample using the routing library .Net wrapper to solve a TSP -/// problem. +/// Minimal TSP. /// A description of the problem can be found here: /// http://en.wikipedia.org/wiki/Travelling_salesman_problem. /// -public class TSP { - class DataProblem { - private int[,] locations_; - +public class Tsp { + // [START data_model] + class DataModel { // Constructor: - public DataProblem() { + public DataModel() { locations_ = new int[,] { {4, 4}, {2, 0}, {8, 0}, @@ -44,38 +45,36 @@ public class TSP { locations_[i, 1] *= 80; } } - public ref readonly int[,] GetLocations() { return ref locations_;} public int GetVehicleNumber() { return 1;} public int GetDepot() { return 0;} + + private int[,] locations_; }; + // [END data_model] - + // [START manhattan_distance] /// /// Manhattan distance implemented as a callback. It uses an array of /// positions and computes the Manhattan distance between the two /// positions of two different indices. /// class ManhattanDistance : LongLongToLong { - private int[,] distances_; - private RoutingIndexManager manager_; - - public ManhattanDistance(in DataProblem data, - in RoutingIndexManager manager) { + public ManhattanDistance( + in DataModel data, + in RoutingIndexManager manager) { // precompute distance between location to have distance callback in O(1) int locationNumber = data.GetLocations().GetLength(0); - distances_ = new int[locationNumber, locationNumber]; - manager_ = manager; + distancesMatrix_ = new long[locationNumber, locationNumber]; + indexManager_ = manager; for (int fromNode = 0; fromNode < locationNumber; fromNode++) { for (int toNode = 0; toNode < locationNumber; toNode++) { if (fromNode == toNode) - distances_[fromNode, toNode] = 0; + distancesMatrix_[fromNode, toNode] = 0; else - distances_[fromNode, toNode] = - Math.Abs(data.GetLocations()[toNode, 0] - - data.GetLocations()[fromNode, 0]) + - Math.Abs(data.GetLocations()[toNode, 1] - - data.GetLocations()[fromNode, 1]); + distancesMatrix_[fromNode, toNode] = + Math.Abs(data.GetLocations()[toNode, 0] - data.GetLocations()[fromNode, 0]) + + Math.Abs(data.GetLocations()[toNode, 1] - data.GetLocations()[fromNode, 1]); } } } @@ -84,67 +83,84 @@ public class TSP { /// Returns the manhattan distance between the two nodes /// public override long Run(long FromIndex, long ToIndex) { - int FromNode = manager_.IndexToNode(FromIndex); - int ToNode = manager_.IndexToNode(ToIndex); - return distances_[FromNode, ToNode]; + int FromNode = indexManager_.IndexToNode(FromIndex); + int ToNode = indexManager_.IndexToNode(ToIndex); + return distancesMatrix_[FromNode, ToNode]; } + private long[,] distancesMatrix_; + private RoutingIndexManager indexManager_; }; + // [END manhattan_distance] + // [START solution_printer] /// - /// Print the solution + /// Print the solution. /// static void PrintSolution( - in DataProblem data, in RoutingModel routing, in RoutingIndexManager manager, in Assignment solution) { Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); // Inspect solution. - var index = routing.Start(0); Console.WriteLine("Route for Vehicle 0:"); - long distance = 0; + 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)); - distance += routing.GetArcCostForVehicle(previousIndex, index, 0); + routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); } Console.WriteLine("{0}", manager.IndexToNode((int)index)); - Console.WriteLine("Distance of the route: {0}m", distance); + Console.WriteLine("Distance of the route: {0}m", routeDistance); } + // [END solution_printer] - /// - /// Solves the current routing problem. - /// - static void Solve() { + public static void Main(String[] args) { // Instantiate the data problem. - DataProblem data = new DataProblem(); + // [START data] + DataModel data = new DataModel(); + // [END data] - // Create Routing Model + // Create Routing Index Manager + // [START index_manager] RoutingIndexManager manager = new RoutingIndexManager( data.GetLocations().GetLength(0), data.GetVehicleNumber(), data.GetDepot()); - RoutingModel routing = new RoutingModel(manager); + // [END index_manager] - // Define weight of each edge + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] LongLongToLong distanceEvaluator = new ManhattanDistance(data, manager); //protect callbacks from the GC GC.KeepAlive(distanceEvaluator); - routing.SetArcCostEvaluatorOfAllVehicles( - routing.RegisterTransitCallback(distanceEvaluator)); + int transitCostIndex = routing.RegisterTransitCallback(distanceEvaluator); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [END arc_cost] - // Setting first solution heuristic (cheapest addition). + // Setting first solution heuristic. + // [START parameters] RoutingSearchParameters searchParameters = - operations_research_constraint_solver.DefaultRoutingSearchParameters(); + operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = - FirstSolutionStrategy.Types.Value.PathCheapestArc; + FirstSolutionStrategy.Types.Value.PathCheapestArc; + // [END parameters] + // Solve the problem. + // [START solve] Assignment solution = routing.SolveWithParameters(searchParameters); - PrintSolution(data, routing, manager, solution); - } + // [END solve] - public static void Main(String[] args) { - Solve(); + // Print solution on console. + // [START print_solution] + PrintSolution(routing, manager, solution); + // [END print_solution] } } +// [END program] diff --git a/ortools/constraint_solver/samples/Tsp.csproj b/ortools/constraint_solver/samples/Tsp.csproj index e8c4ced7b5..b9933418e9 100644 --- a/ortools/constraint_solver/samples/Tsp.csproj +++ b/ortools/constraint_solver/samples/Tsp.csproj @@ -15,6 +15,6 @@ - + diff --git a/ortools/constraint_solver/samples/TspDistanceMatrix.cs b/ortools/constraint_solver/samples/TspDistanceMatrix.cs new file mode 100644 index 0000000000..7ea80687b9 --- /dev/null +++ b/ortools/constraint_solver/samples/TspDistanceMatrix.cs @@ -0,0 +1,130 @@ +// Copyright 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 TspDistanceMatrix { + // [START data_model] + class DataModel { + // Constructor: + public DataModel() { + distancesMatrix_ = new long[,] { + {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662}, + {548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210}, + {776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754}, + {696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358}, + {582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244}, + {274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708}, + {502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480}, + {194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856}, + {308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514}, + {194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468}, + {536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354}, + {502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844}, + {388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730}, + {354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536}, + {468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194}, + {776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798}, + {662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0} + }; + } + public ref readonly long[,] GetDistanceMatrix() { return ref distancesMatrix_;} + public int GetVehicleNumber() { return 1;} + public int GetDepot() { return 0;} + + private long[,] distancesMatrix_; + }; + // [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}", solution.ObjectiveValue()); + // Inspect solution. + Console.WriteLine("Route for Vehicle 0:"); + 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("Distance of the route: {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.GetDistanceMatrix().GetLength(0), + data.GetVehicleNumber(), + data.GetDepot()); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] + int transitCostIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.GetDistanceMatrix()[fromNode, toNode]; } + ); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [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/TspDistanceMatrix.csproj b/ortools/constraint_solver/samples/TspDistanceMatrix.csproj new file mode 100644 index 0000000000..c938f27b96 --- /dev/null +++ b/ortools/constraint_solver/samples/TspDistanceMatrix.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/Vrp.cs b/ortools/constraint_solver/samples/Vrp.cs index d0eb3a61a9..f24c6c0ea6 100644 --- a/ortools/constraint_solver/samples/Vrp.cs +++ b/ortools/constraint_solver/samples/Vrp.cs @@ -1,4 +1,4 @@ -// Copyright 2018 Google +// Copyright 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 @@ -11,171 +11,126 @@ // 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] /// -/// This is a sample using the routing library .Net wrapper to solve a VRP problem. -/// A description of the problem can be found here: -/// http://en.wikipedia.org/wiki/Vehicle_routing_problem. +/// Minimal TSP using distance matrix. /// -public class VRP { - class DataProblem { - private int[,] locations_; - +public class Vrp { + // [START data_model] + class DataModel { // Constructor: - public DataProblem() { - locations_ = new int[,] { - {4, 4}, - {2, 0}, {8, 0}, - {0, 1}, {1, 1}, - {5, 2}, {7, 2}, - {3, 3}, {6, 3}, - {5, 5}, {8, 5}, - {1, 6}, {2, 6}, - {3, 7}, {6, 7}, - {0, 8}, {7, 8} + public DataModel() { + distancesMatrix_ = new long[,] { + {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662}, + {548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210}, + {776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754}, + {696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358}, + {582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244}, + {274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708}, + {502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480}, + {194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856}, + {308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514}, + {194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468}, + {536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354}, + {502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844}, + {388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730}, + {354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536}, + {468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194}, + {776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798}, + {662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0} }; - - // Compute locations in meters using the block dimension defined as follow - // Manhattan average block: 750ft x 264ft -> 228m x 80m - // here we use: 114m x 80m city block - // src: https://nyti.ms/2GDoRIe "NY Times: Know Your distance" - int[] cityBlock = {228/2, 80}; - for (int i=0; i < locations_.GetLength(0); i++) { - locations_[i, 0] = locations_[i, 0] * cityBlock[0]; - locations_[i, 1] = locations_[i, 1] * cityBlock[1]; - } } - + public ref readonly long[,] GetDistanceMatrix() { return ref distancesMatrix_;} public int GetVehicleNumber() { return 4;} - public ref readonly int[,] GetLocations() { return ref locations_;} - public int GetLocationNumber() { return locations_.GetLength(0);} public int GetDepot() { return 0;} + + private long[,] distancesMatrix_; }; + // [END data_model] - + // [START solution_printer] /// - /// Manhattan distance implemented as a callback. It uses an array of - /// positions and computes the Manhattan distance between the two - /// positions of two different indices. - /// - class ManhattanDistance : LongLongToLong { - private int[,] distances_; - private RoutingIndexManager manager_; - - public ManhattanDistance(in DataProblem data, - in RoutingIndexManager manager) { - // precompute distance between location to have distance callback in O(1) - distances_ = new int[data.GetLocationNumber(), data.GetLocationNumber()]; - manager_ = manager; - for (int fromNode = 0; fromNode < data.GetLocationNumber(); fromNode++) { - for (int toNode = 0; toNode < data.GetLocationNumber(); toNode++) { - if (fromNode == toNode) - distances_[fromNode, toNode] = 0; - else - distances_[fromNode, toNode] = - Math.Abs(data.GetLocations()[toNode, 0] - - data.GetLocations()[fromNode, 0]) + - Math.Abs(data.GetLocations()[toNode, 1] - - data.GetLocations()[fromNode, 1]); - } - } - } - - /// - /// Returns the manhattan distance between the two nodes - /// - public override long Run(long FromIndex, long ToIndex) { - int FromNode = manager_.IndexToNode(FromIndex); - int ToNode = manager_.IndexToNode(ToIndex); - return distances_[FromNode, ToNode]; - } - }; - - /// - /// Add distance Dimension - /// - static void AddDistanceDimension( - in DataProblem data, - in RoutingModel routing, - in int distance_index) { - String distance = "Distance"; - routing.AddDimension( - distance_index, - 0, // null slack - 3000, // maximum distance per vehicle - true, // start cumul to zero - distance); - RoutingDimension distanceDimension = routing.GetDimensionOrDie(distance); - // Try to minimize the max distance among vehicles. - // /!\ It doesn't mean the standard deviation is minimized - distanceDimension.SetGlobalSpanCostCoefficient(100); - } - - /// - /// Print the solution + /// Print the solution. /// static void PrintSolution( - in DataProblem data, + in DataModel data, in RoutingModel routing, in RoutingIndexManager manager, in Assignment solution) { Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); // Inspect solution. long totalDistance = 0; - for (int i=0; i < data.GetVehicleNumber(); ++i) { - Console.WriteLine("Route for Vehicle " + i + ":"); - long distance = 0; + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + Console.WriteLine("Route for Vehicle {0}:", i); + long routeDistance = 0; var index = routing.Start(i); while (routing.IsEnd(index) == false) { Console.Write("{0} -> ", manager.IndexToNode((int)index)); var previousIndex = index; index = solution.Value(routing.NextVar(index)); - distance += routing.GetArcCostForVehicle(previousIndex, index, i); + routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); } Console.WriteLine("{0}", manager.IndexToNode((int)index)); - Console.WriteLine("Distance of the route: {0}m", distance); - totalDistance += distance; + Console.WriteLine("Distance of the route: {0}m", routeDistance); + totalDistance += routeDistance; } Console.WriteLine("Total Distance of all routes: {0}m", totalDistance); } - - /// - /// Solves the current routing problem. - /// - static void Solve() { - // Instantiate the data problem. - DataProblem data = new DataProblem(); - - // Create Routing Model - RoutingIndexManager manager = new RoutingIndexManager( - data.GetLocationNumber(), - data.GetVehicleNumber(), - data.GetDepot()); - RoutingModel routing = new RoutingModel(manager); - - // Define weight of each edge - LongLongToLong distanceEvaluator = new ManhattanDistance(data, manager); - //protect callbacks from the GC - GC.KeepAlive(distanceEvaluator); - int distance_index = routing.RegisterTransitCallback(distanceEvaluator); - routing.SetArcCostEvaluatorOfAllVehicles(distance_index); - - AddDistanceDimension(data, routing, distance_index); - - // Setting first solution heuristic (cheapest addition). - RoutingSearchParameters searchParameters = - operations_research_constraint_solver.DefaultRoutingSearchParameters(); - searchParameters.FirstSolutionStrategy = - FirstSolutionStrategy.Types.Value.PathCheapestArc; - - Assignment solution = routing.SolveWithParameters(searchParameters); - PrintSolution(data, routing, manager, solution); - } + // [END solution_printer] public static void Main(String[] args) { - Solve(); + // Instantiate the data problem. + // [START data] + DataModel data = new DataModel(); + // [END data] + + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager = new RoutingIndexManager( + data.GetDistanceMatrix().GetLength(0), + data.GetVehicleNumber(), + data.GetDepot()); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] + int transitCostIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.GetDistanceMatrix()[fromNode, toNode]; } + ); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [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(data, routing, manager, solution); + // [END print_solution] } } +// [END program] diff --git a/ortools/constraint_solver/samples/Vrp.csproj b/ortools/constraint_solver/samples/Vrp.csproj index fb99f95278..52034cc441 100644 --- a/ortools/constraint_solver/samples/Vrp.csproj +++ b/ortools/constraint_solver/samples/Vrp.csproj @@ -15,6 +15,6 @@ - + diff --git a/ortools/constraint_solver/samples/VrpCapacity.cs b/ortools/constraint_solver/samples/VrpCapacity.cs new file mode 100644 index 0000000000..b0967767cd --- /dev/null +++ b/ortools/constraint_solver/samples/VrpCapacity.cs @@ -0,0 +1,162 @@ +// Copyright 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 VrpCapacity { + // [START data_model] + class DataModel { + // Constructor: + public DataModel() { + distancesMatrix_ = new long[,] { + {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662}, + {548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210}, + {776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754}, + {696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358}, + {582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244}, + {274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708}, + {502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480}, + {194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856}, + {308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514}, + {194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468}, + {536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354}, + {502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844}, + {388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730}, + {354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536}, + {468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194}, + {776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798}, + {662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0} + }; + demands_ = new long[] {0, 1, 1, 2, 4, 2, 4, 8, 8, 1, 2, 1, 2, 4, 4, 8, 8}; + vehicleCapacities_ = new long[] {15, 15, 15, 15}; + } + public ref readonly long[,] GetDistanceMatrix() { return ref distancesMatrix_;} + public ref readonly long[] GetDemands() { return ref demands_;} + public int GetVehicleNumber() { return 4;} + public ref readonly long[] GetVehicleCapacities() { return ref vehicleCapacities_;} + public int GetDepot() { return 0;} + + private long[,] distancesMatrix_; + private long[] demands_; + private long[] vehicleCapacities_; + }; + // [END data_model] + + // [START solution_printer] + /// + /// Print the solution. + /// + static void PrintSolution( + in DataModel data, + in RoutingModel routing, + in RoutingIndexManager manager, + in Assignment solution) { + Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); + // Inspect solution. + long totalDistance = 0; + long totalLoad = 0; + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + Console.WriteLine("Route for Vehicle {0}:", i); + long routeDistance = 0; + long routeLoad = 0; + var index = routing.Start(i); + while (routing.IsEnd(index) == false) { + long nodeIndex = manager.IndexToNode(index); + routeLoad += data.GetDemands()[nodeIndex]; + Console.Write("{0} Load({1}) -> ", nodeIndex, routeLoad); + var previousIndex = index; + index = solution.Value(routing.NextVar(index)); + routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); + } + Console.WriteLine("{0}", manager.IndexToNode((int)index)); + Console.WriteLine("Distance of the route: {0}m", routeDistance); + totalDistance += routeDistance; + totalLoad += routeLoad; + } + Console.WriteLine("Total Distance of all routes: {0}m", totalDistance); + Console.WriteLine("Total Load of all routes: {0}m", totalLoad); + } + // [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.GetDistanceMatrix().GetLength(0), + data.GetVehicleNumber(), + data.GetDepot()); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] + int transitCostIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.GetDistanceMatrix()[fromNode, toNode]; } + ); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [END arc_cost] + + // Add Capacity constraint. + // [START capacity_constraint] + int demandCostIndex = routing.RegisterUnaryTransitCallback( + (long fromIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + return data.GetDemands()[fromNode]; } + ); + routing.AddDimensionWithVehicleCapacity( + demandCostIndex, 0, // null capacity slack + data.GetVehicleCapacities(), // vehicle maximum capacities + true, // start cumul to zero + "Capacity"); + // [END capacity_constraint] + + // 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(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/VrpCapacity.csproj b/ortools/constraint_solver/samples/VrpCapacity.csproj new file mode 100644 index 0000000000..1f67cee865 --- /dev/null +++ b/ortools/constraint_solver/samples/VrpCapacity.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/VrpDropNodes.cs b/ortools/constraint_solver/samples/VrpDropNodes.cs new file mode 100644 index 0000000000..e00540bb2e --- /dev/null +++ b/ortools/constraint_solver/samples/VrpDropNodes.cs @@ -0,0 +1,180 @@ +// Copyright 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 Vrp with drop nodes. +/// +public class VrpDropNodes { + // [START data_model] + class DataModel { + // Constructor: + public DataModel() { + distancesMatrix_ = new long[,] { + {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662}, + {548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210}, + {776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754}, + {696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358}, + {582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244}, + {274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708}, + {502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480}, + {194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856}, + {308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514}, + {194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468}, + {536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354}, + {502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844}, + {388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730}, + {354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536}, + {468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194}, + {776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798}, + {662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0} + }; + demands_ = new long[] {0, 1, 1, 3, 6, 3, 6, 8, 8, 1, 2, 1, 2, 6, 6, 8, 8}; + vehicleCapacities_ = new long[] {15, 15, 15, 15}; + } + public ref readonly long[,] GetDistanceMatrix() { return ref distancesMatrix_;} + public ref readonly long[] GetDemands() { return ref demands_;} + public int GetVehicleNumber() { return 4;} + public ref readonly long[] GetVehicleCapacities() { return ref vehicleCapacities_;} + public int GetDepot() { return 0;} + + private long[,] distancesMatrix_; + private long[] demands_; + private long[] vehicleCapacities_; + }; + // [END data_model] + + // [START solution_printer] + /// + /// Print the solution. + /// + static void PrintSolution( + in DataModel data, + in RoutingModel routing, + in RoutingIndexManager manager, + in Assignment solution) { + // Solution cost. + Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); + // Display dropped nodes. + string droppedNodes = "Dropped nodes:"; + for (int index = 0; index < routing.Size(); ++index) { + if (routing.IsStart(index) || routing.IsEnd(index)) { + continue; + } + if (solution.Value(routing.NextVar(index)) == index) { + droppedNodes += " " + manager.IndexToNode(index); + } + } + Console.WriteLine("{0}", droppedNodes); + // Inspect solution. + long totalDistance = 0; + long totalLoad = 0; + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + Console.WriteLine("Route for Vehicle {0}:", i); + long routeDistance = 0; + long routeLoad = 0; + var index = routing.Start(i); + while (routing.IsEnd(index) == false) { + long nodeIndex = manager.IndexToNode(index); + routeLoad += data.GetDemands()[nodeIndex]; + Console.Write("{0} Load({1}) -> ", nodeIndex, routeLoad); + var previousIndex = index; + index = solution.Value(routing.NextVar(index)); + routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); + } + Console.WriteLine("{0}", manager.IndexToNode((int)index)); + Console.WriteLine("Distance of the route: {0}m", routeDistance); + totalDistance += routeDistance; + totalLoad += routeLoad; + } + Console.WriteLine("Total Distance of all routes: {0}m", totalDistance); + Console.WriteLine("Total Load of all routes: {0}m", totalLoad); + } + // [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.GetDistanceMatrix().GetLength(0), + data.GetVehicleNumber(), + data.GetDepot()); + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] + int transitCostIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.GetDistanceMatrix()[fromNode, toNode]; } + ); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [END arc_cost] + + // Add Capacity constraint. + // [START capacity_constraint] + int demandCostIndex = routing.RegisterUnaryTransitCallback( + (long fromIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + return data.GetDemands()[fromNode]; } + ); + routing.AddDimensionWithVehicleCapacity( + demandCostIndex, 0, // null capacity slack + data.GetVehicleCapacities(), // vehicle maximum capacities + true, // start cumul to zero + "Capacity"); + // Allow to drop nodes. + long penalty = 1000; + for (int i = 1; i < data.GetDistanceMatrix().GetLength(0); ++i) { + routing.AddDisjunction( + new long[] {manager.NodeToIndex(i)}, penalty); + } + // [END capacity_constraint] + + // 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(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/VrpDropNodes.csproj b/ortools/constraint_solver/samples/VrpDropNodes.csproj new file mode 100644 index 0000000000..6fb5ecd6b3 --- /dev/null +++ b/ortools/constraint_solver/samples/VrpDropNodes.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/VrpGlobalSpan.cs b/ortools/constraint_solver/samples/VrpGlobalSpan.cs new file mode 100644 index 0000000000..c85931c974 --- /dev/null +++ b/ortools/constraint_solver/samples/VrpGlobalSpan.cs @@ -0,0 +1,146 @@ +// Copyright 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 VrpGlobalSpan { + // [START data_model] + class DataModel { + // Constructor: + public DataModel() { + distancesMatrix_ = new long[,] { + {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662}, + {548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210}, + {776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754}, + {696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358}, + {582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244}, + {274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708}, + {502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480}, + {194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856}, + {308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514}, + {194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468}, + {536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354}, + {502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844}, + {388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730}, + {354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536}, + {468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194}, + {776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798}, + {662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0} + }; + } + public ref readonly long[,] GetDistanceMatrix() { return ref distancesMatrix_;} + public int GetVehicleNumber() { return 4;} + public int GetDepot() { return 0;} + + private long[,] distancesMatrix_; + }; + // [END data_model] + + // [START solution_printer] + /// + /// Print the solution. + /// + static void PrintSolution( + in DataModel data, + in RoutingModel routing, + in RoutingIndexManager manager, + in Assignment solution) { + Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); + // Inspect solution. + long totalDistance = 0; + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + Console.WriteLine("Route for Vehicle {0}:", i); + long routeDistance = 0; + var index = routing.Start(i); + 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("Distance of the route: {0}m", routeDistance); + totalDistance += routeDistance; + } + Console.WriteLine("Total Distance of all routes: {0}m", totalDistance); + } + // [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.GetDistanceMatrix().GetLength(0), + data.GetVehicleNumber(), + data.GetDepot()); + + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] + int transitCostIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.GetDistanceMatrix()[fromNode, toNode]; } + ); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [END arc_cost] + + // Add Distance constraint. + // [START distance_constraint] + routing.AddDimension(transitCostIndex, 0, 3000, + true, // start cumul to zero + "Distance"); + RoutingDimension distanceDimension = routing.GetMutableDimension("Distance"); + distanceDimension.SetGlobalSpanCostCoefficient(100); + // [END distance_constraint] + + // 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(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/VrpGlobalSpan.csproj b/ortools/constraint_solver/samples/VrpGlobalSpan.csproj new file mode 100644 index 0000000000..2059dd24bc --- /dev/null +++ b/ortools/constraint_solver/samples/VrpGlobalSpan.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/VrpStartsEnds.cs b/ortools/constraint_solver/samples/VrpStartsEnds.cs new file mode 100644 index 0000000000..3354343dd1 --- /dev/null +++ b/ortools/constraint_solver/samples/VrpStartsEnds.cs @@ -0,0 +1,152 @@ +// Copyright 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 VrpStartsEnds { + // [START data_model] + class DataModel { + // Constructor: + public DataModel() { + distancesMatrix_ = new long[,] { + {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662}, + {548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210}, + {776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754}, + {696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358}, + {582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244}, + {274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708}, + {502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480}, + {194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856}, + {308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514}, + {194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468}, + {536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354}, + {502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844}, + {388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730}, + {354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536}, + {468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194}, + {776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798}, + {662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0} + }; + starts_ = new int[] {1, 2, 15, 16}; + ends_ = new int[] {0, 0, 0, 0}; + } + public ref readonly long[,] GetDistanceMatrix() { return ref distancesMatrix_;} + public int GetVehicleNumber() { return 4;} + public ref readonly int[] GetStarts() { return ref starts_;} + public ref readonly int[] GetEnds() { return ref ends_;} + + private long[,] distancesMatrix_; + private int[] starts_; + private int[] ends_; + }; + // [END data_model] + + // [START solution_printer] + /// + /// Print the solution. + /// + static void PrintSolution( + in DataModel data, + in RoutingModel routing, + in RoutingIndexManager manager, + in Assignment solution) { + Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); + // Inspect solution. + long totalDistance = 0; + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + Console.WriteLine("Route for Vehicle {0}:", i); + long routeDistance = 0; + var index = routing.Start(i); + 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("Distance of the route: {0}m", routeDistance); + totalDistance += routeDistance; + } + Console.WriteLine("Total Distance of all routes: {0}m", totalDistance); + } + // [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.GetDistanceMatrix().GetLength(0), + data.GetVehicleNumber(), + data.GetStarts(), + data.GetEnds()); + + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] + int transitCostIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.GetDistanceMatrix()[fromNode, toNode]; } + ); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [END arc_cost] + + // Add Distance constraint. + // [START distance_constraint] + routing.AddDimension(transitCostIndex, 0, 2000, + true, // start cumul to zero + "Distance"); + RoutingDimension distanceDimension = routing.GetMutableDimension("Distance"); + distanceDimension.SetGlobalSpanCostCoefficient(100); + // [END distance_constraint] + + // 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(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/VrpStartsEnds.csproj b/ortools/constraint_solver/samples/VrpStartsEnds.csproj new file mode 100644 index 0000000000..87c6f54b13 --- /dev/null +++ b/ortools/constraint_solver/samples/VrpStartsEnds.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/VrpTimeWindows.cs b/ortools/constraint_solver/samples/VrpTimeWindows.cs new file mode 100644 index 0000000000..603579bb0c --- /dev/null +++ b/ortools/constraint_solver/samples/VrpTimeWindows.cs @@ -0,0 +1,200 @@ +// Copyright 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 VrpTimeWindows { + // [START data_model] + class DataModel { + // Constructor: + public DataModel() { + timeMatrix_ = new long[,] { + {0, 6, 9, 8, 7, 3, 6, 2, 3, 2, 6, 6, 4, 4, 5, 9, 7}, + {6, 0, 8, 3, 2, 6, 8, 4, 8, 8, 13, 7, 5, 8, 12, 10, 14}, + {9, 8, 0, 11, 10, 6, 3, 9, 5, 8, 4, 15, 14, 13, 9, 18, 9}, + {8, 3, 11, 0, 1, 7, 10, 6, 10, 10, 14, 6, 7, 9, 14, 6, 16}, + {7, 2, 10, 1, 0, 6, 9, 4, 8, 9, 13, 4, 6, 8, 12, 8, 14}, + {3, 6, 6, 7, 6, 0, 2, 3, 2, 2, 7, 9, 7, 7, 6, 12, 8}, + {6, 8, 3, 10, 9, 2, 0, 6, 2, 5, 4, 12, 10, 10, 6, 15, 5}, + {2, 4, 9, 6, 4, 3, 6, 0, 4, 4, 8, 5, 4, 3, 7, 8, 10}, + {3, 8, 5, 10, 8, 2, 2, 4, 0, 3, 4, 9, 8, 7, 3, 13, 6}, + {2, 8, 8, 10, 9, 2, 5, 4, 3, 0, 4, 6, 5, 4, 3, 9, 5}, + {6, 13, 4, 14, 13, 7, 4, 8, 4, 4, 0, 10, 9, 8, 4, 13, 4}, + {6, 7, 15, 6, 4, 9, 12, 5, 9, 6, 10, 0, 1, 3, 7, 3, 10}, + {4, 5, 14, 7, 6, 7, 10, 4, 8, 5, 9, 1, 0, 2, 6, 4, 8}, + {4, 8, 13, 9, 8, 7, 10, 3, 7, 4, 8, 3, 2, 0, 4, 5, 6}, + {5, 12, 9, 14, 12, 6, 6, 7, 3, 3, 4, 7, 6, 4, 0, 9, 2}, + {9, 10, 18, 6, 8, 12, 15, 8, 13, 9, 13, 3, 4, 5, 9, 0, 9}, + {7, 14, 9, 16, 14, 8, 5, 10, 6, 5, 4, 10, 8, 6, 2, 9, 0}, + }; + timeWindows_ = new long[,] { + {0, 0}, + {10, 15}, + {10, 15}, + {5, 10}, + {5, 10}, + {0, 5}, + {5, 10}, + {0, 5}, + {5, 10}, + {0, 5}, + {10, 15}, + {10, 15}, + {0, 5}, + {5, 10}, + {5, 10}, + {10, 15}, + {5, 10}, + }; + } + public ref readonly long[,] GetTimeMatrix() { return ref timeMatrix_;} + public ref readonly long[,] GetTimeWindows() { return ref timeWindows_;} + public int GetVehicleNumber() { return 4;} + public int GetDepot() { return 0;} + + private long[,] timeMatrix_; + private long[,] timeWindows_; + }; + // [END data_model] + + // [START solution_printer] + /// + /// Print the solution. + /// + static void PrintSolution( + in DataModel data, + in RoutingModel routing, + in RoutingIndexManager manager, + in Assignment solution) { + Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); + RoutingDimension timeDimension = routing.GetMutableDimension("Time"); + // Inspect solution. + long totalTime = 0; + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + Console.WriteLine("Route for Vehicle {0}:", i); + long routeTime = 0; + var index = routing.Start(i); + while (routing.IsEnd(index) == false) { + var timeVar = timeDimension.CumulVar(index); + var slackVar = timeDimension.SlackVar(index); + Console.Write("{0} Time({1},{2}) Slack({3},{4}) -> ", + manager.IndexToNode(index), + solution.Min(timeVar), + solution.Max(timeVar), + solution.Min(slackVar), + solution.Max(slackVar)); + var previousIndex = index; + index = solution.Value(routing.NextVar(index)); + routeTime += routing.GetArcCostForVehicle(previousIndex, index, 0); + } + var endTimeVar = timeDimension.CumulVar(index); + Console.WriteLine("{0} Time({1},{2})", + manager.IndexToNode(index), + solution.Min(endTimeVar), + solution.Max(endTimeVar)); + Console.WriteLine("Time of the route: {0}m", routeTime); + totalTime += routeTime; + } + Console.WriteLine("Total Distance of all routes: {0}m", totalTime); + } + // [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.GetTimeMatrix().GetLength(0), + data.GetVehicleNumber(), + data.GetDepot()); + + // [END index_manager] + + // Create Routing Model. + // [START routing_model] + RoutingModel routing = new RoutingModel(manager); + // [END routing_model] + + // Define cost of each arc. + // [START arc_cost] + int transitCostIndex = routing.RegisterTransitCallback( + (long fromIndex, long toIndex) => { + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return data.GetTimeMatrix()[fromNode, toNode]; } + ); + routing.SetArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [END arc_cost] + + // Add Distance constraint. + // [START time_constraint] + routing.AddDimension( + transitCostIndex, // transit callback + 30, // allow waiting time + 30, // vehicle maximum capacities + false, // start cumul to zero + "Time"); + RoutingDimension timeDimension = routing.GetMutableDimension("Time"); + // Add time window constraints for each location except depot + // and 'copy' the slack var in the solution object (aka Assignment) to print it + for (int i = 1; i < data.GetTimeWindows().GetLength(0); ++i) { + long index = manager.NodeToIndex(i); + timeDimension.CumulVar(index).SetRange( + data.GetTimeWindows()[i, 0], + data.GetTimeWindows()[i, 1]); + routing.AddToAssignment(timeDimension.SlackVar(index)); + } + // Add time window constraints for each vehicle start node + // and 'copy' the slack var in the solution object (aka Assignment) to print + // it + for (int i = 0; i < data.GetVehicleNumber(); ++i) { + long index = routing.Start(i); + timeDimension.CumulVar(index).SetRange( + data.GetTimeWindows()[0, 0], + data.GetTimeWindows()[0, 1]); + routing.AddToAssignment(timeDimension.SlackVar(index)); + } + // [END time_constraint] + + // 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(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program] diff --git a/ortools/constraint_solver/samples/VrpTimeWindows.csproj b/ortools/constraint_solver/samples/VrpTimeWindows.csproj new file mode 100644 index 0000000000..db8e53a17b --- /dev/null +++ b/ortools/constraint_solver/samples/VrpTimeWindows.csproj @@ -0,0 +1,20 @@ + + + Exe + 7.2 + netcoreapp2.1 + false + ../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json + + + + full + true + true + + + + + + +