22#include "absl/log/check.h"
23#include "absl/types/span.h"
33 std::function<const std::vector<int>&(int, int)>;
35template <
bool ignore_path_vars>
37 const std::vector<IntVar*>& vars,
38 const std::vector<IntVar*>& secondary_vars,
39 std::function<
int(int64_t)> start_empty_path_class,
46 get_incoming_neighbors == nullptr && get_outgoing_neighbors == nullptr
50 false,
std::move(start_empty_path_class),
51 std::move(get_incoming_neighbors),
std::move(get_outgoing_neighbors)),
52 arc_evaluator_(
std::move(arc_evaluator)) {}
54template <
bool ignore_path_vars>
56 const auto do_move = [
this](int64_t before_chain, int64_t destination) {
57 int64_t chain_end = this->
Next(before_chain);
58 if (this->
IsPathEnd(chain_end))
return false;
59 if (chain_end == destination)
return false;
60 const int64_t max_arc_value = arc_evaluator_(destination, chain_end);
61 int64_t next = this->
Next(chain_end);
63 arc_evaluator_(chain_end, next) <= max_arc_value) {
70 if (next == destination)
return false;
72 next = this->
Next(chain_end);
74 return MoveChainAndRepair(before_chain, chain_end, destination);
78 if (neighbor < 0 || this->
IsInactive(neighbor))
return false;
84 return do_move(this->
Prev(neighbor),
92template <
bool ignore_path_vars>
93bool MakeRelocateNeighborsOperator<ignore_path_vars>::MoveChainAndRepair(
94 int64_t before_chain, int64_t chain_end, int64_t destination) {
95 if (this->MoveChain(before_chain, chain_end, destination)) {
96 if (!this->IsPathStart(destination)) {
97 int64_t current = this->Prev(destination);
98 int64_t last = chain_end;
99 if (current == last) {
100 current = before_chain;
102 while (last >= 0 && !this->IsPathStart(current) && current != last) {
103 last = Reposition(current, last);
104 current = this->Prev(current);
112template <
bool ignore_path_vars>
113int64_t MakeRelocateNeighborsOperator<ignore_path_vars>::Reposition(
114 int64_t before_to_move, int64_t up_to) {
115 const int64_t kNoChange = -1;
116 const int64_t to_move = this->
Next(before_to_move);
117 int64_t next = this->
Next(to_move);
118 if (this->Var(to_move)->Contains(next)) {
122 next = this->
Next(next);
123 while (prev != up_to) {
124 if (this->Var(prev)->Contains(to_move) &&
125 this->Var(to_move)->Contains(next)) {
126 this->MoveChain(before_to_move, to_move, prev);
130 next = this->
Next(next);
132 if (this->Var(prev)->Contains(to_move)) {
133 this->MoveChain(before_to_move, to_move, prev);
140 Solver* solver,
const std::vector<IntVar*>& vars,
141 const std::vector<IntVar*>& secondary_vars,
142 std::function<
int(int64_t)> start_empty_path_class,
143 std::function<
const std::vector<int>&(
int,
int)> get_incoming_neighbors,
144 std::function<
const std::vector<int>&(
int,
int)> get_outgoing_neighbors,
146 if (secondary_vars.empty()) {
148 vars, secondary_vars, std::move(start_empty_path_class),
149 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
150 std::move(arc_evaluator)));
153 vars, secondary_vars, std::move(start_empty_path_class),
154 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
155 std::move(arc_evaluator)));
159 Solver* solver,
const std::vector<IntVar*>& vars,
160 const std::vector<IntVar*>& secondary_vars,
161 std::function<
int(int64_t)> start_empty_path_class,
164 std::move(start_empty_path_class),
nullptr,
165 nullptr, std::move(arc_evaluator));
169 int num_nodes, std::vector<std::vector<int64_t>> alternative_sets,
171 : arc_evaluator_(
std::move(arc_evaluator)),
172 alternative_sets_(
std::move(alternative_sets)),
173 to_alternative_set_(num_nodes, -1),
174 path_predecessor_(num_nodes, -1),
175 touched_(num_nodes) {
176 for (
int i = 0; i < alternative_sets_.size(); ++i) {
177 for (
int j : alternative_sets_[i]) {
178 if (j < to_alternative_set_.size()) to_alternative_set_[j] = i;
181 for (
int i = 0; i < num_nodes; ++i) {
182 if (to_alternative_set_[i] == -1) {
183 to_alternative_set_[i] = alternative_sets_.size();
184 alternative_sets_.push_back({int64_t{i}});
190 DCHECK_LT(node, to_alternative_set_.size());
191 DCHECK_LT(to_alternative_set_[node], alternative_sets_.size());
192 return alternative_sets_[to_alternative_set_[node]].size() > 1;
196 int64_t source, int64_t sink, absl::Span<const int64_t> chain) {
198 if (chain.empty())
return path_;
200 const std::vector<int64_t> source_alternatives = {source};
201 auto prev_alternative_set = absl::Span<const int64_t>(source_alternatives);
202 std::vector<int64_t> prev_values = {0};
204 auto get_best_predecessor = [
this, &prev_alternative_set, &prev_values](
205 int64_t node) -> std::pair<int64_t, int64_t> {
206 int64_t predecessor = -1;
208 for (
int prev_alternative = 0;
209 prev_alternative < prev_alternative_set.size(); ++prev_alternative) {
210 const int64_t new_value =
211 CapAdd(prev_values[prev_alternative],
212 arc_evaluator_(prev_alternative_set[prev_alternative], node));
213 if (new_value <= min_value) {
214 min_value = new_value;
215 predecessor = prev_alternative_set[prev_alternative];
218 return {predecessor, min_value};
223 for (
const int64_t node : chain) {
224 const std::vector<int64_t>& current_alternative_set =
225 alternative_sets_[to_alternative_set_[node]];
226 current_values_.clear();
227 current_values_.reserve(current_alternative_set.size());
228 for (
int alternative_node : current_alternative_set) {
229 auto [predecessor, min_value] = get_best_predecessor(alternative_node);
230 current_values_.push_back(min_value);
231 path_predecessor_[alternative_node] = predecessor;
233 prev_alternative_set = absl::MakeConstSpan(current_alternative_set);
234 prev_values.swap(current_values_);
237 auto [predecessor, min_value] = get_best_predecessor(sink);
238 if (predecessor == -1)
return path_;
240 path_.resize(chain.size(), predecessor);
241 touched_.SparseClearAll();
242 touched_.Set(predecessor);
243 for (
int rank = chain.size() - 2; rank >= 0; --rank) {
244 path_[rank] = path_predecessor_[path_[rank + 1]];
245 if (touched_[path_[rank]]) {
249 touched_.Set(path_[rank]);
254template <
bool ignore_path_vars>
257 const std::vector<IntVar*>& vars,
258 const std::vector<IntVar*>& secondary_vars,
259 std::function<
int(int64_t)> start_empty_path_class,
260 std::vector<std::vector<int64_t>> alternative_sets,
263 vars, secondary_vars, 2,
265 true,
std::move(start_empty_path_class),
267 shortest_path_manager_(vars.size(),
std::move(alternative_sets),
268 std::move(arc_evaluator)) {}
270template <
bool ignore_path_vars>
273 const int64_t before_chain = this->
BaseNode(0);
278 const int64_t after_chain = this->
BaseNode(1);
279 bool has_alternatives =
false;
280 if (before_chain != after_chain) {
281 const int64_t prev_after_chain = this->
Prev(after_chain);
282 if (prev_after_chain != before_chain &&
283 chain_status_.start == before_chain &&
284 chain_status_.end == prev_after_chain) {
286 chain_status_.has_alternatives ||
287 shortest_path_manager_.HasAlternatives(prev_after_chain);
291 for (int64_t node = this->
Next(before_chain); node != after_chain;
292 node = this->
Next(node)) {
293 has_alternatives |= shortest_path_manager_.HasAlternatives(node);
297 chain_status_.start = before_chain;
298 chain_status_.end = after_chain;
299 chain_status_.has_alternatives = has_alternatives;
300 if (!has_alternatives)
return false;
302 if (!this->
ReverseChain(before_chain, after_chain, &chain_last))
return false;
304 for (int64_t next = this->
Next(before_chain); next != after_chain;
305 next = this->
Next(next)) {
306 chain_.push_back(next);
311 chain_, shortest_path_manager_.GetShortestPath(
312 before_chain, after_chain, chain_)) ||
317 Solver* solver,
const std::vector<IntVar*>& vars,
318 const std::vector<IntVar*>& secondary_vars,
319 std::function<
int(int64_t)> start_empty_path_class,
320 std::vector<std::vector<int64_t>> alternative_sets,
322 if (secondary_vars.empty()) {
324 vars, secondary_vars, std::move(start_empty_path_class),
325 std::move(alternative_sets), std::move(arc_evaluator)));
328 vars, secondary_vars, std::move(start_empty_path_class),
329 std::move(alternative_sets), std::move(arc_evaluator)));
332template <
bool ignore_path_vars>
335 const std::vector<IntVar*>& vars,
336 const std::vector<IntVar*>& secondary_vars,
337 std::function<
int(int64_t)> start_empty_path_class,
338 std::vector<std::vector<int64_t>> alternative_sets,
341 vars, secondary_vars, 1,
343 false,
std::move(start_empty_path_class),
345 shortest_path_manager_(vars.size(),
std::move(alternative_sets),
346 std::move(arc_evaluator)) {}
348template <
bool ignore_path_vars>
350 const int64_t before_chain = this->
BaseNode(0);
352 shortest_path_manager_.HasAlternatives(before_chain)) {
355 int64_t next = this->
Next(before_chain);
358 shortest_path_manager_.HasAlternatives(next)) {
359 chain_.push_back(next);
360 next = this->
Next(next);
363 chain_, shortest_path_manager_.GetShortestPath(
364 before_chain, next, chain_));
368 Solver* solver,
const std::vector<IntVar*>& vars,
369 const std::vector<IntVar*>& secondary_vars,
370 std::function<
int(int64_t)> start_empty_path_class,
371 std::vector<std::vector<int64_t>> alternative_sets,
373 if (secondary_vars.empty()) {
375 vars, secondary_vars, std::move(start_empty_path_class),
376 std::move(alternative_sets), std::move(arc_evaluator)));
379 vars, secondary_vars, std::move(start_empty_path_class),
380 std::move(alternative_sets), std::move(arc_evaluator)));
383template <
bool ignore_path_vars>
385 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 :
PathOperator<ignore_path_vars>(vars, secondary_vars, 2, false, true,
390 std::move(start_empty_path_class), nullptr,
393 inactive_pair_first_index_(0),
394 inactive_pair_second_index_(0),
397template <
bool ignore_path_vars>
399 while (inactive_pair_ < pairs_.size()) {
402 const auto& [pickup_alternatives, delivery_alternatives] =
403 pairs_[inactive_pair_];
404 if (inactive_pair_first_index_ < pickup_alternatives.size() - 1) {
405 ++inactive_pair_first_index_;
406 }
else if (inactive_pair_second_index_ < delivery_alternatives.size() - 1) {
407 inactive_pair_first_index_ = 0;
408 ++inactive_pair_second_index_;
410 inactive_pair_ = FindNextInactivePair(inactive_pair_ + 1);
411 inactive_pair_first_index_ = 0;
412 inactive_pair_second_index_ = 0;
418template <
bool ignore_path_vars>
426 const auto& [pickup_alternatives, delivery_alternatives] =
427 pairs_[inactive_pair_];
428 return this->
MakeActive(delivery_alternatives[inactive_pair_second_index_],
430 this->
MakeActive(pickup_alternatives[inactive_pair_first_index_],
434template <
bool ignore_path_vars>
438 if (base_index == 0 ||
442 return this->
BaseNode(base_index - 1);
446template <
bool ignore_path_vars>
447void MakePairActiveOperator<ignore_path_vars>::OnNodeInitialization() {
448 inactive_pair_ = FindNextInactivePair(0);
449 inactive_pair_first_index_ = 0;
450 inactive_pair_second_index_ = 0;
453template <
bool ignore_path_vars>
454int MakePairActiveOperator<ignore_path_vars>::FindNextInactivePair(
455 int pair_index)
const {
456 for (
int index = pair_index; index < pairs_.size(); ++index) {
457 if (!ContainsActiveNodes(pairs_[index].pickup_alternatives) &&
458 !ContainsActiveNodes(pairs_[index].delivery_alternatives)) {
462 return pairs_.size();
465template <
bool ignore_path_vars>
466bool MakePairActiveOperator<ignore_path_vars>::ContainsActiveNodes(
467 absl::Span<const int64_t> nodes)
const {
468 for (int64_t node : nodes) {
469 if (!this->IsInactive(node))
return true;
475 Solver* solver,
const std::vector<IntVar*>& vars,
476 const std::vector<IntVar*>& secondary_vars,
477 std::function<
int(int64_t)> start_empty_path_class,
478 const std::vector<PickupDeliveryPair>& pairs) {
479 if (secondary_vars.empty()) {
481 vars, secondary_vars, std::move(start_empty_path_class), pairs));
484 vars, secondary_vars, std::move(start_empty_path_class), pairs));
487template <
bool ignore_path_vars>
489 const std::vector<IntVar*>& vars,
490 const std::vector<IntVar*>& secondary_vars,
491 std::function<
int(int64_t)> start_empty_path_class,
492 const std::vector<PickupDeliveryPair>& pairs)
493 :
PathOperator<ignore_path_vars>(vars, secondary_vars, 1, true, false,
494 std::move(start_empty_path_class), nullptr,
499template <
bool ignore_path_vars>
502 const int64_t first_index = this->
Next(base);
504 if (second_index < 0) {
512 Solver* solver,
const std::vector<IntVar*>& vars,
513 const std::vector<IntVar*>& secondary_vars,
514 std::function<
int(int64_t)> start_empty_path_class,
515 const std::vector<PickupDeliveryPair>& pairs) {
516 if (secondary_vars.empty()) {
518 vars, secondary_vars, std::move(start_empty_path_class), pairs));
521 vars, secondary_vars, std::move(start_empty_path_class), pairs));
524template <
bool ignore_path_vars>
526 const std::vector<IntVar*>& vars,
527 const std::vector<IntVar*>& secondary_vars,
528 std::function<
int(int64_t)> start_empty_path_class,
529 const std::vector<PickupDeliveryPair>& pairs)
530 :
PathOperator<ignore_path_vars>(vars, secondary_vars, 3, true, false,
531 std::move(start_empty_path_class), nullptr,
541template <
bool ignore_path_vars>
544 const int64_t first_pair_node = this->
BaseNode(kPairFirstNode);
548 int64_t first_prev = this->
Prev(first_pair_node);
549 const int second_pair_node =
551 if (second_pair_node < 0 || this->
IsPathEnd(second_pair_node) ||
555 const int64_t second_prev = this->
Prev(second_pair_node);
557 const int64_t first_node_destination =
558 this->
BaseNode(kPairFirstNodeDestination);
559 if (first_node_destination == second_pair_node) {
564 const int64_t second_node_destination =
565 this->
BaseNode(kPairSecondNodeDestination);
566 if (second_prev == first_pair_node && first_node_destination == first_prev &&
567 second_node_destination == first_prev) {
577 if (second_pair_node == second_node_destination ||
578 first_pair_node == first_node_destination) {
581 const bool moved_second_pair_node =
582 this->
MoveChain(second_prev, second_pair_node, second_node_destination);
585 const bool moved_first_pair_node = this->
MoveChain(
586 this->
Prev(first_pair_node), first_pair_node, first_node_destination);
592 return moved_first_pair_node || moved_second_pair_node;
595template <
bool ignore_path_vars>
600 if (base_index == kPairSecondNodeDestination) {
601 return this->
BaseNode(kPairFirstNodeDestination);
608 Solver* solver,
const std::vector<IntVar*>& vars,
609 const std::vector<IntVar*>& secondary_vars,
610 std::function<
int(int64_t)> start_empty_path_class,
611 const std::vector<PickupDeliveryPair>& pairs) {
612 if (secondary_vars.empty()) {
614 vars, secondary_vars, std::move(start_empty_path_class), pairs));
617 vars, secondary_vars, std::move(start_empty_path_class), pairs));
620template <
bool ignore_path_vars>
622 const std::vector<IntVar*>& vars,
623 const std::vector<IntVar*>& secondary_vars,
626 const std::vector<PickupDeliveryPair>& pairs)
628 vars, secondary_vars,
630 get_outgoing_neighbors == nullptr ? 2 : 1,
632 false,
std::move(start_empty_path_class),
634 std::move(get_outgoing_neighbors)) {
638template <
bool ignore_path_vars>
640 const auto do_move = [
this](int64_t node, int64_t destination) {
643 if (sibling == -1)
return false;
645 if (destination == node || destination == sibling)
return false;
646 const bool ok = this->
MoveChain(this->
Prev(node), node, destination);
647 return this->
MoveChain(this->
Prev(sibling), sibling, node) || ok;
651 if (neighbor < 0)
return false;
653 return do_move(neighbor, this->
BaseNode(0));
660 Solver* solver,
const std::vector<IntVar*>& vars,
661 const std::vector<IntVar*>& secondary_vars,
662 std::function<
int(int64_t)> start_empty_path_class,
663 std::function<
const std::vector<int>&(
int,
int)> get_incoming_neighbors,
664 std::function<
const std::vector<int>&(
int,
int)> get_outgoing_neighbors,
665 const std::vector<PickupDeliveryPair>& pairs) {
666 if (secondary_vars.empty()) {
668 vars, secondary_vars, std::move(start_empty_path_class),
669 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
673 vars, secondary_vars, std::move(start_empty_path_class),
674 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
680 Solver* solver,
const std::vector<IntVar*>& vars,
681 const std::vector<IntVar*>& secondary_vars,
682 std::function<
int(int64_t)> start_empty_path_class,
683 const std::vector<PickupDeliveryPair>& pairs) {
685 std::move(start_empty_path_class),
nullptr,
689template <
bool ignore_path_vars>
691 const std::vector<IntVar*>& vars,
692 const std::vector<IntVar*>& secondary_vars,
695 const std::vector<PickupDeliveryPair>& pairs,
696 std::function<
bool(int64_t)> force_lifo)
698 vars, secondary_vars,
700 get_outgoing_neighbors == nullptr ? 2 : 1,
702 false,
std::move(start_empty_path_class),
704 std::move(get_outgoing_neighbors)),
705 force_lifo_(
std::move(force_lifo)) {
709template <
bool ignore_path_vars>
711 const auto do_move = [
this](int64_t node, int64_t destination,
712 bool destination_is_lifo) {
717 const int64_t prev = this->
Prev(node);
720 if (sibling == -1 || destination == sibling)
return false;
734 const bool ok = this->
MoveChain(prev, node, destination);
735 const int64_t destination_sibling =
737 if (destination_sibling == -1) {
739 return this->
MoveChain(this->
Prev(sibling), sibling, node) || ok;
744 if (!destination_is_lifo) {
745 if (this->
Prev(destination_sibling) == sibling)
return ok;
747 this->
Prev(destination_sibling)) ||
751 destination_sibling) ||
758 const int64_t destination_sibling =
760 if (destination_sibling == -1)
return false;
761 const bool ok = this->
MoveChain(prev, node, destination);
762 if (!destination_is_lifo) {
764 destination_sibling) ||
767 if (this->
Prev(destination_sibling) == sibling)
return ok;
769 this->
Prev(destination_sibling)) ||
775 if (neighbor < 0)
return false;
779 return do_move(neighbor, this->
BaseNode(0),
784 force_lifo_ !=
nullptr && force_lifo_(this->
StartNode(1)));
788 Solver* solver,
const std::vector<IntVar*>& vars,
789 const std::vector<IntVar*>& secondary_vars,
790 std::function<
int(int64_t)> start_empty_path_class,
791 std::function<
const std::vector<int>&(
int,
int)> get_incoming_neighbors,
792 std::function<
const std::vector<int>&(
int,
int)> get_outgoing_neighbors,
793 const std::vector<PickupDeliveryPair>& pairs,
794 std::function<
bool(int64_t)> force_lifo) {
795 if (secondary_vars.empty()) {
797 vars, secondary_vars, std::move(start_empty_path_class),
798 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
799 pairs, std::move(force_lifo)));
802 vars, secondary_vars, std::move(start_empty_path_class),
803 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
804 pairs, std::move(force_lifo)));
808 Solver* solver,
const std::vector<IntVar*>& vars,
809 const std::vector<IntVar*>& secondary_vars,
810 std::function<
int(int64_t)> start_empty_path_class,
811 const std::vector<PickupDeliveryPair>& pairs,
812 std::function<
bool(int64_t)> force_lifo) {
814 std::move(start_empty_path_class),
nullptr,
815 nullptr, pairs, std::move(force_lifo));
818template <
bool ignore_path_vars>
820 const std::vector<IntVar*>& vars,
821 const std::vector<IntVar*>& secondary_vars,
822 std::function<
int(int64_t)> start_empty_path_class,
825 const std::vector<PickupDeliveryPair>& pairs)
827 vars, secondary_vars,
829 get_incoming_neighbors == nullptr && get_outgoing_neighbors == nullptr
833 false,
std::move(start_empty_path_class),
834 std::move(get_incoming_neighbors),
835 std::move(get_outgoing_neighbors)) {
839template <
bool ignore_path_vars>
841 const int64_t node1 = this->
BaseNode(0);
842 int64_t prev1, sibling1, sibling_prev1 = -1;
843 if (!GetPreviousAndSibling(node1, &prev1, &sibling1, &sibling_prev1)) {
851 if (neighbor < 0 || this->
IsInactive(neighbor))
return false;
857 node2 = outgoing ? this->
Prev(neighbor) : this->
Next(neighbor);
858 if (this->
IsPathEnd(node2))
return false;
860 int64_t prev2, sibling2, sibling_prev2 = -1;
861 if (!GetPreviousAndSibling(node2, &prev2, &sibling2, &sibling_prev2)) {
866 if (node1 == prev2) {
867 status = this->
MoveChain(prev2, node2, prev1);
868 if (sibling_prev1 == node2) sibling_prev1 = node1;
869 if (sibling_prev2 == node2) sibling_prev2 = node1;
870 }
else if (node2 == prev1) {
871 status = this->
MoveChain(prev1, node1, prev2);
872 if (sibling_prev1 == node1) sibling_prev1 = node2;
873 if (sibling_prev2 == node1) sibling_prev2 = node2;
875 status = this->
MoveChain(prev1, node1, node2) &&
877 if (sibling_prev1 == node1) {
878 sibling_prev1 = node2;
879 }
else if (sibling_prev1 == node2) {
880 sibling_prev1 = node1;
882 if (sibling_prev2 == node1) {
883 sibling_prev2 = node2;
884 }
else if (sibling_prev2 == node2) {
885 sibling_prev2 = node1;
888 if (!status)
return false;
890 if (sibling1 == sibling_prev2) {
891 status = this->
MoveChain(sibling_prev2, sibling2, sibling_prev1);
892 }
else if (sibling2 == sibling_prev1) {
893 status = this->
MoveChain(sibling_prev1, sibling1, sibling_prev2);
895 status = this->
MoveChain(sibling_prev1, sibling1, sibling2) &&
896 this->
MoveChain(sibling_prev2, sibling2, sibling_prev1);
909template <
bool ignore_path_vars>
910bool PairExchangeOperator<ignore_path_vars>::GetPreviousAndSibling(
911 int64_t node, int64_t* previous, int64_t* sibling,
912 int64_t* sibling_previous)
const {
913 if (this->IsPathStart(node))
return false;
914 *previous = this->Prev(node);
915 *sibling = this->GetActiveAlternativeSibling(node);
916 *sibling_previous = *sibling >= 0 ? this->Prev(*sibling) : -1;
917 return *sibling_previous >= 0;
921 Solver* solver,
const std::vector<IntVar*>& vars,
922 const std::vector<IntVar*>& secondary_vars,
923 std::function<
int(int64_t)> start_empty_path_class,
924 std::function<
const std::vector<int>&(
int,
int)> get_incoming_neighbors,
925 std::function<
const std::vector<int>&(
int,
int)> get_outgoing_neighbors,
926 const std::vector<PickupDeliveryPair>& pairs) {
927 if (secondary_vars.empty()) {
929 vars, secondary_vars, std::move(start_empty_path_class),
930 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
934 vars, secondary_vars, std::move(start_empty_path_class),
935 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
940 Solver* solver,
const std::vector<IntVar*>& vars,
941 const std::vector<IntVar*>& secondary_vars,
942 std::function<
int(int64_t)> start_empty_path_class,
943 const std::vector<PickupDeliveryPair>& pairs) {
945 std::move(start_empty_path_class),
nullptr,
nullptr,
949template <
bool ignore_path_vars>
951 const std::vector<IntVar*>& vars,
952 const std::vector<IntVar*>& secondary_vars,
953 std::function<
int(int64_t)> start_empty_path_class,
954 const std::vector<PickupDeliveryPair>& pairs)
955 :
PathOperator<ignore_path_vars>(vars, secondary_vars, 6, true, false,
956 std::move(start_empty_path_class), nullptr,
961template <
bool ignore_path_vars>
963 DCHECK_EQ(this->
StartNode(kSecondPairFirstNodeDestination),
964 this->
StartNode(kSecondPairSecondNodeDestination));
965 DCHECK_EQ(this->
StartNode(kSecondPairFirstNode),
966 this->
StartNode(kFirstPairFirstNodeDestination));
967 DCHECK_EQ(this->
StartNode(kSecondPairFirstNode),
968 this->
StartNode(kFirstPairSecondNodeDestination));
970 if (this->
StartNode(kFirstPairFirstNode) ==
980 nodes[0][0] = this->
BaseNode(kFirstPairFirstNode);
981 nodes[1][0] = this->
BaseNode(kSecondPairFirstNode);
982 if (nodes[1][0] <= nodes[0][0]) {
987 if (!this->GetPreviousAndSibling(nodes[0][0], &prev[0][0], &nodes[0][1],
992 if (!this->GetPreviousAndSibling(nodes[1][0], &prev[1][0], &nodes[1][1],
998 if (!this->LoadAndCheckDest(0, 0, kFirstPairFirstNodeDestination, nodes,
1003 if (!this->LoadAndCheckDest(0, 1, kFirstPairSecondNodeDestination, nodes,
1008 if (this->
StartNode(kSecondPairFirstNodeDestination) !=
1010 !this->LoadAndCheckDest(1, 0, kSecondPairFirstNodeDestination, nodes,
1015 if (!this->LoadAndCheckDest(1, 1, kSecondPairSecondNodeDestination, nodes,
1021 if (!this->MoveNode(0, 1, nodes, dest, prev)) {
1025 if (!this->MoveNode(0, 0, nodes, dest, prev)) {
1029 if (!this->MoveNode(1, 1, nodes, dest, prev)) {
1032 if (!this->MoveNode(1, 0, nodes, dest, prev)) {
1038template <
bool ignore_path_vars>
1039bool PairExchangeRelocateOperator<ignore_path_vars>::MoveNode(
1040 int pair,
int node, int64_t nodes[2][2], int64_t dest[2][2],
1041 int64_t prev[2][2]) {
1042 if (!this->MoveChain(prev[pair][node], nodes[pair][node], dest[pair][node])) {
1046 if (prev[1 - pair][0] == dest[pair][node]) {
1047 prev[1 - pair][0] = nodes[pair][node];
1049 if (prev[1 - pair][1] == dest[pair][node]) {
1050 prev[1 - pair][1] = nodes[pair][node];
1055template <
bool ignore_path_vars>
1056bool PairExchangeRelocateOperator<ignore_path_vars>::LoadAndCheckDest(
1057 int pair,
int node, int64_t base_node, int64_t nodes[2][2],
1058 int64_t dest[2][2])
const {
1059 dest[pair][node] = this->BaseNode(base_node);
1061 return !(nodes[0][0] == dest[pair][node] || nodes[0][1] == dest[pair][node] ||
1062 nodes[1][0] == dest[pair][node] || nodes[1][1] == dest[pair][node]);
1065template <
bool ignore_path_vars>
1067 int64_t base_index) {
1071 return base_index == kFirstPairFirstNodeDestination ||
1072 base_index == kFirstPairSecondNodeDestination ||
1073 base_index == kSecondPairSecondNodeDestination;
1076template <
bool ignore_path_vars>
1080 if (base_index == kFirstPairSecondNodeDestination ||
1081 base_index == kSecondPairSecondNodeDestination) {
1082 return this->
BaseNode(base_index - 1);
1088template <
bool ignore_path_vars>
1089bool PairExchangeRelocateOperator<ignore_path_vars>::GetPreviousAndSibling(
1090 int64_t node, int64_t* previous, int64_t* sibling,
1091 int64_t* sibling_previous)
const {
1092 if (this->IsPathStart(node))
return false;
1093 *previous = this->Prev(node);
1094 *sibling = this->GetActiveAlternativeSibling(node);
1095 *sibling_previous = *sibling >= 0 ? this->Prev(*sibling) : -1;
1096 return *sibling_previous >= 0;
1100 Solver* solver,
const std::vector<IntVar*>& vars,
1101 const std::vector<IntVar*>& secondary_vars,
1102 std::function<
int(int64_t)> start_empty_path_class,
1103 const std::vector<PickupDeliveryPair>& pairs) {
1104 if (secondary_vars.empty()) {
1106 vars, secondary_vars, std::move(start_empty_path_class), pairs));
1109 vars, secondary_vars, std::move(start_empty_path_class), pairs));
1113 const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& path_vars,
1114 const std::vector<PickupDeliveryPair>& pairs)
1120 number_of_nexts_(vars.size()),
1121 ignore_path_vars_(path_vars.empty()) {
1122 if (!ignore_path_vars_) {
1129 const int64_t kNoPath = -1;
1130 CHECK(delta !=
nullptr);
1134 if (pair_index_ >= pairs_.size())
return false;
1135 const int64_t path =
1136 ignore_path_vars_ ? 0LL :
Value(first_active_ + number_of_nexts_);
1137 const int64_t prev_first = prevs_[first_active_];
1138 const int64_t next_first =
Value(first_active_);
1140 SetNext(first_active_, first_active_, kNoPath);
1142 const auto& [pickup_alternatives, delivery_alternatives] =
1143 pairs_[pair_index_];
1144 const int64_t insert_first = pickup_alternatives[first_index_];
1145 SetNext(prev_first, insert_first, path);
1146 SetNext(insert_first, next_first, path);
1147 int64_t prev_second = prevs_[second_active_];
1148 if (prev_second == first_active_) {
1149 prev_second = insert_first;
1151 DCHECK_EQ(path, ignore_path_vars_
1153 :
Value(second_active_ + number_of_nexts_));
1154 const int64_t next_second =
Value(second_active_);
1156 SetNext(second_active_, second_active_, kNoPath);
1158 const int64_t insert_second = delivery_alternatives[second_index_];
1159 SetNext(prev_second, insert_second, path);
1160 SetNext(insert_second, next_second, path);
1163 if (second_index_ >= delivery_alternatives.size()) {
1166 if (first_index_ >= pickup_alternatives.size()) {
1170 if (!UpdateActiveNodes())
break;
1171 if (first_active_ != -1 && second_active_ != -1) {
1184 prevs_.resize(number_of_nexts_, -1);
1185 for (
int index = 0; index < number_of_nexts_; ++index) {
1186 const int64_t next =
Value(index);
1187 if (next >= prevs_.size()) prevs_.resize(next + 1, -1);
1188 prevs_[next] = index;
1194 second_active_ = -1;
1196 if (!UpdateActiveNodes())
break;
1197 if (first_active_ != -1 && second_active_ != -1) {
1204bool SwapIndexPairOperator::UpdateActiveNodes() {
1205 if (pair_index_ < pairs_.size()) {
1206 const auto& [pickup_alternatives, delivery_alternatives] =
1207 pairs_[pair_index_];
1209 second_active_ = -1;
1210 if (pickup_alternatives.size() == 1 && delivery_alternatives.size() == 1) {
1215 for (
const int64_t first : pickup_alternatives) {
1216 if (
Value(first) != first) {
1217 first_active_ = first;
1221 for (
const int64_t second : delivery_alternatives) {
1222 if (
Value(second) != second) {
1223 second_active_ = second;
1232template <
bool ignore_path_vars>
1234 const std::vector<IntVar*>& vars,
1235 const std::vector<IntVar*>& secondary_vars,
1236 std::function<
int(int64_t)> start_empty_path_class,
1237 const std::vector<PickupDeliveryPair>& pairs)
1238 :
PathOperator<ignore_path_vars>(vars, secondary_vars, 1, true, false,
1239 std::move(start_empty_path_class), nullptr,
1245template <
bool ignore_path_vars>
1248 while (inactive_node_ < this->
Size()) {
1260template <
bool ignore_path_vars>
1263 const int64_t next = this->
Next(base);
1273template <
bool ignore_path_vars>
1274void IndexPairSwapActiveOperator<ignore_path_vars>::OnNodeInitialization() {
1276 for (
int i = 0; i < this->Size(); ++i) {
1277 if (this->IsInactive(i)) {
1282 inactive_node_ = this->Size();
1286 Solver* solver,
const std::vector<IntVar*>& vars,
1287 const std::vector<IntVar*>& secondary_vars,
1288 std::function<
int(int64_t)> start_empty_path_class,
1289 const std::vector<PickupDeliveryPair>& pairs) {
1290 if (secondary_vars.empty()) {
1292 vars, secondary_vars, std::move(start_empty_path_class), pairs));
1295 vars, secondary_vars, std::move(start_empty_path_class), pairs));
1298template <
bool ignore_path_vars>
1300 const std::vector<IntVar*>& vars,
1301 const std::vector<IntVar*>& secondary_vars,
1302 std::function<
int(int64_t)> start_empty_path_class,
1303 int num_arcs_to_consider,
1304 std::function<int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start)
1305 :
PathOperator<ignore_path_vars>(vars, secondary_vars, 1, false, false,
1306 std::move(start_empty_path_class), nullptr,
1308 num_arcs_to_consider_(num_arcs_to_consider),
1310 current_expensive_arc_indices_({-1, -1}),
1311 arc_cost_for_path_start_(std::move(arc_cost_for_path_start)),
1313 has_non_empty_paths_to_explore_(
false) {
1314 DCHECK_GE(num_arcs_to_consider_, 2);
1317template <
bool ignore_path_vars>
1321 const int first_arc_index = current_expensive_arc_indices_.first;
1322 const int second_arc_index = current_expensive_arc_indices_.second;
1323 DCHECK_LE(0, first_arc_index);
1324 DCHECK_LT(first_arc_index, second_arc_index);
1325 DCHECK_LT(second_arc_index, most_expensive_arc_starts_and_ranks_.size());
1327 const std::pair<int, int>& first_start_and_rank =
1328 most_expensive_arc_starts_and_ranks_[first_arc_index];
1329 const std::pair<int, int>& second_start_and_rank =
1330 most_expensive_arc_starts_and_ranks_[second_arc_index];
1331 if (first_start_and_rank.second < second_start_and_rank.second) {
1333 second_start_and_rank.first,
1334 this->BaseNode(0)) &&
1335 this->
MoveChain(first_start_and_rank.first,
1336 second_start_and_rank.first, this->BaseNode(0));
1339 first_start_and_rank.first,
1340 this->BaseNode(0)) &&
1341 this->
MoveChain(second_start_and_rank.first,
1342 first_start_and_rank.first, this->BaseNode(0));
1345template <
bool ignore_path_vars>
1347 while (has_non_empty_paths_to_explore_) {
1351 if (IncrementCurrentArcIndices()) {
1355 IncrementCurrentPath();
1356 has_non_empty_paths_to_explore_ =
1357 current_path_ != end_path_ &&
1358 FindMostExpensiveChainsOnRemainingPaths();
1366template <
bool ignore_path_vars>
1367void RelocateExpensiveChain<ignore_path_vars>::OnNodeInitialization() {
1368 if (current_path_ >= this->path_starts().size()) {
1373 end_path_ = current_path_;
1374 has_non_empty_paths_to_explore_ = FindMostExpensiveChainsOnRemainingPaths();
1377template <
bool ignore_path_vars>
1378void RelocateExpensiveChain<ignore_path_vars>::IncrementCurrentPath() {
1379 const int num_paths = this->path_starts().size();
1380 if (++current_path_ == num_paths) {
1385template <
bool ignore_path_vars>
1386bool RelocateExpensiveChain<ignore_path_vars>::IncrementCurrentArcIndices() {
1387 int& second_index = current_expensive_arc_indices_.second;
1388 if (++second_index < most_expensive_arc_starts_and_ranks_.size()) {
1391 int& first_index = current_expensive_arc_indices_.first;
1392 if (first_index + 2 < most_expensive_arc_starts_and_ranks_.size()) {
1394 second_index = first_index + 1;
1400template <
bool ignore_path_vars>
1402 ignore_path_vars>::FindMostExpensiveChainsOnRemainingPaths() {
1405 num_arcs_to_consider_, this->path_starts()[current_path_],
1406 [
this](int64_t i) {
return this->OldNext(i); },
1407 [
this](int64_t node) {
return this->IsPathEnd(node); },
1408 arc_cost_for_path_start_, &most_expensive_arc_starts_and_ranks_,
1409 ¤t_expensive_arc_indices_)) {
1412 IncrementCurrentPath();
1413 }
while (current_path_ != end_path_);
1418 Solver* solver,
const std::vector<IntVar*>& vars,
1419 const std::vector<IntVar*>& secondary_vars,
1420 std::function<
int(int64_t)> start_empty_path_class,
1421 int num_arcs_to_consider,
1422 std::function<int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start) {
1423 if (secondary_vars.empty()) {
1425 vars, secondary_vars, std::move(start_empty_path_class),
1426 num_arcs_to_consider, std::move(arc_cost_for_path_start)));
1429 vars, secondary_vars, std::move(start_empty_path_class),
1430 num_arcs_to_consider, std::move(arc_cost_for_path_start)));
1434 int num_nodes, absl::Span<const PickupDeliveryPair> pairs)
1435 : is_pickup_node_(num_nodes, false),
1436 is_delivery_node_(num_nodes, false),
1437 pair_of_node_(num_nodes, -1) {
1438 for (
int pair_index = 0; pair_index < pairs.size(); ++pair_index) {
1439 for (
const int node : pairs[pair_index].pickup_alternatives) {
1440 is_pickup_node_[node] =
true;
1441 pair_of_node_[node] = pair_index;
1443 for (
const int node : pairs[pair_index].delivery_alternatives) {
1444 is_delivery_node_[node] =
true;
1445 pair_of_node_[node] = pair_index;
1450template <
bool ignore_path_vars>
1452 const std::vector<IntVar*>& vars,
1453 const std::vector<IntVar*>& secondary_vars,
1456 absl::Span<const PickupDeliveryPair> pairs)
1458 vars, secondary_vars,
1460 get_outgoing_neighbors == nullptr ? 2 : 1,
1462 false,
std::move(start_empty_path_class),
1464 std::move(get_outgoing_neighbors)),
1466 opened_pairs_set_.resize(pairs.size(),
false);
1469template <
bool ignore_path_vars>
1470void RelocateSubtrip<ignore_path_vars>::SetPath(absl::Span<const int64_t> path,
1472 for (
int i = 1; i < path.size(); ++i) {
1473 this->SetNext(path[i - 1], path[i], path_id);
1477template <
bool ignore_path_vars>
1478bool RelocateSubtrip<ignore_path_vars>::RelocateSubTripFromPickup(
1479 const int64_t chain_first_node,
const int64_t insertion_node) {
1480 if (this->IsPathEnd(insertion_node))
return false;
1481 if (this->Prev(chain_first_node) == insertion_node)
1484 int num_opened_pairs = 0;
1486 rejected_nodes_ = {this->Prev(chain_first_node)};
1487 subtrip_nodes_ = {insertion_node};
1488 int current = chain_first_node;
1490 if (current == insertion_node) {
1492 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1495 const int pair = pd_data_.GetPairOfNode(current);
1496 if (pd_data_.IsDeliveryNode(current) && !opened_pairs_set_[pair]) {
1497 rejected_nodes_.push_back(current);
1499 subtrip_nodes_.push_back(current);
1500 if (pd_data_.IsPickupNode(current)) {
1502 opened_pairs_set_[pair] =
true;
1503 }
else if (pd_data_.IsDeliveryNode(current)) {
1505 opened_pairs_set_[pair] =
false;
1508 current = this->
Next(current);
1509 }
while (num_opened_pairs != 0 && !this->IsPathEnd(current));
1510 DCHECK_EQ(num_opened_pairs, 0);
1511 rejected_nodes_.push_back(current);
1512 subtrip_nodes_.push_back(this->
Next(insertion_node));
1515 SetPath(rejected_nodes_, this->Path(chain_first_node));
1516 SetPath(subtrip_nodes_, this->Path(insertion_node));
1520template <
bool ignore_path_vars>
1521bool RelocateSubtrip<ignore_path_vars>::RelocateSubTripFromDelivery(
1522 const int64_t chain_last_node,
const int64_t insertion_node) {
1523 if (this->IsPathEnd(insertion_node))
return false;
1526 DCHECK(std::none_of(opened_pairs_set_.begin(), opened_pairs_set_.end(),
1527 [](
bool value) { return value; }));
1528 int num_opened_pairs = 0;
1530 rejected_nodes_ = {this->
Next(chain_last_node)};
1531 subtrip_nodes_ = {this->
Next(insertion_node)};
1532 int current = chain_last_node;
1534 if (current == insertion_node) {
1535 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1538 const int pair = pd_data_.GetPairOfNode(current);
1539 if (pd_data_.IsPickupNode(current) && !opened_pairs_set_[pair]) {
1540 rejected_nodes_.push_back(current);
1542 subtrip_nodes_.push_back(current);
1543 if (pd_data_.IsDeliveryNode(current)) {
1545 opened_pairs_set_[pair] =
true;
1546 }
else if (pd_data_.IsPickupNode(current)) {
1548 opened_pairs_set_[pair] =
false;
1551 current = this->Prev(current);
1552 }
while (num_opened_pairs != 0 && !this->IsPathStart(current));
1553 DCHECK_EQ(num_opened_pairs, 0);
1554 if (current == insertion_node)
return false;
1555 rejected_nodes_.push_back(current);
1556 subtrip_nodes_.push_back(insertion_node);
1560 std::reverse(rejected_nodes_.begin(), rejected_nodes_.end());
1561 std::reverse(subtrip_nodes_.begin(), subtrip_nodes_.end());
1564 SetPath(rejected_nodes_, this->Path(chain_last_node));
1565 SetPath(subtrip_nodes_, this->Path(insertion_node));
1569template <
bool ignore_path_vars>
1571 const auto do_move = [
this](int64_t node, int64_t insertion_node) {
1573 if (pd_data_.IsPickupNode(node)) {
1574 return RelocateSubTripFromPickup(node, insertion_node);
1575 }
else if (pd_data_.IsDeliveryNode(node)) {
1576 return RelocateSubTripFromDelivery(node, insertion_node);
1583 if (neighbor < 0)
return false;
1585 if (this->
IsInactive(neighbor))
return false;
1586 return do_move(neighbor, this->
BaseNode(0));
1593 Solver* solver,
const std::vector<IntVar*>& vars,
1594 const std::vector<IntVar*>& secondary_vars,
1595 std::function<
int(int64_t)> start_empty_path_class,
1596 std::function<
const std::vector<int>&(
int,
int)> get_incoming_neighbors,
1597 std::function<
const std::vector<int>&(
int,
int)> get_outgoing_neighbors,
1598 absl::Span<const PickupDeliveryPair> pairs) {
1599 if (secondary_vars.empty()) {
1601 vars, secondary_vars, std::move(start_empty_path_class),
1602 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
1606 vars, secondary_vars, std::move(start_empty_path_class),
1607 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
1612 Solver* solver,
const std::vector<IntVar*>& vars,
1613 const std::vector<IntVar*>& secondary_vars,
1614 std::function<
int(int64_t)> start_empty_path_class,
1615 absl::Span<const PickupDeliveryPair> pairs) {
1617 std::move(start_empty_path_class),
nullptr,
1621template <
bool ignore_path_vars>
1623 const std::vector<IntVar*>& vars,
1624 const std::vector<IntVar*>& secondary_vars,
1627 absl::Span<const PickupDeliveryPair> pairs)
1629 vars, secondary_vars,
1631 get_outgoing_neighbors == nullptr ? 2 : 1,
1633 false,
std::move(start_empty_path_class),
1635 std::move(get_outgoing_neighbors)),
1637 opened_pairs_set_.resize(pairs.size(),
false);
1640template <
bool ignore_path_vars>
1641void ExchangeSubtrip<ignore_path_vars>::SetPath(absl::Span<const int64_t> path,
1643 for (
int i = 1; i < path.size(); ++i) {
1644 this->SetNext(path[i - 1], path[i], path_id);
1649bool VectorContains(absl::Span<const int64_t> values, int64_t target) {
1650 return std::find(values.begin(), values.end(), target) != values.end();
1654template <
bool ignore_path_vars>
1659 const int64_t node = this->
BaseNode(0);
1661 if (neighbor < 0)
return false;
1663 if (this->
IsInactive(neighbor))
return false;
1664 if (pd_data_.IsDeliveryNode(node) &&
1665 pd_data_.IsDeliveryNode(this->Prev(neighbor))) {
1667 node1 = this->
Prev(neighbor);
1668 }
else if (pd_data_.IsPickupNode(neighbor) &&
1669 !this->IsPathEnd(this->Next(node)) &&
1670 pd_data_.IsPickupNode(this->Next(node))) {
1671 node0 = this->
Next(node);
1681 if (pd_data_.GetPairOfNode(node0) == -1)
return false;
1682 if (pd_data_.GetPairOfNode(node1) == -1)
return false;
1685 if (node0 >= node1)
return false;
1688 if (!ExtractChainsAndCheckCanonical(node0, &rejects0_, &subtrip0_)) {
1693 if (!ExtractChainsAndCheckCanonical(node1, &rejects1_, &subtrip1_)) {
1699 if (VectorContains(rejects0_, subtrip1_.front()))
return false;
1700 if (VectorContains(rejects1_, subtrip0_.front()))
return false;
1701 if (VectorContains(subtrip0_, subtrip1_.front()))
return false;
1702 if (VectorContains(subtrip1_, subtrip0_.front()))
return false;
1706 path0_ = {this->
Prev(subtrip0_.front())};
1707 path1_ = {this->
Prev(subtrip1_.front())};
1708 const int64_t last0 = this->
Next(subtrip0_.back());
1709 const int64_t last1 = this->
Next(subtrip1_.back());
1710 const bool concatenated01 = last0 == subtrip1_.front();
1711 const bool concatenated10 = last1 == subtrip0_.front();
1713 if (pd_data_.IsDeliveryNode(node0)) std::swap(subtrip1_, rejects0_);
1714 path0_.insert(path0_.end(), subtrip1_.begin(), subtrip1_.end());
1715 path0_.insert(path0_.end(), rejects0_.begin(), rejects0_.end());
1716 path0_.push_back(last0);
1718 if (pd_data_.IsDeliveryNode(node1)) std::swap(subtrip0_, rejects1_);
1719 path1_.insert(path1_.end(), subtrip0_.begin(), subtrip0_.end());
1720 path1_.insert(path1_.end(), rejects1_.begin(), rejects1_.end());
1721 path1_.push_back(last1);
1724 if (concatenated01) {
1726 path1_.front() = path0_.back();
1727 }
else if (concatenated10) {
1729 path0_.front() = path1_.back();
1734 const int64_t path0_id = this->
Path(node0);
1735 const int64_t path1_id = this->
Path(node1);
1736 SetPath(path0_, path0_id);
1737 SetPath(path1_, path1_id);
1741template <
bool ignore_path_vars>
1742bool ExchangeSubtrip<ignore_path_vars>::ExtractChainsAndCheckCanonical(
1743 int64_t base_node, std::vector<int64_t>* rejects,
1744 std::vector<int64_t>* subtrip) {
1745 const bool extracted =
1746 pd_data_.IsPickupNode(base_node)
1747 ? ExtractChainsFromPickup(base_node, rejects, subtrip)
1748 : ExtractChainsFromDelivery(base_node, rejects, subtrip);
1749 if (!extracted)
return false;
1751 return !pd_data_.IsDeliveryNode(base_node) ||
1752 pd_data_.GetPairOfNode(subtrip->front()) !=
1753 pd_data_.GetPairOfNode(subtrip->back()) ||
1757template <
bool ignore_path_vars>
1758bool ExchangeSubtrip<ignore_path_vars>::ExtractChainsFromPickup(
1759 int64_t base_node, std::vector<int64_t>* rejects,
1760 std::vector<int64_t>* subtrip) {
1761 DCHECK(pd_data_.IsPickupNode(base_node));
1762 DCHECK(rejects->empty());
1763 DCHECK(subtrip->empty());
1766 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1767 int num_opened_pairs = 0;
1768 int current = base_node;
1770 const int pair = pd_data_.GetPairOfNode(current);
1771 if (pd_data_.IsDeliveryNode(current) && !opened_pairs_set_[pair]) {
1772 rejects->push_back(current);
1774 subtrip->push_back(current);
1775 if (pd_data_.IsPickupNode(current)) {
1777 opened_pairs_set_[pair] =
true;
1778 }
else if (pd_data_.IsDeliveryNode(current)) {
1780 opened_pairs_set_[pair] =
false;
1783 current = this->
Next(current);
1784 }
while (num_opened_pairs != 0 && !this->IsPathEnd(current));
1785 return num_opened_pairs == 0;
1788template <
bool ignore_path_vars>
1789bool ExchangeSubtrip<ignore_path_vars>::ExtractChainsFromDelivery(
1790 int64_t base_node, std::vector<int64_t>* rejects,
1791 std::vector<int64_t>* subtrip) {
1792 DCHECK(pd_data_.IsDeliveryNode(base_node));
1793 DCHECK(rejects->empty());
1794 DCHECK(subtrip->empty());
1797 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1798 int num_opened_pairs = 0;
1799 int current = base_node;
1801 const int pair = pd_data_.GetPairOfNode(current);
1802 if (pd_data_.IsPickupNode(current) && !opened_pairs_set_[pair]) {
1803 rejects->push_back(current);
1805 subtrip->push_back(current);
1806 if (pd_data_.IsDeliveryNode(current)) {
1808 opened_pairs_set_[pair] =
true;
1809 }
else if (pd_data_.IsPickupNode(current)) {
1811 opened_pairs_set_[pair] =
false;
1814 current = this->Prev(current);
1815 }
while (num_opened_pairs != 0 && !this->IsPathStart(current));
1816 if (num_opened_pairs != 0)
return false;
1817 std::reverse(rejects->begin(), rejects->end());
1818 std::reverse(subtrip->begin(), subtrip->end());
1823 Solver* solver,
const std::vector<IntVar*>& vars,
1824 const std::vector<IntVar*>& secondary_vars,
1825 std::function<
int(int64_t)> start_empty_path_class,
1826 std::function<
const std::vector<int>&(
int,
int)> get_incoming_neighbors,
1827 std::function<
const std::vector<int>&(
int,
int)> get_outgoing_neighbors,
1828 absl::Span<const PickupDeliveryPair> pairs) {
1829 if (secondary_vars.empty()) {
1831 vars, secondary_vars, std::move(start_empty_path_class),
1832 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
1836 vars, secondary_vars, std::move(start_empty_path_class),
1837 std::move(get_incoming_neighbors), std::move(get_outgoing_neighbors),
1842 Solver* solver,
const std::vector<IntVar*>& vars,
1843 const std::vector<IntVar*>& secondary_vars,
1844 std::function<
int(int64_t)> start_empty_path_class,
1845 absl::Span<const PickupDeliveryPair> pairs) {
1847 std::move(start_empty_path_class),
nullptr,
bool MakeNeighbor() 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)
bool MakeNeighbor() override
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 MakeNeighbor() override
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
void RevertChanges(bool change_was_incremental)
void AddVars(const std::vector< IntVar * > &vars)
int64_t Value(int64_t index) const
bool ApplyChanges(Assignment *delta, Assignment *deltadelta) const
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)
bool MakeNeighbor() override
virtual bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta)=0
bool MakeOneNeighbor() override
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)
bool MakeNeighbor() override
int64_t GetBaseNodeRestartPosition(int base_index) override
Operator which makes pairs of active nodes inactive.
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)
bool MakeNeighbor() override
bool MakeNeighbor() override
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)
bool MakeNeighbor() override
int64_t GetBaseNodeRestartPosition(int base_index) override
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 MakeNeighbor() override
bool OnSamePathAsPreviousBase(int64_t 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)
int64_t GetBaseNodeRestartPosition(int base_index) override
bool MakeNeighbor() override
bool HasNeighbors() const
int64_t Prev(int64_t node) const
Returns the node before node in the current delta.
bool SwapActiveAndInactive(int64_t active, int64_t inactive)
Replaces active by inactive in the current path, making active inactive.
int64_t Path(int64_t node) const
void AddPairAlternativeSets(const std::vector< PairType > &pair_alternative_sets)
int64_t BaseSiblingAlternativeNode(int i) const
Returns the alternative node for the sibling of the ith base node.
const int number_of_nexts_
virtual void OnNodeInitialization()
int64_t GetActiveAlternativeSibling(int node) const
bool IsPathStart(int64_t node) const
Returns true if node is the first node on the path.
bool MoveChain(int64_t before_chain, int64_t chain_end, int64_t destination)
bool IsPathEnd(int64_t node) const
bool SwapActiveAndInactiveChains(absl::Span< const int64_t > active_chain, absl::Span< const int64_t > inactive_chain)
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.
bool CheckChainValidity(int64_t before_chain, int64_t chain_end, int64_t exclude) const
bool ReverseChain(int64_t before_chain, int64_t after_chain, int64_t *chain_last)
virtual void SetNextBaseToIncrement(int64_t base_index)
Neighbor GetNeighborForBaseNode(int64_t base_index) const
int64_t BaseAlternativeNode(int i) const
Returns the alternative node for the ith base node.
bool MakeOneNeighbor() override
This method should not be overridden. Override MakeNeighbor() instead.
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.
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.
bool MakeNeighbor() override
bool MakeNeighbor() 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)
bool HasAlternatives(int node) const
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.
bool MakeNeighbor() override
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 MakeNeighbor() override
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.
std::function< const std::vector< int > &(int, int)> NeighborAccessor
--— Path-based Operators --—
int64_t CapAdd(int64_t x, int64_t y)
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)
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)
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 --—
static const int64_t kint64max