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);
63bool 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);
83int64_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,
114 std::move(start_empty_path_class)),
116 inactive_pair_first_index_(0),
117 inactive_pair_second_index_(0),
121 while (inactive_pair_ < pairs_.size()) {
124 if (inactive_pair_first_index_ < pairs_[inactive_pair_].first.size() - 1) {
125 ++inactive_pair_first_index_;
126 }
else if (inactive_pair_second_index_ <
127 pairs_[inactive_pair_].second.size() - 1) {
128 inactive_pair_first_index_ = 0;
129 ++inactive_pair_second_index_;
131 inactive_pair_ = FindNextInactivePair(inactive_pair_ + 1);
132 inactive_pair_first_index_ = 0;
133 inactive_pair_second_index_ = 0;
146 return MakeActive(pairs_[inactive_pair_].second[inactive_pair_second_index_],
148 MakeActive(pairs_[inactive_pair_].first[inactive_pair_first_index_],
161void MakePairActiveOperator::OnNodeInitialization() {
162 inactive_pair_ = FindNextInactivePair(0);
163 inactive_pair_first_index_ = 0;
164 inactive_pair_second_index_ = 0;
167int MakePairActiveOperator::FindNextInactivePair(
int pair_index)
const {
169 if (!ContainsActiveNodes(pairs_[
index].first) &&
170 !ContainsActiveNodes(pairs_[
index].second)) {
174 return pairs_.size();
177bool MakePairActiveOperator::ContainsActiveNodes(
178 const std::vector<int64_t>&
nodes)
const {
179 for (int64_t node :
nodes) {
186 const std::vector<IntVar*>& vars,
187 const std::vector<IntVar*>& secondary_vars,
188 std::function<
int(int64_t)> start_empty_path_class,
191 std::move(start_empty_path_class)) {
197 const int64_t first_index =
Next(base);
199 if (second_index < 0) {
207 const std::vector<IntVar*>& vars,
208 const std::vector<IntVar*>& secondary_vars,
209 std::function<
int(int64_t)> start_empty_path_class,
212 std::move(start_empty_path_class)) {
218 const int64_t first_pair_node =
BaseNode(kPairFirstNode);
222 int64_t first_prev =
Prev(first_pair_node);
224 if (second_pair_node < 0 ||
IsPathEnd(second_pair_node) ||
228 const int64_t second_prev =
Prev(second_pair_node);
230 const int64_t first_node_destination =
BaseNode(kPairFirstNodeDestination);
231 if (first_node_destination == second_pair_node) {
236 const int64_t second_node_destination =
BaseNode(kPairSecondNodeDestination);
237 if (second_prev == first_pair_node && first_node_destination == first_prev &&
238 second_node_destination == first_prev) {
248 if (second_pair_node == second_node_destination ||
249 first_pair_node == first_node_destination) {
252 const bool moved_second_pair_node =
253 MoveChain(second_prev, second_pair_node, second_node_destination);
256 const bool moved_first_pair_node =
257 MoveChain(
Prev(first_pair_node), first_pair_node, first_node_destination);
262 return moved_first_pair_node || moved_second_pair_node;
268 if (base_index == kPairSecondNodeDestination) {
269 return BaseNode(kPairFirstNodeDestination);
276 const std::vector<IntVar*>& vars,
277 const std::vector<IntVar*>& secondary_vars,
278 std::function<
int(int64_t)> start_empty_path_class,
281 std::move(start_empty_path_class)) {
287 const int64_t node1 =
Next(prev1);
290 if (sibling1 == -1)
return false;
292 if (node2 == sibling1)
return false;
294 if (sibling2 == -1)
return false;
299 const bool ok =
MoveChain(prev1, node1, node2);
304 const std::vector<IntVar*>& vars,
305 const std::vector<IntVar*>& secondary_vars,
306 std::function<
int(int64_t)> start_empty_path_class,
309 std::move(start_empty_path_class)) {
315 int64_t prev1, sibling1, sibling_prev1 = -1;
316 if (!GetPreviousAndSibling(node1, &prev1, &sibling1, &sibling_prev1)) {
320 int64_t prev2, sibling2, sibling_prev2 = -1;
321 if (!GetPreviousAndSibling(node2, &prev2, &sibling2, &sibling_prev2)) {
326 if (node1 == prev2) {
328 if (sibling_prev1 == node2) sibling_prev1 = node1;
329 if (sibling_prev2 == node2) sibling_prev2 = node1;
330 }
else if (node2 == prev1) {
332 if (sibling_prev1 == node1) sibling_prev1 = node2;
333 if (sibling_prev2 == node1) sibling_prev2 = node2;
336 if (sibling_prev1 == node1) {
337 sibling_prev1 = node2;
338 }
else if (sibling_prev1 == node2) {
339 sibling_prev1 = node1;
341 if (sibling_prev2 == node1) {
342 sibling_prev2 = node2;
343 }
else if (sibling_prev2 == node2) {
344 sibling_prev2 = node1;
347 if (!
status)
return false;
349 if (sibling1 == sibling_prev2) {
351 }
else if (sibling2 == sibling_prev1) {
355 MoveChain(sibling_prev2, sibling2, sibling_prev1);
365bool PairExchangeOperator::GetPreviousAndSibling(
366 int64_t node, int64_t* previous, int64_t* sibling,
367 int64_t* sibling_previous)
const {
369 *previous =
Prev(node);
371 *sibling_previous = *sibling >= 0 ?
Prev(*sibling) : -1;
372 return *sibling_previous >= 0;
376 const std::vector<IntVar*>& vars,
377 const std::vector<IntVar*>& secondary_vars,
378 std::function<
int(int64_t)> start_empty_path_class,
381 std::move(start_empty_path_class)) {
387 StartNode(kSecondPairSecondNodeDestination));
389 StartNode(kFirstPairFirstNodeDestination));
391 StartNode(kFirstPairSecondNodeDestination));
409 if (!GetPreviousAndSibling(
nodes[0][0], &prev[0][0], &
nodes[0][1],
414 if (!GetPreviousAndSibling(
nodes[1][0], &prev[1][0], &
nodes[1][1],
420 if (!LoadAndCheckDest(0, 0, kFirstPairFirstNodeDestination,
nodes, dest)) {
424 if (!LoadAndCheckDest(0, 1, kFirstPairSecondNodeDestination,
nodes, dest)) {
428 if (
StartNode(kSecondPairFirstNodeDestination) !=
430 !LoadAndCheckDest(1, 0, kSecondPairFirstNodeDestination,
nodes, dest)) {
434 if (!LoadAndCheckDest(1, 1, kSecondPairSecondNodeDestination,
nodes, dest)) {
439 if (!MoveNode(0, 1,
nodes, dest, prev)) {
443 if (!MoveNode(0, 0,
nodes, dest, prev)) {
447 if (!MoveNode(1, 1,
nodes, dest, prev)) {
450 if (!MoveNode(1, 0,
nodes, dest, prev)) {
456bool PairExchangeRelocateOperator::MoveNode(
int pair,
int node,
459 int64_t prev[2][2]) {
460 if (!
MoveChain(prev[pair][node],
nodes[pair][node], dest[pair][node])) {
464 if (prev[1 - pair][0] == dest[pair][node]) {
465 prev[1 - pair][0] =
nodes[pair][node];
467 if (prev[1 - pair][1] == dest[pair][node]) {
468 prev[1 - pair][1] =
nodes[pair][node];
473bool PairExchangeRelocateOperator::LoadAndCheckDest(
int pair,
int node,
476 int64_t dest[2][2])
const {
477 dest[pair][node] =
BaseNode(base_node);
479 return !(
nodes[0][0] == dest[pair][node] ||
nodes[0][1] == dest[pair][node] ||
480 nodes[1][0] == dest[pair][node] ||
nodes[1][1] == dest[pair][node]);
484 int64_t base_index) {
488 return base_index == kFirstPairFirstNodeDestination ||
489 base_index == kFirstPairSecondNodeDestination ||
490 base_index == kSecondPairSecondNodeDestination;
495 if (base_index == kFirstPairSecondNodeDestination ||
496 base_index == kSecondPairSecondNodeDestination) {
503bool PairExchangeRelocateOperator::GetPreviousAndSibling(
504 int64_t node, int64_t* previous, int64_t* sibling,
505 int64_t* sibling_previous)
const {
507 *previous =
Prev(node);
509 *sibling_previous = *sibling >= 0 ?
Prev(*sibling) : -1;
510 return *sibling_previous >= 0;
514 const std::vector<IntVar*>& vars,
const std::vector<IntVar*>& path_vars,
515 std::function<
int(int64_t)> start_empty_path_class,
518 index_pairs_(index_pairs),
522 number_of_nexts_(vars.size()),
523 ignore_path_vars_(path_vars.empty()) {
524 if (!ignore_path_vars_) {
531 const int64_t kNoPath = -1;
536 if (pair_index_ < index_pairs_.size()) {
538 ignore_path_vars_ ? 0LL :
Value(first_active_ + number_of_nexts_);
539 const int64_t prev_first = prevs_[first_active_];
540 const int64_t next_first =
Value(first_active_);
542 SetNext(first_active_, first_active_, kNoPath);
544 const int64_t insert_first =
545 index_pairs_[pair_index_].first[first_index_];
546 SetNext(prev_first, insert_first, path);
547 SetNext(insert_first, next_first, path);
548 int64_t prev_second = prevs_[second_active_];
549 if (prev_second == first_active_) {
550 prev_second = insert_first;
554 :
Value(second_active_ + number_of_nexts_));
555 const int64_t next_second =
Value(second_active_);
557 SetNext(second_active_, second_active_, kNoPath);
559 const int64_t insert_second =
560 index_pairs_[pair_index_].second[second_index_];
561 SetNext(prev_second, insert_second, path);
562 SetNext(insert_second, next_second, path);
565 if (second_index_ >= index_pairs_[pair_index_].second.size()) {
568 if (first_index_ >= index_pairs_[pair_index_].first.size()) {
587 prevs_.resize(number_of_nexts_, -1);
590 if (
next >= prevs_.size()) prevs_.resize(
next + 1, -1);
599 if (!UpdateActiveNodes())
break;
600 if (first_active_ != -1 && second_active_ != -1) {
607bool SwapIndexPairOperator::UpdateActiveNodes() {
608 if (pair_index_ < index_pairs_.size()) {
609 for (
const int64_t first : index_pairs_[pair_index_].first) {
610 if (
Value(first) != first) {
611 first_active_ = first;
615 for (
const int64_t second : index_pairs_[pair_index_].second) {
616 if (
Value(second) != second) {
617 second_active_ = second;
627 const std::vector<IntVar*>& vars,
628 const std::vector<IntVar*>& secondary_vars,
629 std::function<
int(int64_t)> start_empty_path_class,
632 std::move(start_empty_path_class)),
639 while (inactive_node_ <
Size()) {
662void IndexPairSwapActiveOperator::OnNodeInitialization() {
664 for (
int i = 0; i <
Size(); ++i) {
670 inactive_node_ =
Size();
676 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
677 bool keep_inverse_values)
679 keep_inverse_values),
680 model_(heuristic->
model()),
681 removed_nodes_(model_->Size()),
682 heuristic_(
std::move(heuristic)),
683 consider_vehicle_vars_(!model_->CostsAreHomogeneousAcrossVehicles()) {
684 if (consider_vehicle_vars_) {
689bool FilteredHeuristicLocalSearchOperator::MakeOneNeighbor() {
700 if (MakeChangesAndInsertNodes()) {
707bool FilteredHeuristicLocalSearchOperator::MakeChangesAndInsertNodes() {
710 const std::function<int64_t(int64_t)> next_accessor =
712 if (next_accessor ==
nullptr) {
715 const Assignment*
const result_assignment =
716 heuristic_->BuildSolutionFromRoutes(next_accessor);
718 if (result_assignment ==
nullptr) {
722 bool has_change =
false;
723 const std::vector<IntVarElement>& elements =
724 result_assignment->IntVarContainer().elements();
730 const IntVarElement& node_element = elements[node_index];
733 const int64_t new_node_value = node_element.Value();
736 const int64_t vehicle_var_index = VehicleVarIndex(node_index);
737 if (
OldValue(node_index) != new_node_value ||
738 (consider_vehicle_vars_ &&
OldValue(vehicle_var_index) != vehicle)) {
740 SetValue(node_index, new_node_value);
741 if (consider_vehicle_vars_) {
742 SetValue(vehicle_var_index, vehicle);
745 node_index = new_node_value;
751 const IntVarElement& node_element = elements[node];
753 if (node_element.Value() == node) {
757 if (consider_vehicle_vars_) {
758 const int64_t vehicle_var_index = VehicleVarIndex(node);
770 std::unique_ptr<RoutingFilteredHeuristic> heuristic)
774 just_started_(false) {}
776void FilteredHeuristicPathLNSOperator::OnStart() {
779 last_route_ = current_route_;
780 if (CurrentRouteIsEmpty()) {
781 IncrementCurrentRouteToNextNonEmpty();
783 just_started_ =
true;
786bool FilteredHeuristicPathLNSOperator::IncrementPosition() {
788 just_started_ =
false;
789 return !CurrentRouteIsEmpty();
791 IncrementCurrentRouteToNextNonEmpty();
792 return current_route_ != last_route_;
795bool FilteredHeuristicPathLNSOperator::CurrentRouteIsEmpty()
const {
799void FilteredHeuristicPathLNSOperator::IncrementCurrentRouteToNextNonEmpty() {
802 ++current_route_ %= num_routes;
803 if (current_route_ == last_route_) {
807 }
while (CurrentRouteIsEmpty());
810std::function<int64_t(int64_t)>
811FilteredHeuristicPathLNSOperator::SetupNextAccessorForNeighbor() {
812 const int64_t start_node =
model_->
Start(current_route_);
813 const int64_t end_node =
model_->
End(current_route_);
815 int64_t node =
Value(start_node);
816 while (node != end_node) {
821 return [
this, start_node, end_node](int64_t node) {
822 if (node == start_node)
return end_node;
831 std::unique_ptr<RoutingFilteredHeuristic> heuristic)
833 route_to_relocate_index_(0),
834 empty_route_index_(0),
835 just_started_(false) {}
837void RelocatePathAndHeuristicInsertUnperformedOperator::OnStart() {
838 has_unperformed_nodes_ =
false;
840 routes_to_relocate_.clear();
841 empty_routes_.clear();
842 std::vector<bool> empty_vehicle_of_vehicle_class_added(
844 for (int64_t node = 0; node <
model_->
Size(); node++) {
847 has_unperformed_nodes_ =
true;
858 routes_to_relocate_.push_back(vehicle);
864 empty_routes_.push_back(vehicle);
869 if (empty_route_index_ >= empty_routes_.size()) {
870 empty_route_index_ = 0;
872 if (route_to_relocate_index_ >= routes_to_relocate_.size()) {
873 route_to_relocate_index_ = 0;
875 last_empty_route_index_ = empty_route_index_;
876 last_route_to_relocate_index_ = route_to_relocate_index_;
878 just_started_ =
true;
881bool RelocatePathAndHeuristicInsertUnperformedOperator::IncrementPosition() {
882 if (!has_unperformed_nodes_ || empty_routes_.empty() ||
883 routes_to_relocate_.empty()) {
887 just_started_ =
false;
890 return IncrementRoutes();
893bool RelocatePathAndHeuristicInsertUnperformedOperator::IncrementRoutes() {
894 ++empty_route_index_ %= empty_routes_.size();
895 if (empty_route_index_ != last_empty_route_index_) {
898 ++route_to_relocate_index_ %= routes_to_relocate_.size();
899 return route_to_relocate_index_ != last_route_to_relocate_index_;
902std::function<int64_t(int64_t)>
903RelocatePathAndHeuristicInsertUnperformedOperator::
904 SetupNextAccessorForNeighbor() {
905 const int empty_route = empty_routes_[empty_route_index_];
906 const int relocated_route = routes_to_relocate_[route_to_relocate_index_];
913 const int64_t empty_start_node =
model_->
Start(empty_route);
914 const int64_t empty_end_node =
model_->
End(empty_route);
916 const int64_t relocated_route_start =
model_->
Start(relocated_route);
917 const int64_t first_relocated_node =
OldValue(relocated_route_start);
918 const int64_t last_relocated_node = last_node_on_route_[relocated_route];
919 const int64_t relocated_route_end =
model_->
End(relocated_route);
921 return [
this, empty_start_node, empty_end_node, first_relocated_node,
922 last_relocated_node, relocated_route_start,
923 relocated_route_end](int64_t node) {
924 if (node == relocated_route_start)
return relocated_route_end;
925 if (node == empty_start_node)
return first_relocated_node;
926 if (node == last_relocated_node)
return empty_end_node;
934 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
int num_close_nodes)
937 pickup_delivery_pairs_(model_->GetPickupAndDeliveryPairs()),
940 close_nodes_(model_->Size()),
941 new_nexts_(model_->Size()),
942 changed_nexts_(model_->Size()),
943 new_prevs_(model_->Size()),
944 changed_prevs_(model_->Size()) {
946 const int64_t max_num_neighbors =
948 const int64_t num_closest_neighbors =
949 std::min<int64_t>(num_close_nodes, max_num_neighbors);
952 if (num_closest_neighbors == 0)
return;
956 for (int64_t node = 0; node < size; node++) {
959 std::vector<std::pair< double, int64_t>>
961 costed_after_nodes.reserve(size);
962 for (int64_t after_node = 0; after_node < size; after_node++) {
964 after_node == node) {
967 double total_cost = 0.0;
970 for (
int cost_class = 1; cost_class < num_cost_classes; cost_class++) {
973 costed_after_nodes.emplace_back(total_cost, after_node);
976 std::nth_element(costed_after_nodes.begin(),
977 costed_after_nodes.begin() + num_closest_neighbors - 1,
978 costed_after_nodes.end());
979 std::vector<int64_t>& neighbors = close_nodes_[node];
980 neighbors.reserve(num_closest_neighbors);
982 neighbors.push_back(costed_after_nodes[
index].second);
987void FilteredHeuristicCloseNodesLNSOperator::OnStart() {
988 last_node_ = current_node_;
989 just_started_ =
true;
992bool FilteredHeuristicCloseNodesLNSOperator::IncrementPosition() {
994 just_started_ =
false;
998 return current_node_ != last_node_;
1001void FilteredHeuristicCloseNodesLNSOperator::RemoveNode(int64_t node) {
1007 const int64_t prev = Prev(node);
1008 const int64_t
next = Next(node);
1009 changed_nexts_.
Set(prev);
1010 new_nexts_[prev] =
next;
1011 if (next < model_->
Size()) {
1013 new_prevs_[
next] = prev;
1017void FilteredHeuristicCloseNodesLNSOperator::RemoveNodeAndActiveSibling(
1019 if (!IsActive(node))
return;
1022 for (int64_t sibling_node : GetActiveSiblings(node)) {
1024 RemoveNode(sibling_node);
1029std::vector<int64_t> FilteredHeuristicCloseNodesLNSOperator::GetActiveSiblings(
1030 int64_t node)
const {
1034 std::vector<int64_t> active_siblings;
1035 for (std::pair<int64_t, int64_t> index_pair :
1037 for (int64_t sibling_delivery :
1038 pickup_delivery_pairs_[index_pair.first].second) {
1039 if (IsActive(sibling_delivery)) {
1040 active_siblings.push_back(sibling_delivery);
1045 for (std::pair<int64_t, int64_t> index_pair :
1047 for (int64_t sibling_pickup :
1048 pickup_delivery_pairs_[index_pair.first].first) {
1049 if (IsActive(sibling_pickup)) {
1050 active_siblings.push_back(sibling_pickup);
1055 return active_siblings;
1058std::function<int64_t(int64_t)>
1059FilteredHeuristicCloseNodesLNSOperator::SetupNextAccessorForNeighbor() {
1068 RemoveNodeAndActiveSibling(current_node_);
1070 for (int64_t neighbor : close_nodes_[current_node_]) {
1071 RemoveNodeAndActiveSibling(neighbor);
1074 return [
this](int64_t node) {
return Next(node); };
1081 std::unique_ptr<RoutingFilteredHeuristic> heuristic,
1082 int num_arcs_to_consider,
1083 std::function<int64_t(int64_t, int64_t, int64_t)>
1084 arc_cost_for_route_start)
1088 num_arcs_to_consider_(num_arcs_to_consider),
1089 current_expensive_arc_indices_({-1, -1}),
1090 arc_cost_for_route_start_(std::move(arc_cost_for_route_start)),
1091 just_started_(
false) {
1095void FilteredHeuristicExpensiveChainLNSOperator::OnStart() {
1096 last_route_ = current_route_;
1097 just_started_ =
true;
1100bool FilteredHeuristicExpensiveChainLNSOperator::IncrementPosition() {
1101 if (just_started_) {
1102 just_started_ =
false;
1103 return FindMostExpensiveChainsOnRemainingRoutes();
1106 if (IncrementCurrentArcIndices())
return true;
1108 return IncrementRoute() && FindMostExpensiveChainsOnRemainingRoutes();
1111std::function<int64_t(int64_t)>
1112FilteredHeuristicExpensiveChainLNSOperator::SetupNextAccessorForNeighbor() {
1113 const int first_arc_index = current_expensive_arc_indices_.first;
1114 const int second_arc_index = current_expensive_arc_indices_.second;
1116 DCHECK_LT(first_arc_index, second_arc_index);
1117 DCHECK_LT(second_arc_index, most_expensive_arc_starts_and_ranks_.size());
1119 const std::pair<int, int>& first_start_and_rank =
1120 most_expensive_arc_starts_and_ranks_[first_arc_index];
1121 const std::pair<int, int>& second_start_and_rank =
1122 most_expensive_arc_starts_and_ranks_[second_arc_index];
1123 int64_t before_chain, after_chain;
1124 if (first_start_and_rank.second < second_start_and_rank.second) {
1125 before_chain = first_start_and_rank.first;
1126 after_chain =
OldValue(second_start_and_rank.first);
1128 before_chain = second_start_and_rank.first;
1129 after_chain =
OldValue(first_start_and_rank.first);
1132 int node =
Value(before_chain);
1133 while (node != after_chain) {
1138 return [
this, before_chain, after_chain](int64_t node) {
1139 if (node == before_chain)
return after_chain;
1144bool FilteredHeuristicExpensiveChainLNSOperator::IncrementRoute() {
1146 return current_route_ != last_route_;
1149bool FilteredHeuristicExpensiveChainLNSOperator::IncrementCurrentArcIndices() {
1150 int& second_index = current_expensive_arc_indices_.second;
1151 if (++second_index < most_expensive_arc_starts_and_ranks_.size()) {
1154 int& first_index = current_expensive_arc_indices_.first;
1155 if (first_index + 2 < most_expensive_arc_starts_and_ranks_.size()) {
1157 second_index = first_index + 1;
1168bool FindMostExpensiveArcsOnRoute(
1169 int num_arcs, int64_t
start,
1170 const std::function<int64_t(int64_t)>& next_accessor,
1171 const std::function<
bool(int64_t)>& is_end,
1172 const std::function<int64_t(int64_t, int64_t, int64_t)>&
1173 arc_cost_for_route_start,
1174 std::vector<std::pair<int64_t, int>>* most_expensive_arc_starts_and_ranks,
1175 std::pair<int, int>* first_expensive_arc_indices) {
1176 if (is_end(next_accessor(
start))) {
1178 *first_expensive_arc_indices = {-1, -1};
1184 using ArcCostNegativeRankStart = std::tuple<int64_t, int, int64_t>;
1185 std::priority_queue<ArcCostNegativeRankStart,
1186 std::vector<ArcCostNegativeRankStart>,
1187 std::greater<ArcCostNegativeRankStart>>
1190 int64_t before_node =
start;
1192 while (!is_end(before_node)) {
1193 const int64_t after_node = next_accessor(before_node);
1194 const int64_t arc_cost =
1195 arc_cost_for_route_start(before_node, after_node,
start);
1196 arc_info_pq.emplace(arc_cost, -rank, before_node);
1198 before_node = after_node;
1201 if (rank > num_arcs) {
1209 most_expensive_arc_starts_and_ranks->resize(arc_info_pq.size());
1210 int arc_index = arc_info_pq.size() - 1;
1211 while (!arc_info_pq.empty()) {
1212 const ArcCostNegativeRankStart& arc_info = arc_info_pq.top();
1213 (*most_expensive_arc_starts_and_ranks)[arc_index] = {
1214 std::get<2>(arc_info), -std::get<1>(arc_info)};
1219 *first_expensive_arc_indices = {0, 1};
1225bool FilteredHeuristicExpensiveChainLNSOperator::
1226 FindMostExpensiveChainsOnRemainingRoutes() {
1228 if (FindMostExpensiveArcsOnRoute(
1229 num_arcs_to_consider_,
model_->
Start(current_route_),
1230 [
this](int64_t i) { return OldValue(i); },
1231 [
this](int64_t node) { return model_->IsEnd(node); },
1232 arc_cost_for_route_start_, &most_expensive_arc_starts_and_ranks_,
1233 ¤t_expensive_arc_indices_)) {
1236 }
while (IncrementRoute());
1242 const std::vector<IntVar*>& vars,
1243 const std::vector<IntVar*>& secondary_vars,
1244 std::function<
int(int64_t)> start_empty_path_class,
1245 int num_arcs_to_consider,
1246 std::function<int64_t(int64_t, int64_t, int64_t)> arc_cost_for_path_start)
1248 std::move(start_empty_path_class)),
1249 num_arcs_to_consider_(num_arcs_to_consider),
1251 current_expensive_arc_indices_({-1, -1}),
1252 arc_cost_for_path_start_(std::move(arc_cost_for_path_start)),
1254 has_non_empty_paths_to_explore_(
false) {
1259 const int first_arc_index = current_expensive_arc_indices_.first;
1260 const int second_arc_index = current_expensive_arc_indices_.second;
1262 DCHECK_LT(first_arc_index, second_arc_index);
1263 DCHECK_LT(second_arc_index, most_expensive_arc_starts_and_ranks_.size());
1265 const std::pair<int, int>& first_start_and_rank =
1266 most_expensive_arc_starts_and_ranks_[first_arc_index];
1267 const std::pair<int, int>& second_start_and_rank =
1268 most_expensive_arc_starts_and_ranks_[second_arc_index];
1269 if (first_start_and_rank.second < second_start_and_rank.second) {
1271 second_start_and_rank.first,
BaseNode(0)) &&
1272 MoveChain(first_start_and_rank.first, second_start_and_rank.first,
1276 first_start_and_rank.first,
BaseNode(0)) &&
1277 MoveChain(second_start_and_rank.first, first_start_and_rank.first,
1282 while (has_non_empty_paths_to_explore_) {
1286 if (IncrementCurrentArcIndices()) {
1290 IncrementCurrentPath();
1291 has_non_empty_paths_to_explore_ =
1292 current_path_ != end_path_ &&
1293 FindMostExpensiveChainsOnRemainingPaths();
1301void RelocateExpensiveChain::OnNodeInitialization() {
1307 end_path_ = current_path_;
1308 has_non_empty_paths_to_explore_ = FindMostExpensiveChainsOnRemainingPaths();
1311void RelocateExpensiveChain::IncrementCurrentPath() {
1313 if (++current_path_ == num_paths) {
1318bool RelocateExpensiveChain::IncrementCurrentArcIndices() {
1319 int& second_index = current_expensive_arc_indices_.second;
1320 if (++second_index < most_expensive_arc_starts_and_ranks_.size()) {
1323 int& first_index = current_expensive_arc_indices_.first;
1324 if (first_index + 2 < most_expensive_arc_starts_and_ranks_.size()) {
1326 second_index = first_index + 1;
1332bool RelocateExpensiveChain::FindMostExpensiveChainsOnRemainingPaths() {
1334 if (FindMostExpensiveArcsOnRoute(
1335 num_arcs_to_consider_,
path_starts()[current_path_],
1336 [
this](int64_t i) {
return OldNext(i); },
1337 [
this](int64_t node) {
return IsPathEnd(node); },
1338 arc_cost_for_path_start_, &most_expensive_arc_starts_and_ranks_,
1339 ¤t_expensive_arc_indices_)) {
1342 IncrementCurrentPath();
1343 }
while (current_path_ != end_path_);
1348 const std::vector<IntVar*>& vars,
1349 const std::vector<IntVar*>& secondary_vars,
1350 std::function<
int(int64_t)> start_empty_path_class,
1354 std::move(start_empty_path_class)) {
1358 for (
int pair_index = 0; pair_index < pairs.size(); ++pair_index) {
1359 for (
const int node : pairs[pair_index].first) {
1360 is_pickup_node_[node] =
true;
1361 pair_of_node_[node] = pair_index;
1363 for (
const int node : pairs[pair_index].second) {
1364 is_delivery_node_[node] =
true;
1365 pair_of_node_[node] = pair_index;
1368 opened_pairs_bitset_.resize(pairs.size(),
false);
1371bool RelocateSubtrip::RelocateSubTripFromPickup(
const int64_t chain_first_node,
1372 const int64_t insertion_node) {
1373 if (
IsPathEnd(insertion_node))
return false;
1374 if (
Prev(chain_first_node) == insertion_node)
1377 int num_opened_pairs = 0;
1379 rejected_nodes_ = {
Prev(chain_first_node)};
1380 subtrip_nodes_ = {insertion_node};
1381 int current = chain_first_node;
1383 if (current == insertion_node) {
1385 opened_pairs_bitset_.assign(opened_pairs_bitset_.size(),
false);
1388 const int pair = pair_of_node_[current];
1389 if (is_delivery_node_[current] && !opened_pairs_bitset_[pair]) {
1390 rejected_nodes_.push_back(current);
1392 subtrip_nodes_.push_back(current);
1393 if (is_pickup_node_[current]) {
1395 opened_pairs_bitset_[pair] =
true;
1396 }
else if (is_delivery_node_[current]) {
1398 opened_pairs_bitset_[pair] =
false;
1401 current =
Next(current);
1402 }
while (num_opened_pairs != 0 && !
IsPathEnd(current));
1404 rejected_nodes_.push_back(current);
1405 subtrip_nodes_.push_back(
Next(insertion_node));
1408 const int64_t rejected_path =
Path(chain_first_node);
1409 for (
int i = 1; i < rejected_nodes_.size(); ++i) {
1410 SetNext(rejected_nodes_[i - 1], rejected_nodes_[i], rejected_path);
1412 const int64_t insertion_path =
Path(insertion_node);
1413 for (
int i = 1; i < subtrip_nodes_.size(); ++i) {
1414 SetNext(subtrip_nodes_[i - 1], subtrip_nodes_[i], insertion_path);
1419bool RelocateSubtrip::RelocateSubTripFromDelivery(
1420 const int64_t chain_last_node,
const int64_t insertion_node) {
1421 if (
IsPathEnd(insertion_node))
return false;
1424 DCHECK(std::none_of(opened_pairs_bitset_.begin(), opened_pairs_bitset_.end(),
1425 [](
bool value) { return value; }));
1426 int num_opened_pairs = 0;
1428 rejected_nodes_ = {
Next(chain_last_node)};
1429 subtrip_nodes_ = {
Next(insertion_node)};
1430 int current = chain_last_node;
1432 if (current == insertion_node) {
1433 opened_pairs_bitset_.assign(opened_pairs_bitset_.size(),
false);
1436 const int pair = pair_of_node_[current];
1437 if (is_pickup_node_[current] && !opened_pairs_bitset_[pair]) {
1438 rejected_nodes_.push_back(current);
1440 subtrip_nodes_.push_back(current);
1441 if (is_delivery_node_[current]) {
1443 opened_pairs_bitset_[pair] =
true;
1444 }
else if (is_pickup_node_[current]) {
1446 opened_pairs_bitset_[pair] =
false;
1449 current =
Prev(current);
1450 }
while (num_opened_pairs != 0 && !
IsPathStart(current));
1452 if (current == insertion_node)
return false;
1453 rejected_nodes_.push_back(current);
1454 subtrip_nodes_.push_back(insertion_node);
1458 std::reverse(rejected_nodes_.begin(), rejected_nodes_.end());
1459 std::reverse(subtrip_nodes_.begin(), subtrip_nodes_.end());
1462 const int64_t rejected_path =
Path(chain_last_node);
1463 for (
int i = 1; i < rejected_nodes_.size(); ++i) {
1464 SetNext(rejected_nodes_[i - 1], rejected_nodes_[i], rejected_path);
1466 const int64_t insertion_path =
Path(insertion_node);
1467 for (
int i = 1; i < subtrip_nodes_.size(); ++i) {
1468 SetNext(subtrip_nodes_[i - 1], subtrip_nodes_[i], insertion_path);
1474 if (is_pickup_node_[
BaseNode(0)]) {
1476 }
else if (is_delivery_node_[
BaseNode(0)]) {
1484 const std::vector<IntVar*>& vars,
1485 const std::vector<IntVar*>& secondary_vars,
1486 std::function<
int(int64_t)> start_empty_path_class,
1489 std::move(start_empty_path_class)) {
1493 for (
int pair_index = 0; pair_index < pairs.size(); ++pair_index) {
1494 for (
const int node : pairs[pair_index].first) {
1495 is_pickup_node_[node] =
true;
1496 pair_of_node_[node] = pair_index;
1498 for (
const int node : pairs[pair_index].second) {
1499 is_delivery_node_[node] =
true;
1500 pair_of_node_[node] = pair_index;
1503 opened_pairs_set_.resize(pairs.size(),
false);
1506void ExchangeSubtrip::SetPath(
const std::vector<int64_t>& path,
int path_id) {
1507 for (
int i = 1; i < path.size(); ++i) {
1508 SetNext(path[i - 1], path[i], path_id);
1513bool VectorContains(
const std::vector<int64_t>& values, int64_t target) {
1514 return std::find(values.begin(), values.end(), target) != values.end();
1519 if (pair_of_node_[
BaseNode(0)] == -1)
return false;
1520 if (pair_of_node_[
BaseNode(1)] == -1)
return false;
1526 if (!ExtractChainsAndCheckCanonical(
BaseNode(0), &rejects0_, &subtrip0_)) {
1531 if (!ExtractChainsAndCheckCanonical(
BaseNode(1), &rejects1_, &subtrip1_)) {
1537 if (VectorContains(rejects0_, subtrip1_.front()))
return false;
1538 if (VectorContains(rejects1_, subtrip0_.front()))
return false;
1539 if (VectorContains(subtrip0_, subtrip1_.front()))
return false;
1540 if (VectorContains(subtrip1_, subtrip0_.front()))
return false;
1544 path0_ = {
Prev(subtrip0_.front())};
1545 path1_ = {
Prev(subtrip1_.front())};
1546 const int64_t last0 =
Next(subtrip0_.back());
1547 const int64_t last1 =
Next(subtrip1_.back());
1548 const bool concatenated01 = last0 == subtrip1_.front();
1549 const bool concatenated10 = last1 == subtrip0_.front();
1552 path0_.insert(path0_.end(), subtrip1_.begin(), subtrip1_.end());
1553 path0_.insert(path0_.end(), rejects0_.begin(), rejects0_.end());
1554 path0_.push_back(last0);
1557 path1_.insert(path1_.end(), subtrip0_.begin(), subtrip0_.end());
1558 path1_.insert(path1_.end(), rejects1_.begin(), rejects1_.end());
1559 path1_.push_back(last1);
1562 if (concatenated01) {
1564 path1_.front() = path0_.back();
1565 }
else if (concatenated10) {
1567 path0_.front() = path1_.back();
1574 SetPath(path0_, path0_id);
1575 SetPath(path1_, path1_id);
1579bool ExchangeSubtrip::ExtractChainsAndCheckCanonical(
1580 int64_t base_node, std::vector<int64_t>* rejects,
1581 std::vector<int64_t>* subtrip) {
1582 const bool extracted =
1583 is_pickup_node_[base_node]
1584 ? ExtractChainsFromPickup(base_node, rejects, subtrip)
1585 : ExtractChainsFromDelivery(base_node, rejects, subtrip);
1586 if (!extracted)
return false;
1588 return !is_delivery_node_[base_node] ||
1589 pair_of_node_[subtrip->front()] != pair_of_node_[subtrip->back()] ||
1593bool ExchangeSubtrip::ExtractChainsFromPickup(int64_t base_node,
1594 std::vector<int64_t>* rejects,
1595 std::vector<int64_t>* subtrip) {
1596 DCHECK(is_pickup_node_[base_node]);
1597 DCHECK(rejects->empty());
1598 DCHECK(subtrip->empty());
1601 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1602 int num_opened_pairs = 0;
1603 int current = base_node;
1605 const int pair = pair_of_node_[current];
1606 if (is_delivery_node_[current] && !opened_pairs_set_[pair]) {
1607 rejects->push_back(current);
1609 subtrip->push_back(current);
1610 if (is_pickup_node_[current]) {
1612 opened_pairs_set_[pair] =
true;
1613 }
else if (is_delivery_node_[current]) {
1615 opened_pairs_set_[pair] =
false;
1618 current =
Next(current);
1619 }
while (num_opened_pairs != 0 && !
IsPathEnd(current));
1620 return num_opened_pairs == 0;
1623bool ExchangeSubtrip::ExtractChainsFromDelivery(int64_t base_node,
1624 std::vector<int64_t>* rejects,
1625 std::vector<int64_t>* subtrip) {
1626 DCHECK(is_delivery_node_[base_node]);
1627 DCHECK(rejects->empty());
1628 DCHECK(subtrip->empty());
1631 opened_pairs_set_.assign(opened_pairs_set_.size(),
false);
1632 int num_opened_pairs = 0;
1633 int current = base_node;
1635 const int pair = pair_of_node_[current];
1636 if (is_pickup_node_[current] && !opened_pairs_set_[pair]) {
1637 rejects->push_back(current);
1639 subtrip->push_back(current);
1640 if (is_delivery_node_[current]) {
1642 opened_pairs_set_[pair] =
true;
1643 }
else if (is_pickup_node_[current]) {
1645 opened_pairs_set_[pair] =
false;
1648 current =
Prev(current);
1649 }
while (num_opened_pairs != 0 && !
IsPathStart(current));
1650 if (num_opened_pairs != 0)
return false;
1651 std::reverse(rejects->begin(), rejects->end());
1652 std::reverse(subtrip->begin(), subtrip->end());
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
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)
RoutingModel *const model_
virtual bool IncrementPosition()=0
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.
SparseBitset removed_nodes_
Keeps track of removed nodes when making a neighbor.
FilteredHeuristicPathLNSOperator(std::unique_ptr< RoutingFilteredHeuristic > heuristic)
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
Redefines MakeNextNeighbor to export a simpler interface.
Specialization of LocalSearchOperator built from an array of IntVars which specifies the scope of the...
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
Redefines MakeNextNeighbor to export a simpler interface.
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)
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 ...
const std::vector< int64_t > & path_starts() const
Returns the vector of path start nodes.
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.
void SetNext(int64_t from, int64_t to, int64_t path)
Sets 'to' to be the node after 'from' on the given path.
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 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.
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
const std::vector< IntVar * > & VehicleVars() const
Returns all vehicle variables of the model, such that VehicleVars(i) is the vehicle variable of the n...
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.
bool CheckLimit()
Returns true if the search limit has been crossed.
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.
IntVar * NextVar(int64_t index) const
!defined(SWIGPYTHON)
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.
void Set(IntegerType index)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void OnStart() override
Called by Start() after synchronizing the operator with the current assignment.
bool MakeNextNeighbor(Assignment *delta, Assignment *deltadelta) override
Redefines MakeNextNeighbor to export a simpler interface.
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)
std::string DebugString() const override
void RevertChanges(bool incremental)
void SetValue(int64_t index, const int64_t &value)
const int64_t & Value(int64_t index) const
Returns the value in the current assignment of the variable of given index.
const int64_t & OldValue(int64_t index) const
IntVar * Var(int64_t index) const
Returns the variable of given index.
bool ApplyChanges(Assignment *delta, Assignment *deltadelta) const
void AddVars(const std::vector< IntVar * > &vars)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Collection of objects used to extend the Constraint Solver library.
std::function< int64_t(int64_t, int64_t)> RoutingTransitCallback2
std::vector< RoutingIndexPair > RoutingIndexPairs