OR-Tools  9.6
cvrptw_lib.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 
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <limits>
19 #include <memory>
20 #include <random>
21 #include <set>
22 #include <string>
23 #include <utility>
24 
25 #include "absl/container/btree_set.h"
26 #include "absl/strings/str_format.h"
27 #include "ortools/base/logging.h"
30 
31 namespace operations_research {
32 
34 
35 int32_t GetSeed(bool deterministic) {
36  if (deterministic) {
37  return 7777777;
38  } else {
39  return absl::Uniform<int64_t>(absl::BitGen(), 0,
41  }
42 }
43 
44 LocationContainer::LocationContainer(int64_t speed, bool use_deterministic_seed)
45  : randomizer_(GetSeed(use_deterministic_seed)), speed_(speed) {
46  CHECK_LT(0, speed_);
47 }
48 
49 void LocationContainer::AddRandomLocation(int64_t x_max, int64_t y_max) {
50  AddRandomLocation(x_max, y_max, 1);
51 }
52 
53 void LocationContainer::AddRandomLocation(int64_t x_max, int64_t y_max,
54  int duplicates) {
55  const int64_t x = absl::Uniform(randomizer_, 0, x_max + 1);
56  const int64_t y = absl::Uniform(randomizer_, 0, y_max + 1);
57  for (int i = 0; i < duplicates; ++i) {
58  AddLocation(x, y);
59  }
60 }
61 
63  NodeIndex to) const {
64  return locations_[from].DistanceTo(locations_[to]);
65 }
66 
68  NodeIndex to) const {
69  return -ManhattanDistance(from, to);
70 }
71 
73  return ManhattanDistance(from, to) / speed_;
74 }
75 
77  if (node1 < locations_.size() && node2 < locations_.size()) {
78  return locations_[node1].IsAtSameLocation(locations_[node2]);
79  }
80  return false;
81 }
83  int64_t node2) const {
84  // The direct conversion from constraint model indices to routing model
85  // nodes is correct because the depot is node 0.
86  // TODO(user): Fetch proper indices from routing model.
87  return SameLocation(NodeIndex(node1), NodeIndex(node2));
88 }
89 
90 LocationContainer::Location::Location() : x_(0), y_(0) {}
91 
92 LocationContainer::Location::Location(int64_t x, int64_t y) : x_(x), y_(y) {}
93 
94 int64_t LocationContainer::Location::DistanceTo(
95  const Location& location) const {
96  return Abs(x_ - location.x_) + Abs(y_ - location.y_);
97 }
98 
99 bool LocationContainer::Location::IsAtSameLocation(
100  const Location& location) const {
101  return x_ == location.x_ && y_ == location.y_;
102 }
103 
104 int64_t LocationContainer::Location::Abs(int64_t value) {
105  return std::max(value, -value);
106 }
107 
109  bool use_deterministic_seed)
110  : size_(size),
111  depot_(depot),
112  use_deterministic_seed_(use_deterministic_seed) {
113  CHECK_LT(0, size_);
114 }
115 
117  const int64_t kDemandMax = 5;
118  const int64_t kDemandMin = 1;
119  demand_ = std::make_unique<int64_t[]>(size_);
120  std::mt19937 randomizer(GetSeed(use_deterministic_seed_));
121  for (int order = 0; order < size_; ++order) {
122  if (order == depot_) {
123  demand_[order] = 0;
124  } else {
125  demand_[order] = kDemandMin + absl::Uniform(randomizer, 0,
126  kDemandMax - kDemandMin + 1);
127  }
128  }
129 }
130 
131 int64_t RandomDemand::Demand(NodeIndex from, NodeIndex /*to*/) const {
132  return demand_[from.value()];
133 }
134 
136  int64_t time_per_demand_unit, RoutingNodeEvaluator2 demand,
137  RoutingNodeEvaluator2 transition_time)
138  : time_per_demand_unit_(time_per_demand_unit),
139  demand_(std::move(demand)),
140  transition_time_(std::move(transition_time)) {}
141 
143  return time_per_demand_unit_ * demand_(from, to) + transition_time_(from, to);
144 }
145 
147  int64_t stop_time, const LocationContainer& location_container,
148  RoutingNodeEvaluator2 transition_time)
149  : stop_time_(stop_time),
150  location_container_(location_container),
151  transition_time_(std::move(transition_time)) {}
152 
154  NodeIndex to) const {
155  return location_container_.SameLocation(from, to)
156  ? 0
157  : stop_time_ + transition_time_(from, to);
158 }
159 
161  const RoutingIndexManager& manager, const RoutingModel& routing,
162  const operations_research::Assignment& plan, bool use_same_vehicle_costs,
163  int64_t max_nodes_per_group, int64_t same_vehicle_cost,
164  const operations_research::RoutingDimension& capacity_dimension,
165  const operations_research::RoutingDimension& time_dimension) {
166  // Display plan cost.
167  std::string plan_output = absl::StrFormat("Cost %d\n", plan.ObjectiveValue());
168 
169  // Display dropped orders.
170  std::string dropped;
171  for (int64_t order = 0; order < routing.Size(); ++order) {
172  if (routing.IsStart(order) || routing.IsEnd(order)) continue;
173  if (plan.Value(routing.NextVar(order)) == order) {
174  if (dropped.empty()) {
175  absl::StrAppendFormat(&dropped, " %d",
176  manager.IndexToNode(order).value());
177  } else {
178  absl::StrAppendFormat(&dropped, ", %d",
179  manager.IndexToNode(order).value());
180  }
181  }
182  }
183  if (!dropped.empty()) {
184  plan_output += "Dropped orders:" + dropped + "\n";
185  }
186 
187  if (use_same_vehicle_costs) {
188  int group_size = 0;
189  int64_t group_same_vehicle_cost = 0;
190  absl::btree_set<int> visited;
191  for (int64_t order = 0; order < routing.Size(); ++order) {
192  if (routing.IsStart(order) || routing.IsEnd(order)) continue;
193  ++group_size;
194  visited.insert(plan.Value(routing.VehicleVar(order)));
195  if (group_size == max_nodes_per_group) {
196  if (visited.size() > 1) {
197  group_same_vehicle_cost += (visited.size() - 1) * same_vehicle_cost;
198  }
199  group_size = 0;
200  visited.clear();
201  }
202  }
203  if (visited.size() > 1) {
204  group_same_vehicle_cost += (visited.size() - 1) * same_vehicle_cost;
205  }
206  LOG(INFO) << "Same vehicle costs: " << group_same_vehicle_cost;
207  }
208 
209  // Display actual output for each vehicle.
210  for (int route_number = 0; route_number < routing.vehicles();
211  ++route_number) {
212  int64_t order = routing.Start(route_number);
213  absl::StrAppendFormat(&plan_output, "Route %d: ", route_number);
214  if (routing.IsEnd(plan.Value(routing.NextVar(order)))) {
215  plan_output += "Empty\n";
216  } else {
217  while (true) {
218  operations_research::IntVar* const load_var =
219  capacity_dimension.CumulVar(order);
220  operations_research::IntVar* const time_var =
221  time_dimension.CumulVar(order);
222  operations_research::IntVar* const slack_var =
223  routing.IsEnd(order) ? nullptr : time_dimension.SlackVar(order);
224  if (slack_var != nullptr && plan.Contains(slack_var)) {
225  absl::StrAppendFormat(
226  &plan_output, "%d Load(%d) Time(%d, %d) Slack(%d, %d)",
227  manager.IndexToNode(order).value(), plan.Value(load_var),
228  plan.Min(time_var), plan.Max(time_var), plan.Min(slack_var),
229  plan.Max(slack_var));
230  } else {
231  absl::StrAppendFormat(&plan_output, "%d Load(%d) Time(%d, %d)",
232  manager.IndexToNode(order).value(),
233  plan.Value(load_var), plan.Min(time_var),
234  plan.Max(time_var));
235  }
236  if (routing.IsEnd(order)) break;
237  plan_output += " -> ";
238  order = plan.Value(routing.NextVar(order));
239  }
240  plan_output += "\n";
241  }
242  }
243  LOG(INFO) << plan_output;
244 }
245 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
size_type size() const
An Assignment is a variable -> domains mapping, used to report solutions to the user.
bool Contains(const IntVar *const var) const
int64_t Max(const IntVar *const var) const
int64_t Value(const IntVar *const var) const
int64_t Min(const IntVar *const var) const
The class IntVar is a subset of IntExpr.
bool SameLocation(RoutingIndexManager::NodeIndex node1, RoutingIndexManager::NodeIndex node2) const
Definition: cvrptw_lib.cc:76
void AddLocation(int64_t x, int64_t y)
Definition: cvrptw_lib.h:40
LocationContainer(int64_t speed, bool use_deterministic_seed)
Definition: cvrptw_lib.cc:44
int64_t ManhattanTime(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:72
int64_t SameLocationFromIndex(int64_t node1, int64_t node2) const
Definition: cvrptw_lib.cc:82
void AddRandomLocation(int64_t x_max, int64_t y_max)
Definition: cvrptw_lib.cc:49
int64_t NegManhattanDistance(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:67
int64_t ManhattanDistance(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:62
int64_t Demand(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:131
RandomDemand(int size, RoutingIndexManager::NodeIndex depot, bool use_deterministic_seed)
Definition: cvrptw_lib.cc:108
Dimensions represent quantities accumulated at nodes along the routes.
Definition: routing.h:2750
IntVar * SlackVar(int64_t index) const
Definition: routing.h:2774
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
bool IsStart(int64_t index) const
Returns true if 'index' represents the first node of a route.
Definition: routing.h:1454
IntVar * NextVar(int64_t index) const
!defined(SWIGPYTHON)
Definition: routing.h:1485
IntVar * VehicleVar(int64_t index) const
Returns the vehicle variable of the node corresponding to index.
Definition: routing.h:1501
int64_t Size() const
Returns the number of next variables in the model.
Definition: routing.h:1654
int64_t Start(int vehicle) const
Model inspection.
Definition: routing.h:1450
int vehicles() const
Returns the number of vehicle routes in the model.
Definition: routing.h:1652
bool IsEnd(int64_t index) const
Returns true if 'index' represents the last node of a route.
Definition: routing.h:1456
int64_t Compute(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:142
ServiceTimePlusTransition(int64_t time_per_demand_unit, operations_research::RoutingNodeEvaluator2 demand, operations_research::RoutingNodeEvaluator2 transition_time)
Definition: cvrptw_lib.cc:135
int64_t Compute(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition: cvrptw_lib.cc:153
StopServiceTimePlusTransition(int64_t stop_time, const LocationContainer &location_container, operations_research::RoutingNodeEvaluator2 transition_time)
Definition: cvrptw_lib.cc:146
int64_t value
Collection of objects used to extend the Constraint Solver library.
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
std::function< int64_t(RoutingNodeIndex, RoutingNodeIndex)> RoutingNodeEvaluator2
Definition: cvrptw_lib.h:30
int64_t demand
Definition: resource.cc:126