OR-Tools  9.6
cvrptw_with_resources.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // Capacitated Vehicle Routing Problem with Time Windows and capacitated
15 // resources.
16 // This is an extension to the model in cvrptw.cc so refer to that file for
17 // more information on the common part of the model. The model implemented here
18 // limits the number of vehicles which can simultaneously leave or enter the
19 // depot due to limited resources (or capacity) available.
20 // TODO(user): The current model consumes resources even for vehicles with
21 // empty routes; fix this when we have an API on the cumulative constraints
22 // with variable demands.
23 
24 #include <cstdint>
25 #include <random>
26 #include <vector>
27 
28 #include "absl/random/random.h"
29 #include "google/protobuf/text_format.h"
33 #include "ortools/base/logging.h"
37 #include "ortools/constraint_solver/routing_parameters.pb.h"
39 
50 using operations_research::RoutingNodeIndex;
51 using operations_research::RoutingSearchParameters;
54 
55 ABSL_FLAG(int, vrp_orders, 100, "Nodes in the problem.");
56 ABSL_FLAG(int, vrp_vehicles, 20,
57  "Size of Traveling Salesman Problem instance.");
58 ABSL_FLAG(bool, vrp_use_deterministic_random_seed, false,
59  "Use deterministic random seeds.");
60 ABSL_FLAG(std::string, routing_search_parameters, "",
61  "Text proto RoutingSearchParameters (possibly partial) that will "
62  "override the DefaultRoutingSearchParameters()");
63 
64 const char* kTime = "Time";
65 const char* kCapacity = "Capacity";
66 
67 int main(int argc, char** argv) {
68  InitGoogle(argv[0], &argc, &argv, true);
69  CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders))
70  << "Specify an instance size greater than 0.";
71  CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles))
72  << "Specify a non-null vehicle fleet size.";
73  // VRP of size absl::GetFlag(FLAGS_vrp_size).
74  // Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and
75  // ends of the routes are at node 0.
76  const RoutingIndexManager::NodeIndex kDepot(0);
77  RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1,
78  absl::GetFlag(FLAGS_vrp_vehicles), kDepot);
79  RoutingModel routing(manager);
80 
81  // Setting up locations.
82  const int64_t kXMax = 100000;
83  const int64_t kYMax = 100000;
84  const int64_t kSpeed = 10;
85  LocationContainer locations(
86  kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
87  for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders);
88  ++location) {
89  locations.AddRandomLocation(kXMax, kYMax);
90  }
91 
92  // Setting the cost function.
93  const int vehicle_cost = routing.RegisterTransitCallback(
94  [&locations, &manager](int64_t i, int64_t j) {
95  return locations.ManhattanDistance(manager.IndexToNode(i),
96  manager.IndexToNode(j));
97  });
98  routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
99 
100  // Adding capacity dimension constraints.
101  const int64_t kVehicleCapacity = 40;
102  const int64_t kNullCapacitySlack = 0;
103  RandomDemand demand(manager.num_nodes(), kDepot,
104  absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
105  demand.Initialize();
106  routing.AddDimension(routing.RegisterTransitCallback(
107  [&demand, &manager](int64_t i, int64_t j) {
108  return demand.Demand(manager.IndexToNode(i),
109  manager.IndexToNode(j));
110  }),
111  kNullCapacitySlack, kVehicleCapacity,
112  /*fix_start_cumul_to_zero=*/true, kCapacity);
113 
114  // Adding time dimension constraints.
115  const int64_t kTimePerDemandUnit = 300;
116  const int64_t kHorizon = 24 * 3600;
118  kTimePerDemandUnit,
119  [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
120  return demand.Demand(i, j);
121  },
122  [&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
123  return locations.ManhattanTime(i, j);
124  });
125  routing.AddDimension(
126  routing.RegisterTransitCallback([&time, &manager](int64_t i, int64_t j) {
127  return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
128  }),
129  kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
130  const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime);
131 
132  // Adding time windows.
133  std::mt19937 randomizer(
134  GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)));
135  const int64_t kTWDuration = 5 * 3600;
136  for (int order = 1; order < manager.num_nodes(); ++order) {
137  const int64_t start =
138  absl::Uniform<int32_t>(randomizer, 0, kHorizon - kTWDuration);
139  time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration);
140  }
141 
142  // Adding resource constraints at the depot (start and end location of
143  // routes).
144  std::vector<IntVar*> start_end_times;
145  for (int i = 0; i < absl::GetFlag(FLAGS_vrp_vehicles); ++i) {
146  start_end_times.push_back(time_dimension.CumulVar(routing.End(i)));
147  start_end_times.push_back(time_dimension.CumulVar(routing.Start(i)));
148  }
149  // Build corresponding time intervals.
150  const int64_t kVehicleSetup = 180;
151  Solver* const solver = routing.solver();
152  std::vector<IntervalVar*> intervals;
153  solver->MakeFixedDurationIntervalVarArray(start_end_times, kVehicleSetup,
154  "depot_interval", &intervals);
155  // Constrain the number of maximum simultaneous intervals at depot.
156  const int64_t kDepotCapacity = 5;
157  std::vector<int64_t> depot_usage(start_end_times.size(), 1);
158  solver->AddConstraint(
159  solver->MakeCumulative(intervals, depot_usage, kDepotCapacity, "depot"));
160  // Instantiate route start and end times to produce feasible times.
161  for (int i = 0; i < start_end_times.size(); ++i) {
162  routing.AddVariableMinimizedByFinalizer(start_end_times[i]);
163  }
164 
165  // Adding penalty costs to allow skipping orders.
166  const int64_t kPenalty = 100000;
167  const RoutingIndexManager::NodeIndex kFirstNodeAfterDepot(1);
168  for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot;
169  order < manager.num_nodes(); ++order) {
170  std::vector<int64_t> orders(1, manager.NodeToIndex(order));
171  routing.AddDisjunction(orders, kPenalty);
172  }
173 
174  // Solve, returns a solution if any (owned by RoutingModel).
175  RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
176  CHECK(google::protobuf::TextFormat::MergeFromString(
177  absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
178  const Assignment* solution = routing.SolveWithParameters(parameters);
179  if (solution != nullptr) {
180  DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false,
181  /*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0,
182  routing.GetDimensionOrDie(kCapacity),
183  routing.GetDimensionOrDie(kTime));
184  } else {
185  LOG(INFO) << "No solution found.";
186  }
187  return EXIT_SUCCESS;
188 }
An Assignment is a variable -> domains mapping, used to report solutions to the user.
virtual void SetRange(int64_t l, int64_t u)
This method sets both the min and the max of the expression.
The class IntVar is a subset of IntExpr.
Interval variables are often used in scheduling.
int64_t ManhattanTime(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:72
void AddRandomLocation(int64_t x_max, int64_t y_max)
Definition: cvrptw_lib.cc:49
int64_t ManhattanDistance(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:62
Dimensions represent quantities accumulated at nodes along the routes.
Definition: routing.h:2750
IntVar * CumulVar(int64_t index) const
Get the cumul, transit and slack variables for the given node (given as int64_t var index).
Definition: routing.h:2769
Manager for any NodeIndex <-> variable index conversion.
NodeIndex IndexToNode(int64_t index) const
int64_t NodeToIndex(NodeIndex node) const
void AddVariableMinimizedByFinalizer(IntVar *var)
Adds a variable to minimize in the solution finalizer.
Definition: routing.cc:6114
Solver * solver() const
Returns the underlying constraint solver.
Definition: routing.h:1630
DisjunctionIndex AddDisjunction(const std::vector< int64_t > &indices, int64_t penalty=kNoPenalty, int64_t max_cardinality=1)
Adds a disjunction constraint on the indices: exactly 'max_cardinality' of the indices are active.
Definition: routing.cc:2179
const Assignment * SolveWithParameters(const RoutingSearchParameters &search_parameters, std::vector< const Assignment * > *solutions=nullptr)
Solves the current routing model with the given parameters.
Definition: routing.cc:3311
int RegisterTransitCallback(TransitCallback2 callback)
Definition: routing.cc:1301
int64_t Start(int vehicle) const
Model inspection.
Definition: routing.h:1450
void SetArcCostEvaluatorOfAllVehicles(int evaluator_index)
Sets the cost function of the model such that the cost of a segment of a route between node 'from' an...
Definition: routing.cc:1783
int64_t End(int vehicle) const
Returns the variable index of the ending node of a vehicle route.
Definition: routing.h:1452
bool AddDimension(int evaluator_index, int64_t slack_max, int64_t capacity, bool fix_start_cumul_to_zero, const std::string &name)
Model creation.
Definition: routing.cc:1358
const RoutingDimension & GetDimensionOrDie(const std::string &dimension_name) const
Returns a dimension from its name. Dies if the dimension does not exist.
Definition: routing.cc:1685
void AddConstraint(Constraint *const c)
Adds the constraint 'c' to the model.
Constraint * MakeCumulative(const std::vector< IntervalVar * > &intervals, const std::vector< int64_t > &demands, int64_t capacity, const std::string &name)
This constraint forces that, for any integer t, the sum of the demands corresponding to an interval c...
Definition: resource.cc:2598
void MakeFixedDurationIntervalVarArray(int count, int64_t start_min, int64_t start_max, int64_t duration, bool optional, const std::string &name, std::vector< IntervalVar * > *const array)
This method fills the vector with 'count' interval variables built with the corresponding parameters.
Definition: interval.cc:2287
SatParameters parameters
int main(int argc, char **argv)
const char * kCapacity
const char * kTime
ABSL_FLAG(int, vrp_orders, 100, "Nodes in the problem.")
void InitGoogle(const char *usage, int *argc, char ***argv, bool deprecated)
Definition: init_google.h:34
void DisplayPlan(const RoutingIndexManager &manager, const RoutingModel &routing, const operations_research::Assignment &plan, bool use_same_vehicle_costs, int64_t max_nodes_per_group, int64_t same_vehicle_cost, const operations_research::RoutingDimension &capacity_dimension, const operations_research::RoutingDimension &time_dimension)
Definition: cvrptw_lib.cc:160
int32_t GetSeed(bool deterministic)
Definition: cvrptw_lib.cc:35
RoutingSearchParameters DefaultRoutingSearchParameters()
int64_t demand
Definition: resource.cc:126
int64_t time
Definition: resource.cc:1694
int64_t start