39 const std::vector<IntVar*>& vars,
40 const std::vector<IntVar*>& secondary_vars,
41 std::function<
int(int64_t)> start_empty_path_class,
44 std::move(start_empty_path_class)),
45 arc_evaluator_(std::move(arc_evaluator)) {}
48 const int64_t before_chain =
BaseNode(0);
49 int64_t chain_end =
Next(before_chain);
51 const int64_t destination =
BaseNode(1);
52 if (chain_end == destination)
return false;
53 const int64_t max_arc_value = arc_evaluator_(destination, chain_end);
56 if (
next == destination)
return false;
60 return MoveChainAndRepair(before_chain, chain_end, destination);
63 bool MakeRelocateNeighborsOperator::MoveChainAndRepair(int64_t before_chain,
65 int64_t destination) {
66 if (
MoveChain(before_chain, chain_end, destination)) {
68 int64_t current =
Prev(destination);
69 int64_t last = chain_end;
70 if (current == last) {
71 current = before_chain;
73 while (last >= 0 && !
IsPathStart(current) && current != last) {
74 last = Reposition(current, last);
75 current =
Prev(current);
83 int64_t MakeRelocateNeighborsOperator::Reposition(int64_t before_to_move,
85 const int64_t kNoChange = -1;
86 const int64_t to_move =
Next(before_to_move);
88 if (
Var(to_move)->Contains(
next)) {
93 while (prev != up_to) {
94 if (
Var(prev)->Contains(to_move) &&
Var(to_move)->Contains(
next)) {
101 if (
Var(prev)->Contains(to_move)) {
102 MoveChain(before_to_move, to_move, prev);
109 const std::vector<IntVar*>& vars,
110 const std::vector<IntVar*>& secondary_vars,
111 std::function<
int(int64_t)> start_empty_path_class,
112 std::vector<std::vector<int64_t>> alternative_sets,
115 std::move(start_empty_path_class)),
116 arc_evaluator_(std::move(arc_evaluator)),
117 alternative_sets_(std::move(alternative_sets)),
118 to_alternative_set_(vars.size(), -1),
119 path_predecessor_(vars.size(), -1) {
120 for (
int i = 0; i < alternative_sets_.size(); ++i) {
121 for (
int j : alternative_sets_[i]) {
122 if (j < to_alternative_set_.size()) to_alternative_set_[j] = i;
128 const int64_t before_chain =
BaseNode(0);
129 if (to_alternative_set_[before_chain] != -1)
return false;
131 std::vector<int> alternatives;
133 alternative_sets_[to_alternative_set_[
next]].size() > 1) {
134 alternatives.push_back(to_alternative_set_[
next]);
137 if (alternatives.empty())
return false;
139 bool swap_done =
false;
140 UpdateShortestPath(before_chain,
next, alternatives);
141 for (int64_t node : path_) {
151 void SwapActiveToShortestPathOperator::UpdateShortestPath(
152 int source,
int sink,
const std::vector<int>& alternative_chain) {
154 if (alternative_chain.empty())
return;
157 const std::vector<int64_t>& first_alternative_set =
158 alternative_sets_[alternative_chain[0]];
159 std::vector<int64_t> prev_values;
160 prev_values.reserve(first_alternative_set.size());
161 for (
int alternative_node : first_alternative_set) {
162 prev_values.push_back(arc_evaluator_(source, alternative_node));
166 std::vector<int64_t> current_values;
167 for (
int rank = 1; rank < alternative_chain.size(); ++rank) {
168 const std::vector<int64_t>& current_alternative_set =
169 alternative_sets_[alternative_chain[rank]];
170 current_values.clear();
171 current_values.reserve(current_alternative_set.size());
172 const std::vector<int64_t>& prev_alternative_set =
173 alternative_sets_[alternative_chain[rank - 1]];
174 for (
int alternative_node : current_alternative_set) {
176 int predecessor = -1;
177 for (
int prev_alternative = 0;
178 prev_alternative < prev_alternative_set.size(); ++prev_alternative) {
179 const int64_t new_value =
180 CapAdd(prev_values[prev_alternative],
181 arc_evaluator_(prev_alternative_set[prev_alternative],
183 if (new_value <= min_value) {
184 min_value = new_value;
185 predecessor = prev_alternative_set[prev_alternative];
188 current_values.push_back(min_value);
189 path_predecessor_[alternative_node] = predecessor;
191 prev_values.swap(current_values);
195 int predecessor = -1;
196 const std::vector<int64_t>& last_alternative_set =
197 alternative_sets_[alternative_chain.back()];
198 for (
int alternative = 0; alternative < last_alternative_set.size();
200 const int64_t new_value =
201 CapAdd(prev_values[alternative],
202 arc_evaluator_(last_alternative_set[alternative], sink));
203 if (new_value <= min_value) {
204 min_value = new_value;
205 predecessor = last_alternative_set[alternative];
208 if (predecessor == -1)
return;
210 path_.resize(alternative_chain.size(), predecessor);
211 for (
int rank = alternative_chain.size() - 2; rank >= 0; --rank) {
212 path_[rank] = path_predecessor_[path_[rank + 1]];
217 const std::vector<IntVar*>& vars,
218 const std::vector<IntVar*>& secondary_vars,
219 std::function<
int(int64_t)> start_empty_path_class,
222 std::move(start_empty_path_class)),
224 inactive_pair_first_index_(0),
225 inactive_pair_second_index_(0),
229 while (inactive_pair_ < pairs_.size()) {
232 if (inactive_pair_first_index_ < pairs_[inactive_pair_].first.size() - 1) {
233 ++inactive_pair_first_index_;
234 }
else if (inactive_pair_second_index_ <
235 pairs_[inactive_pair_].second.size() - 1) {
236 inactive_pair_first_index_ = 0;
237 ++inactive_pair_second_index_;
239 inactive_pair_ = FindNextInactivePair(inactive_pair_ + 1);
240 inactive_pair_first_index_ = 0;
241 inactive_pair_second_index_ = 0;
254 return MakeActive(pairs_[inactive_pair_].second[inactive_pair_second_index_],
256 MakeActive(pairs_[inactive_pair_].first[inactive_pair_first_index_],
269 void MakePairActiveOperator::OnNodeInitialization() {
270 inactive_pair_ = FindNextInactivePair(0);
271 inactive_pair_first_index_ = 0;
272 inactive_pair_second_index_ = 0;
275 int MakePairActiveOperator::FindNextInactivePair(
int pair_index)
const {
277 if (!ContainsActiveNodes(pairs_[
index].first) &&
278 !ContainsActiveNodes(pairs_[
index].second)) {
282 return pairs_.size();
285 bool MakePairActiveOperator::ContainsActiveNodes(
286 const std::vector<int64_t>&
nodes)
const {
287 for (int64_t node :
nodes) {
294 const std::vector<IntVar*>& vars,
295 const std::vector<IntVar*>& secondary_vars,
296 std::function<
int(int64_t)> start_empty_path_class,
299 std::move(start_empty_path_class)) {
305 const int64_t first_index =
Next(base);
307 if (second_index < 0) {
315 const std::vector<IntVar*>& vars,
316 const std::vector<IntVar*>& secondary_vars,
317 std::function<
int(int64_t)> start_empty_path_class,
320 std::move(start_empty_path_class)) {
326 const int64_t first_pair_node =
BaseNode(kPairFirstNode);
330 int64_t first_prev =
Prev(first_pair_node);
332 if (second_pair_node < 0 ||
IsPathEnd(second_pair_node) ||
336 const int64_t second_prev =
Prev(second_pair_node);
338 const int64_t first_node_destination =
BaseNode(kPairFirstNodeDestination);
339 if (first_node_destination == second_pair_node) {
344 const int64_t second_node_destination =
BaseNode(kPairSecondNodeDestination);
345 if (second_prev == first_pair_node && first_node_destination == first_prev &&
346 second_node_destination == first_prev) {
356 if (second_pair_node == second_node_destination ||
357 first_pair_node == first_node_destination) {
360 const bool moved_second_pair_node =
361 MoveChain(second_prev, second_pair_node, second_node_destination);
364 const bool moved_first_pair_node =
365 MoveChain(
Prev(first_pair_node), first_pair_node, first_node_destination);
370 return moved_first_pair_node || moved_second_pair_node;
376 if (base_index == kPairSecondNodeDestination) {
377 return BaseNode(kPairFirstNodeDestination);
384 const std::vector<IntVar*>& vars,
385 const std::vector<IntVar*>& secondary_vars,
386 std::function<
int(int64_t)> start_empty_path_class,
389 std::move(start_empty_path_class)) {
395 const int64_t node1 =
Next(prev1);
398 if (sibling1 == -1)
return false;
401 if (node2 == node1 || node2 == sibling1)
return false;
402 const bool ok =
MoveChain(prev1, node1, node2);
407 const std::vector<IntVar*>& vars,
408 const std::vector<IntVar*>& secondary_vars,
409 std::function<
int(int64_t)> start_empty_path_class,
411 std::function<
bool(int64_t)> force_lifo)
413 std::move(start_empty_path_class)),
414 force_lifo_(std::move(force_lifo)) {
420 const int64_t node1 =
Next(prev1);
423 if (sibling1 == -1)
return false;
425 if (node2 == sibling1)
return false;
426 const bool path2_is_lifo =
427 (force_lifo_ !=
nullptr && force_lifo_(
StartNode(1)));
439 const bool ok =
MoveChain(prev1, node1, node2);
441 if (sibling2 == -1) {
447 if (!path2_is_lifo) {
448 if (
Prev(sibling2) == sibling1)
return ok;
457 if (sibling2 == -1)
return false;
458 const bool ok =
MoveChain(prev1, node1, node2);
459 if (!path2_is_lifo) {
462 if (
Prev(sibling2) == sibling1)
return ok;
468 const std::vector<IntVar*>& vars,
469 const std::vector<IntVar*>& secondary_vars,
470 std::function<
int(int64_t)> start_empty_path_class,
473 std::move(start_empty_path_class)) {
479 int64_t prev1, sibling1, sibling_prev1 = -1;
480 if (!GetPreviousAndSibling(node1, &prev1, &sibling1, &sibling_prev1)) {
484 int64_t prev2, sibling2, sibling_prev2 = -1;
485 if (!GetPreviousAndSibling(node2, &prev2, &sibling2, &sibling_prev2)) {
490 if (node1 == prev2) {
492 if (sibling_prev1 == node2) sibling_prev1 = node1;
493 if (sibling_prev2 == node2) sibling_prev2 = node1;
494 }
else if (node2 == prev1) {
496 if (sibling_prev1 == node1) sibling_prev1 = node2;
497 if (sibling_prev2 == node1) sibling_prev2 = node2;
500 if (sibling_prev1 == node1) {
501 sibling_prev1 = node2;
502 }
else if (sibling_prev1 == node2) {
503 sibling_prev1 = node1;
505 if (sibling_prev2 == node1) {
506 sibling_prev2 = node2;
507 }
else if (sibling_prev2 == node2) {
508 sibling_prev2 = node1;
511 if (!
status)
return false;
513 if (sibling1 == sibling_prev2) {
515 }
else if (sibling2 == sibling_prev1) {
519 MoveChain(sibling_prev2, sibling2, sibling_prev1);
529 bool PairExchangeOperator::GetPreviousAndSibling(
530 int64_t node, int64_t* previous, int64_t* sibling,
531 int64_t* sibling_previous)
const {
533 *previous =
Prev(node);
535 *sibling_previous = *sibling >= 0 ?
Prev(*sibling) : -1;
536 return *sibling_previous >= 0;
540 const std::vector<IntVar*>& vars,
541 const std::vector<IntVar*>& secondary_vars,
542 std::function<
int(int64_t)> start_empty_path_class,
545 std::move(start_empty_path_class)) {
550 DCHECK_EQ(
StartNode(kSecondPairFirstNodeDestination),
551 StartNode(kSecondPairSecondNodeDestination));
552 DCHECK_EQ(
StartNode(kSecondPairFirstNode),
553 StartNode(kFirstPairFirstNodeDestination));
554 DCHECK_EQ(
StartNode(kSecondPairFirstNode),
555 StartNode(kFirstPairSecondNodeDestination));
573 if (!GetPreviousAndSibling(
nodes[0][0], &prev[0][0], &
nodes[0][1],
578 if (!GetPreviousAndSibling(
nodes[1][0], &prev[1][0], &
nodes[1][1],
584 if (!LoadAndCheckDest(0, 0, kFirstPairFirstNodeDestination,
nodes, dest)) {
588 if (!LoadAndCheckDest(0, 1, kFirstPairSecondNodeDestination,
nodes, dest)) {
592 if (
StartNode(kSecondPairFirstNodeDestination) !=
594 !LoadAndCheckDest(1, 0, kSecondPairFirstNodeDestination,
nodes, dest)) {
598 if (!LoadAndCheckDest(1, 1, kSecondPairSecondNodeDestination,
nodes, dest)) {
603 if (!MoveNode(0, 1,
nodes, dest, prev)) {
607 if (!MoveNode(0, 0,
nodes, dest, prev)) {
611 if (!MoveNode(1, 1,
nodes, dest, prev)) {
614 if (!MoveNode(1, 0,
nodes, dest, prev)) {
620 bool PairExchangeRelocateOperator::MoveNode(
int pair,
int node,
623 int64_t prev[2][2]) {
624 if (!
MoveChain(prev[pair][node],
nodes[pair][node], dest[pair][node])) {
628 if (prev[1 - pair][0] == dest[pair][node]) {
629 prev[1 - pair][0] =
nodes[pair][node];
631 if (prev[1 - pair][1] == dest[pair][node]) {
632 prev[1 - pair][1] =
nodes[pair][node];
637 bool PairExchangeRelocateOperator::LoadAndCheckDest(
int pair,
int node,
640 int64_t dest[2][2])
const {
641 dest[pair][node] =
BaseNode(base_node);
643 return !(
nodes[0][0] == dest[pair][node] ||
nodes[0][1] == dest[pair][node] ||
644 nodes[1][0] == dest[pair][node] ||
nodes[1][1] == dest[pair][node]);
648 int64_t base_index) {
652 return base_index == kFirstPairFirstNodeDestination ||
653 base_index == kFirstPairSecondNodeDestination ||
654 base_index == kSecondPairSecondNodeDestination;
659 if (base_index == kFirstPairSecondNodeDestination ||
660 base_index == kSecondPairSecondNodeDestination) {
667 bool PairExchangeRelocateOperator::GetPreviousAndSibling(
668 int64_t node, int64_t* previous, int64_t* sibling,
669 int64_t* sibling_previous)
const {
671 *previous =
Prev(node);
673 *sibling_previous = *sibling >= 0 ?
Prev(*sibling) : -1;
674 return *sibling_previous >= 0;
678 const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& path_vars,
679 std::function<
int(int64_t)> start_empty_path_class,
682 index_pairs_(index_pairs),
686 number_of_nexts_(vars.size()),
687 ignore_path_vars_(path_vars.empty()) {
688 if (!ignore_path_vars_) {
695 const int64_t kNoPath = -1;
696 CHECK(
delta !=
nullptr);
700 if (pair_index_ < index_pairs_.size()) {
702 ignore_path_vars_ ? 0LL :
Value(first_active_ + number_of_nexts_);
703 const int64_t prev_first = prevs_[first_active_];
704 const int64_t next_first =
Value(first_active_);
706 SetNext(first_active_, first_active_, kNoPath);
708 const int64_t insert_first =
709 index_pairs_[pair_index_].first[first_index_];
710 SetNext(prev_first, insert_first, path);
711 SetNext(insert_first, next_first, path);
712 int64_t prev_second = prevs_[second_active_];
713 if (prev_second == first_active_) {
714 prev_second = insert_first;
716 DCHECK_EQ(path, ignore_path_vars_
718 :
Value(second_active_ + number_of_nexts_));
719 const int64_t next_second =
Value(second_active_);
721 SetNext(second_active_, second_active_, kNoPath);
723 const int64_t insert_second =
724 index_pairs_[pair_index_].second[second_index_];
725 SetNext(prev_second, insert_second, path);
726 SetNext(insert_second, next_second, path);
729 if (second_index_ >= index_pairs_[pair_index_].second.size()) {
732 if (first_index_ >= index_pairs_[pair_index_].first.size()) {
748 prevs_.resize(number_of_nexts_, -1);
751 if (
next >= prevs_.size()) prevs_.resize(
next + 1, -1);
760 if (!UpdateActiveNodes())
break;
761 if (first_active_ != -1 && second_active_ != -1) {
768 bool SwapIndexPairOperator::UpdateActiveNodes() {
769 if (pair_index_ < index_pairs_.size()) {
770 for (
const int64_t first : index_pairs_[pair_index_].first) {
771 if (
Value(first) != first) {
772 first_active_ = first;
776 for (
const int64_t second : index_pairs_[pair_index_].second) {
777 if (
Value(second) != second) {
778 second_active_ = second;
788 const std::vector<IntVar*>& vars,
789 const std::vector<IntVar*>& secondary_vars,
790 std::function<
int(int64_t)> start_empty_path_class,
793 std::move(start_empty_path_class)),
800 while (inactive_node_ <
Size()) {
823 void IndexPairSwapActiveOperator::OnNodeInitialization() {
825 for (
int i = 0; i <
Size(); ++i) {
831 inactive_node_ =
Size();
837 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
838 bool keep_inverse_values)
840 keep_inverse_values),
841 model_(heuristic->
model()),
842 removed_nodes_(model_->Size()),
843 heuristic_(std::move(heuristic)),
844 consider_vehicle_vars_(!model_->CostsAreHomogeneousAcrossVehicles()) {
845 if (consider_vehicle_vars_) {
850 bool FilteredHeuristicLocalSearchOperator::MakeOneNeighbor() {
861 if (MakeChangesAndInsertNodes()) {
868 bool FilteredHeuristicLocalSearchOperator::MakeChangesAndInsertNodes() {
871 const std::function<int64_t(int64_t)> next_accessor =
873 if (next_accessor ==
nullptr) {
876 const Assignment*
const result_assignment =
877 heuristic_->BuildSolutionFromRoutes(next_accessor);
879 if (result_assignment ==
nullptr) {
883 bool has_change =
false;
884 const std::vector<IntVarElement>& elements =
885 result_assignment->IntVarContainer().elements();
891 const IntVarElement& node_element = elements[node_index];
894 const int64_t new_node_value = node_element.Value();
895 DCHECK_NE(new_node_value, node_index);
897 const int64_t vehicle_var_index = VehicleVarIndex(node_index);
898 if (
OldValue(node_index) != new_node_value ||
899 (consider_vehicle_vars_ &&
OldValue(vehicle_var_index) != vehicle)) {
901 SetValue(node_index, new_node_value);
902 if (consider_vehicle_vars_) {
903 SetValue(vehicle_var_index, vehicle);
906 node_index = new_node_value;
912 const IntVarElement& node_element = elements[node];
914 if (node_element.Value() == node) {
918 if (consider_vehicle_vars_) {
919 const int64_t vehicle_var_index = VehicleVarIndex(node);
920 DCHECK_NE(
OldValue(vehicle_var_index), -1);
931 std::unique_ptr<RoutingFilteredHeuristic> heuristic)
935 just_started_(false) {}
937 void FilteredHeuristicPathLNSOperator::OnStart() {
940 last_route_ = current_route_;
941 if (CurrentRouteIsEmpty()) {
942 IncrementCurrentRouteToNextNonEmpty();
944 just_started_ =
true;
947 bool FilteredHeuristicPathLNSOperator::IncrementPosition() {
949 just_started_ =
false;
950 return !CurrentRouteIsEmpty();
952 IncrementCurrentRouteToNextNonEmpty();
953 return current_route_ != last_route_;
956 bool FilteredHeuristicPathLNSOperator::CurrentRouteIsEmpty()
const {
960 void FilteredHeuristicPathLNSOperator::IncrementCurrentRouteToNextNonEmpty() {
963 ++current_route_ %= num_routes;
964 if (current_route_ == last_route_) {
968 }
while (CurrentRouteIsEmpty());
971 std::function<int64_t(int64_t)>
972 FilteredHeuristicPathLNSOperator::SetupNextAccessorForNeighbor() {
973 const int64_t start_node =
model_->
Start(current_route_);
974 const int64_t end_node =
model_->
End(current_route_);
976 int64_t node =
Value(start_node);
977 while (node != end_node) {
982 return [
this, start_node, end_node](int64_t node) {
983 if (node == start_node)
return end_node;
992 std::unique_ptr<RoutingFilteredHeuristic> heuristic)
994 route_to_relocate_index_(0),
995 empty_route_index_(0),
996 just_started_(false) {}
998 void RelocatePathAndHeuristicInsertUnperformedOperator::OnStart() {
999 has_unperformed_nodes_ =
false;
1001 routes_to_relocate_.clear();
1002 empty_routes_.clear();
1003 std::vector<bool> empty_vehicle_of_vehicle_class_added(
1005 for (int64_t node = 0; node <
model_->
Size(); node++) {
1008 has_unperformed_nodes_ =
true;
1019 routes_to_relocate_.push_back(vehicle);
1025 empty_routes_.push_back(vehicle);
1030 if (empty_route_index_ >= empty_routes_.size()) {
1031 empty_route_index_ = 0;
1033 if (route_to_relocate_index_ >= routes_to_relocate_.size()) {
1034 route_to_relocate_index_ = 0;
1036 last_empty_route_index_ = empty_route_index_;
1037 last_route_to_relocate_index_ = route_to_relocate_index_;
1039 just_started_ =
true;
1042 bool RelocatePathAndHeuristicInsertUnperformedOperator::IncrementPosition() {
1043 if (!has_unperformed_nodes_ || empty_routes_.empty() ||
1044 routes_to_relocate_.empty()) {
1047 if (just_started_) {
1048 just_started_ =
false;
1051 return IncrementRoutes();
1054 bool RelocatePathAndHeuristicInsertUnperformedOperator::IncrementRoutes() {
1055 ++empty_route_index_ %= empty_routes_.size();
1056 if (empty_route_index_ != last_empty_route_index_) {
1059 ++route_to_relocate_index_ %= routes_to_relocate_.size();
1060 return route_to_relocate_index_ != last_route_to_relocate_index_;
1063 std::function<int64_t(int64_t)>
1064 RelocatePathAndHeuristicInsertUnperformedOperator::
1065 SetupNextAccessorForNeighbor() {
1066 const int empty_route = empty_routes_[empty_route_index_];
1067 const int relocated_route = routes_to_relocate_[route_to_relocate_index_];
1074 const int64_t empty_start_node =
model_->
Start(empty_route);
1075 const int64_t empty_end_node =
model_->
End(empty_route);
1077 const int64_t relocated_route_start =
model_->
Start(relocated_route);
1078 const int64_t first_relocated_node =
OldValue(relocated_route_start);
1079 const int64_t last_relocated_node = last_node_on_route_[relocated_route];
1080 const int64_t relocated_route_end =
model_->
End(relocated_route);
1082 return [
this, empty_start_node, empty_end_node, first_relocated_node,
1083 last_relocated_node, relocated_route_start,
1084 relocated_route_end](int64_t node) {
1085 if (node == relocated_route_start)
return relocated_route_end;
1086 if (node == empty_start_node)
return first_relocated_node;
1087 if (node == last_relocated_node)
return empty_end_node;
1095 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
int num_close_nodes)
1098 pickup_delivery_pairs_(model_->GetPickupAndDeliveryPairs()),
1101 just_started_(false),
1102 initialized_(false),
1103 close_nodes_(model_->Size()),
1104 num_close_nodes_(num_close_nodes),
1105 new_nexts_(model_->Size()),
1106 changed_nexts_(model_->Size()),
1107 new_prevs_(model_->Size()),
1108 changed_prevs_(model_->Size()) {}
1110 void FilteredHeuristicCloseNodesLNSOperator::Initialize() {
1111 if (initialized_)
return;
1112 initialized_ =
true;
1114 const int64_t max_num_neighbors =
1116 const int64_t num_closest_neighbors =
1117 std::min<int64_t>(num_close_nodes_, max_num_neighbors);
1118 DCHECK_GE(num_closest_neighbors, 0);
1120 if (num_closest_neighbors == 0)
return;
1124 for (int64_t node = 0; node < size; node++) {
1127 std::vector<std::pair< double, int64_t>>
1129 costed_after_nodes.reserve(size);
1130 for (int64_t after_node = 0; after_node < size; after_node++) {
1132 after_node == node) {
1135 double total_cost = 0.0;
1138 for (
int cost_class = 1; cost_class < num_cost_classes; cost_class++) {
1141 costed_after_nodes.emplace_back(total_cost, after_node);
1144 std::nth_element(costed_after_nodes.begin(),
1145 costed_after_nodes.begin() + num_closest_neighbors - 1,
1146 costed_after_nodes.end());
1147 std::vector<int64_t>& neighbors = close_nodes_[node];
1148 neighbors.reserve(num_closest_neighbors);
1150 neighbors.push_back(costed_after_nodes[
index].second);
1155 void FilteredHeuristicCloseNodesLNSOperator::OnStart() {
1157 last_node_ = current_node_;
1158 just_started_ =
true;
1161 bool FilteredHeuristicCloseNodesLNSOperator::IncrementPosition() {
1162 DCHECK(initialized_);
1163 if (just_started_) {
1164 just_started_ =
false;
1168 return current_node_ != last_node_;
1171 void FilteredHeuristicCloseNodesLNSOperator::RemoveNode(int64_t node) {
1173 DCHECK_NE(
Value(node), node);
1174 DCHECK(IsActive(node));
1177 const int64_t prev = Prev(node);
1178 const int64_t
next = Next(node);
1179 changed_nexts_.
Set(prev);
1180 new_nexts_[prev] =
next;
1181 if (next < model_->
Size()) {
1183 new_prevs_[
next] = prev;
1187 void FilteredHeuristicCloseNodesLNSOperator::RemoveNodeAndActiveSibling(
1189 if (!IsActive(node))
return;
1192 for (int64_t sibling_node : GetActiveSiblings(node)) {
1194 RemoveNode(sibling_node);
1199 std::vector<int64_t> FilteredHeuristicCloseNodesLNSOperator::GetActiveSiblings(
1200 int64_t node)
const {
1204 std::vector<int64_t> active_siblings;
1205 for (std::pair<int64_t, int64_t> index_pair :
1207 for (int64_t sibling_delivery :
1208 pickup_delivery_pairs_[index_pair.first].second) {
1209 if (IsActive(sibling_delivery)) {
1210 active_siblings.push_back(sibling_delivery);
1215 for (std::pair<int64_t, int64_t> index_pair :
1217 for (int64_t sibling_pickup :
1218 pickup_delivery_pairs_[index_pair.first].first) {
1219 if (IsActive(sibling_pickup)) {
1220 active_siblings.push_back(sibling_pickup);
1225 return active_siblings;
1228 std::function<int64_t(int64_t)>
1229 FilteredHeuristicCloseNodesLNSOperator::SetupNextAccessorForNeighbor() {
1230 DCHECK(initialized_);
1239 RemoveNodeAndActiveSibling(current_node_);
1241 for (int64_t neighbor : close_nodes_[current_node_]) {
1242 RemoveNodeAndActiveSibling(neighbor);
1245 return [
this](int64_t node) {
return Next(node); };
1252 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
1253 int num_arcs_to_consider,
1254 std::function<int64_t(int64_t, int64_t, int64_t)>
1255 arc_cost_for_route_start)
1259 num_arcs_to_consider_(num_arcs_to_consider),
1260 current_expensive_arc_indices_({-1, -1}),
1261 arc_cost_for_route_start_(std::move(arc_cost_for_route_start)),
1262 just_started_(
false) {
1263 DCHECK_GE(num_arcs_to_consider_, 2);
1266 void FilteredHeuristicExpensiveChainLNSOperator::OnStart() {
1267 last_route_ = current_route_;
1268 just_started_ =
true;
1271 bool FilteredHeuristicExpensiveChainLNSOperator::IncrementPosition() {
1272 if (just_started_) {
1273 just_started_ =
false;
1274 return FindMostExpensiveChainsOnRemainingRoutes();
1277 if (IncrementCurrentArcIndices())
return true;
1279 return IncrementRoute() && FindMostExpensiveChainsOnRemainingRoutes();
1282 std::function<int64_t(int64_t)>
1283 FilteredHeuristicExpensiveChainLNSOperator::SetupNextAccessorForNeighbor() {
1284 const int first_arc_index = current_expensive_arc_indices_.first;
1285 const int second_arc_index = current_expensive_arc_indices_.second;
1286 DCHECK_LE(0, first_arc_index);
1287 DCHECK_LT(first_arc_index, second_arc_index);
1288 DCHECK_LT(second_arc_index, most_expensive_arc_starts_and_ranks_.size());
1290 const std::pair<int, int>& first_start_and_rank =
1291 most_expensive_arc_starts_and_ranks_[first_arc_index];
1292 const std::pair<int, int>& second_start_and_rank =
1293 most_expensive_arc_starts_and_ranks_[second_arc_index];
1294 int64_t before_chain, after_chain;
1295 if (first_start_and_rank.second < second_start_and_rank.second) {
1296 before_chain = first_start_and_rank.first;
1297 after_chain =
OldValue(second_start_and_rank.first);
1299 before_chain = second_start_and_rank.first;
1300 after_chain =
OldValue(first_start_and_rank.first);
1303 int node =
Value(before_chain);
1304 while (node != after_chain) {
1309 return [
this, before_chain, after_chain](int64_t node) {
1310 if (node == before_chain)
return after_chain;
1315 bool FilteredHeuristicExpensiveChainLNSOperator::IncrementRoute() {
1317 return current_route_ != last_route_;
1320 bool FilteredHeuristicExpensiveChainLNSOperator::IncrementCurrentArcIndices() {
1321 int& second_index = current_expensive_arc_indices_.second;
1322 if (++second_index < most_expensive_arc_starts_and_ranks_.size()) {
1325 int& first_index = current_expensive_arc_indices_.first;
1326 if (first_index + 2 < most_expensive_arc_starts_and_ranks_.size()) {
1328 second_index = first_index + 1;
1339 bool FindMostExpensiveArcsOnRoute(
1340 int num_arcs, int64_t
start,
1341 const std::function<int64_t(int64_t)>& next_accessor,
1342 const std::function<
bool(int64_t)>& is_end,
1343 const std::function<int64_t(int64_t, int64_t, int64_t)>&
1344 arc_cost_for_route_start,
1345 std::vector<std::pair<int64_t, int>>* most_expensive_arc_starts_and_ranks,
1346 std::pair<int, int>* first_expensive_arc_indices) {
1347 if (is_end(next_accessor(
start))) {
1349 *first_expensive_arc_indices = {-1, -1};
1355 using ArcCostNegativeRankStart = std::tuple<int64_t, int, int64_t>;
1356 std::priority_queue<ArcCostNegativeRankStart,
1357 std::vector<ArcCostNegativeRankStart>,
1358 std::greater<ArcCostNegativeRankStart>>
1361 int64_t before_node =
start;
1363 while (!is_end(before_node)) {
1364 const int64_t after_node = next_accessor(before_node);
1365 const int64_t arc_cost =
1366 arc_cost_for_route_start(before_node, after_node,
start);
1367 arc_info_pq.emplace(arc_cost, -rank, before_node);
1369 before_node = after_node;
1372 if (rank > num_arcs) {
1378 DCHECK_EQ(arc_info_pq.size(),
std::min(rank, num_arcs));
1380 most_expensive_arc_starts_and_ranks->resize(arc_info_pq.size());
1381 int arc_index = arc_info_pq.size() - 1;
1382 while (!arc_info_pq.empty()) {
1383 const ArcCostNegativeRankStart& arc_info = arc_info_pq.top();
1384 (*most_expensive_arc_starts_and_ranks)[arc_index] = {
1385 std::get<2>(arc_info), -std::get<1>(arc_info)};
1390 *first_expensive_arc_indices = {0, 1};
1396 bool FilteredHeuristicExpensiveChainLNSOperator::
1397 FindMostExpensiveChainsOnRemainingRoutes() {
1399 if (FindMostExpensiveArcsOnRoute(
1400 num_arcs_to_consider_,
model_->
Start(current_route_),
1401 [
this](int64_t i) { return OldValue(i); },
1402 [
this](int64_t node) { return model_->IsEnd(node); },
1403 arc_cost_for_route_start_, &most_expensive_arc_starts_and_ranks_,
1404 ¤t_expensive_arc_indices_)) {
1407 }
while (IncrementRoute());
1413 const std::vector<IntVar*>& vars,
1414 const std::vector<IntVar*>& secondary_vars,
1415 std::function<
int(int64_t)> start_empty_path_class,
1416 int num_arcs_to_consider,
1417 std::function<int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start)
1419 std::move(start_empty_path_class)),
1420 num_arcs_to_consider_(num_arcs_to_consider),
1422 current_expensive_arc_indices_({-1, -1}),
1423 arc_cost_for_path_start_(std::move(arc_cost_for_path_start)),
1425 has_non_empty_paths_to_explore_(
false) {
1426 DCHECK_GE(num_arcs_to_consider_, 2);
1430 const int first_arc_index = current_expensive_arc_indices_.first;
1431 const int second_arc_index = current_expensive_arc_indices_.second;
1432 DCHECK_LE(0, first_arc_index);
1433 DCHECK_LT(first_arc_index, second_arc_index);
1434 DCHECK_LT(second_arc_index, most_expensive_arc_starts_and_ranks_.size());
1436 const std::pair<int, int>& first_start_and_rank =
1437 most_expensive_arc_starts_and_ranks_[first_arc_index];
1438 const std::pair<int, int>& second_start_and_rank =
1439 most_expensive_arc_starts_and_ranks_[second_arc_index];
1440 if (first_start_and_rank.second < second_start_and_rank.second) {
1442 second_start_and_rank.first,
BaseNode(0)) &&
1443 MoveChain(first_start_and_rank.first, second_start_and_rank.first,
1447 first_start_and_rank.first,
BaseNode(0)) &&
1448 MoveChain(second_start_and_rank.first, first_start_and_rank.first,
1453 while (has_non_empty_paths_to_explore_) {
1457 if (IncrementCurrentArcIndices()) {
1461 IncrementCurrentPath();
1462 has_non_empty_paths_to_explore_ =
1463 current_path_ != end_path_ &&
1464 FindMostExpensiveChainsOnRemainingPaths();
1472 void RelocateExpensiveChain::OnNodeInitialization() {
1478 end_path_ = current_path_;
1479 has_non_empty_paths_to_explore_ = FindMostExpensiveChainsOnRemainingPaths();
1482 void RelocateExpensiveChain::IncrementCurrentPath() {
1484 if (++current_path_ == num_paths) {
1489 bool RelocateExpensiveChain::IncrementCurrentArcIndices() {
1490 int& second_index = current_expensive_arc_indices_.second;
1491 if (++second_index < most_expensive_arc_starts_and_ranks_.size()) {
1494 int& first_index = current_expensive_arc_indices_.first;
1495 if (first_index + 2 < most_expensive_arc_starts_and_ranks_.size()) {
1497 second_index = first_index + 1;
1503 bool RelocateExpensiveChain::FindMostExpensiveChainsOnRemainingPaths() {
1505 if (FindMostExpensiveArcsOnRoute(
1506 num_arcs_to_consider_,
path_starts()[current_path_],
1507 [
this](int64_t i) {
return OldNext(i); },
1508 [
this](int64_t node) {
return IsPathEnd(node); },
1509 arc_cost_for_path_start_, &most_expensive_arc_starts_and_ranks_,
1510 ¤t_expensive_arc_indices_)) {
1513 IncrementCurrentPath();
1514 }
while (current_path_ != end_path_);
1519 const std::vector<IntVar*>& vars,
1520 const std::vector<IntVar*>& secondary_vars,
1521 std::function<
int(int64_t)> start_empty_path_class,
1525 std::move(start_empty_path_class)) {
1529 for (
int pair_index = 0; pair_index < pairs.size(); ++pair_index) {
1530 for (
const int node : pairs[pair_index].first) {
1531 is_pickup_node_[node] =
true;
1532 pair_of_node_[node] = pair_index;
1534 for (
const int node : pairs[pair_index].second) {
1535 is_delivery_node_[node] =
true;
1536 pair_of_node_[node] = pair_index;
1539 opened_pairs_bitset_.resize(pairs.size(),
false);
1542 bool RelocateSubtrip::RelocateSubTripFromPickup(
const int64_t chain_first_node,
1543 const int64_t insertion_node) {
1544 if (
IsPathEnd(insertion_node))
return false;
1545 if (
Prev(chain_first_node) == insertion_node)
1548 int num_opened_pairs = 0;
1550 rejected_nodes_ = {
Prev(chain_first_node)};
1551 subtrip_nodes_ = {insertion_node};
1552 int current = chain_first_node;
1554 if (current == insertion_node) {
1556 opened_pairs_bitset_.assign(opened_pairs_bitset_.size(),
false);
1559 const int pair = pair_of_node_[current];
1560 if (is_delivery_node_[current] && !opened_pairs_bitset_[pair]) {
1561 rejected_nodes_.push_back(current);
1563 subtrip_nodes_.push_back(current);
1564 if (is_pickup_node_[current]) {
1566 opened_pairs_bitset_[pair] =
true;
1567 }
else if (is_delivery_node_[current]) {
1569 opened_pairs_bitset_[pair] =
false;
1572 current =
Next(current);
1573 }
while (num_opened_pairs != 0 && !
IsPathEnd(current));
1574 DCHECK_EQ(num_opened_pairs, 0);
1575 rejected_nodes_.push_back(current);
1576 subtrip_nodes_.push_back(
Next(insertion_node));
1579 const int64_t rejected_path =
Path(chain_first_node);
1580 for (
int i = 1; i < rejected_nodes_.size(); ++i) {
1581 SetNext(rejected_nodes_[i - 1], rejected_nodes_[i], rejected_path);
1583 const int64_t insertion_path =
Path(insertion_node);
1584 for (
int i = 1; i < subtrip_nodes_.size(); ++i) {
1585 SetNext(subtrip_nodes_[i - 1], subtrip_nodes_[i], insertion_path);
1590 bool RelocateSubtrip::RelocateSubTripFromDelivery(
1591 const int64_t chain_last_node,
const int64_t insertion_node) {
1592 if (
IsPathEnd(insertion_node))
return false;
1595 DCHECK(std::none_of(opened_pairs_bitset_.begin(), opened_pairs_bitset_.end(),
1596 [](
bool value) { return value; }));
1597 int num_opened_pairs = 0;
1599 rejected_nodes_ = {
Next(chain_last_node)};
1600 subtrip_nodes_ = {
Next(insertion_node)};
1601 int current = chain_last_node;
1603 if (current == insertion_node) {
1604 opened_pairs_bitset_.assign(opened_pairs_bitset_.size(),
false);
1607 const int pair = pair_of_node_[current];
1608 if (is_pickup_node_[current] && !opened_pairs_bitset_[pair]) {
1609 rejected_nodes_.push_back(current);
1611 subtrip_nodes_.push_back(current);
1612 if (is_delivery_node_[current]) {
1614 opened_pairs_bitset_[pair] =
true;
1615 }
else if (is_pickup_node_[current]) {
1617 opened_pairs_bitset_[pair] =
false;
1620 current =
Prev(current);
1621 }
while (num_opened_pairs != 0 && !
IsPathStart(current));
1622 DCHECK_EQ(num_opened_pairs, 0);
1623 if (current == insertion_node)
return false;
1624 rejected_nodes_.push_back(current);
1625 subtrip_nodes_.push_back(insertion_node);
1629 std::reverse(rejected_nodes_.begin(), rejected_nodes_.end());
1630 std::reverse(subtrip_nodes_.begin(), subtrip_nodes_.end());
1633 const int64_t rejected_path =
Path(chain_last_node);
1634 for (
int i = 1; i < rejected_nodes_.size(); ++i) {
1635 SetNext(rejected_nodes_[i - 1], rejected_nodes_[i], rejected_path);
1637 const int64_t insertion_path =
Path(insertion_node);
1638 for (
int i = 1; i < subtrip_nodes_.size(); ++i) {
1639 SetNext(subtrip_nodes_[i - 1], subtrip_nodes_[i], insertion_path);
1645 if (is_pickup_node_[
BaseNode(0)]) {
1647 }
else if (is_delivery_node_[
BaseNode(0)]) {
1655 const std::vector<IntVar*>& vars,
1656 const std::vector<IntVar*>& secondary_vars,
1657 std::function<
int(int64_t)> start_empty_path_class,
1660 std::move(start_empty_path_class)) {
1664 for (
int pair_index = 0; pair_index < pairs.size(); ++pair_index) {
1665 for (
const int node : pairs[pair_index].first) {
1666 is_pickup_node_[node] =
true;
1667 pair_of_node_[node] = pair_index;
1669 for (
const int node : pairs[pair_index].second) {
1670 is_delivery_node_[node] =
true;
1671 pair_of_node_[node] = pair_index;
1674 opened_pairs_set_.resize(pairs.size(),
false);
1677 void ExchangeSubtrip::SetPath(
const std::vector<int64_t>& path,
int path_id) {
1678 for (
int i = 1; i < path.size(); ++i) {
1679 SetNext(path[i - 1], path[i], path_id);
1684 bool VectorContains(
const std::vector<int64_t>& values, int64_t target) {
1685 return std::find(values.begin(), values.end(), target) != values.end();
1690 if (pair_of_node_[
BaseNode(0)] == -1)
return false;
1691 if (pair_of_node_[
BaseNode(1)] == -1)
return false;
1697 if (!ExtractChainsAndCheckCanonical(
BaseNode(0), &rejects0_, &subtrip0_)) {
1702 if (!ExtractChainsAndCheckCanonical(
BaseNode(1), &rejects1_, &subtrip1_)) {
1708 if (VectorContains(rejects0_, subtrip1_.front()))
return false;
1709 if (VectorContains(rejects1_, subtrip0_.front()))
return false;
1710 if (VectorContains(subtrip0_, subtrip1_.front()))
return false;
1711 if (VectorContains(subtrip1_, subtrip0_.front()))
return false;
1715 path0_ = {
Prev(subtrip0_.front())};
1716 path1_ = {
Prev(subtrip1_.front())};
1717 const int64_t last0 =
Next(subtrip0_.back());
1718 const int64_t last1 =
Next(subtrip1_.back());
1719 const bool concatenated01 = last0 == subtrip1_.front();
1720 const bool concatenated10 = last1 == subtrip0_.front();
1723 path0_.insert(path0_.end(), subtrip1_.begin(), subtrip1_.end());
1724 path0_.insert(path0_.end(), rejects0_.begin(), rejects0_.end());
1725 path0_.push_back(last0);
1728 path1_.insert(path1_.end(), subtrip0_.begin(), subtrip0_.end());
1729 path1_.insert(path1_.end(), rejects1_.begin(), rejects1_.end());
1730 path1_.push_back(last1);
1733 if (concatenated01) {
1735 path1_.front() = path0_.back();
1736 }
else if (concatenated10) {
1738 path0_.front() = path1_.back();
1745 SetPath(path0_, path0_id);
1746 SetPath(path1_, path1_id);
1750 bool ExchangeSubtrip::ExtractChainsAndCheckCanonical(
1751 int64_t base_node, std::vector<int64_t>* rejects,
1752 std::vector<int64_t>* subtrip) {
1753 const bool extracted =
1754 is_pickup_node_[base_node]
1755 ? ExtractChainsFromPickup(base_node, rejects, subtrip)
1756 : ExtractChainsFromDelivery(base_node, rejects, subtrip);
1757 if (!extracted)
return false;
1759 return !is_delivery_node_[base_node] ||
1760 pair_of_node_[subtrip->front()] != pair_of_node_[subtrip->back()] ||
1764 bool ExchangeSubtrip::ExtractChainsFromPickup(int64_t base_node,
1765 std::vector<int64_t>* rejects,
1766 std::vector<int64_t>* subtrip) {
1767 DCHECK(is_pickup_node_[base_node]);
1768 DCHECK(rejects->empty());
1769 DCHECK(subtrip->empty());
1772 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1773 int num_opened_pairs = 0;
1774 int current = base_node;
1776 const int pair = pair_of_node_[current];
1777 if (is_delivery_node_[current] && !opened_pairs_set_[pair]) {
1778 rejects->push_back(current);
1780 subtrip->push_back(current);
1781 if (is_pickup_node_[current]) {
1783 opened_pairs_set_[pair] =
true;
1784 }
else if (is_delivery_node_[current]) {
1786 opened_pairs_set_[pair] =
false;
1789 current =
Next(current);
1790 }
while (num_opened_pairs != 0 && !
IsPathEnd(current));
1791 return num_opened_pairs == 0;
1794 bool ExchangeSubtrip::ExtractChainsFromDelivery(int64_t base_node,
1795 std::vector<int64_t>* rejects,
1796 std::vector<int64_t>* subtrip) {
1797 DCHECK(is_delivery_node_[base_node]);
1798 DCHECK(rejects->empty());
1799 DCHECK(subtrip->empty());
1802 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1803 int num_opened_pairs = 0;
1804 int current = base_node;
1806 const int pair = pair_of_node_[current];
1807 if (is_pickup_node_[current] && !opened_pairs_set_[pair]) {
1808 rejects->push_back(current);
1810 subtrip->push_back(current);
1811 if (is_delivery_node_[current]) {
1813 opened_pairs_set_[pair] =
true;
1814 }
else if (is_pickup_node_[current]) {
1816 opened_pairs_set_[pair] =
false;
1819 current =
Prev(current);
1820 }
while (num_opened_pairs != 0 && !
IsPathStart(current));
1821 if (num_opened_pairs != 0)
return false;
1822 std::reverse(rejects->begin(), rejects->end());
1823 std::reverse(subtrip->begin(), subtrip->end());
An Assignment is a variable -> domains mapping, used to report solutions to the user.
bool MakeNeighbor() override
ExchangeSubtrip(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &pairs)
FilteredHeuristicCloseNodesLNSOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic, int num_close_nodes)
FilteredHeuristicExpensiveChainLNSOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic, int num_arcs_to_consider, std::function< int64_t(int64_t, int64_t, int64_t)> arc_cost_for_route_start)
Class of operators using a RoutingFilteredHeuristic to insert unperformed nodes after changes have be...
FilteredHeuristicLocalSearchOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic, bool keep_inverse_values=false)
virtual std::function< int64_t(int64_t)> SetupNextAccessorForNeighbor()=0
Virtual method to return the next_accessor to be passed to the heuristic to build a new solution.
RoutingModel *const model_
virtual bool IncrementPosition()=0
SparseBitset removed_nodes_
Keeps track of removed nodes when making a neighbor.
FilteredHeuristicPathLNSOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic)
bool MakeNeighbor() override
GroupPairAndRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_pairs)
IndexPairSwapActiveOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_pairs)
bool MakeNeighbor() override
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
OnStart() should really be protected, but then SWIG doesn't see it.
Specialization of LocalSearchOperator built from an array of IntVars which specifies the scope of the...
void SetValue(int64_t index, int64_t value)
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
OnStart() should really be protected, but then SWIG doesn't see it.
void RevertChanges(bool change_was_incremental)
bool ApplyChanges(Assignment *delta, Assignment *deltadelta) const
int64_t OldValue(int64_t index) const
int64_t Value(int64_t index) const
Returns the value in the current assignment of the variable of given index.
IntVar * Var(int64_t index) const
Returns the variable of given index.
void AddVars(const std::vector< IntVar * > &vars)
bool MakeNeighbor() override
LightPairRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_pairs, std::function< bool(int64_t)> force_lifo=nullptr)
int64_t GetBaseNodeRestartPosition(int base_index) override
Returns the index of the node to which the base node of index base_index must be set to when it reach...
bool MakeNeighbor() override
MakePairActiveOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &pairs)
bool MakeOneNeighbor() override
This method should not be overridden. Override MakeNeighbor() instead.
MakePairInactiveOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_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, RoutingTransitCallback2 arc_evaluator)
bool MakeNeighbor() override
PairExchangeOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_pairs)
int64_t GetBaseNodeRestartPosition(int base_index) override
Returns the index of the node to which the base node of index base_index must be set to when it reach...
bool MakeNeighbor() override
PairExchangeRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_pairs)
bool OnSamePathAsPreviousBase(int64_t base_index) override
Returns true if a base node has to be on the same path as the "previous" base node (base node of inde...
int64_t GetBaseNodeRestartPosition(int base_index) override
Returns the index of the node to which the base node of index base_index must be set to when it reach...
bool MakeNeighbor() override
PairRelocateOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_pairs)
Base class of the local search operators dedicated to path modifications (a path is a set of nodes li...
int64_t StartNode(int i) const
Returns the start node of the ith base node.
bool IsInactive(int64_t node) const
Returns true if node is inactive.
virtual void OnNodeInitialization()
Called by OnStart() after initializing node information.
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
Returns true if the chain is a valid path without cycles from before_chain to chain_end and does not ...
bool IsPathEnd(int64_t node) const
Returns true if node is the last node on the path; defined by the fact that node is outside the range...
int64_t Next(int64_t node) const
Returns the node after node in the current delta.
bool MoveChain(int64_t before_chain, int64_t chain_end, int64_t destination)
Moves the chain starting after the node before_chain and ending at the node chain_end after the node ...
bool MakeActive(int64_t node, int64_t destination)
Insert the inactive node after destination.
const std::vector< int64_t > & path_starts() const
Returns the vector of path start nodes.
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 BaseSiblingAlternativeNode(int i) const
Returns the alternative node for the sibling of the ith base node.
int64_t Prev(int64_t node) const
Returns the node before node in the current delta.
int64_t GetActiveAlternativeSibling(int node) const
Returns the active node in the alternative set of the sibling of the given node.
int64_t OldNext(int64_t node) const
const int number_of_nexts_
bool SwapActiveAndInactive(int64_t active, int64_t inactive)
Replaces active by inactive in the current path, making active inactive.
void ResetPosition()
Reset the position of the operator to its position when Start() was last called; this can be used to ...
int64_t BaseNode(int i) const
Returns the ith base node of the operator.
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.
void AddPairAlternativeSets(const std::vector< std::pair< std::vector< int64_t >, std::vector< int64_t >>> &pair_alternative_sets)
Adds all sets of node alternatives of a vector of alternative pairs.
int64_t Path(int64_t node) const
Returns the index of the path to which node belongs in the current delta.
virtual void SetNextBaseToIncrement(int64_t base_index)
Set the next base to increment on next iteration.
bool MakeChainInactive(int64_t before_chain, int64_t chain_end)
Makes the nodes on the chain starting after before_chain and ending at chain_end inactive.
bool MakeNeighbor() override
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
RelocateSubtrip(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &pairs)
VehicleClassIndex GetVehicleClassIndexOfVehicle(int64_t vehicle) const
int GetVehicleClassesCount() const
Returns the number of different vehicle classes in the model.
bool IsStart(int64_t index) const
Returns true if 'index' represents the first node of a route.
IntVar * NextVar(int64_t index) const
!defined(SWIGPYTHON)
const std::vector< std::pair< int, int > > & GetDeliveryIndexPairs(int64_t node_index) const
Same as above for deliveries.
int64_t Size() const
Returns the number of next variables in the model.
bool CheckLimit(absl::Duration offset=absl::ZeroDuration())
Returns true if the search limit has been crossed with the given time offset.
const std::vector< IntVar * > & VehicleVars() const
Returns all vehicle variables of the model, such that VehicleVars(i) is the vehicle variable of the n...
int64_t Start(int vehicle) const
Model inspection.
int vehicles() const
Returns the number of vehicle routes in the model.
int64_t GetArcCostForClass(int64_t from_index, int64_t to_index, int64_t cost_class_index) const
Returns the cost of the segment between two nodes for a given cost class.
const std::vector< std::pair< int, int > > & GetPickupIndexPairs(int64_t node_index) const
Returns pairs for which the node is a pickup; the first element of each pair is the index in the pick...
bool IsEnd(int64_t index) const
Returns true if 'index' represents the last node of a route.
int GetCostClassesCount() const
Returns the number of different cost classes in the model.
int VehicleIndex(int64_t index) const
Returns the vehicle of the given start/end index, and -1 if the given index is not a vehicle start/en...
int64_t End(int vehicle) const
Returns the variable index of the ending node of a vehicle route.
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
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)
void OnStart() override
Called by Start() after synchronizing the operator with the current assignment.
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
OnStart() should really be protected, but then SWIG doesn't see it.
SwapIndexPairOperator(const std::vector< IntVar * > &vars, const std::vector< IntVar * > &path_vars, std::function< int(int64_t)> start_empty_path_class, const RoutingIndexPairs &index_pairs)
static const int64_t kint64max
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
std::function< int64_t(int64_t, int64_t)> RoutingTransitCallback2
std::vector< RoutingIndexPair > RoutingIndexPairs