diff --git a/makefiles/Makefile.cpp.mk b/makefiles/Makefile.cpp.mk
index 9f1d4a01a4..2e580a8c43 100755
--- a/makefiles/Makefile.cpp.mk
+++ b/makefiles/Makefile.cpp.mk
@@ -381,6 +381,7 @@ test_cc_constraint_solver_samples: \
rcc_vrp_pickup_delivery \
rcc_vrp_pickup_delivery_fifo \
rcc_vrp_pickup_delivery_lifo \
+ rcc_vrp_resources \
rcc_vrp_starts_ends \
rcc_vrp_time_windows \
diff --git a/makefiles/Makefile.dotnet.mk b/makefiles/Makefile.dotnet.mk
index 155fd5e392..63a5a496de 100644
--- a/makefiles/Makefile.dotnet.mk
+++ b/makefiles/Makefile.dotnet.mk
@@ -453,6 +453,7 @@ test_dotnet_constraint_solver_samples:
$(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpPickupDelivery.cs
$(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpPickupDeliveryFifo.cs
$(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpPickupDeliveryLifo.cs
+ $(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpResources.cs
$(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpStartsEnds.cs
$(MAKE) run SOURCE=ortools/constraint_solver/samples/VrpTimeWindows.cs
diff --git a/makefiles/Makefile.java.mk b/makefiles/Makefile.java.mk
index dfdce49081..9befd7c5a9 100755
--- a/makefiles/Makefile.java.mk
+++ b/makefiles/Makefile.java.mk
@@ -386,6 +386,7 @@ test_java_constraint_solver_samples: \
rjava_VrpPickupDelivery \
rjava_VrpPickupDeliveryFifo \
rjava_VrpPickupDeliveryLifo \
+ rjava_VrpResources \
rjava_VrpStartsEnds \
rjava_VrpTimeWindows \
diff --git a/makefiles/Makefile.python.mk b/makefiles/Makefile.python.mk
index 9094c261f3..9008928748 100755
--- a/makefiles/Makefile.python.mk
+++ b/makefiles/Makefile.python.mk
@@ -512,6 +512,7 @@ test_python_constraint_solver_samples: \
rpy_vrp_pickup_delivery \
rpy_vrp_pickup_delivery_fifo \
rpy_vrp_pickup_delivery_lifo \
+ rpy_vrp_resources \
rpy_vrp_starts_ends \
rpy_vrp_time_windows \
\
diff --git a/ortools/constraint_solver/doc/generate_svg.sh b/ortools/constraint_solver/doc/generate_svg.sh
index 2f603ae0ad..1e04eee776 100755
--- a/ortools/constraint_solver/doc/generate_svg.sh
+++ b/ortools/constraint_solver/doc/generate_svg.sh
@@ -31,6 +31,10 @@ set -x
./routing_svg.py --time-windows > vrp_time_windows.svg
./routing_svg.py --time-windows --solution > vrp_time_windows_solution.svg
+# Ressource Problem
+./routing_svg.py --resources > vrp_resources.svg
+./routing_svg.py --resources --solution > vrp_resources_solution.svg
+
# VRP Starts Ends
./routing_svg.py --starts-ends > vrp_starts_ends.svg
./routing_svg.py --starts-ends --solution > vrp_starts_ends_solution.svg
@@ -47,7 +51,3 @@ set -x
## Fuel Problem
#./routing_svg.py --fuel > vrpf.svg
#./routing_svg.py --fuel --solution > vrpf_solution.svg
-#
-## Ressource Problem
-#./routing_svg.py --resource > vrpr.svg
-#./routing_svg.py --resource --solution > vrpr_solution.svg
diff --git a/ortools/constraint_solver/doc/vrp.md b/ortools/constraint_solver/doc/vrp.md
index 9ff1485798..494e17b7b7 100644
--- a/ortools/constraint_solver/doc/vrp.md
+++ b/ortools/constraint_solver/doc/vrp.md
@@ -82,3 +82,16 @@ Samples:
* [VrpTimeWindows.java](../samples/VrpTimeWindows.java)
* [VrpTimeWindows.cs](../samples/VrpTimeWindows.cs)
+## Resource Constraints
+Data Problem:
+
+
+Solution:
+
+
+Samples:
+* [vrp_resources.cc](../samples/vrp_resources.cc)
+* [vrp_resources.py](../samples/vrp_resources.py)
+* [VrpResources.java](../samples/VrpResources.java)
+* [VrpResources.cs](../samples/VrpResources.cs)
+
diff --git a/ortools/constraint_solver/doc/vrp_resources.svg b/ortools/constraint_solver/doc/vrp_resources.svg
new file mode 100644
index 0000000000..8f348a0e7f
--- /dev/null
+++ b/ortools/constraint_solver/doc/vrp_resources.svg
@@ -0,0 +1,96 @@
+
diff --git a/ortools/constraint_solver/doc/vrp_resources_solution.svg b/ortools/constraint_solver/doc/vrp_resources_solution.svg
new file mode 100644
index 0000000000..31eb60eb05
--- /dev/null
+++ b/ortools/constraint_solver/doc/vrp_resources_solution.svg
@@ -0,0 +1,150 @@
+
diff --git a/ortools/constraint_solver/samples/VrpResources.cs b/ortools/constraint_solver/samples/VrpResources.cs
new file mode 100644
index 0000000000..b322b634de
--- /dev/null
+++ b/ortools/constraint_solver/samples/VrpResources.cs
@@ -0,0 +1,232 @@
+// Copyright 2010-2018 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// [START program]
+// [START import]
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using Google.OrTools.ConstraintSolver;
+// [END import]
+
+///
+/// Vehicles Routing Problem (VRP) with Resource Constraints.
+///
+public class VrpResources {
+ // [START data_model]
+ class DataModel {
+ public long[,] TimeMatrix = {
+ {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},
+ };
+ public long[,] TimeWindows = {
+ {0, 5}, // depot
+ {7, 12}, // 1
+ {10, 15}, // 2
+ {5, 14}, // 3
+ {5, 13}, // 4
+ {0, 5}, // 5
+ {5, 10}, // 6
+ {0, 10}, // 7
+ {5, 10}, // 8
+ {0, 5}, // 9
+ {10, 16}, // 10
+ {10, 15}, // 11
+ {0, 5}, // 12
+ {5, 10}, // 13
+ {7, 12}, // 14
+ {10, 15}, // 15
+ {5, 15}, // 16
+ };
+ public int VehicleNumber = 4;
+ // [START resources_data]
+ public int VehicleLoadTime = 5;
+ public int VehicleUnloadTime = 5;
+ public int DepotCapacity = 2;
+ // [END resources_data]
+ public int Depot = 0;
+ };
+ // [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.VehicleNumber; ++i) {
+ Console.WriteLine("Route for Vehicle {0}:", i);
+ 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));
+ }
+ 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}min", solution.Min(endTimeVar));
+ totalTime += solution.Min(endTimeVar);
+ }
+ Console.WriteLine("Total time of all routes: {0}min", 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.TimeMatrix.GetLength(0),
+ data.VehicleNumber,
+ data.Depot);
+ // [END index_manager]
+
+ // Create Routing Model.
+ // [START routing_model]
+ RoutingModel routing = new RoutingModel(manager);
+ // [END routing_model]
+
+ // Create and register a transit callback.
+ // [START transit_callback]
+ int transitCallbackIndex = routing.RegisterTransitCallback(
+ (long fromIndex, long toIndex) => {
+ // Convert from routing variable Index to distance matrix NodeIndex.
+ var fromNode = manager.IndexToNode(fromIndex);
+ var toNode = manager.IndexToNode(toIndex);
+ return data.TimeMatrix[fromNode, toNode]; }
+ );
+ // [END transit_callback]
+
+ // Define cost of each arc.
+ // [START arc_cost]
+ routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
+ // [END arc_cost]
+
+ // Add Distance constraint.
+ // [START time_constraint]
+ routing.AddDimension(
+ transitCallbackIndex, // 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.TimeWindows.GetLength(0); ++i) {
+ long index = manager.NodeToIndex(i);
+ timeDimension.CumulVar(index).SetRange(
+ data.TimeWindows[i, 0],
+ data.TimeWindows[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.VehicleNumber; ++i) {
+ long index = routing.Start(i);
+ timeDimension.CumulVar(index).SetRange(
+ data.TimeWindows[0, 0],
+ data.TimeWindows[0, 1]);
+ routing.AddToAssignment(timeDimension.SlackVar(index));
+ }
+ // [END time_constraint]
+
+ // Add resource constraints at the depot.
+ // [START depot_load_time]
+ Solver solver = routing.solver();
+ IntervalVar[] intervals = new IntervalVar[ data.VehicleNumber * 2 ];
+ for (int i = 0; i < data.VehicleNumber; ++i) {
+ // Add load duration at start of routes
+ intervals[2*i] = solver.MakeFixedDurationIntervalVar(
+ timeDimension.CumulVar(routing.Start(i)), data.VehicleLoadTime,
+ "depot_interval");
+ // Add unload duration at end of routes.
+ intervals[2*i+1] = solver.MakeFixedDurationIntervalVar(
+ timeDimension.CumulVar(routing.End(i)), data.VehicleUnloadTime,
+ "depot_interval");
+ }
+ // [END depot_load_time]
+
+ // [START depot_capacity]
+ long[] depot_usage = Enumerable.Repeat(1, intervals.Length).ToArray();
+ solver.Add(solver.MakeCumulative(intervals, depot_usage,
+ data.DepotCapacity, "depot"));
+ // [END depot_capacity]
+
+ // Instantiate route start and end times to produce feasible times.
+ // [START depot_start_end_times]
+ for (int i = 0; i < data.VehicleNumber; ++i) {
+ routing.AddVariableMinimizedByFinalizer(
+ timeDimension.CumulVar(routing.Start(i)));
+ routing.AddVariableMinimizedByFinalizer(
+ timeDimension.CumulVar(routing.End(i)));
+ }
+ // [END depot_start_end_times]
+
+ // 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/VrpResources.csproj b/ortools/constraint_solver/samples/VrpResources.csproj
new file mode 100644
index 0000000000..5c978d5514
--- /dev/null
+++ b/ortools/constraint_solver/samples/VrpResources.csproj
@@ -0,0 +1,22 @@
+
+
+ Exe
+ 7.2
+ netcoreapp2.1
+ false
+ ../../../packages;$(RestoreSources);https://api.nuget.org/v3/index.json
+ Google.OrTools.VrpResources
+ true
+
+
+
+ full
+ true
+ true
+
+
+
+
+
+
+
diff --git a/ortools/constraint_solver/samples/VrpResources.java b/ortools/constraint_solver/samples/VrpResources.java
new file mode 100644
index 0000000000..bf42d23cdb
--- /dev/null
+++ b/ortools/constraint_solver/samples/VrpResources.java
@@ -0,0 +1,230 @@
+// Copyright 2010-2018 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// [START program]
+// [START import]
+import com.google.ortools.constraintsolver.Assignment;
+import com.google.ortools.constraintsolver.FirstSolutionStrategy;
+import com.google.ortools.constraintsolver.IntVar;
+import com.google.ortools.constraintsolver.IntervalVar;
+import com.google.ortools.constraintsolver.RoutingDimension;
+import com.google.ortools.constraintsolver.RoutingIndexManager;
+import com.google.ortools.constraintsolver.RoutingModel;
+import com.google.ortools.constraintsolver.RoutingSearchParameters;
+import com.google.ortools.constraintsolver.Solver;
+import com.google.ortools.constraintsolver.main;
+import java.util.Arrays;
+import java.util.logging.Logger;
+// [END import]
+
+/** Minimal VRP with Resource Constraints.*/
+public class VrpResources {
+ static {
+ System.loadLibrary("jniortools");
+ }
+
+ private static final Logger logger = Logger.getLogger(VrpResources.class.getName());
+
+ // [START data_model]
+ static class DataModel {
+ public final long[][] timeMatrix = {
+ {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},
+ };
+ public final long[][] timeWindows = {
+ {0, 5}, // depot
+ {7, 12}, // 1
+ {10, 15}, // 2
+ {5, 14}, // 3
+ {5, 13}, // 4
+ {0, 5}, // 5
+ {5, 10}, // 6
+ {0, 10}, // 7
+ {5, 10}, // 8
+ {0, 5}, // 9
+ {10, 16}, // 10
+ {10, 15}, // 11
+ {0, 5}, // 12
+ {5, 10}, // 13
+ {7, 12}, // 14
+ {10, 15}, // 15
+ {5, 15}, // 16
+ };
+ public final int vehicleNumber = 4;
+ // [START resources_data]
+ public final int vehicleLoadTime = 5;
+ public final int vehicleUnloadTime = 5;
+ public final int depotCapacity = 2;
+ // [END resources_data]
+ public final int depot = 0;
+ }
+ // [END data_model]
+
+ // [START solution_printer]
+ /// @brief Print the solution.
+ static void printSolution(
+ DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
+ logger.info("Objective : " + solution.objectiveValue());
+ RoutingDimension timeDimension = routing.getMutableDimension("Time");
+ long totalTime = 0;
+ for (int i = 0; i < data.vehicleNumber; ++i) {
+ long index = routing.start(i);
+ logger.info("Route for Vehicle " + i + ":");
+ String route = "";
+ while (!routing.isEnd(index)) {
+ IntVar timeVar = timeDimension.cumulVar(index);
+ IntVar slackVar = timeDimension.slackVar(index);
+ route += manager.indexToNode(index) + " Time(" + solution.min(timeVar) + ","
+ + solution.max(timeVar) + ") Slack(" + solution.min(slackVar) + ","
+ + solution.max(slackVar) + ") -> ";
+ long previousIndex = index;
+ index = solution.value(routing.nextVar(index));
+ }
+ IntVar timeVar = timeDimension.cumulVar(index);
+ route += manager.indexToNode(index) + " Time(" + solution.min(timeVar) + ","
+ + solution.max(timeVar) + ")";
+ logger.info(route);
+ logger.info("Time of the route: " + solution.min(timeVar) + "min");
+ totalTime += solution.min(timeVar);
+ }
+ logger.info("Total time of all routes: " + totalTime + "min");
+ }
+ // [END solution_printer]
+
+ public static void main(String[] args) throws Exception {
+ // Instantiate the data problem.
+ // [START data]
+ final DataModel data = new DataModel();
+ // [END data]
+
+ // Create Routing Index Manager
+ // [START index_manager]
+ RoutingIndexManager manager =
+ new RoutingIndexManager(data.timeMatrix.length, data.vehicleNumber, data.depot);
+ // [END index_manager]
+
+ // Create Routing Model.
+ // [START routing_model]
+ RoutingModel routing = new RoutingModel(manager);
+ // [END routing_model]
+
+ // Create and register a transit callback.
+ // [START transit_callback]
+ final int transitCallbackIndex =
+ routing.registerTransitCallback((long fromIndex, long toIndex) -> {
+ // Convert from routing variable Index to user NodeIndex.
+ int fromNode = manager.indexToNode(fromIndex);
+ int toNode = manager.indexToNode(toIndex);
+ return data.timeMatrix[fromNode][toNode];
+ });
+ // [END transit_callback]
+
+ // Define cost of each arc.
+ // [START arc_cost]
+ routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
+ // [END arc_cost]
+
+ // Add Time constraint.
+ // [START time_constraint]
+ routing.addDimension(transitCallbackIndex, // 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.timeWindows.length; ++i) {
+ long index = manager.nodeToIndex(i);
+ timeDimension.cumulVar(index).setRange(data.timeWindows[i][0], data.timeWindows[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.vehicleNumber; ++i) {
+ long index = routing.start(i);
+ timeDimension.cumulVar(index).setRange(data.timeWindows[0][0], data.timeWindows[0][1]);
+ routing.addToAssignment(timeDimension.slackVar(index));
+ }
+ // [END time_constraint]
+
+ // Add resource constraints at the depot.
+ // [START depot_load_time]
+ Solver solver = routing.solver();
+ IntervalVar[] intervals = new IntervalVar[ data.vehicleNumber * 2 ];
+ for (int i = 0; i < data.vehicleNumber; ++i) {
+ // Add load duration at start of routes
+ intervals[2*i] = solver.makeFixedDurationIntervalVar(
+ timeDimension.cumulVar(routing.start(i)), data.vehicleLoadTime,
+ "depot_interval");
+ // Add unload duration at end of routes.
+ intervals[2*i+1] = solver.makeFixedDurationIntervalVar(
+ timeDimension.cumulVar(routing.end(i)), data.vehicleUnloadTime,
+ "depot_interval");
+ }
+ // [END depot_load_time]
+
+ // [START depot_capacity]
+ long[] depot_usage = new long[ intervals.length ];
+ Arrays.fill(depot_usage, 1);
+ solver.addConstraint(solver.makeCumulative(intervals, depot_usage,
+ data.depotCapacity, "depot"));
+ // [END depot_capacity]
+
+ // Instantiate route start and end times to produce feasible times.
+ // [START depot_start_end_times]
+ for (int i = 0; i < data.vehicleNumber; ++i) {
+ routing.addVariableMinimizedByFinalizer(
+ timeDimension.cumulVar(routing.start(i)));
+ routing.addVariableMinimizedByFinalizer(
+ timeDimension.cumulVar(routing.end(i)));
+ }
+ // [END depot_start_end_times]
+
+ // Setting first solution heuristic.
+ // [START parameters]
+ RoutingSearchParameters searchParameters =
+ main.defaultRoutingSearchParameters()
+ .toBuilder()
+ .setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
+ .build();
+ // [END parameters]
+
+ // Solve the problem.
+ // [START solve]
+ Assignment solution = routing.solveWithParameters(searchParameters);
+ // [END solve]
+
+ // Print solution on console.
+ // [START print_solution]
+ printSolution(data, routing, manager, solution);
+ // [END print_solution]
+ }
+}
+// [END program]
diff --git a/ortools/constraint_solver/samples/vrp_resources.cc b/ortools/constraint_solver/samples/vrp_resources.cc
new file mode 100644
index 0000000000..a0ccafc4aa
--- /dev/null
+++ b/ortools/constraint_solver/samples/vrp_resources.cc
@@ -0,0 +1,231 @@
+// Copyright 2010-2018 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// [START program]
+// [START import]
+#include
+#include
+#include "ortools/constraint_solver/routing.h"
+#include "ortools/constraint_solver/routing_enums.pb.h"
+#include "ortools/constraint_solver/routing_index_manager.h"
+#include "ortools/constraint_solver/routing_parameters.h"
+// [END import]
+
+namespace operations_research {
+// [START data_model]
+struct DataModel {
+ const std::vector> time_matrix{
+ {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},
+ };
+ const std::vector> time_windows{
+ {0, 5}, // depot
+ {7, 12}, // 1
+ {10, 15}, // 2
+ {5, 14}, // 3
+ {5, 13}, // 4
+ {0, 5}, // 5
+ {5, 10}, // 6
+ {0, 10}, // 7
+ {5, 10}, // 8
+ {0, 5}, // 9
+ {10, 16}, // 10
+ {10, 15}, // 11
+ {0, 5}, // 12
+ {5, 10}, // 13
+ {7, 12}, // 14
+ {10, 15}, // 15
+ {5, 15}, // 16
+ };
+ const int num_vehicles = 4;
+ // [START resources_data]
+ const int vehicle_load_time = 5;
+ const int vehicle_unload_time = 5;
+ const int depot_capacity = 2;
+ // [END resources_data]
+ const RoutingIndexManager::NodeIndex depot{0};
+};
+// [END data_model]
+
+// [START solution_printer]
+//! @brief Print the solution.
+//! @param[in] data Data of the problem.
+//! @param[in] manager Index manager used.
+//! @param[in] routing Routing solver used.
+//! @param[in] solution Solution found by the solver.
+void PrintSolution(const DataModel& data, const RoutingIndexManager& manager,
+ const RoutingModel& routing, const Assignment& solution) {
+ LOG(INFO) << "Objective: " << solution.ObjectiveValue();
+ const RoutingDimension& time_dimension = routing.GetDimensionOrDie("Time");
+ int64 total_time{0};
+ for (int vehicle_id = 0; vehicle_id < data.num_vehicles; ++vehicle_id) {
+ int64 index = routing.Start(vehicle_id);
+ LOG(INFO) << "Route for vehicle " << vehicle_id << ":";
+ std::ostringstream route;
+ while (routing.IsEnd(index) == false) {
+ auto time_var = time_dimension.CumulVar(index);
+ auto slack_var = time_dimension.SlackVar(index);
+ route << manager.IndexToNode(index).value() << " Time("
+ << solution.Min(time_var) << ", " << solution.Max(time_var)
+ << ") Slack(" << solution.Min(slack_var) << ", "
+ << solution.Max(slack_var) << ") -> ";
+ int64 previous_index = index;
+ index = solution.Value(routing.NextVar(index));
+ }
+ auto time_var = time_dimension.CumulVar(index);
+ LOG(INFO) << route.str() << manager.IndexToNode(index).value() << " Time("
+ << solution.Min(time_var) << ", " << solution.Max(time_var)
+ << ")";
+ LOG(INFO) << "Time of the route: " << solution.Min(time_var) << "min";
+ total_time += solution.Min(time_var);
+ }
+ LOG(INFO) << "Total time of all routes: " << total_time << "min";
+ LOG(INFO) << "";
+ LOG(INFO) << "Advanced usage:";
+ LOG(INFO) << "Problem solved in " << routing.solver()->wall_time() << "ms";
+}
+// [END solution_printer]
+
+void VrpTimeWindows() {
+ // Instantiate the data problem.
+ // [START data]
+ DataModel data;
+ // [END data]
+
+ // Create Routing Index Manager
+ // [START index_manager]
+ RoutingIndexManager manager(data.time_matrix.size(), data.num_vehicles,
+ data.depot);
+ // [END index_manager]
+
+ // Create Routing Model.
+ // [START routing_model]
+ RoutingModel routing(manager);
+ // [END routing_model]
+
+ // Create and register a transit callback.
+ // [START transit_callback]
+ const int transit_callback_index = routing.RegisterTransitCallback(
+ [&data, &manager](int64 from_index, int64 to_index) -> int64 {
+ // Convert from routing variable Index to time matrix NodeIndex.
+ auto from_node = manager.IndexToNode(from_index).value();
+ auto to_node = manager.IndexToNode(to_index).value();
+ return data.time_matrix[from_node][to_node];
+ });
+ // [END transit_callback]
+
+ // Define cost of each arc.
+ // [START arc_cost]
+ routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index);
+ // [END arc_cost]
+
+ // Add Time constraint.
+ // [START time_constraint]
+ std::string time{"Time"};
+ routing.AddDimension(transit_callback_index, // transit callback index
+ int64{30}, // allow waiting time
+ int64{30}, // maximum time per vehicle
+ false, // Don't force start cumul to zero
+ time);
+ const RoutingDimension& time_dimension = routing.GetDimensionOrDie(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.time_windows.size(); ++i) {
+ int64 index = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i));
+ time_dimension.CumulVar(index)->SetRange(data.time_windows[i].first,
+ data.time_windows[i].second);
+ routing.AddToAssignment(time_dimension.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.num_vehicles; ++i) {
+ int64 index = routing.Start(i);
+ time_dimension.CumulVar(index)->SetRange(data.time_windows[0].first,
+ data.time_windows[0].second);
+ routing.AddToAssignment(time_dimension.SlackVar(index));
+ }
+ // [END time_constraint]
+
+ // Add resource constraints at the depot.
+ // [START depot_load_time]
+ Solver* solver = routing.solver();
+ std::vector intervals;
+ for (int i = 0; i < data.num_vehicles; ++i) {
+ // Add load duration at start of routes
+ intervals.push_back(solver->MakeFixedDurationIntervalVar(
+ time_dimension.CumulVar(routing.Start(i)), data.vehicle_load_time,
+ "depot_interval"));
+ // Add unload duration at end of routes.
+ intervals.push_back(solver->MakeFixedDurationIntervalVar(
+ time_dimension.CumulVar(routing.End(i)), data.vehicle_unload_time,
+ "depot_interval"));
+ }
+ // [END depot_load_time]
+
+ // [START depot_capacity]
+ std::vector depot_usage(intervals.size(), 1);
+ solver->AddConstraint(solver->MakeCumulative(intervals, depot_usage,
+ data.depot_capacity, "depot"));
+ // [END depot_capacity]
+
+ // Instantiate route start and end times to produce feasible times.
+ // [START depot_start_end_times]
+ for (int i = 0; i < data.num_vehicles; ++i) {
+ routing.AddVariableMinimizedByFinalizer(
+ time_dimension.CumulVar(routing.End(i)));
+ routing.AddVariableMinimizedByFinalizer(
+ time_dimension.CumulVar(routing.Start(i)));
+ }
+ // [END depot_start_end_times]
+
+ // Setting first solution heuristic.
+ // [START parameters]
+ RoutingSearchParameters searchParameters = DefaultRoutingSearchParameters();
+ searchParameters.set_first_solution_strategy(
+ FirstSolutionStrategy::PATH_CHEAPEST_ARC);
+ // [END parameters]
+
+ // Solve the problem.
+ // [START solve]
+ const Assignment* solution = routing.SolveWithParameters(searchParameters);
+ // [END solve]
+
+ // Print solution on console.
+ // [START print_solution]
+ PrintSolution(data, manager, routing, *solution);
+ // [END print_solution]
+}
+} // namespace operations_research
+
+int main(int argc, char** argv) {
+ operations_research::VrpTimeWindows();
+ return EXIT_SUCCESS;
+}
+// [END program]
diff --git a/ortools/constraint_solver/samples/vrp_resources.py b/ortools/constraint_solver/samples/vrp_resources.py
new file mode 100644
index 0000000000..49dc23613b
--- /dev/null
+++ b/ortools/constraint_solver/samples/vrp_resources.py
@@ -0,0 +1,227 @@
+# Copyright 2010-2018 Google LLC
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# [START program]
+"""Vehicles Routing Problem (VRP) with Resource Constraints."""
+
+# [START import]
+from __future__ import print_function
+from ortools.constraint_solver import routing_enums_pb2
+from ortools.constraint_solver import pywrapcp
+
+# [END import]
+
+
+# [START data_model]
+def create_data_model():
+ """Stores the data for the problem."""
+ data = {}
+ data['time_matrix'] = [
+ [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],
+ ]
+ data['time_windows'] = [
+ (0, 5), # depot
+ (7, 12), # 1
+ (10, 15), # 2
+ (5, 14), # 3
+ (5, 13), # 4
+ (0, 5), # 5
+ (5, 10), # 6
+ (0, 10), # 7
+ (5, 10), # 8
+ (0, 5), # 9
+ (10, 16), # 10
+ (10, 15), # 11
+ (0, 5), # 12
+ (5, 10), # 13
+ (7, 12), # 14
+ (10, 15), # 15
+ (5, 15), # 16
+ ]
+ data['num_vehicles'] = 4
+ # [START resources_data]
+ data['vehicle_load_time'] = 5
+ data['vehicle_unload_time'] = 5
+ data['depot_capacity'] = 2
+ # [END resources_data]
+ data['depot'] = 0
+ return data
+ # [END data_model]
+
+
+# [START solution_printer]
+def print_solution(data, manager, routing, assignment):
+ """Prints assignment on console."""
+ print('Objective: {}'.format(assignment.ObjectiveValue()))
+ time_dimension = routing.GetDimensionOrDie('Time')
+ total_time = 0
+ for vehicle_id in range(data['num_vehicles']):
+ index = routing.Start(vehicle_id)
+ plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
+ while not routing.IsEnd(index):
+ time_var = time_dimension.CumulVar(index)
+ slack_var = time_dimension.SlackVar(index)
+ plan_output += ' {0} Time({1},{2}) Slack({3},{4})-> '.format(
+ manager.IndexToNode(index), assignment.Min(time_var),
+ assignment.Max(time_var), assignment.Min(slack_var),
+ assignment.Max(slack_var))
+ previous_index = index
+ index = assignment.Value(routing.NextVar(index))
+ time_var = time_dimension.CumulVar(index)
+ plan_output += ' {0} Time({1},{2})\n'.format(
+ manager.IndexToNode(index), assignment.Min(time_var),
+ assignment.Max(time_var))
+ plan_output += 'Time of the route: {}min\n'.format(assignment.Min(time_var))
+ print(plan_output)
+ total_time += assignment.Min(time_var)
+ print('Total time of all routes: {}min'.format(total_time))
+ # [END solution_printer]
+
+
+def main():
+ """Solve the VRP with time windows."""
+ # Instantiate the data problem.
+ # [START data]
+ data = create_data_model()
+ # [END data]
+
+ # Create the routing index manager.
+ # [START index_manager]
+ manager = pywrapcp.RoutingIndexManager(
+ len(data['time_matrix']), data['num_vehicles'], data['depot'])
+ # [END index_manager]
+
+ # Create Routing Model.
+ # [START routing_model]
+ routing = pywrapcp.RoutingModel(manager)
+
+ # [END routing_model]
+
+ # Create and register a transit callback.
+ # [START transit_callback]
+ def time_callback(from_index, to_index):
+ """Returns the travel time between the two nodes."""
+ # Convert from routing variable Index to time matrix NodeIndex.
+ from_node = manager.IndexToNode(from_index)
+ to_node = manager.IndexToNode(to_index)
+ return data['time_matrix'][from_node][to_node]
+
+ transit_callback_index = routing.RegisterTransitCallback(time_callback)
+ # [END transit_callback]
+
+ # Define cost of each arc.
+ # [START arc_cost]
+ routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
+ # [END arc_cost]
+
+ # Add Time Windows constraint.
+ # [START time_windows_constraint]
+ time = 'Time'
+ routing.AddDimension(
+ transit_callback_index,
+ 60, # allow waiting time
+ 60, # maximum time per vehicle
+ False, # Don't force start cumul to zero.
+ time)
+ time_dimension = routing.GetDimensionOrDie(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 location_idx, time_window in enumerate(data['time_windows']):
+ if location_idx == 0:
+ continue
+ index = manager.NodeToIndex(location_idx)
+ time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])
+ routing.AddToAssignment(time_dimension.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 vehicle_id in range(data['num_vehicles']):
+ index = routing.Start(vehicle_id)
+ time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],
+ data['time_windows'][0][1])
+ routing.AddToAssignment(time_dimension.SlackVar(index))
+ # [END time_windows_constraint]
+
+ # Add resource constraints at the depot.
+ # [START depot_load_time]
+ solver = routing.solver()
+ intervals = []
+ for i in range(data['num_vehicles']):
+ # Add time windows at start of routes
+ intervals.append(
+ solver.FixedDurationIntervalVar(
+ time_dimension.CumulVar(routing.Start(i)),
+ data['vehicle_load_time'], 'depot_interval'))
+ # Add time windows at end of routes.
+ intervals.append(
+ solver.FixedDurationIntervalVar(
+ time_dimension.CumulVar(routing.End(i)),
+ data['vehicle_unload_time'], 'depot_interval'))
+ # [END depot_load_time]
+
+ # [START depot_capacity]
+ depot_usage = [1 for i in range(len(intervals))]
+ solver.AddConstraint(
+ solver.Cumulative(
+ intervals,
+ depot_usage,
+ data['depot_capacity'],
+ 'depot'))
+ # [END depot_capacity]
+
+ # Instantiate route start and end times to produce feasible times.
+ # [START depot_start_end_times]
+ for i in range(data['num_vehicles']):
+ routing.AddVariableMinimizedByFinalizer(
+ time_dimension.CumulVar(routing.Start(i)))
+ routing.AddVariableMinimizedByFinalizer(
+ time_dimension.CumulVar(routing.End(i)))
+ # [END depot_start_end_times]
+
+ # Setting first solution heuristic.
+ # [START parameters]
+ search_parameters = pywrapcp.DefaultRoutingSearchParameters()
+ search_parameters.first_solution_strategy = (
+ routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
+ # [END parameters]
+
+ # Solve the problem.
+ # [START solve]
+ assignment = routing.SolveWithParameters(search_parameters)
+ # [END solve]
+
+ # Print solution on console.
+ # [START print_solution]
+ if assignment:
+ print_solution(data, manager, routing, assignment)
+ # [END print_solution]
+ else:
+ print('No solution found !')
+
+if __name__ == '__main__':
+ main()
+# [END program]