Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
cvrptw_lib.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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"
30
31namespace operations_research {
32
34
35int32_t GetSeed(bool deterministic) {
36 if (deterministic) {
37 return 7777777;
38 } else {
39 return absl::Uniform<int64_t>(absl::BitGen(), 0,
40 std::numeric_limits<int64_t>::max());
41 }
42}
43
44LocationContainer::LocationContainer(int64_t speed, bool use_deterministic_seed)
45 : randomizer_(GetSeed(use_deterministic_seed)), speed_(speed) {
46 CHECK_LT(0, speed_);
47}
48
49void LocationContainer::AddRandomLocation(int64_t x_max, int64_t y_max) {
50 AddRandomLocation(x_max, y_max, 1);
51}
52
53void 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
90LocationContainer::Location::Location() : x_(0), y_(0) {}
91
92LocationContainer::Location::Location(int64_t x, int64_t y) : x_(x), y_(y) {}
93
94int64_t LocationContainer::Location::DistanceTo(
95 const Location& location) const {
96 return Abs(x_ - location.x_) + Abs(y_ - location.y_);
97}
98
99bool LocationContainer::Location::IsAtSameLocation(
100 const Location& location) const {
101 return x_ == location.x_ && y_ == location.y_;
102}
103
104int64_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
131int64_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
IntegerValue y
IntegerValue size
int64_t Value(const IntVar *var) const
int64_t Max(const IntVar *var) const
int64_t Min(const IntVar *var) const
bool Contains(const IntVar *var) const
int64_t ManhattanDistance(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition cvrptw_lib.cc:62
void AddRandomLocation(int64_t x_max, int64_t y_max)
Definition cvrptw_lib.cc:49
int64_t ManhattanTime(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition cvrptw_lib.cc:72
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 NegManhattanDistance(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
Definition cvrptw_lib.cc:67
int64_t SameLocationFromIndex(int64_t node1, int64_t node2) const
Definition cvrptw_lib.cc:82
int64_t Demand(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
RandomDemand(int size, RoutingIndexManager::NodeIndex depot, bool use_deterministic_seed)
NodeIndex IndexToNode(int64_t index) const
ServiceTimePlusTransition(int64_t time_per_demand_unit, operations_research::RoutingNodeEvaluator2 demand, operations_research::RoutingNodeEvaluator2 transition_time)
int64_t Compute(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
StopServiceTimePlusTransition(int64_t stop_time, const LocationContainer &location_container, operations_research::RoutingNodeEvaluator2 transition_time)
int64_t Compute(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const
int64_t value
In SWIG mode, we don't want anything besides these top-level includes.
int32_t GetSeed(bool deterministic)
Random seed generator.
Definition cvrptw_lib.cc:35
std::function< int64_t(RoutingNodeIndex, RoutingNodeIndex)> RoutingNodeEvaluator2
Definition cvrptw_lib.h:30
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)
STL namespace.
trees with all degrees equal to
const Variable x
Definition qp_tests.cc:127
int64_t demand
Definition resource.cc:126