22#include "absl/log/check.h"
23#include "absl/types/span.h"
34 const std::vector<IntVar*>& vars,
35 const std::vector<IntVar*>& secondary_vars,
36 std::function<
int(int64_t)> start_empty_path_class,
37 std::function<
const std::vector<int>&(
int,
int)> get_neighbors,
40 get_neighbors == nullptr ? 2 : 1,
43 std::move(start_empty_path_class),
std::move(get_neighbors)),
44 arc_evaluator_(
std::move(arc_evaluator)) {}
47 const auto do_move = [
this](int64_t before_chain, int64_t destination) {
48 int64_t chain_end =
Next(before_chain);
50 if (chain_end == destination)
return false;
51 const int64_t max_arc_value = arc_evaluator_(destination, chain_end);
54 arc_evaluator_(chain_end,
next) <= max_arc_value) {
61 if (
next == destination)
return false;
65 return MoveChainAndRepair(before_chain, chain_end, destination);
70 return do_move(
Prev(node),
78bool MakeRelocateNeighborsOperator::MoveChainAndRepair(int64_t before_chain,
80 int64_t destination) {
81 if (
MoveChain(before_chain, chain_end, destination)) {
83 int64_t current =
Prev(destination);
84 int64_t last = chain_end;
85 if (current == last) {
86 current = before_chain;
88 while (last >= 0 && !
IsPathStart(current) && current != last) {
89 last = Reposition(current, last);
90 current =
Prev(current);
98int64_t MakeRelocateNeighborsOperator::Reposition(int64_t before_to_move,
100 const int64_t kNoChange = -1;
101 const int64_t to_move =
Next(before_to_move);
103 if (
Var(to_move)->Contains(
next)) {
108 while (prev != up_to) {
109 if (
Var(prev)->Contains(to_move) &&
Var(to_move)->Contains(
next)) {
110 MoveChain(before_to_move, to_move, prev);
116 if (
Var(prev)->Contains(to_move)) {
117 MoveChain(before_to_move, to_move, prev);
124 const std::vector<IntVar*>& vars,
125 const std::vector<IntVar*>& secondary_vars,
126 std::function<
int(int64_t)> start_empty_path_class,
127 std::vector<std::vector<int64_t>> alternative_sets,
130 std::move(start_empty_path_class), nullptr),
131 arc_evaluator_(
std::move(arc_evaluator)),
132 alternative_sets_(
std::move(alternative_sets)),
133 to_alternative_set_(vars.
size(), -1),
134 path_predecessor_(vars.
size(), -1),
135 touched_(vars.
size()) {
136 for (
int i = 0; i < alternative_sets_.size(); ++i) {
137 for (
int j : alternative_sets_[i]) {
138 if (j < to_alternative_set_.size()) to_alternative_set_[j] = i;
144 const int64_t before_chain =
BaseNode(0);
145 if (to_alternative_set_[before_chain] != -1)
return false;
147 std::vector<int> alternatives;
149 alternative_sets_[to_alternative_set_[
next]].
size() > 1) {
150 alternatives.push_back(to_alternative_set_[
next]);
153 if (alternatives.empty())
return false;
154 const int sink =
next;
156 bool swap_done =
false;
157 for (int64_t node : GetShortestPath(before_chain, sink, alternatives)) {
167const std::vector<int64_t>& SwapActiveToShortestPathOperator::GetShortestPath(
168 int source,
int sink,
const std::vector<int>& alternative_chain) {
170 if (alternative_chain.empty())
return path_;
173 const std::vector<int64_t>& first_alternative_set =
174 alternative_sets_[alternative_chain[0]];
175 std::vector<int64_t> prev_values;
176 prev_values.reserve(first_alternative_set.size());
177 for (
int alternative_node : first_alternative_set) {
178 prev_values.push_back(arc_evaluator_(source, alternative_node));
182 std::vector<int64_t> current_values;
183 for (
int rank = 1; rank < alternative_chain.size(); ++rank) {
184 const std::vector<int64_t>& current_alternative_set =
185 alternative_sets_[alternative_chain[rank]];
186 current_values.clear();
187 current_values.reserve(current_alternative_set.size());
188 const std::vector<int64_t>& prev_alternative_set =
189 alternative_sets_[alternative_chain[rank - 1]];
190 for (
int alternative_node : current_alternative_set) {
192 int predecessor = -1;
193 for (
int prev_alternative = 0;
194 prev_alternative < prev_alternative_set.size(); ++prev_alternative) {
195 const int64_t new_value =
196 CapAdd(prev_values[prev_alternative],
197 arc_evaluator_(prev_alternative_set[prev_alternative],
199 if (new_value <= min_value) {
200 min_value = new_value;
201 predecessor = prev_alternative_set[prev_alternative];
204 current_values.push_back(min_value);
205 path_predecessor_[alternative_node] = predecessor;
207 prev_values.swap(current_values);
211 int predecessor = -1;
212 const std::vector<int64_t>& last_alternative_set =
213 alternative_sets_[alternative_chain.back()];
214 for (
int alternative = 0; alternative < last_alternative_set.size();
216 const int64_t new_value =
217 CapAdd(prev_values[alternative],
218 arc_evaluator_(last_alternative_set[alternative], sink));
219 if (new_value <= min_value) {
220 min_value = new_value;
221 predecessor = last_alternative_set[alternative];
224 if (predecessor == -1)
return path_;
226 path_.resize(alternative_chain.size(), predecessor);
228 touched_.
Set(predecessor);
229 for (
int rank = alternative_chain.size() - 2; rank >= 0; --rank) {
230 path_[rank] = path_predecessor_[path_[rank + 1]];
231 if (touched_[path_[rank]]) {
235 touched_.
Set(path_[rank]);
241 const std::vector<IntVar*>& vars,
242 const std::vector<IntVar*>& secondary_vars,
243 std::function<
int(int64_t)> start_empty_path_class,
244 const std::vector<PickupDeliveryPair>& pairs)
246 std::move(start_empty_path_class), nullptr),
248 inactive_pair_first_index_(0),
249 inactive_pair_second_index_(0),
253 while (inactive_pair_ < pairs_.size()) {
256 const auto& [pickup_alternatives, delivery_alternatives] =
257 pairs_[inactive_pair_];
258 if (inactive_pair_first_index_ < pickup_alternatives.size() - 1) {
259 ++inactive_pair_first_index_;
260 }
else if (inactive_pair_second_index_ < delivery_alternatives.size() - 1) {
261 inactive_pair_first_index_ = 0;
262 ++inactive_pair_second_index_;
264 inactive_pair_ = FindNextInactivePair(inactive_pair_ + 1);
265 inactive_pair_first_index_ = 0;
266 inactive_pair_second_index_ = 0;
279 const auto& [pickup_alternatives, delivery_alternatives] =
280 pairs_[inactive_pair_];
281 return MakeActive(delivery_alternatives[inactive_pair_second_index_],
283 MakeActive(pickup_alternatives[inactive_pair_first_index_],
296void MakePairActiveOperator::OnNodeInitialization() {
297 inactive_pair_ = FindNextInactivePair(0);
298 inactive_pair_first_index_ = 0;
299 inactive_pair_second_index_ = 0;
302int MakePairActiveOperator::FindNextInactivePair(
int pair_index)
const {
304 if (!ContainsActiveNodes(pairs_[
index].pickup_alternatives) &&
305 !ContainsActiveNodes(pairs_[
index].delivery_alternatives)) {
309 return pairs_.size();
312bool MakePairActiveOperator::ContainsActiveNodes(
313 const std::vector<int64_t>&
nodes)
const {
314 for (int64_t node :
nodes) {
321 const std::vector<IntVar*>& vars,
322 const std::vector<IntVar*>& secondary_vars,
323 std::function<
int(int64_t)> start_empty_path_class,
324 const std::vector<PickupDeliveryPair>& pairs)
326 std::move(start_empty_path_class), nullptr) {
332 const int64_t first_index =
Next(base);
334 if (second_index < 0) {
342 const std::vector<IntVar*>& vars,
343 const std::vector<IntVar*>& secondary_vars,
344 std::function<
int(int64_t)> start_empty_path_class,
345 const std::vector<PickupDeliveryPair>& pairs)
347 std::move(start_empty_path_class), nullptr) {
353 const int64_t first_pair_node =
BaseNode(kPairFirstNode);
357 int64_t first_prev =
Prev(first_pair_node);
359 if (second_pair_node < 0 ||
IsPathEnd(second_pair_node) ||
363 const int64_t second_prev =
Prev(second_pair_node);
365 const int64_t first_node_destination =
BaseNode(kPairFirstNodeDestination);
366 if (first_node_destination == second_pair_node) {
371 const int64_t second_node_destination =
BaseNode(kPairSecondNodeDestination);
372 if (second_prev == first_pair_node && first_node_destination == first_prev &&
373 second_node_destination == first_prev) {
383 if (second_pair_node == second_node_destination ||
384 first_pair_node == first_node_destination) {
387 const bool moved_second_pair_node =
388 MoveChain(second_prev, second_pair_node, second_node_destination);
391 const bool moved_first_pair_node =
392 MoveChain(
Prev(first_pair_node), first_pair_node, first_node_destination);
397 return moved_first_pair_node || moved_second_pair_node;
403 if (base_index == kPairSecondNodeDestination) {
404 return BaseNode(kPairFirstNodeDestination);
411 const std::vector<IntVar*>& vars,
412 const std::vector<IntVar*>& secondary_vars,
413 std::function<
int(int64_t)> start_empty_path_class,
414 std::function<
const std::vector<int>&(
int,
int)> get_neighbors,
415 const std::vector<PickupDeliveryPair>& pairs)
417 get_neighbors == nullptr ? 2 : 1,
420 std::move(start_empty_path_class),
421 std::move(get_neighbors)) {
426 const auto do_move = [
this](int64_t node, int64_t destination) {
429 if (sibling == -1)
return false;
431 if (destination == node || destination == sibling)
return false;
442 const std::vector<IntVar*>& vars,
443 const std::vector<IntVar*>& secondary_vars,
444 std::function<
int(int64_t)> start_empty_path_class,
445 std::function<
const std::vector<int>&(
int,
int)> get_neighbors,
446 const std::vector<PickupDeliveryPair>& pairs,
447 std::function<
bool(int64_t)> force_lifo)
449 get_neighbors == nullptr ? 2 : 1,
452 std::move(start_empty_path_class),
std::move(get_neighbors)),
453 force_lifo_(
std::move(force_lifo)) {
458 const std::vector<IntVar*>& vars,
459 const std::vector<IntVar*>& secondary_vars,
460 std::function<
int(int64_t)> start_empty_path_class,
461 const std::vector<PickupDeliveryPair>& pairs,
462 std::function<
bool(int64_t)> force_lifo)
464 nullptr, pairs,
std::move(force_lifo)) {}
467 const auto do_move = [
this](int64_t node, int64_t destination,
468 bool destination_is_lifo) {
470 const int64_t prev =
Prev(node);
473 if (sibling == -1 || destination == sibling)
return false;
487 const bool ok =
MoveChain(prev, node, destination);
488 const int64_t destination_sibling =
490 if (destination_sibling == -1) {
497 if (!destination_is_lifo) {
498 if (
Prev(destination_sibling) == sibling)
return ok;
502 return MoveChain(
Prev(sibling), sibling, destination_sibling) || ok;
508 const int64_t destination_sibling =
510 if (destination_sibling == -1)
return false;
511 const bool ok =
MoveChain(prev, node, destination);
512 if (!destination_is_lifo) {
513 return MoveChain(
Prev(sibling), sibling, destination_sibling) || ok;
515 if (
Prev(destination_sibling) == sibling)
return ok;
525 force_lifo_ !=
nullptr && force_lifo_(
StartNode(1)));
529 const std::vector<IntVar*>& vars,
530 const std::vector<IntVar*>& secondary_vars,
531 std::function<
int(int64_t)> start_empty_path_class,
532 std::function<
const std::vector<int>&(
int,
int)> get_neighbors,
533 const std::vector<PickupDeliveryPair>& pairs)
535 get_neighbors == nullptr ? 2 : 1,
538 std::move(start_empty_path_class),
539 std::move(get_neighbors)) {
545 int64_t prev1, sibling1, sibling_prev1 = -1;
546 if (!GetPreviousAndSibling(node1, &prev1, &sibling1, &sibling_prev1)) {
555 node2 =
Prev(neighbor);
557 int64_t prev2, sibling2, sibling_prev2 = -1;
558 if (!GetPreviousAndSibling(node2, &prev2, &sibling2, &sibling_prev2)) {
563 if (node1 == prev2) {
565 if (sibling_prev1 == node2) sibling_prev1 = node1;
566 if (sibling_prev2 == node2) sibling_prev2 = node1;
567 }
else if (node2 == prev1) {
569 if (sibling_prev1 == node1) sibling_prev1 = node2;
570 if (sibling_prev2 == node1) sibling_prev2 = node2;
573 if (sibling_prev1 == node1) {
574 sibling_prev1 = node2;
575 }
else if (sibling_prev1 == node2) {
576 sibling_prev1 = node1;
578 if (sibling_prev2 == node1) {
579 sibling_prev2 = node2;
580 }
else if (sibling_prev2 == node2) {
581 sibling_prev2 = node1;
584 if (!
status)
return false;
586 if (sibling1 == sibling_prev2) {
588 }
else if (sibling2 == sibling_prev1) {
592 MoveChain(sibling_prev2, sibling2, sibling_prev1);
605bool PairExchangeOperator::GetPreviousAndSibling(
606 int64_t node, int64_t* previous, int64_t* sibling,
607 int64_t* sibling_previous)
const {
609 *previous =
Prev(node);
611 *sibling_previous = *sibling >= 0 ?
Prev(*sibling) : -1;
612 return *sibling_previous >= 0;
616 const std::vector<IntVar*>& vars,
617 const std::vector<IntVar*>& secondary_vars,
618 std::function<
int(int64_t)> start_empty_path_class,
619 const std::vector<PickupDeliveryPair>& pairs)
621 std::move(start_empty_path_class), nullptr) {
626 DCHECK_EQ(
StartNode(kSecondPairFirstNodeDestination),
627 StartNode(kSecondPairSecondNodeDestination));
628 DCHECK_EQ(
StartNode(kSecondPairFirstNode),
629 StartNode(kFirstPairFirstNodeDestination));
630 DCHECK_EQ(
StartNode(kSecondPairFirstNode),
631 StartNode(kFirstPairSecondNodeDestination));
649 if (!GetPreviousAndSibling(
nodes[0][0], &prev[0][0], &
nodes[0][1],
654 if (!GetPreviousAndSibling(
nodes[1][0], &prev[1][0], &
nodes[1][1],
660 if (!LoadAndCheckDest(0, 0, kFirstPairFirstNodeDestination,
nodes, dest)) {
664 if (!LoadAndCheckDest(0, 1, kFirstPairSecondNodeDestination,
nodes, dest)) {
668 if (
StartNode(kSecondPairFirstNodeDestination) !=
670 !LoadAndCheckDest(1, 0, kSecondPairFirstNodeDestination,
nodes, dest)) {
674 if (!LoadAndCheckDest(1, 1, kSecondPairSecondNodeDestination,
nodes, dest)) {
679 if (!MoveNode(0, 1,
nodes, dest, prev)) {
683 if (!MoveNode(0, 0,
nodes, dest, prev)) {
687 if (!MoveNode(1, 1,
nodes, dest, prev)) {
690 if (!MoveNode(1, 0,
nodes, dest, prev)) {
696bool PairExchangeRelocateOperator::MoveNode(
int pair,
int node,
699 int64_t prev[2][2]) {
700 if (!
MoveChain(prev[pair][node],
nodes[pair][node], dest[pair][node])) {
704 if (prev[1 - pair][0] == dest[pair][node]) {
705 prev[1 - pair][0] =
nodes[pair][node];
707 if (prev[1 - pair][1] == dest[pair][node]) {
708 prev[1 - pair][1] =
nodes[pair][node];
713bool PairExchangeRelocateOperator::LoadAndCheckDest(
int pair,
int node,
716 int64_t dest[2][2])
const {
717 dest[pair][node] =
BaseNode(base_node);
719 return !(
nodes[0][0] == dest[pair][node] ||
nodes[0][1] == dest[pair][node] ||
720 nodes[1][0] == dest[pair][node] ||
nodes[1][1] == dest[pair][node]);
724 int64_t base_index) {
728 return base_index == kFirstPairFirstNodeDestination ||
729 base_index == kFirstPairSecondNodeDestination ||
730 base_index == kSecondPairSecondNodeDestination;
735 if (base_index == kFirstPairSecondNodeDestination ||
736 base_index == kSecondPairSecondNodeDestination) {
743bool PairExchangeRelocateOperator::GetPreviousAndSibling(
744 int64_t node, int64_t* previous, int64_t* sibling,
745 int64_t* sibling_previous)
const {
747 *previous =
Prev(node);
749 *sibling_previous = *sibling >= 0 ?
Prev(*sibling) : -1;
750 return *sibling_previous >= 0;
754 const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& path_vars,
755 const std::vector<PickupDeliveryPair>& pairs)
761 number_of_nexts_(vars.
size()),
762 ignore_path_vars_(path_vars.empty()) {
763 if (!ignore_path_vars_) {
770 const int64_t kNoPath = -1;
771 CHECK(
delta !=
nullptr);
775 if (pair_index_ >= pairs_.size())
return false;
777 ignore_path_vars_ ? 0LL :
Value(first_active_ + number_of_nexts_);
778 const int64_t prev_first = prevs_[first_active_];
779 const int64_t next_first =
Value(first_active_);
781 SetNext(first_active_, first_active_, kNoPath);
783 const auto& [pickup_alternatives, delivery_alternatives] =
785 const int64_t insert_first = pickup_alternatives[first_index_];
786 SetNext(prev_first, insert_first, path);
787 SetNext(insert_first, next_first, path);
788 int64_t prev_second = prevs_[second_active_];
789 if (prev_second == first_active_) {
790 prev_second = insert_first;
792 DCHECK_EQ(path, ignore_path_vars_
794 :
Value(second_active_ + number_of_nexts_));
795 const int64_t next_second =
Value(second_active_);
797 SetNext(second_active_, second_active_, kNoPath);
799 const int64_t insert_second = delivery_alternatives[second_index_];
800 SetNext(prev_second, insert_second, path);
801 SetNext(insert_second, next_second, path);
804 if (second_index_ >= delivery_alternatives.size()) {
807 if (first_index_ >= pickup_alternatives.size()) {
811 if (!UpdateActiveNodes())
break;
812 if (first_active_ != -1 && second_active_ != -1) {
825 prevs_.resize(number_of_nexts_, -1);
828 if (
next >= prevs_.size()) prevs_.resize(
next + 1, -1);
837 if (!UpdateActiveNodes())
break;
838 if (first_active_ != -1 && second_active_ != -1) {
845bool SwapIndexPairOperator::UpdateActiveNodes() {
846 if (pair_index_ < pairs_.size()) {
847 const auto& [pickup_alternatives, delivery_alternatives] =
851 if (pickup_alternatives.size() == 1 && delivery_alternatives.size() == 1) {
856 for (
const int64_t first : pickup_alternatives) {
857 if (
Value(first) != first) {
858 first_active_ = first;
862 for (
const int64_t second : delivery_alternatives) {
863 if (
Value(second) != second) {
864 second_active_ = second;
874 const std::vector<IntVar*>& vars,
875 const std::vector<IntVar*>& secondary_vars,
876 std::function<
int(int64_t)> start_empty_path_class,
877 const std::vector<PickupDeliveryPair>& pairs)
879 std::move(start_empty_path_class), nullptr),
886 while (inactive_node_ <
Size()) {
909void IndexPairSwapActiveOperator::OnNodeInitialization() {
911 for (
int i = 0; i <
Size(); ++i) {
917 inactive_node_ =
Size();
921 const std::vector<IntVar*>& vars,
922 const std::vector<IntVar*>& secondary_vars,
923 std::function<
int(int64_t)> start_empty_path_class,
924 int num_arcs_to_consider,
925 std::function<int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start)
927 std::move(start_empty_path_class), nullptr),
928 num_arcs_to_consider_(num_arcs_to_consider),
930 current_expensive_arc_indices_({-1, -1}),
931 arc_cost_for_path_start_(std::move(arc_cost_for_path_start)),
933 has_non_empty_paths_to_explore_(
false) {
934 DCHECK_GE(num_arcs_to_consider_, 2);
938 const int first_arc_index = current_expensive_arc_indices_.first;
939 const int second_arc_index = current_expensive_arc_indices_.second;
940 DCHECK_LE(0, first_arc_index);
941 DCHECK_LT(first_arc_index, second_arc_index);
942 DCHECK_LT(second_arc_index, most_expensive_arc_starts_and_ranks_.size());
944 const std::pair<int, int>& first_start_and_rank =
945 most_expensive_arc_starts_and_ranks_[first_arc_index];
946 const std::pair<int, int>& second_start_and_rank =
947 most_expensive_arc_starts_and_ranks_[second_arc_index];
948 if (first_start_and_rank.second < second_start_and_rank.second) {
950 second_start_and_rank.first,
BaseNode(0)) &&
951 MoveChain(first_start_and_rank.first, second_start_and_rank.first,
955 first_start_and_rank.first,
BaseNode(0)) &&
956 MoveChain(second_start_and_rank.first, first_start_and_rank.first,
960 while (has_non_empty_paths_to_explore_) {
964 if (IncrementCurrentArcIndices()) {
968 IncrementCurrentPath();
969 has_non_empty_paths_to_explore_ =
970 current_path_ != end_path_ &&
971 FindMostExpensiveChainsOnRemainingPaths();
979void RelocateExpensiveChain::OnNodeInitialization() {
985 end_path_ = current_path_;
986 has_non_empty_paths_to_explore_ = FindMostExpensiveChainsOnRemainingPaths();
989void RelocateExpensiveChain::IncrementCurrentPath() {
991 if (++current_path_ == num_paths) {
996bool RelocateExpensiveChain::IncrementCurrentArcIndices() {
997 int& second_index = current_expensive_arc_indices_.second;
998 if (++second_index < most_expensive_arc_starts_and_ranks_.size()) {
1001 int& first_index = current_expensive_arc_indices_.first;
1002 if (first_index + 2 < most_expensive_arc_starts_and_ranks_.size()) {
1004 second_index = first_index + 1;
1010bool RelocateExpensiveChain::FindMostExpensiveChainsOnRemainingPaths() {
1013 num_arcs_to_consider_,
path_starts()[current_path_],
1014 [
this](int64_t i) {
return OldNext(i); },
1015 [
this](int64_t node) {
return IsPathEnd(node); },
1016 arc_cost_for_path_start_, &most_expensive_arc_starts_and_ranks_,
1017 ¤t_expensive_arc_indices_)) {
1020 IncrementCurrentPath();
1021 }
while (current_path_ != end_path_);
1026 int num_nodes, absl::Span<const PickupDeliveryPair> pairs)
1027 : is_pickup_node_(num_nodes, false),
1028 is_delivery_node_(num_nodes, false),
1029 pair_of_node_(num_nodes, -1) {
1030 for (
int pair_index = 0; pair_index < pairs.size(); ++pair_index) {
1031 for (
const int node : pairs[pair_index].pickup_alternatives) {
1032 is_pickup_node_[node] =
true;
1033 pair_of_node_[node] = pair_index;
1035 for (
const int node : pairs[pair_index].delivery_alternatives) {
1036 is_delivery_node_[node] =
true;
1037 pair_of_node_[node] = pair_index;
1043 const std::vector<IntVar*>& vars,
1044 const std::vector<IntVar*>& secondary_vars,
1045 std::function<
int(int64_t)> start_empty_path_class,
1046 std::function<
const std::vector<int>&(
int,
int)> get_neighbors,
1047 const std::vector<PickupDeliveryPair>& pairs)
1049 get_neighbors == nullptr ? 2 : 1,
1052 std::move(start_empty_path_class),
std::move(get_neighbors)),
1053 pd_data_(number_of_nexts_, pairs) {
1054 opened_pairs_set_.resize(pairs.size(),
false);
1057void RelocateSubtrip::SetPath(absl::Span<const int64_t> path,
int path_id) {
1058 for (
int i = 1; i < path.size(); ++i) {
1059 SetNext(path[i - 1], path[i], path_id);
1063bool RelocateSubtrip::RelocateSubTripFromPickup(
const int64_t chain_first_node,
1064 const int64_t insertion_node) {
1065 if (
IsPathEnd(insertion_node))
return false;
1066 if (
Prev(chain_first_node) == insertion_node)
1069 int num_opened_pairs = 0;
1071 rejected_nodes_ = {
Prev(chain_first_node)};
1072 subtrip_nodes_ = {insertion_node};
1073 int current = chain_first_node;
1075 if (current == insertion_node) {
1077 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1081 if (pd_data_.
IsDeliveryNode(current) && !opened_pairs_set_[pair]) {
1082 rejected_nodes_.push_back(current);
1084 subtrip_nodes_.push_back(current);
1087 opened_pairs_set_[pair] =
true;
1090 opened_pairs_set_[pair] =
false;
1093 current =
Next(current);
1094 }
while (num_opened_pairs != 0 && !
IsPathEnd(current));
1095 DCHECK_EQ(num_opened_pairs, 0);
1096 rejected_nodes_.push_back(current);
1097 subtrip_nodes_.push_back(
Next(insertion_node));
1100 SetPath(rejected_nodes_,
Path(chain_first_node));
1101 SetPath(subtrip_nodes_,
Path(insertion_node));
1105bool RelocateSubtrip::RelocateSubTripFromDelivery(
1106 const int64_t chain_last_node,
const int64_t insertion_node) {
1107 if (
IsPathEnd(insertion_node))
return false;
1110 DCHECK(std::none_of(opened_pairs_set_.begin(), opened_pairs_set_.end(),
1111 [](
bool value) { return value; }));
1112 int num_opened_pairs = 0;
1114 rejected_nodes_ = {
Next(chain_last_node)};
1115 subtrip_nodes_ = {
Next(insertion_node)};
1116 int current = chain_last_node;
1118 if (current == insertion_node) {
1119 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1123 if (pd_data_.
IsPickupNode(current) && !opened_pairs_set_[pair]) {
1124 rejected_nodes_.push_back(current);
1126 subtrip_nodes_.push_back(current);
1129 opened_pairs_set_[pair] =
true;
1132 opened_pairs_set_[pair] =
false;
1135 current =
Prev(current);
1136 }
while (num_opened_pairs != 0 && !
IsPathStart(current));
1137 DCHECK_EQ(num_opened_pairs, 0);
1138 if (current == insertion_node)
return false;
1139 rejected_nodes_.push_back(current);
1140 subtrip_nodes_.push_back(insertion_node);
1144 std::reverse(rejected_nodes_.begin(), rejected_nodes_.end());
1145 std::reverse(subtrip_nodes_.begin(), subtrip_nodes_.end());
1148 SetPath(rejected_nodes_,
Path(chain_last_node));
1149 SetPath(subtrip_nodes_,
Path(insertion_node));
1154 const auto do_move = [
this](int64_t node, int64_t insertion_node) {
1157 return RelocateSubTripFromPickup(node, insertion_node);
1159 return RelocateSubTripFromDelivery(node, insertion_node);
1171 const std::vector<IntVar*>& vars,
1172 const std::vector<IntVar*>& secondary_vars,
1173 std::function<
int(int64_t)> start_empty_path_class,
1174 std::function<
const std::vector<int>&(
int,
int)> get_neighbors,
1175 const std::vector<PickupDeliveryPair>& pairs)
1177 get_neighbors == nullptr ? 2 : 1,
1180 std::move(start_empty_path_class),
std::move(get_neighbors)),
1181 pd_data_(number_of_nexts_, pairs) {
1182 opened_pairs_set_.resize(pairs.size(),
false);
1185void ExchangeSubtrip::SetPath(
const std::vector<int64_t>& path,
int path_id) {
1186 for (
int i = 1; i < path.size(); ++i) {
1187 SetNext(path[i - 1], path[i], path_id);
1192bool VectorContains(absl::Span<const int64_t> values, int64_t target) {
1193 return std::find(values.begin(), values.end(), target) != values.end();
1207 node1 =
Prev(neighbor);
1224 if (node0 >= node1)
return false;
1227 if (!ExtractChainsAndCheckCanonical(node0, &rejects0_, &subtrip0_)) {
1232 if (!ExtractChainsAndCheckCanonical(node1, &rejects1_, &subtrip1_)) {
1238 if (VectorContains(rejects0_, subtrip1_.front()))
return false;
1239 if (VectorContains(rejects1_, subtrip0_.front()))
return false;
1240 if (VectorContains(subtrip0_, subtrip1_.front()))
return false;
1241 if (VectorContains(subtrip1_, subtrip0_.front()))
return false;
1245 path0_ = {
Prev(subtrip0_.front())};
1246 path1_ = {
Prev(subtrip1_.front())};
1247 const int64_t last0 =
Next(subtrip0_.back());
1248 const int64_t last1 =
Next(subtrip1_.back());
1249 const bool concatenated01 = last0 == subtrip1_.front();
1250 const bool concatenated10 = last1 == subtrip0_.front();
1252 if (pd_data_.
IsDeliveryNode(node0)) std::swap(subtrip1_, rejects0_);
1253 path0_.insert(path0_.end(), subtrip1_.begin(), subtrip1_.end());
1254 path0_.insert(path0_.end(), rejects0_.begin(), rejects0_.end());
1255 path0_.push_back(last0);
1257 if (pd_data_.
IsDeliveryNode(node1)) std::swap(subtrip0_, rejects1_);
1258 path1_.insert(path1_.end(), subtrip0_.begin(), subtrip0_.end());
1259 path1_.insert(path1_.end(), rejects1_.begin(), rejects1_.end());
1260 path1_.push_back(last1);
1263 if (concatenated01) {
1265 path1_.front() = path0_.back();
1266 }
else if (concatenated10) {
1268 path0_.front() = path1_.back();
1273 const int64_t path0_id =
Path(node0);
1274 const int64_t path1_id =
Path(node1);
1275 SetPath(path0_, path0_id);
1276 SetPath(path1_, path1_id);
1280bool ExchangeSubtrip::ExtractChainsAndCheckCanonical(
1281 int64_t base_node, std::vector<int64_t>* rejects,
1282 std::vector<int64_t>* subtrip) {
1283 const bool extracted =
1285 ? ExtractChainsFromPickup(base_node, rejects, subtrip)
1286 : ExtractChainsFromDelivery(base_node, rejects, subtrip);
1287 if (!extracted)
return false;
1295bool ExchangeSubtrip::ExtractChainsFromPickup(int64_t base_node,
1296 std::vector<int64_t>* rejects,
1297 std::vector<int64_t>* subtrip) {
1299 DCHECK(rejects->empty());
1300 DCHECK(subtrip->empty());
1303 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1304 int num_opened_pairs = 0;
1305 int current = base_node;
1308 if (pd_data_.
IsDeliveryNode(current) && !opened_pairs_set_[pair]) {
1309 rejects->push_back(current);
1311 subtrip->push_back(current);
1314 opened_pairs_set_[pair] =
true;
1317 opened_pairs_set_[pair] =
false;
1320 current =
Next(current);
1321 }
while (num_opened_pairs != 0 && !
IsPathEnd(current));
1322 return num_opened_pairs == 0;
1325bool ExchangeSubtrip::ExtractChainsFromDelivery(int64_t base_node,
1326 std::vector<int64_t>* rejects,
1327 std::vector<int64_t>* subtrip) {
1329 DCHECK(rejects->empty());
1330 DCHECK(subtrip->empty());
1333 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1334 int num_opened_pairs = 0;
1335 int current = base_node;
1338 if (pd_data_.
IsPickupNode(current) && !opened_pairs_set_[pair]) {
1339 rejects->push_back(current);
1341 subtrip->push_back(current);
1344 opened_pairs_set_[pair] =
true;
1347 opened_pairs_set_[pair] =
false;
1350 current =
Prev(current);
1351 }
while (num_opened_pairs != 0 && !
IsPathStart(current));
1352 if (num_opened_pairs != 0)
return false;
1353 std::reverse(rejects->begin(), rejects->end());
1354 std::reverse(subtrip->begin(), subtrip->end());
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_neighbors, const std::vector< PickupDeliveryPair > &pairs)
bool MakeNeighbor() override
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_neighbors, const std::vector< PickupDeliveryPair > &pairs)
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
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)
void RevertChanges(bool change_was_incremental)
void AddVars(const std::vector< IntVar * > &vars)
IntVar * Var(int64_t index) const
Returns the variable of given index.
int64_t Value(int64_t index) const
bool ApplyChanges(Assignment *delta, Assignment *deltadelta) const
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_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
bool MakeNeighbor() override
int64_t GetBaseNodeRestartPosition(int base_index) 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
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
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_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_neighbors, const std::vector< PickupDeliveryPair > &pairs)
bool MakeNeighbor() override
int64_t GetBaseNodeRestartPosition(int base_index) override
bool OnSamePathAsPreviousBase(int64_t 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 MakeNeighbor() override
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)
int64_t Prev(int64_t node) const
Returns the node before node in the current delta.
bool MakeActive(int64_t node, int64_t destination)
Insert the inactive node after destination.
bool IsPathStart(int64_t node) const
Returns true if node is the first node on the path.
bool CheckChainValidity(int64_t before_chain, int64_t chain_end, int64_t exclude) const
int GetNeighborForBaseNode(int64_t base_index) const
bool HasNeighbors() const
int64_t OldNext(int64_t node) const
bool MakeChainInactive(int64_t before_chain, int64_t chain_end)
bool IsInactive(int64_t node) const
Returns true if node is inactive.
virtual void OnNodeInitialization()
bool SwapActiveAndInactive(int64_t active, int64_t inactive)
Replaces active by inactive in the current path, making active inactive.
void AddPairAlternativeSets(const std::vector< PairType > &pair_alternative_sets)
bool MakeOneNeighbor() override
This method should not be overridden. Override MakeNeighbor() instead.
int64_t BaseSiblingAlternativeNode(int i) const
Returns the alternative node for the sibling of the ith base node.
int64_t BaseAlternativeNode(int i) const
Returns the alternative node for the ith base node.
const std::vector< int64_t > & path_starts() const
Returns the vector of path start nodes.
int64_t Path(int64_t node) const
int64_t GetActiveAlternativeSibling(int node) const
bool MoveChain(int64_t before_chain, int64_t chain_end, int64_t destination)
int64_t StartNode(int i) const
Returns the start node of the ith base node.
virtual void SetNextBaseToIncrement(int64_t base_index)
bool IsPathEnd(int64_t node) const
void SetNext(int64_t from, int64_t to, int64_t path)
Sets 'to' to be the node after 'from' on the given path.
int64_t BaseNode(int i) const
Returns the ith base node of the operator.
int GetPairOfNode(int64_t node) const
PickupAndDeliveryData(int num_nodes, absl::Span< const PickupDeliveryPair > pairs)
bool IsDeliveryNode(int64_t node) const
bool IsPickupNode(int64_t node) const
bool MakeNeighbor() override
bool MakeOneNeighbor() override
This method should not be overridden. Override MakeNeighbor() instead.
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)
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_neighbors, const std::vector< PickupDeliveryPair > &pairs)
bool MakeNeighbor() override
void Set(IntegerType index)
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)
bool MakeNeighbor() override
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 --—
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
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)
std::function< int64_t(int64_t, int64_t)> RoutingTransitCallback2
static const int64_t kint64max