23#include "absl/log/check.h"
37 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
38 bool keep_inverse_values)
41 model_(heuristic->
model()),
42 removed_nodes_(model_->Size()),
43 heuristic_(
std::move(heuristic)),
44 consider_vehicle_vars_(!model_->CostsAreHomogeneousAcrossVehicles()) {
45 if (consider_vehicle_vars_) {
50bool FilteredHeuristicLocalSearchOperator::MakeOneNeighbor() {
52 if (
model_->CheckLimit()) {
61 if (MakeChangesAndInsertNodes()) {
68bool FilteredHeuristicLocalSearchOperator::MakeChangesAndInsertNodes() {
71 const std::function<int64_t(int64_t)> next_accessor =
73 if (next_accessor ==
nullptr) {
76 const Assignment*
const result_assignment =
77 heuristic_->BuildSolutionFromRoutes(next_accessor);
79 if (result_assignment ==
nullptr) {
83 bool has_change =
false;
84 const std::vector<IntVarElement>& elements =
85 result_assignment->IntVarContainer().elements();
86 for (
int vehicle = 0; vehicle <
model_->vehicles(); vehicle++) {
87 int64_t node_index =
model_->Start(vehicle);
88 while (!
model_->IsEnd(node_index)) {
91 const IntVarElement& node_element = elements[node_index];
92 DCHECK_EQ(node_element.Var(),
model_->NextVar(node_index));
94 const int64_t new_node_value = node_element.Value();
95 DCHECK_NE(new_node_value, node_index);
97 const int64_t vehicle_var_index = VehicleVarIndex(node_index);
98 if (
OldValue(node_index) != new_node_value ||
99 (consider_vehicle_vars_ &&
OldValue(vehicle_var_index) != vehicle)) {
101 SetValue(node_index, new_node_value);
102 if (consider_vehicle_vars_) {
103 SetValue(vehicle_var_index, vehicle);
106 node_index = new_node_value;
112 const IntVarElement& node_element = elements[node];
113 DCHECK_EQ(node_element.Var(),
model_->NextVar(node));
114 if (node_element.Value() == node) {
118 if (consider_vehicle_vars_) {
119 const int64_t vehicle_var_index = VehicleVarIndex(node);
120 DCHECK_NE(
OldValue(vehicle_var_index), -1);
131 std::unique_ptr<RoutingFilteredHeuristic> heuristic)
135 just_started_(false) {}
137void FilteredHeuristicPathLNSOperator::OnStart() {
140 last_route_ = current_route_;
141 if (CurrentRouteIsEmpty()) {
142 IncrementCurrentRouteToNextNonEmpty();
144 just_started_ =
true;
147bool FilteredHeuristicPathLNSOperator::IncrementPosition() {
149 just_started_ =
false;
150 return !CurrentRouteIsEmpty();
152 IncrementCurrentRouteToNextNonEmpty();
153 return current_route_ != last_route_;
156bool FilteredHeuristicPathLNSOperator::CurrentRouteIsEmpty()
const {
160void FilteredHeuristicPathLNSOperator::IncrementCurrentRouteToNextNonEmpty() {
161 const int num_routes =
model_->vehicles();
163 ++current_route_ %= num_routes;
164 if (current_route_ == last_route_) {
168 }
while (CurrentRouteIsEmpty());
171std::function<int64_t(int64_t)>
172FilteredHeuristicPathLNSOperator::SetupNextAccessorForNeighbor() {
173 const int64_t start_node =
model_->Start(current_route_);
174 const int64_t end_node =
model_->End(current_route_);
176 int64_t node =
Value(start_node);
177 while (node != end_node) {
182 return [
this, start_node, end_node](int64_t node) {
183 if (node == start_node)
return end_node;
192 std::unique_ptr<RoutingFilteredHeuristic> heuristic)
194 route_to_relocate_index_(0),
195 empty_route_index_(0),
196 just_started_(false) {}
198void RelocatePathAndHeuristicInsertUnperformedOperator::OnStart() {
199 has_unperformed_nodes_ =
false;
200 last_node_on_route_.resize(
model_->vehicles());
201 routes_to_relocate_.clear();
202 empty_routes_.clear();
203 std::vector<bool> empty_vehicle_of_vehicle_class_added(
204 model_->GetVehicleClassesCount(),
false);
205 for (int64_t node = 0; node <
model_->Size(); node++) {
208 has_unperformed_nodes_ =
true;
212 last_node_on_route_[
model_->VehicleIndex(
next)] = node;
216 for (
int vehicle = 0; vehicle <
model_->vehicles(); vehicle++) {
219 routes_to_relocate_.push_back(vehicle);
223 model_->GetVehicleClassIndexOfVehicle(vehicle).value();
225 empty_routes_.push_back(vehicle);
230 if (empty_route_index_ >= empty_routes_.size()) {
231 empty_route_index_ = 0;
233 if (route_to_relocate_index_ >= routes_to_relocate_.size()) {
234 route_to_relocate_index_ = 0;
236 last_empty_route_index_ = empty_route_index_;
237 last_route_to_relocate_index_ = route_to_relocate_index_;
239 just_started_ =
true;
242bool RelocatePathAndHeuristicInsertUnperformedOperator::IncrementPosition() {
243 if (!has_unperformed_nodes_ || empty_routes_.empty() ||
244 routes_to_relocate_.empty()) {
248 just_started_ =
false;
251 return IncrementRoutes();
254bool RelocatePathAndHeuristicInsertUnperformedOperator::IncrementRoutes() {
255 ++empty_route_index_ %= empty_routes_.size();
256 if (empty_route_index_ != last_empty_route_index_) {
259 ++route_to_relocate_index_ %= routes_to_relocate_.size();
260 return route_to_relocate_index_ != last_route_to_relocate_index_;
263std::function<int64_t(int64_t)>
264RelocatePathAndHeuristicInsertUnperformedOperator::
265 SetupNextAccessorForNeighbor() {
266 const int empty_route = empty_routes_[empty_route_index_];
267 const int relocated_route = routes_to_relocate_[route_to_relocate_index_];
268 if (
model_->GetVehicleClassIndexOfVehicle(empty_route) ==
269 model_->GetVehicleClassIndexOfVehicle(relocated_route)) {
274 const int64_t empty_start_node =
model_->Start(empty_route);
275 const int64_t empty_end_node =
model_->End(empty_route);
277 const int64_t relocated_route_start =
model_->Start(relocated_route);
278 const int64_t first_relocated_node =
OldValue(relocated_route_start);
279 const int64_t last_relocated_node = last_node_on_route_[relocated_route];
280 const int64_t relocated_route_end =
model_->End(relocated_route);
282 return [
this, empty_start_node, empty_end_node, first_relocated_node,
283 last_relocated_node, relocated_route_start,
284 relocated_route_end](int64_t node) {
285 if (node == relocated_route_start)
return relocated_route_end;
286 if (node == empty_start_node)
return first_relocated_node;
287 if (node == last_relocated_node)
return empty_end_node;
295 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
int num_close_nodes)
298 pickup_delivery_pairs_(model_->GetPickupAndDeliveryPairs()),
301 just_started_(false),
303 close_nodes_(model_->Size()),
304 num_close_nodes_(num_close_nodes),
305 new_nexts_(model_->Size()),
306 changed_nexts_(model_->Size()),
307 new_prevs_(model_->Size()),
308 changed_prevs_(model_->Size()) {}
310void FilteredHeuristicCloseNodesLNSOperator::Initialize() {
311 if (initialized_)
return;
314 const int64_t max_num_neighbors =
315 std::max<int64_t>(0,
size - 1 -
model_->vehicles());
316 const int64_t num_closest_neighbors =
317 std::min<int64_t>(num_close_nodes_, max_num_neighbors);
318 DCHECK_GE(num_closest_neighbors, 0);
320 if (num_closest_neighbors == 0)
return;
322 const int64_t num_cost_classes =
model_->GetCostClassesCount();
324 for (int64_t node = 0; node <
size; node++) {
325 if (
model_->IsStart(node) ||
model_->IsEnd(node))
continue;
327 std::vector<std::pair< double, int64_t>>
329 costed_after_nodes.reserve(
size);
330 for (int64_t after_node = 0; after_node <
size; after_node++) {
331 if (
model_->IsStart(after_node) ||
model_->IsEnd(after_node) ||
332 after_node == node) {
335 double total_cost = 0.0;
338 for (
int cost_class = 1; cost_class < num_cost_classes; cost_class++) {
339 total_cost +=
model_->GetArcCostForClass(node, after_node, cost_class);
341 costed_after_nodes.emplace_back(total_cost, after_node);
344 std::nth_element(costed_after_nodes.begin(),
345 costed_after_nodes.begin() + num_closest_neighbors - 1,
346 costed_after_nodes.end());
347 std::vector<int64_t>& neighbors = close_nodes_[node];
348 neighbors.reserve(num_closest_neighbors);
350 neighbors.push_back(costed_after_nodes[
index].second);
355void FilteredHeuristicCloseNodesLNSOperator::OnStart() {
357 last_node_ = current_node_;
358 just_started_ =
true;
361bool FilteredHeuristicCloseNodesLNSOperator::IncrementPosition() {
362 DCHECK(initialized_);
364 just_started_ =
false;
367 ++current_node_ %=
model_->Size();
368 return current_node_ != last_node_;
371void FilteredHeuristicCloseNodesLNSOperator::RemoveNode(int64_t node) {
373 DCHECK_NE(
Value(node), node);
374 DCHECK(IsActive(node));
377 const int64_t prev = Prev(node);
379 changed_nexts_.
Set(prev);
380 new_nexts_[prev] =
next;
383 new_prevs_[
next] = prev;
387void FilteredHeuristicCloseNodesLNSOperator::RemoveNodeAndActiveSibling(
389 if (!IsActive(node))
return;
392 for (int64_t sibling_node : GetActiveSiblings(node)) {
393 if (!
model_->IsStart(sibling_node) && !
model_->IsEnd(sibling_node)) {
394 RemoveNode(sibling_node);
399std::vector<int64_t> FilteredHeuristicCloseNodesLNSOperator::GetActiveSiblings(
400 int64_t node)
const {
404 std::vector<int64_t> active_siblings;
405 for (
const auto& [pair_index, unused] :
model_->GetPickupPositions(node)) {
406 for (int64_t sibling_delivery :
407 pickup_delivery_pairs_[pair_index].delivery_alternatives) {
408 if (IsActive(sibling_delivery)) {
409 active_siblings.push_back(sibling_delivery);
414 for (
const auto& [pair_index, unused] :
model_->GetDeliveryPositions(node)) {
415 for (int64_t sibling_pickup :
416 pickup_delivery_pairs_[pair_index].pickup_alternatives) {
417 if (IsActive(sibling_pickup)) {
418 active_siblings.push_back(sibling_pickup);
423 return active_siblings;
426std::function<int64_t(int64_t)>
427FilteredHeuristicCloseNodesLNSOperator::SetupNextAccessorForNeighbor() {
428 DCHECK(initialized_);
429 if (
model_->IsStart(current_node_)) {
432 DCHECK(!
model_->IsEnd(current_node_));
437 RemoveNodeAndActiveSibling(current_node_);
439 for (int64_t neighbor : close_nodes_[current_node_]) {
440 RemoveNodeAndActiveSibling(neighbor);
443 return [
this](int64_t node) {
return Next(node); };
450 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
451 int num_arcs_to_consider,
452 std::function<int64_t(int64_t, int64_t, int64_t)>
453 arc_cost_for_route_start)
457 num_arcs_to_consider_(num_arcs_to_consider),
458 current_expensive_arc_indices_({-1, -1}),
459 arc_cost_for_route_start_(std::move(arc_cost_for_route_start)),
460 just_started_(
false) {
461 DCHECK_GE(num_arcs_to_consider_, 2);
464void FilteredHeuristicExpensiveChainLNSOperator::OnStart() {
465 last_route_ = current_route_;
466 just_started_ =
true;
469bool FilteredHeuristicExpensiveChainLNSOperator::IncrementPosition() {
471 just_started_ =
false;
472 return FindMostExpensiveChainsOnRemainingRoutes();
475 if (IncrementCurrentArcIndices())
return true;
477 return IncrementRoute() && FindMostExpensiveChainsOnRemainingRoutes();
480std::function<int64_t(int64_t)>
481FilteredHeuristicExpensiveChainLNSOperator::SetupNextAccessorForNeighbor() {
482 const int first_arc_index = current_expensive_arc_indices_.first;
483 const int second_arc_index = current_expensive_arc_indices_.second;
484 DCHECK_LE(0, first_arc_index);
485 DCHECK_LT(first_arc_index, second_arc_index);
486 DCHECK_LT(second_arc_index, most_expensive_arc_starts_and_ranks_.size());
488 const std::pair<int, int>& first_start_and_rank =
489 most_expensive_arc_starts_and_ranks_[first_arc_index];
490 const std::pair<int, int>& second_start_and_rank =
491 most_expensive_arc_starts_and_ranks_[second_arc_index];
492 int64_t before_chain, after_chain;
493 if (first_start_and_rank.second < second_start_and_rank.second) {
494 before_chain = first_start_and_rank.first;
495 after_chain =
OldValue(second_start_and_rank.first);
497 before_chain = second_start_and_rank.first;
498 after_chain =
OldValue(first_start_and_rank.first);
501 int node =
Value(before_chain);
502 while (node != after_chain) {
507 return [
this, before_chain, after_chain](int64_t node) {
508 if (node == before_chain)
return after_chain;
513bool FilteredHeuristicExpensiveChainLNSOperator::IncrementRoute() {
514 ++current_route_ %=
model_->vehicles();
515 return current_route_ != last_route_;
518bool FilteredHeuristicExpensiveChainLNSOperator::IncrementCurrentArcIndices() {
519 int& second_index = current_expensive_arc_indices_.second;
520 if (++second_index < most_expensive_arc_starts_and_ranks_.size()) {
523 int& first_index = current_expensive_arc_indices_.first;
524 if (first_index + 2 < most_expensive_arc_starts_and_ranks_.size()) {
526 second_index = first_index + 1;
532bool FilteredHeuristicExpensiveChainLNSOperator::
533 FindMostExpensiveChainsOnRemainingRoutes() {
536 num_arcs_to_consider_,
model_->Start(current_route_),
537 [
this](int64_t i) { return OldValue(i); },
538 [
this](int64_t node) { return model_->IsEnd(node); },
539 arc_cost_for_route_start_, &most_expensive_arc_starts_and_ranks_,
540 ¤t_expensive_arc_indices_)) {
543 }
while (IncrementRoute());
FilteredHeuristicCloseNodesLNSOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic, int num_close_nodes)
FilteredHeuristicCloseNodesLNSOperator.
FilteredHeuristicExpensiveChainLNSOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic, int num_arcs_to_consider, std::function< int64_t(int64_t, int64_t, int64_t)> arc_cost_for_route_start)
FilteredHeuristicExpensiveChainLNSOperator.
RoutingModel *const model_
SparseBitset removed_nodes_
Keeps track of removed nodes when making a neighbor.
virtual std::function< int64_t(int64_t)> SetupNextAccessorForNeighbor()=0
virtual bool IncrementPosition()=0
FilteredHeuristicLocalSearchOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic, bool keep_inverse_values=false)
FilteredHeuristicLocalSearchOperator.
FilteredHeuristicPathLNSOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic)
FilteredHeuristicPathLNSOperator.
void SetValue(int64_t index, int64_t value)
void AddVars(const std::vector< IntVar * > &vars)
int64_t Value(int64_t index) const
int64_t OldValue(int64_t index) const
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
In SWIG mode, we don't want anything besides these top-level includes.
bool FindMostExpensiveArcsOnRoute(int num_arcs, int64_t start, const std::function< int64_t(int64_t)> &next_accessor, const std::function< bool(int64_t)> &is_end, const std::function< int64_t(int64_t, int64_t, int64_t)> &arc_cost_for_route_start, std::vector< std::pair< int64_t, int > > *most_expensive_arc_starts_and_ranks, std::pair< int, int > *first_expensive_arc_indices)