Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
routing_neighborhoods.h
Go to the documentation of this file.
1// Copyright 2010-2025 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#ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_NEIGHBORHOODS_H_
15#define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_NEIGHBORHOODS_H_
16
17#include <stdbool.h>
18
19#include <cstdint>
20#include <functional>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include "absl/log/check.h"
26#include "absl/types/span.h"
30#include "ortools/util/bitset.h"
31
32namespace operations_research {
33
54// TODO(user): Consider merging with standard Relocate in local_search.cc.
55
56template <bool ignore_path_vars>
57class MakeRelocateNeighborsOperator : public PathOperator<ignore_path_vars> {
58 public:
60 const std::vector<IntVar*>& vars,
61 const std::vector<IntVar*>& secondary_vars,
62 std::function<int(int64_t)> start_empty_path_class,
63 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
64 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
65 RoutingTransitCallback2 arc_evaluator);
66 ~MakeRelocateNeighborsOperator() override = default;
67
68 bool MakeNeighbor() override;
69 std::string DebugString() const override { return "RelocateNeighbors"; }
70
71 private:
78 bool MoveChainAndRepair(int64_t before_chain, int64_t chain_end,
79 int64_t destination);
80
88 int64_t Reposition(int64_t before_to_move, int64_t up_to);
89
90 RoutingTransitCallback2 arc_evaluator_;
91};
92
93LocalSearchOperator* MakeRelocateNeighbors(
94 Solver* solver, const std::vector<IntVar*>& vars,
95 const std::vector<IntVar*>& secondary_vars,
96 std::function<int(int64_t)> start_empty_path_class,
97 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
98 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
99 RoutingTransitCallback2 arc_evaluator);
100
101LocalSearchOperator* MakeRelocateNeighbors(
102 Solver* solver, const std::vector<IntVar*>& vars,
103 const std::vector<IntVar*>& secondary_vars,
104 std::function<int(int64_t)> start_empty_path_class,
105 RoutingTransitCallback2 arc_evaluator);
106
107// Class used to compute shortest paths on DAGs formed by chains of alternative
108// node sets.
110 public:
111 ShortestPathOnAlternatives(int num_nodes,
112 std::vector<std::vector<int64_t>> alternative_sets,
113 RoutingTransitCallback2 arc_evaluator);
114 bool HasAlternatives(int node) const;
115 // Returns the shortest path between source and sink, going through the DAG
116 // formed by the alternative nodes of the chain. The path omits source and
117 // sink.
118 absl::Span<const int64_t> GetShortestPath(int64_t source, int64_t sink,
119 absl::Span<const int64_t> chain);
120
121 private:
122 RoutingTransitCallback2 arc_evaluator_;
123 std::vector<std::vector<int64_t>> alternative_sets_;
124 std::vector<int> to_alternative_set_;
125 std::vector<int64_t> path_predecessor_;
126 std::vector<int64_t> path_;
127 std::vector<int64_t> current_values_;
128 SparseBitset<int64_t> touched_;
129};
130
131// Reverses a sub-chain of a path and then replaces it with the shortest path on
132// the DAG formed by the sequence of its node alternatives. This operator will
133// only reverse chains with at least a node with multiple alternatives.
134template <bool ignore_path_vars>
135class TwoOptWithShortestPathOperator : public PathOperator<ignore_path_vars> {
136 public:
138 const std::vector<IntVar*>& vars,
139 const std::vector<IntVar*>& secondary_vars,
140 std::function<int(int64_t)> start_empty_path_class,
141 std::vector<std::vector<int64_t>> alternative_sets,
142 RoutingTransitCallback2 arc_evaluator);
144 bool MakeNeighbor() override;
145 std::string DebugString() const override { return "TwoOptWithShortestPath"; }
146
147 protected:
148 bool OnSamePathAsPreviousBase(int64_t /*base_index*/) override {
149 // Both base nodes have to be on the same path.
150 return true;
151 }
152 int64_t GetBaseNodeRestartPosition(int base_index) override {
153 return (base_index == 0) ? this->StartNode(0) : this->BaseNode(0);
154 }
155 // Necessary to have proper information about alternatives of current path.
156 bool RestartAtPathStartOnSynchronize() override { return true; }
157
158 private:
159 void ResetIncrementalism() override { ResetChainStatus(); }
160 void OnNodeInitialization() override { ResetChainStatus(); }
161 void ResetChainStatus() {
162 chain_status_.start = -1;
163 chain_status_.end = -1;
164 chain_status_.has_alternatives = false;
165 }
166
167 struct ChainStatus {
168 int64_t start = -1;
169 int64_t end = -1;
170 bool has_alternatives = false;
171 };
172 ChainStatus chain_status_;
173 ShortestPathOnAlternatives shortest_path_manager_;
174 std::vector<int64_t> chain_;
175};
176
178 Solver* solver, const std::vector<IntVar*>& vars,
179 const std::vector<IntVar*>& secondary_vars,
180 std::function<int(int64_t)> start_empty_path_class,
181 std::vector<std::vector<int64_t>> alternative_sets,
182 RoutingTransitCallback2 arc_evaluator);
183
184// Swaps active nodes from node alternatives in sequence. Considers chains of
185// nodes with alternatives, builds a DAG from the chain, each "layer" of the DAG
186// being composed of the set of alternatives of the node at a given rank in the
187// chain, fully connected to the next layer. A neighbor is built from the
188// shortest path starting from the node before the chain (source), through the
189// DAG to the node following the chain. The path is valued with a given
190// callback.
191// Example:
192// Alternative sets: {1,2} and {3,4}
193// Current path: 0 -> 1 -> 3 -> 5
194// DAG + source and sink: -> 1 ---> 3 --
195// | \ / v
196// 0 X 5
197// | / \ ^
198// -> 2 ---> 4 --
199// Supposing the shortest path from 0 to 5 is 0, 2, 3, 5, the neighbor for the
200// chain will be: 0 -> 2 -> 3 -> 5.
201// TODO(user): Support vehicle-class-dependent arc_evaluators.
202template <bool ignore_path_vars>
203class SwapActiveToShortestPathOperator : public PathOperator<ignore_path_vars> {
204 public:
206 const std::vector<IntVar*>& vars,
207 const std::vector<IntVar*>& secondary_vars,
208 std::function<int(int64_t)> start_empty_path_class,
209 std::vector<std::vector<int64_t>> alternative_sets,
210 RoutingTransitCallback2 arc_evaluator);
212 bool MakeNeighbor() override;
213 std::string DebugString() const override {
214 return "SwapActiveToShortestPath";
215 }
216
217 private:
218 ShortestPathOnAlternatives shortest_path_manager_;
219 std::vector<int64_t> chain_;
220};
221
222LocalSearchOperator* MakeSwapActiveToShortestPath(
223 Solver* solver, const std::vector<IntVar*>& vars,
224 const std::vector<IntVar*>& secondary_vars,
225 std::function<int(int64_t)> start_empty_path_class,
226 std::vector<std::vector<int64_t>> alternative_sets,
227 RoutingTransitCallback2 arc_evaluator);
228
233// TODO(user): Add option to prune neighbors where the order of node pairs
234// is violated (ie precedence between pickup and delivery nodes).
235// TODO(user): Move this to local_search.cc if it's generic enough.
236// TODO(user): Detect pairs automatically by parsing the constraint model;
237// we could then get rid of the pair API in the RoutingModel
238// class.
239
252template <bool ignore_path_vars>
253class MakePairActiveOperator : public PathOperator<ignore_path_vars> {
254 public:
255 MakePairActiveOperator(const std::vector<IntVar*>& vars,
256 const std::vector<IntVar*>& secondary_vars,
257 std::function<int(int64_t)> start_empty_path_class,
258 const std::vector<PickupDeliveryPair>& pairs);
259 ~MakePairActiveOperator() override = default;
260 bool MakeNeighbor() override;
261 std::string DebugString() const override { return "MakePairActive"; }
262
263 protected:
264 bool MakeOneNeighbor() override;
265 bool OnSamePathAsPreviousBase(int64_t /*base_index*/) override {
268 return true;
269 }
270
271 int64_t GetBaseNodeRestartPosition(int base_index) override;
272
275 bool RestartAtPathStartOnSynchronize() override { return true; }
276
277 private:
278 void OnNodeInitialization() override;
279 int FindNextInactivePair(int pair_index) const;
280 bool ContainsActiveNodes(absl::Span<const int64_t> nodes) const;
281
282 int inactive_pair_;
283 int inactive_pair_first_index_;
284 int inactive_pair_second_index_;
285 const std::vector<PickupDeliveryPair> pairs_;
286};
287
288LocalSearchOperator* MakePairActive(
289 Solver* solver, const std::vector<IntVar*>& vars,
290 const std::vector<IntVar*>& secondary_vars,
291 std::function<int(int64_t)> start_empty_path_class,
292 const std::vector<PickupDeliveryPair>& pairs);
293
295template <bool ignore_path_vars>
296class MakePairInactiveOperator : public PathOperator<ignore_path_vars> {
297 public:
298 MakePairInactiveOperator(const std::vector<IntVar*>& vars,
299 const std::vector<IntVar*>& secondary_vars,
300 std::function<int(int64_t)> start_empty_path_class,
301 const std::vector<PickupDeliveryPair>& pairs);
302
303 bool MakeNeighbor() override;
304 std::string DebugString() const override { return "MakePairInActive"; }
305};
306
307LocalSearchOperator* MakePairInactive(
308 Solver* solver, const std::vector<IntVar*>& vars,
309 const std::vector<IntVar*>& secondary_vars,
310 std::function<int(int64_t)> start_empty_path_class,
311 const std::vector<PickupDeliveryPair>& pairs);
312
321template <bool ignore_path_vars>
322class PairRelocateOperator : public PathOperator<ignore_path_vars> {
323 public:
324 PairRelocateOperator(const std::vector<IntVar*>& vars,
325 const std::vector<IntVar*>& secondary_vars,
326 std::function<int(int64_t)> start_empty_path_class,
327 const std::vector<PickupDeliveryPair>& pairs);
328 ~PairRelocateOperator() override = default;
329
330 bool MakeNeighbor() override;
331 std::string DebugString() const override { return "PairRelocateOperator"; }
332
333 protected:
334 bool OnSamePathAsPreviousBase(int64_t base_index) override {
336 return base_index == kPairSecondNodeDestination;
337 }
338 int64_t GetBaseNodeRestartPosition(int base_index) override;
339
340 bool ConsiderAlternatives(int64_t base_index) const override {
341 return base_index == kPairFirstNode;
342 }
343
344 private:
345 bool RestartAtPathStartOnSynchronize() override { return true; }
346
347 static constexpr int kPairFirstNode = 0;
348 static constexpr int kPairFirstNodeDestination = 1;
349 static constexpr int kPairSecondNodeDestination = 2;
350};
351
353 Solver* solver, const std::vector<IntVar*>& vars,
354 const std::vector<IntVar*>& secondary_vars,
355 std::function<int(int64_t)> start_empty_path_class,
356 const std::vector<PickupDeliveryPair>& pairs);
357
360template <bool ignore_path_vars>
361class GroupPairAndRelocateOperator : public PathOperator<ignore_path_vars> {
362 public:
364 const std::vector<IntVar*>& vars,
365 const std::vector<IntVar*>& secondary_vars,
366 std::function<int(int64_t)> start_empty_path_class,
367 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
368 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
369 const std::vector<PickupDeliveryPair>& pairs);
370 ~GroupPairAndRelocateOperator() override = default;
371
372 bool MakeNeighbor() override;
373 std::string DebugString() const override { return "GroupPairAndRelocate"; }
374};
375
376LocalSearchOperator* MakeGroupPairAndRelocate(
377 Solver* solver, const std::vector<IntVar*>& vars,
378 const std::vector<IntVar*>& secondary_vars,
379 std::function<int(int64_t)> start_empty_path_class,
380 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
381 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
382 const std::vector<PickupDeliveryPair>& pairs);
383
384LocalSearchOperator* MakeGroupPairAndRelocate(
385 Solver* solver, const std::vector<IntVar*>& vars,
386 const std::vector<IntVar*>& secondary_vars,
387 std::function<int(int64_t)> start_empty_path_class,
388 const std::vector<PickupDeliveryPair>& pairs);
389
399// TODO(user): Add a version which inserts the first node before the other
400// pair's first node; there are many redundant neighbors if done blindly.
401template <bool ignore_path_vars>
402class LightPairRelocateOperator : public PathOperator<ignore_path_vars> {
403 public:
405 const std::vector<IntVar*>& vars,
406 const std::vector<IntVar*>& secondary_vars,
407 std::function<int(int64_t)> start_empty_path_class,
408 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
409 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
410 const std::vector<PickupDeliveryPair>& pairs,
411 std::function<bool(int64_t)> force_lifo = nullptr);
412 ~LightPairRelocateOperator() override = default;
413
414 bool MakeNeighbor() override;
415 std::string DebugString() const override {
416 return "LightPairRelocateOperator";
417 }
418
419 private:
420 std::function<bool(int64_t)> force_lifo_;
421};
422
423LocalSearchOperator* MakeLightPairRelocate(
424 Solver* solver, const std::vector<IntVar*>& vars,
425 const std::vector<IntVar*>& secondary_vars,
426 std::function<int(int64_t)> start_empty_path_class,
427 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
428 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
429 const std::vector<PickupDeliveryPair>& pairs,
430 std::function<bool(int64_t)> force_lifo = nullptr);
431
432LocalSearchOperator* MakeLightPairRelocate(
433 Solver* solver, const std::vector<IntVar*>& vars,
434 const std::vector<IntVar*>& secondary_vars,
435 std::function<int(int64_t)> start_empty_path_class,
436 const std::vector<PickupDeliveryPair>& pairs,
437 std::function<bool(int64_t)> force_lifo = nullptr);
438
445template <bool ignore_path_vars>
446class PairExchangeOperator : public PathOperator<ignore_path_vars> {
447 public:
449 const std::vector<IntVar*>& vars,
450 const std::vector<IntVar*>& secondary_vars,
451 std::function<int(int64_t)> start_empty_path_class,
452 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
453 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
454 const std::vector<PickupDeliveryPair>& pairs);
455 ~PairExchangeOperator() override = default;
456
457 bool MakeNeighbor() override;
458 std::string DebugString() const override { return "PairExchangeOperator"; }
459
460 private:
461 bool RestartAtPathStartOnSynchronize() override { return true; }
462 bool ConsiderAlternatives(int64_t /*base_index*/) const override {
463 return true;
464 }
465 bool GetPreviousAndSibling(int64_t node, int64_t* previous, int64_t* sibling,
466 int64_t* sibling_previous) const;
467};
468
470 Solver* solver, const std::vector<IntVar*>& vars,
471 const std::vector<IntVar*>& secondary_vars,
472 std::function<int(int64_t)> start_empty_path_class,
473 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
474 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
475 const std::vector<PickupDeliveryPair>& pairs);
476
478 Solver* solver, const std::vector<IntVar*>& vars,
479 const std::vector<IntVar*>& secondary_vars,
480 std::function<int(int64_t)> start_empty_path_class,
481 const std::vector<PickupDeliveryPair>& pairs);
482
496template <bool ignore_path_vars>
497class PairExchangeRelocateOperator : public PathOperator<ignore_path_vars> {
498 public:
500 const std::vector<IntVar*>& vars,
501 const std::vector<IntVar*>& secondary_vars,
502 std::function<int(int64_t)> start_empty_path_class,
503 const std::vector<PickupDeliveryPair>& pairs);
504 ~PairExchangeRelocateOperator() override = default;
505
506 bool MakeNeighbor() override;
507 std::string DebugString() const override {
508 return "PairExchangeRelocateOperator";
509 }
510
511 protected:
512 bool OnSamePathAsPreviousBase(int64_t base_index) override;
513 int64_t GetBaseNodeRestartPosition(int base_index) override;
514
515 private:
516 bool RestartAtPathStartOnSynchronize() override { return true; }
517 bool GetPreviousAndSibling(int64_t node, int64_t* previous, int64_t* sibling,
518 int64_t* sibling_previous) const;
519 bool MoveNode(int pair, int node, int64_t nodes[2][2], int64_t dest[2][2],
520 int64_t prev[2][2]);
521 bool LoadAndCheckDest(int pair, int node, int64_t base_node,
522 int64_t nodes[2][2], int64_t dest[2][2]) const;
523
524 static constexpr int kFirstPairFirstNode = 0;
525 static constexpr int kSecondPairFirstNode = 1;
526 static constexpr int kFirstPairFirstNodeDestination = 2;
527 static constexpr int kFirstPairSecondNodeDestination = 3;
528 static constexpr int kSecondPairFirstNodeDestination = 4;
529 static constexpr int kSecondPairSecondNodeDestination = 5;
530};
531
533 Solver* solver, const std::vector<IntVar*>& vars,
534 const std::vector<IntVar*>& secondary_vars,
535 std::function<int(int64_t)> start_empty_path_class,
536 const std::vector<PickupDeliveryPair>& pairs);
537
549 public:
550 SwapIndexPairOperator(const std::vector<IntVar*>& vars,
551 const std::vector<IntVar*>& path_vars,
552 const std::vector<PickupDeliveryPair>& pairs);
553 ~SwapIndexPairOperator() override = default;
554
555 bool MakeNextNeighbor(Assignment* delta, Assignment* deltadelta) override;
556 void OnStart() override;
557 std::string DebugString() const override { return "SwapIndexPairOperator"; }
558
559 private:
562 bool UpdateActiveNodes();
564 void SetNext(int64_t from, int64_t to, int64_t path) {
565 DCHECK_LT(from, number_of_nexts_);
566 SetValue(from, to);
567 if (!ignore_path_vars_) {
568 DCHECK_LT(from + number_of_nexts_, Size());
569 SetValue(from + number_of_nexts_, path);
570 }
571 }
572
573 const std::vector<PickupDeliveryPair> pairs_;
574 int pair_index_;
575 int first_index_;
576 int second_index_;
577 int64_t first_active_;
578 int64_t second_active_;
579 std::vector<int64_t> prevs_;
580 const int number_of_nexts_;
581 const bool ignore_path_vars_;
582};
583
586template <bool ignore_path_vars>
587class IndexPairSwapActiveOperator : public PathOperator<ignore_path_vars> {
588 public:
590 const std::vector<IntVar*>& vars,
591 const std::vector<IntVar*>& secondary_vars,
592 std::function<int(int64_t)> start_empty_path_class,
593 const std::vector<PickupDeliveryPair>& pairs);
594 ~IndexPairSwapActiveOperator() override = default;
595
596 bool MakeNextNeighbor(Assignment* delta, Assignment* deltadelta) override;
597 bool MakeNeighbor() override;
598 std::string DebugString() const override {
599 return "IndexPairSwapActiveOperator";
600 }
601
602 private:
603 void OnNodeInitialization() override;
604
605 int inactive_node_;
606};
607
608LocalSearchOperator* MakeIndexPairSwapActive(
609 Solver* solver, const std::vector<IntVar*>& vars,
610 const std::vector<IntVar*>& secondary_vars,
611 std::function<int(int64_t)> start_empty_path_class,
612 const std::vector<PickupDeliveryPair>& pairs);
613
621template <bool ignore_path_vars>
622class RelocateExpensiveChain : public PathOperator<ignore_path_vars> {
623 public:
624 RelocateExpensiveChain(const std::vector<IntVar*>& vars,
625 const std::vector<IntVar*>& secondary_vars,
626 std::function<int(int64_t)> start_empty_path_class,
627 int num_arcs_to_consider,
628 std::function<int64_t(int64_t, int64_t, int64_t)>
629 arc_cost_for_path_start);
630 ~RelocateExpensiveChain() override = default;
631
632 bool MakeNeighbor() override;
633 bool MakeOneNeighbor() override;
634
635 std::string DebugString() const override { return "RelocateExpensiveChain"; }
636
637 private:
638 void OnNodeInitialization() override;
639 void IncrementCurrentPath();
640 bool IncrementCurrentArcIndices();
644 bool FindMostExpensiveChainsOnRemainingPaths();
645
646 int num_arcs_to_consider_;
647 int current_path_;
648 std::vector<std::pair<int64_t, int>> most_expensive_arc_starts_and_ranks_;
651 std::pair</*first_arc_index*/ int, /*second_arc_index*/ int>
652 current_expensive_arc_indices_;
653 std::function<int64_t(/*before_node*/ int64_t, /*after_node*/ int64_t,
654 /*path_start*/ int64_t)>
655 arc_cost_for_path_start_;
656 int end_path_;
659 bool has_non_empty_paths_to_explore_;
660};
661
663 Solver* solver, const std::vector<IntVar*>& vars,
664 const std::vector<IntVar*>& secondary_vars,
665 std::function<int(int64_t)> start_empty_path_class,
666 int num_arcs_to_consider,
667 std::function<int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start);
668
676template <bool swap_first, bool ignore_path_vars>
677class PairNodeSwapActiveOperator : public PathOperator<ignore_path_vars> {
678 public:
679 PairNodeSwapActiveOperator(const std::vector<IntVar*>& vars,
680 const std::vector<IntVar*>& secondary_vars,
681 std::function<int(int64_t)> start_empty_path_class,
682 const std::vector<PickupDeliveryPair>& pairs);
683 ~PairNodeSwapActiveOperator() override = default;
684
685 bool MakeNextNeighbor(Assignment* delta, Assignment* deltadelta) override;
686 bool MakeNeighbor() override;
687 std::string DebugString() const override {
688 return "PairNodeSwapActiveOperator";
690
691 protected:
692 bool OnSamePathAsPreviousBase(int64_t /*base_index*/) override {
694 /// nodes after which unactive node pairs will be moved.
695 return true;
696 }
697
698 int64_t GetBaseNodeRestartPosition(int base_index) override;
699
702 bool RestartAtPathStartOnSynchronize() override { return true; }
703
704 private:
705 void OnNodeInitialization() override;
706
707 int inactive_pair_;
708 std::vector<PickupDeliveryPair> pairs_;
709};
710
711// ==========================================================================
712// Section: Implementations of the template classes declared above.
713
714template <bool swap_first, bool ignore_path_vars>
717 const std::vector<IntVar*>& vars,
718 const std::vector<IntVar*>& secondary_vars,
719 std::function<int(int64_t)> start_empty_path_class,
720 const std::vector<PickupDeliveryPair>& pairs)
721 : PathOperator<ignore_path_vars>(vars, secondary_vars, 2, false, false,
722 std::move(start_empty_path_class), nullptr,
723 nullptr),
724 inactive_pair_(0),
725 pairs_(pairs) {}
726
727template <bool swap_first, bool ignore_path_vars>
729 swap_first, ignore_path_vars>::GetBaseNodeRestartPosition(int base_index) {
730 // Base node 1 must be after base node 0 if they are both on the same path.
731 if (base_index == 0 ||
732 this->StartNode(base_index) != this->StartNode(base_index - 1)) {
733 return this->StartNode(base_index);
734 } else {
735 return this->BaseNode(base_index - 1);
736 }
737}
738
739template <bool swap_first, bool ignore_path_vars>
740void PairNodeSwapActiveOperator<swap_first,
741 ignore_path_vars>::OnNodeInitialization() {
742 for (int i = 0; i < pairs_.size(); ++i) {
743 if (this->IsInactive(pairs_[i].pickup_alternatives[0]) &&
744 this->IsInactive(pairs_[i].delivery_alternatives[0])) {
745 inactive_pair_ = i;
746 return;
747 }
748 }
749 inactive_pair_ = pairs_.size();
750}
751
752template <bool swap_first, bool ignore_path_vars>
754 Assignment* delta, Assignment* deltadelta) {
755 while (inactive_pair_ < pairs_.size()) {
756 if (!this->IsInactive(pairs_[inactive_pair_].pickup_alternatives[0]) ||
757 !this->IsInactive(pairs_[inactive_pair_].delivery_alternatives[0]) ||
759 this->ResetPosition();
760 ++inactive_pair_;
761 } else {
762 return true;
763 }
764 }
765 return false;
766}
767
768template <bool swap_first, bool ignore_path_vars>
770 const int64_t base = this->BaseNode(0);
771 if (this->IsPathEnd(base)) {
772 return false;
773 }
774 const int64_t pair_first = pairs_[inactive_pair_].pickup_alternatives[0];
775 const int64_t pair_second = pairs_[inactive_pair_].delivery_alternatives[0];
776 if (swap_first) {
777 return this->MakeActive(pair_second, this->BaseNode(1)) &&
778 this->MakeActive(pair_first, base) &&
779 this->MakeChainInactive(pair_first, this->Next(pair_first));
780 } else {
781 return this->MakeActive(pair_second, this->BaseNode(1)) &&
782 this->MakeActive(pair_first, base) &&
783 this->MakeChainInactive(pair_second, this->Next(pair_second));
784 }
785}
786
787template <bool swap_first>
789 Solver* solver, const std::vector<IntVar*>& vars,
790 const std::vector<IntVar*>& secondary_vars,
791 std::function<int(int64_t)> start_empty_path_class,
792 const std::vector<PickupDeliveryPair>& pairs) {
793 if (secondary_vars.empty()) {
794 return solver->RevAlloc(new PairNodeSwapActiveOperator<swap_first, true>(
795 vars, secondary_vars, std::move(start_empty_path_class), pairs));
796 }
797 return solver->RevAlloc(new PairNodeSwapActiveOperator<swap_first, false>(
798 vars, secondary_vars, std::move(start_empty_path_class), pairs));
799}
800
802class PickupAndDeliveryData {
803 public:
804 PickupAndDeliveryData(int num_nodes,
805 absl::Span<const PickupDeliveryPair> pairs);
806 bool IsPickupNode(int64_t node) const {
807 DCHECK_LT(node, is_pickup_node_.size());
808 return is_pickup_node_[node];
810 bool IsDeliveryNode(int64_t node) const {
811 DCHECK_LT(node, is_delivery_node_.size());
812 return is_delivery_node_[node];
814 int GetPairOfNode(int64_t node) const {
815 DCHECK_LT(node, pair_of_node_.size());
816 return pair_of_node_[node];
818
819 private:
820 std::vector<bool> is_pickup_node_;
821 std::vector<bool> is_delivery_node_;
822 std::vector<int> pair_of_node_;
823};
824
827
836template <bool ignore_path_vars>
837class RelocateSubtrip : public PathOperator<ignore_path_vars> {
838 public:
840 const std::vector<IntVar*>& vars,
841 const std::vector<IntVar*>& secondary_vars,
842 std::function<int(int64_t)> start_empty_path_class,
843 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
844 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
845 absl::Span<const PickupDeliveryPair> pairs);
846
847 std::string DebugString() const override { return "RelocateSubtrip"; }
848 bool MakeNeighbor() override;
849
850 private:
851 // Relocates the subtrip starting at chain_first_node. It must be a pickup.
852 bool RelocateSubTripFromPickup(int64_t chain_first_node,
853 int64_t insertion_node);
855 bool RelocateSubTripFromDelivery(int64_t chain_last_node,
856 int64_t insertion_node);
857 void SetPath(absl::Span<const int64_t> path, int path_id);
858
859 const PickupAndDeliveryData pd_data_;
860 // Represents the set of pairs that have been opened during a call to
861 // MakeNeighbor(). This vector must be all false before and after calling
862 // RelocateSubTripFromPickup() and RelocateSubTripFromDelivery().
863 std::vector<bool> opened_pairs_set_;
864
865 std::vector<int64_t> rejected_nodes_;
866 std::vector<int64_t> subtrip_nodes_;
867};
868
870 Solver* solver, const std::vector<IntVar*>& vars,
871 const std::vector<IntVar*>& secondary_vars,
872 std::function<int(int64_t)> start_empty_path_class,
873 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
874 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
875 absl::Span<const PickupDeliveryPair> pairs);
876
878 Solver* solver, const std::vector<IntVar*>& vars,
879 const std::vector<IntVar*>& secondary_vars,
880 std::function<int(int64_t)> start_empty_path_class,
881 absl::Span<const PickupDeliveryPair> pairs);
882
883template <bool ignore_path_vars>
884class ExchangeSubtrip : public PathOperator<ignore_path_vars> {
885 public:
887 const std::vector<IntVar*>& vars,
888 const std::vector<IntVar*>& secondary_vars,
889 std::function<int(int64_t)> start_empty_path_class,
890 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
891 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
892 absl::Span<const PickupDeliveryPair> pairs);
893
894 std::string DebugString() const override { return "ExchangeSubtrip"; }
895 bool MakeNeighbor() override;
896
897 private:
898 // Try to extract a subtrip from base_node (see below) and check that the move
899 // will be canonical.
900 // Given a pickup/delivery pair, this operator could generate the same move
901 // twice, the first time with base_node == pickup, the second time with
902 // base_node == delivery. This happens only when no nodes in the subtrip
903 // remain in the original path, i.e. when rejects is empty after
904 // chain extraction. In that case, we keep only a canonical move out of the
905 // two possibilities, the move where base_node is a pickup.
906 bool ExtractChainsAndCheckCanonical(int64_t base_node,
907 std::vector<int64_t>* rejects,
908 std::vector<int64_t>* subtrip);
909 // Reads the path from base_node forward, collecting subtrip nodes in
910 // subtrip and non-subtrip nodes in rejects.
911 // Non-subtrip nodes will be unmatched delivery nodes.
912 // base_node must be a pickup, and remaining/extracted_nodes must be empty.
913 // Returns true if such chains could be extracted.
914 bool ExtractChainsFromPickup(int64_t base_node, std::vector<int64_t>* rejects,
915 std::vector<int64_t>* subtrip);
916 // Reads the path from base_node backward, collecting subtrip nodes in
917 // subtrip and non-subtrip nodes in rejects.
918 // Non-subtrip nodes will be unmatched pickup nodes.
919 // base_node must be a delivery, and remaining/extracted_nodes must be empty.
920 // Returns true if such chains could be extracted.
921 bool ExtractChainsFromDelivery(int64_t base_node,
922 std::vector<int64_t>* rejects,
923 std::vector<int64_t>* subtrip);
924 void SetPath(absl::Span<const int64_t> path, int path_id);
925
926 const PickupAndDeliveryData pd_data_;
927 // Represents the set of opened pairs during ExtractChainsFromXXX().
928 std::vector<bool> opened_pairs_set_;
929 // Keep internal structures under hand to avoid reallocation.
930 std::vector<int64_t> rejects0_;
931 std::vector<int64_t> subtrip0_;
932 std::vector<int64_t> rejects1_;
933 std::vector<int64_t> subtrip1_;
934 std::vector<int64_t> path0_;
935 std::vector<int64_t> path1_;
936};
937
939 Solver* solver, const std::vector<IntVar*>& vars,
940 const std::vector<IntVar*>& secondary_vars,
941 std::function<int(int64_t)> start_empty_path_class,
942 std::function<const std::vector<int>&(int, int)> get_incoming_neighbors,
943 std::function<const std::vector<int>&(int, int)> get_outgoing_neighbors,
944 absl::Span<const PickupDeliveryPair> pairs);
945
947 Solver* solver, const std::vector<IntVar*>& vars,
948 const std::vector<IntVar*>& secondary_vars,
949 std::function<int(int64_t)> start_empty_path_class,
950 absl::Span<const PickupDeliveryPair> pairs);
951
952} // namespace operations_research
953
954#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_NEIGHBORHOODS_H_
std::string DebugString() const override
ExchangeSubtrip(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, absl::Span< const PickupDeliveryPair > pairs)
GroupPairAndRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, const std::vector< PickupDeliveryPair > &pairs)
IndexPairSwapActiveOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
void SetValue(int64_t index, int64_t value)
IntVarLocalSearchOperator(const std::vector< IntVar * > &vars, bool keep_inverse_values=false)
LightPairRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, const std::vector< PickupDeliveryPair > &pairs, std::function< bool(int64_t)> force_lifo=nullptr)
virtual bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta)=0
MakePairActiveOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
int64_t GetBaseNodeRestartPosition(int base_index) override
MakePairInactiveOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
MakeRelocateNeighborsOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, RoutingTransitCallback2 arc_evaluator)
PairExchangeOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, const std::vector< PickupDeliveryPair > &pairs)
PairExchangeRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
--— Base operator class for operators manipulating IntVars --—
PairNodeSwapActiveOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
Section: Implementations of the template classes declared above.
int64_t GetBaseNodeRestartPosition(int base_index) override
PairRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
bool OnSamePathAsPreviousBase(int64_t base_index) override
bool ConsiderAlternatives(int64_t base_index) const override
int64_t GetBaseNodeRestartPosition(int base_index) override
PathOperator(const std::vector< IntVar * > &next_vars, const std::vector< IntVar * > &path_vars, IterationParameters iteration_parameters)
Builds an instance of PathOperator from next and path variables.
bool IsInactive(int64_t node) const
Returns true if node is inactive.
int64_t StartNode(int i) const
Returns the start node of the ith base node.
int64_t BaseNode(int i) const
Returns the ith base node of the operator.
A utility class to maintain pickup and delivery information of nodes.
PickupAndDeliveryData(int num_nodes, absl::Span< const PickupDeliveryPair > pairs)
RelocateExpensiveChain(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, int num_arcs_to_consider, std::function< int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start)
bool MakeOneNeighbor() override
This method should not be overridden. Override MakeNeighbor() instead.
std::string DebugString() const override
RelocateSubtrip(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, absl::Span< const PickupDeliveryPair > pairs)
absl::Span< const int64_t > GetShortestPath(int64_t source, int64_t sink, absl::Span< const int64_t > chain)
ShortestPathOnAlternatives(int num_nodes, std::vector< std::vector< int64_t > > alternative_sets, RoutingTransitCallback2 arc_evaluator)
For the time being, Solver is neither MT_SAFE nor MT_HOT.
SwapActiveToShortestPathOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::vector< std::vector< int64_t > > alternative_sets, RoutingTransitCallback2 arc_evaluator)
SwapIndexPairOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &path_vars, const std::vector< PickupDeliveryPair > &pairs)
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
--— Base operator class for operators manipulating IntVars --—
bool RestartAtPathStartOnSynchronize() override
Necessary to have proper information about alternatives of current path.
TwoOptWithShortestPathOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::vector< std::vector< int64_t > > alternative_sets, RoutingTransitCallback2 arc_evaluator)
In SWIG mode, we don't want anything besides these top-level includes.
LocalSearchOperator * MakePairNodeSwapActive(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakeExchangeSubtrip(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, absl::Span< const PickupDeliveryPair > pairs)
LocalSearchOperator * MakePairActive(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakeLightPairRelocate(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, const std::vector< PickupDeliveryPair > &pairs, std::function< bool(int64_t)> force_lifo)
LocalSearchOperator * MakePairExchangeRelocate(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakeGroupPairAndRelocate(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakePairInactive(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakePairRelocate(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakeSwapActiveToShortestPath(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::vector< std::vector< int64_t > > alternative_sets, RoutingTransitCallback2 arc_evaluator)
LocalSearchOperator * MakeRelocateExpensiveChain(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, int num_arcs_to_consider, std::function< int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start)
LocalSearchOperator * MakeIndexPairSwapActive(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakeChainInactive(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class)
--— MakeChainInactive --—
LocalSearchOperator * MakeRelocateSubtrip(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, absl::Span< const PickupDeliveryPair > pairs)
LocalSearchOperator * MakeTwoOptWithShortestPath(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::vector< std::vector< int64_t > > alternative_sets, RoutingTransitCallback2 arc_evaluator)
std::function< int64_t(int64_t, int64_t)> RoutingTransitCallback2
LocalSearchOperator * MakeRelocateNeighbors(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, RoutingTransitCallback2 arc_evaluator)
LocalSearchOperator * MakePairExchange(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors, const std::vector< PickupDeliveryPair > &pairs)
LocalSearchOperator * MakeActive(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, std::function< const std::vector< int > &(int, int)> get_incoming_neighbors=nullptr, std::function< const std::vector< int > &(int, int)> get_outgoing_neighbors=nullptr)
--— MakeActive --—
STL namespace.
bool Next()
trees with all degrees equal to