Add .Net routing samples

This commit is contained in:
Corentin Le Molgat
2019-01-09 13:16:32 +01:00
parent 0024336ce9
commit cd59b90650
18 changed files with 1253 additions and 192 deletions

View File

@@ -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: ;

View File

@@ -21,10 +21,7 @@ using Google.OrTools.ConstraintSolver;
/// This is a sample using the routing library .Net wrapper.
/// </summary>
public class SimpleRoutingProgram {
/// <summary>
/// Solves the current routing problem.
/// </summary>
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]

View File

@@ -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]
/// <summary>
/// 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.
/// </summary>
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]
/// <summary>
/// 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.
/// </summary>
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
/// </summary>
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]
/// <summary>
/// Print the solution
/// Print the solution.
/// </summary>
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]
/// <summary>
/// Solves the current routing problem.
/// </summary>
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]

View File

@@ -15,6 +15,6 @@
<ItemGroup>
<Compile Include="Tsp.cs" />
<PackageReference Include="Google.OrTools" Version="7.0-*" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>

View File

@@ -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]
/// <summary>
/// Minimal TSP using distance matrix.
/// </summary>
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]
/// <summary>
/// Print the solution.
/// </summary>
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]

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion>7.2</LangVersion>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
<RestoreSources>../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<GenerateTailCalls>true</GenerateTailCalls>
</PropertyGroup>
<ItemGroup>
<Compile Include="TspDistanceMatrix.cs" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>

View File

@@ -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]
/// <summary>
/// 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.
/// </summary>
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]
/// <summary>
/// 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.
/// </summary>
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]);
}
}
}
/// <summary>
/// Returns the manhattan distance between the two nodes
/// </summary>
public override long Run(long FromIndex, long ToIndex) {
int FromNode = manager_.IndexToNode(FromIndex);
int ToNode = manager_.IndexToNode(ToIndex);
return distances_[FromNode, ToNode];
}
};
/// <summary>
/// Add distance Dimension
/// </summary>
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);
}
/// <summary>
/// Print the solution
/// Print the solution.
/// </summary>
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);
}
/// <summary>
/// Solves the current routing problem.
/// </summary>
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]

View File

@@ -15,6 +15,6 @@
<ItemGroup>
<Compile Include="Vrp.cs" />
<PackageReference Include="Google.OrTools" Version="7.0-*" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>

View File

@@ -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]
/// <summary>
/// Minimal TSP using distance matrix.
/// </summary>
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]
/// <summary>
/// Print the solution.
/// </summary>
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]

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion>7.2</LangVersion>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
<RestoreSources>../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<GenerateTailCalls>true</GenerateTailCalls>
</PropertyGroup>
<ItemGroup>
<Compile Include="VrpCapacity.cs" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>

View File

@@ -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]
/// <summary>
/// Minimal Vrp with drop nodes.
/// </summary>
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]
/// <summary>
/// Print the solution.
/// </summary>
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]

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion>7.2</LangVersion>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
<RestoreSources>../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<GenerateTailCalls>true</GenerateTailCalls>
</PropertyGroup>
<ItemGroup>
<Compile Include="VrpDropNodes.cs" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>

View File

@@ -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]
/// <summary>
/// Minimal TSP using distance matrix.
/// </summary>
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]
/// <summary>
/// Print the solution.
/// </summary>
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]

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion>7.2</LangVersion>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
<RestoreSources>../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<GenerateTailCalls>true</GenerateTailCalls>
</PropertyGroup>
<ItemGroup>
<Compile Include="VrpGlobalSpan.cs" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>

View File

@@ -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]
/// <summary>
/// Minimal TSP using distance matrix.
/// </summary>
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]
/// <summary>
/// Print the solution.
/// </summary>
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]

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion>7.2</LangVersion>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
<RestoreSources>../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<GenerateTailCalls>true</GenerateTailCalls>
</PropertyGroup>
<ItemGroup>
<Compile Include="VrpStartsEnds.cs" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>

View File

@@ -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]
/// <summary>
/// Minimal TSP using distance matrix.
/// </summary>
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]
/// <summary>
/// Print the solution.
/// </summary>
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]

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion>7.2</LangVersion>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
<RestoreSources>../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json</RestoreSources>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<GenerateTailCalls>true</GenerateTailCalls>
</PropertyGroup>
<ItemGroup>
<Compile Include="VrpTimeWindows.cs" />
<PackageReference Include="Google.OrTools" Version="7.0.6170-*" />
</ItemGroup>
</Project>