Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
routing_search.h
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_SEARCH_H_
15#define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_SEARCH_H_
16
17#include <sys/types.h>
18
19#include <algorithm>
20#include <cstddef>
21#include <cstdint>
22#include <deque>
23#include <functional>
24#include <initializer_list>
25#include <limits>
26#include <map>
27#include <memory>
28#include <optional>
29#include <queue>
30#include <set>
31#include <string>
32#include <tuple>
33#include <type_traits>
34#include <utility>
35#include <vector>
36
37#include "absl/container/flat_hash_set.h"
38#include "absl/container/inlined_vector.h"
39#include "absl/log/check.h"
40#include "absl/types/span.h"
45#include "ortools/constraint_solver/routing_enums.pb.h"
46#include "ortools/constraint_solver/routing_parameters.pb.h"
49#include "ortools/util/bitset.h"
50
51namespace operations_research {
52
53// Solves a routing model using alternative models. This assumes that the models
54// are equivalent in the sense that a solution to one model is also a solution
55// to the other models. This is true for models that differ only by their arc
56// costs or objective for instance.
57// The primary model is the main model, to which the returned solution will
58// correspond.
59// The method solves the primary model and alternative models alternatively.
60// It works as follows (all solves use 'parameters'):
61// 1) solve the primary model with a greedy descent,
62// 2) let 'alt' be the first alternative model,
63// 3) solve 'alt' starting from the solution to the primary model with a greedy
64// descent,
65// 4) solve the primary model from the solution to 'alt' with a greedy descent,
66// 5) if the new solution improves the best solution found so far, update it,
67// otherwise increase the iteration counter,
68// 6) if the iteration counter is less than 'max_non_improving_iterations', let
69// 'alt' be the next "round-robin" alternative model, and go to step 3,
70// 7) if 'parameters' specified a metaheuristic, solve the primary model using
71// that metaheuristic starting from the best solution found so far,
72// 8) return the best solution found.
73// Note that if the time limit is reached at any stage, the search is
74// interrupted and the best solution found will be returned immediately.
75// TODO(user): Add a version taking search parameters for alternative models.
77 RoutingModel* primary_model,
78 const std::vector<RoutingModel*>& alternative_models,
79 const RoutingSearchParameters& parameters,
80 int max_non_improving_iterations);
81// Same as above, but taking an initial solution.
83 const Assignment* assignment, RoutingModel* primary_model,
84 const std::vector<RoutingModel*>& alternative_models,
85 const RoutingSearchParameters& parameters,
86 int max_non_improving_iterations);
87// Same as above but taking alternative parameters for each alternative model.
89 const Assignment* assignment, RoutingModel* primary_model,
90 const RoutingSearchParameters& parameters,
91 const std::vector<RoutingModel*>& alternative_models,
92 const std::vector<RoutingSearchParameters>& alternative_parameters,
93 int max_non_improving_iterations);
94
96#ifndef SWIG
101 public:
103 const RoutingModel::VehicleTypeContainer& vehicle_type_container)
104 : vehicle_type_container_(&vehicle_type_container) {}
105
106 int NumTypes() const { return vehicle_type_container_->NumTypes(); }
107
108 int Type(int vehicle) const { return vehicle_type_container_->Type(vehicle); }
109
112 void Reset(const std::function<bool(int)>& store_vehicle);
113
116 void Update(const std::function<bool(int)>& remove_vehicle);
117
119 DCHECK_LT(type, NumTypes());
120 const std::set<VehicleClassEntry>& vehicle_classes =
121 sorted_vehicle_classes_per_type_[type];
122 if (vehicle_classes.empty()) {
123 return -1;
124 }
125 const int vehicle_class = (vehicle_classes.begin())->vehicle_class;
126 DCHECK(!vehicles_per_vehicle_class_[vehicle_class].empty());
127 return vehicles_per_vehicle_class_[vehicle_class][0];
128 }
129
130 void ReinjectVehicleOfClass(int vehicle, int vehicle_class,
131 int64_t fixed_cost) {
132 std::vector<int>& vehicles = vehicles_per_vehicle_class_[vehicle_class];
133 if (vehicles.empty()) {
136 std::set<VehicleClassEntry>& vehicle_classes =
137 sorted_vehicle_classes_per_type_[Type(vehicle)];
138 const auto& insertion =
139 vehicle_classes.insert({vehicle_class, fixed_cost});
140 DCHECK(insertion.second);
141 }
142 vehicles.push_back(vehicle);
143 }
144
148 int type, const std::function<bool(int)>& vehicle_is_compatible) const;
157 std::pair<int, int> GetCompatibleVehicleOfType(
158 int type, const std::function<bool(int)>& vehicle_is_compatible,
159 const std::function<bool(int)>& stop_and_return_vehicle);
160
161 private:
162 using VehicleClassEntry =
163 RoutingModel::VehicleTypeContainer::VehicleClassEntry;
164 const RoutingModel::VehicleTypeContainer* const vehicle_type_container_;
165 // clang-format off
166 std::vector<std::set<VehicleClassEntry> > sorted_vehicle_classes_per_type_;
167 std::vector<std::vector<int> > vehicles_per_vehicle_class_;
168 // clang-format on
169};
170
173operations_research::FirstSolutionStrategy::Value
174AutomaticFirstSolutionStrategy(bool has_pickup_deliveries,
175 bool has_node_precedences,
176 bool has_single_vehicle_node);
177
180std::vector<int64_t> ComputeVehicleEndChainStarts(const RoutingModel& model);
181
194
196// TODO(user): Eventually move this to the core CP solver library
199 public:
201 std::unique_ptr<IntVarFilteredHeuristic> heuristic);
202
203 ~IntVarFilteredDecisionBuilder() override = default;
204
205 Decision* Next(Solver* solver) override;
206
207 std::string DebugString() const override;
208
210 int64_t number_of_decisions() const;
211 int64_t number_of_rejects() const;
212
213 private:
214 const std::unique_ptr<IntVarFilteredHeuristic> heuristic_;
215};
216
219 public:
220 IntVarFilteredHeuristic(Solver* solver, const std::vector<IntVar*>& vars,
221 const std::vector<IntVar*>& secondary_vars,
222 LocalSearchFilterManager* filter_manager);
223
224 virtual ~IntVarFilteredHeuristic() = default;
225
229
232 int64_t number_of_decisions() const { return number_of_decisions_; }
233 int64_t number_of_rejects() const { return number_of_rejects_; }
234
235 virtual std::string DebugString() const { return "IntVarFilteredHeuristic"; }
236
237 protected:
239 void ResetSolution();
241 virtual void Initialize() {}
243 virtual bool InitializeSolution() { return true; }
245 virtual bool BuildSolutionInternal() = 0;
253 std::optional<int64_t> Evaluate(bool commit, bool ignore_upper_bound = false,
254 bool update_upper_bound = true);
256 virtual bool StopSearch() { return false; }
259 void SetValue(int64_t index, int64_t value) {
260 DCHECK_LT(index, is_in_delta_.size());
261 if (!is_in_delta_[index]) {
262 delta_->FastAdd(vars_[index])->SetValue(value);
263 delta_indices_.push_back(index);
264 is_in_delta_[index] = true;
265 } else {
266 delta_->SetValue(vars_[index], value);
267 }
268 }
269
270 const std::vector<int>& delta_indices() const { return delta_indices_; }
273 int64_t Value(int64_t index) const {
274 return assignment_->IntVarContainer().Element(index).Value();
275 }
276
277 bool Contains(int64_t index) const {
278 return assignment_->IntVarContainer().Element(index).Var() != nullptr;
279 }
280
281 IntVar* Var(int64_t index) const { return vars_[index]; }
283 int64_t SecondaryVarIndex(int64_t index) const {
284 DCHECK(HasSecondaryVars());
285 return index + base_vars_size_;
286 }
287
288 bool HasSecondaryVars() const { return base_vars_size_ != vars_.size(); }
290 bool IsSecondaryVar(int64_t index) const { return index >= base_vars_size_; }
292 void SynchronizeFilters();
293
295
296 private:
299 bool FilterAccept(bool ignore_upper_bound);
300
301 Solver* solver_;
302 std::vector<IntVar*> vars_;
303 const int base_vars_size_;
304 Assignment* const delta_;
305 std::vector<int> delta_indices_;
306 std::vector<bool> is_in_delta_;
307 Assignment* const empty_;
308 LocalSearchFilterManager* filter_manager_;
309 int64_t objective_upper_bound_;
311 int64_t number_of_decisions_;
312 int64_t number_of_rejects_;
313};
314
317 public:
318 RoutingFilteredHeuristic(RoutingModel* model,
319 std::function<bool()> stop_search,
320 LocalSearchFilterManager* filter_manager);
321 ~RoutingFilteredHeuristic() override = default;
324 const std::function<int64_t(int64_t)>& next_accessor);
325 RoutingModel* model() const { return model_; }
327 int GetStartChainEnd(int vehicle) const { return start_chain_ends_[vehicle]; }
329 int GetEndChainStart(int vehicle) const { return end_chain_starts_[vehicle]; }
332 void MakeDisjunctionNodesUnperformed(int64_t node);
342
343 protected:
344 bool StopSearch() override { return stop_search_(); }
345 virtual void SetVehicleIndex(int64_t /*node*/, int /*vehicle*/) {}
346 virtual void ResetVehicleIndices() {}
347 bool VehicleIsEmpty(int vehicle) const {
348 return Value(model()->Start(vehicle)) == model()->End(vehicle);
349 }
350 void SetNext(int64_t node, int64_t next, int vehicle) {
351 SetValue(node, next);
352 if (HasSecondaryVars()) SetValue(SecondaryVarIndex(node), vehicle);
353 }
354
355 private:
357 bool InitializeSolution() override;
358
359 RoutingModel* const model_;
360 std::function<bool()> stop_search_;
361 std::vector<int64_t> start_chain_ends_;
362 std::vector<int64_t> end_chain_starts_;
363};
364
366 public:
369 RoutingModel* model, std::function<bool()> stop_search,
370 std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
371 std::function<int64_t(int64_t)> penalty_evaluator,
372 LocalSearchFilterManager* filter_manager);
374
375 protected:
380 int64_t value;
381
382 bool operator<(const NodeInsertion& other) const {
383 return std::tie(neg_hint_weight, value, insert_after, vehicle) <
384 std::tie(other.neg_hint_weight, other.value, other.insert_after,
385 other.vehicle);
386 }
387 };
389 int64_t distance;
391
392 bool operator<(const StartEndValue& other) const {
393 return std::tie(distance, vehicle) <
394 std::tie(other.distance, other.vehicle);
395 }
396 };
397 struct Seed {
398 absl::InlinedVector<int64_t, 8> properties;
402 bool is_node_index = true;
403 int index;
404
405 bool operator>(const Seed& other) const {
406 for (size_t i = 0; i < properties.size(); ++i) {
407 if (properties[i] == other.properties[i]) continue;
408 return properties[i] > other.properties[i];
409 }
410 return std::tie(vehicle, is_node_index, index) >
411 std::tie(other.vehicle, other.is_node_index, other.index);
412 }
413 };
414 // clang-format off
415 struct SeedQueue {
418
421 std::priority_queue<Seed, std::vector<Seed>, std::greater<Seed> >
426 };
427
433 std::vector<std::vector<StartEndValue> >
434 ComputeStartEndDistanceForVehicles(absl::Span<const int> vehicles);
435
440 std::vector<std::vector<StartEndValue> >* start_end_distances_per_node,
441 SeedQueue* sq);
442 // clang-format on
443
446 void AddSeedNodeToQueue(int node,
447 std::vector<StartEndValue>* start_end_distances,
448 SeedQueue* sq);
449
455 void InsertBetween(int64_t node, int64_t predecessor, int64_t successor,
456 int vehicle = -1);
462 int64_t node_to_insert, int64_t start, int64_t next_after_start,
463 int vehicle, bool ignore_cost,
464 std::vector<NodeInsertion>* node_insertions);
469 // TODO(user): Replace 'insert_before' and 'insert_after' by 'predecessor'
470 // and 'successor' in the code.
471 int64_t GetInsertionCostForNodeAtPosition(int64_t node_to_insert,
472 int64_t insert_after,
473 int64_t insert_before,
474 int vehicle) const;
477 int64_t GetUnperformedValue(int64_t node_to_insert) const;
478
479 bool HasHintedNext(int node) const {
480 CHECK_LT(node, hint_next_values_.size());
481 return hint_next_values_[node] != -1;
482 }
483 bool HasHintedPrev(int node) const {
484 CHECK_LT(node, hint_prev_values_.size());
485 return hint_prev_values_[node] != -1;
486 }
487 bool IsHint(int node, int64_t next) const {
488 return node < hint_next_values_.size() && hint_next_values_[node] == next;
489 }
490
491 std::function<int64_t(int64_t, int64_t, int64_t)> evaluator_;
492 std::function<int64_t(int64_t)> penalty_evaluator_;
493 std::vector<int> hint_next_values_;
494 std::vector<int> hint_prev_values_;
495};
496
506 public:
530
533 RoutingModel* model, std::function<bool()> stop_search,
534 std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
535 std::function<int64_t(int64_t)> penalty_evaluator,
536 LocalSearchFilterManager* filter_manager,
539 bool BuildSolutionInternal() override;
540 std::string DebugString() const override {
541 return "GlobalCheapestInsertionFilteredHeuristic";
542 }
543
544 private:
546 class NodeEntryQueue;
547
549 class PairEntry {
550 public:
551 PairEntry(int pickup_to_insert, int pickup_insert_after,
552 int delivery_to_insert, int delivery_insert_after, int vehicle,
553 int64_t bucket)
554 : value_(std::numeric_limits<int64_t>::max()),
555 heap_index_(-1),
556 pickup_to_insert_(pickup_to_insert),
557 pickup_insert_after_(pickup_insert_after),
558 delivery_to_insert_(delivery_to_insert),
559 delivery_insert_after_(delivery_insert_after),
560 vehicle_(vehicle),
561 bucket_(bucket) {}
562 // Note: for compatibility reasons, comparator follows tie-breaking rules
563 // used in the first version of GlobalCheapestInsertion.
564 bool operator<(const PairEntry& other) const {
565 // We give higher priority to insertions from lower buckets.
566 if (bucket_ != other.bucket_) {
567 return bucket_ > other.bucket_;
568 }
569 // We then compare by value, then we favor insertions (vehicle != -1).
570 // The rest of the tie-breaking is done with std::tie.
571 if (value_ != other.value_) {
572 return value_ > other.value_;
573 }
574 if ((vehicle_ == -1) ^ (other.vehicle_ == -1)) {
575 return vehicle_ == -1;
576 }
577 return std::tie(pickup_insert_after_, pickup_to_insert_,
578 delivery_insert_after_, delivery_to_insert_, vehicle_) >
579 std::tie(other.pickup_insert_after_, other.pickup_to_insert_,
580 other.delivery_insert_after_, other.delivery_to_insert_,
581 other.vehicle_);
582 }
583 void SetHeapIndex(int h) { heap_index_ = h; }
584 int GetHeapIndex() const { return heap_index_; }
585 void set_value(int64_t value) { value_ = value; }
586 int pickup_to_insert() const { return pickup_to_insert_; }
587 int pickup_insert_after() const { return pickup_insert_after_; }
588 void set_pickup_insert_after(int pickup_insert_after) {
589 pickup_insert_after_ = pickup_insert_after;
590 }
591 int delivery_to_insert() const { return delivery_to_insert_; }
592 int delivery_insert_after() const { return delivery_insert_after_; }
593 int vehicle() const { return vehicle_; }
594 void set_vehicle(int vehicle) { vehicle_ = vehicle; }
595
596 private:
597 int64_t value_;
598 int heap_index_;
599 int pickup_to_insert_;
600 int pickup_insert_after_;
601 int delivery_to_insert_;
602 int delivery_insert_after_;
603 int vehicle_;
604 int64_t bucket_;
605 };
606
607 typedef absl::flat_hash_set<PairEntry*> PairEntries;
608
610 template <typename T>
611 class EntryAllocator {
612 public:
613 EntryAllocator() = default;
614 void Clear() {
615 entries_.clear();
616 free_entries_.clear();
617 }
618 template <typename... Args>
619 T* NewEntry(const Args&... args) {
620 if (!free_entries_.empty()) {
621 auto* entry = free_entries_.back();
622 free_entries_.pop_back();
623 *entry = T(args...);
624 return entry;
625 } else {
626 entries_.emplace_back(args...);
627 return &entries_.back();
628 }
629 }
630 void FreeEntry(T* entry) { free_entries_.push_back(entry); }
631
632 private:
634 std::deque<T> entries_;
635 std::vector<T*> free_entries_;
636 };
637
644 bool InsertPairsAndNodesByRequirementTopologicalOrder();
645
652 bool InsertPairs(
653 const std::map<int64_t, std::vector<int>>& pair_indices_by_bucket);
654
658 bool UseEmptyVehicleTypeCuratorForVehicle(int vehicle,
659 bool all_vehicles = true) {
660 return vehicle >= 0 && VehicleIsEmpty(vehicle) && all_vehicles;
661 }
662
669 bool InsertPairEntryUsingEmptyVehicleTypeCurator(
670 const absl::flat_hash_set<int>& pair_indices, PairEntry* pair_entry,
671 AdjustablePriorityQueue<PairEntry>* priority_queue,
672 std::vector<PairEntries>* pickup_to_entries,
673 std::vector<PairEntries>* delivery_to_entries);
674
682 bool InsertNodesOnRoutes(
683 const std::map<int64_t, std::vector<int>>& nodes_by_bucket,
684 const absl::flat_hash_set<int>& vehicles);
685
693 bool InsertNodeEntryUsingEmptyVehicleTypeCurator(
694 const SparseBitset<int>& nodes, bool all_vehicles, NodeEntryQueue* queue);
695
701 bool SequentialInsertNodes(
702 const std::map<int64_t, std::vector<int>>& nodes_by_bucket);
703
707 void DetectUsedVehicles(std::vector<bool>* is_vehicle_used,
708 std::vector<int>* unused_vehicles,
709 absl::flat_hash_set<int>* used_vehicles);
710
713 bool IsCheapestClassRepresentative(int vehicle) const;
714
718 void InsertFarthestNodesAsSeeds();
719
728 int InsertSeedNode(
729 std::vector<std::vector<StartEndValue>>* start_end_distances_per_node,
730 SeedQueue* sq, std::vector<bool>* is_vehicle_used);
731 // clang-format on
732
735 bool InitializePairPositions(
736 const absl::flat_hash_set<int>& pair_indices,
737 AdjustablePriorityQueue<PairEntry>* priority_queue,
738 std::vector<PairEntries>* pickup_to_entries,
739 std::vector<PairEntries>* delivery_to_entries);
745 void InitializeInsertionEntriesPerformingPair(
746 int64_t pickup, int64_t delivery,
747 AdjustablePriorityQueue<PairEntry>* priority_queue,
748 std::vector<PairEntries>* pickup_to_entries,
749 std::vector<PairEntries>* delivery_to_entries);
753 bool UpdateAfterPairInsertion(
754 const absl::flat_hash_set<int>& pair_indices, int vehicle, int64_t pickup,
755 int64_t pickup_position, int64_t delivery, int64_t delivery_position,
756 AdjustablePriorityQueue<PairEntry>* priority_queue,
757 std::vector<PairEntries>* pickup_to_entries,
758 std::vector<PairEntries>* delivery_to_entries);
762 bool UpdateExistingPairEntriesOnChain(
763 int64_t insert_after_start, int64_t insert_after_end,
764 AdjustablePriorityQueue<PairEntry>* priority_queue,
765 std::vector<PairEntries>* pickup_to_entries,
766 std::vector<PairEntries>* delivery_to_entries);
772 bool AddPairEntriesAfter(const absl::flat_hash_set<int>& pair_indices,
773 int vehicle, int64_t insert_after,
774 int64_t skip_entries_inserting_delivery_after,
775 AdjustablePriorityQueue<PairEntry>* priority_queue,
776 std::vector<PairEntries>* pickup_to_entries,
777 std::vector<PairEntries>* delivery_to_entries) {
778 return AddPairEntriesWithDeliveryAfter(pair_indices, vehicle, insert_after,
779 priority_queue, pickup_to_entries,
780 delivery_to_entries) &&
781 AddPairEntriesWithPickupAfter(pair_indices, vehicle, insert_after,
782 skip_entries_inserting_delivery_after,
783 priority_queue, pickup_to_entries,
784 delivery_to_entries);
785 }
792 bool AddPairEntriesWithPickupAfter(
793 const absl::flat_hash_set<int>& pair_indices, int vehicle,
794 int64_t insert_after, int64_t skip_entries_inserting_delivery_after,
795 AdjustablePriorityQueue<PairEntry>* priority_queue,
796 std::vector<PairEntries>* pickup_to_entries,
797 std::vector<PairEntries>* delivery_to_entries);
801 bool AddPairEntriesWithDeliveryAfter(
802 const absl::flat_hash_set<int>& pair_indices, int vehicle,
803 int64_t insert_after, AdjustablePriorityQueue<PairEntry>* priority_queue,
804 std::vector<PairEntries>* pickup_to_entries,
805 std::vector<PairEntries>* delivery_to_entries);
808 void DeletePairEntry(PairEntry* entry,
809 AdjustablePriorityQueue<PairEntry>* priority_queue,
810 std::vector<PairEntries>* pickup_to_entries,
811 std::vector<PairEntries>* delivery_to_entries);
816 void AddPairEntry(int64_t pickup, int64_t pickup_insert_after,
817 int64_t delivery, int64_t delivery_insert_after,
818 int vehicle,
819 AdjustablePriorityQueue<PairEntry>* priority_queue,
820 std::vector<PairEntries>* pickup_entries,
821 std::vector<PairEntries>* delivery_entries) const;
824 void UpdatePairEntry(
825 PairEntry* pair_entry,
826 AdjustablePriorityQueue<PairEntry>* priority_queue) const;
830 int64_t GetInsertionValueForPairAtPositions(int64_t pickup,
831 int64_t pickup_insert_after,
832 int64_t delivery,
833 int64_t delivery_insert_after,
834 int vehicle) const;
835
838 bool InitializePositions(const SparseBitset<int>& nodes,
839 const absl::flat_hash_set<int>& vehicles,
840 NodeEntryQueue* queue);
846 void InitializeInsertionEntriesPerformingNode(
847 int64_t node, const absl::flat_hash_set<int>& vehicles,
848 NodeEntryQueue* queue);
851 bool UpdateAfterNodeInsertion(const SparseBitset<int>& nodes, int vehicle,
852 int64_t node, int64_t insert_after,
853 bool all_vehicles, NodeEntryQueue* queue);
857 bool UpdateExistingNodeEntriesOnChain(const SparseBitset<int>& nodes,
858 int vehicle, int64_t insert_after_start,
859 int64_t insert_after_end,
860 bool all_vehicles,
861 NodeEntryQueue* queue);
864 bool AddNodeEntriesAfter(const SparseBitset<int>& nodes, int vehicle,
865 int64_t insert_after, bool all_vehicles,
866 NodeEntryQueue* queue);
867
871 void AddNodeEntry(int64_t node, int64_t insert_after, int vehicle,
872 bool all_vehicles, NodeEntryQueue* queue) const;
873
874 void ResetVehicleIndices() override {
875 node_index_to_vehicle_.assign(node_index_to_vehicle_.size(), -1);
876 }
877
878 void SetVehicleIndex(int64_t node, int vehicle) override {
879 DCHECK_LT(node, node_index_to_vehicle_.size());
880 node_index_to_vehicle_[node] = vehicle;
881 }
882
885 bool CheckVehicleIndices() const;
886
888 int64_t GetBucketOfNode(int node) const {
889 return model()->VehicleVar(node)->Size();
890 }
891
893 int64_t GetBucketOfPair(const PickupDeliveryPair& pair) const {
894 int64_t max_pickup_bucket = 0;
895 for (int64_t pickup : pair.pickup_alternatives) {
896 max_pickup_bucket = std::max(max_pickup_bucket, GetBucketOfNode(pickup));
897 }
898 int64_t max_delivery_bucket = 0;
899 for (int64_t delivery : pair.delivery_alternatives) {
900 max_delivery_bucket =
901 std::max(max_delivery_bucket, GetBucketOfNode(delivery));
902 }
903 return std::min(max_pickup_bucket, max_delivery_bucket);
904 }
905
908 template <typename T>
909 bool StopSearchAndCleanup(AdjustablePriorityQueue<T>* priority_queue) {
910 if (!StopSearch()) return false;
911 if constexpr (std::is_same_v<T, PairEntry>) {
912 pair_entry_allocator_.Clear();
913 }
914 priority_queue->Clear();
915 return true;
916 }
917
920 std::vector<int> node_index_to_vehicle_;
921
922 const RoutingModel::NodeNeighborsByCostClass*
923 node_index_to_neighbors_by_cost_class_;
924
925 std::unique_ptr<VehicleTypeCurator> empty_vehicle_type_curator_;
926
927 mutable EntryAllocator<PairEntry> pair_entry_allocator_;
928};
929
930// Holds sequences of insertions.
931// A sequence of insertions must be in the same path, each insertion must
932// take place either after the previously inserted node or further down the
933// path, never before.
935 private:
936 // InsertionSequenceContainer holds all insertion sequences in the same vector
937 // contiguously, each insertion sequence is defined by a pair of bounds.
938 // Using Insertion* directly to delimit bounds would cause out-of-memory reads
939 // when the underlying vector<Insertion> is extended and reallocated,
940 // so this stores integer bounds in InsertionBounds to delimit sequences,
941 // and InsertionSequenceIterator translates those bounds to
942 // Insertion*-based ranges (InsertionSequence) on-the-fly when iterating over
943 // all sequences.
944 struct InsertionBounds {
945 size_t begin;
946 size_t end;
947 int vehicle;
948 int neg_hint_weight;
949 int64_t cost;
950 bool operator<(const InsertionBounds& other) const {
951 return std::tie(neg_hint_weight, cost, vehicle, begin) <
952 std::tie(other.neg_hint_weight, other.cost, other.vehicle,
953 other.begin);
954 }
955 size_t Size() const { return end - begin; }
956 };
957
958 public:
959 struct Insertion {
960 int pred;
961 int node;
962 bool operator==(const Insertion& other) const {
963 return pred == other.pred && node == other.node;
964 }
965 };
966
967 // Represents an insertion sequence as passed to AddInsertionSequence.
968 // This only allows to modify the cost, as a means to reorder sequences.
970 public:
971 InsertionSequence(Insertion* data, InsertionBounds* bounds)
972 : data_(data), bounds_(bounds) {}
973
974 bool operator!=(const InsertionSequence& other) const {
975 DCHECK_NE(data_, other.data_);
976 return bounds_ != other.bounds_;
977 }
978
979 const Insertion* begin() const { return data_ + bounds_->begin; }
980 const Insertion* end() const { return data_ + bounds_->end; }
981 size_t Size() const { return bounds_->Size(); }
982 int Vehicle() const { return bounds_->vehicle; }
983 int64_t Cost() const { return bounds_->cost; }
984 int64_t& Cost() { return bounds_->cost; }
985 void SetHintWeight(int hint_weight) {
986 bounds_->neg_hint_weight = -hint_weight;
987 }
988 int NegHintWeight() const { return bounds_->neg_hint_weight; }
989
990 private:
991 const Insertion* const data_;
992 InsertionBounds* const bounds_;
993 };
995 public:
996 InsertionSequenceIterator(Insertion* data, InsertionBounds* bounds)
997 : data_(data), bounds_(bounds) {}
998 bool operator!=(const InsertionSequenceIterator& other) const {
999 DCHECK_EQ(data_, other.data_);
1000 return bounds_ != other.bounds_;
1001 }
1003 ++bounds_;
1004 return *this;
1005 }
1006 InsertionSequence operator*() const { return {data_, bounds_}; }
1007
1008 private:
1009 Insertion* data_;
1010 InsertionBounds* bounds_;
1011 };
1012
1013 // InsertionSequenceContainer is a range over insertion sequences.
1015 return {insertions_.data(), insertion_bounds_.data()};
1016 }
1018 return {insertions_.data(),
1019 insertion_bounds_.data() + insertion_bounds_.size()};
1020 }
1021 // Returns the number of sequences of this container.
1022 size_t Size() const { return insertion_bounds_.size(); }
1023
1024 // Adds an insertion sequence to the container.
1025 // Passing an initializer_list allows deeper optimizations by the compiler
1026 // for cases where the sequence has a compile-time fixed size.
1028 int vehicle, std::initializer_list<Insertion> insertion_sequence) {
1029 insertion_bounds_.push_back(
1030 {.begin = insertions_.size(),
1031 .end = insertions_.size() + insertion_sequence.size(),
1032 .vehicle = vehicle,
1033 .cost = 0});
1034 insertions_.insert(insertions_.end(), insertion_sequence.begin(),
1035 insertion_sequence.end());
1036 }
1037
1038 // Adds an insertion sequence to the container.
1039 void AddInsertionSequence(int vehicle,
1040 absl::Span<const Insertion> insertion_sequence) {
1041 insertion_bounds_.push_back(
1042 {.begin = insertions_.size(),
1043 .end = insertions_.size() + insertion_sequence.size(),
1044 .vehicle = vehicle,
1045 .cost = 0});
1046 insertions_.insert(insertions_.end(), insertion_sequence.begin(),
1047 insertion_sequence.end());
1048 }
1049
1050 // Similar to std::remove_if(), removes all sequences that match a predicate.
1051 // This keeps original order, and removes selected sequences.
1052 void RemoveIf(const std::function<bool(const InsertionSequence&)>& p) {
1053 size_t from = 0;
1054 size_t to = 0;
1055 for (const InsertionSequence& sequence : *this) {
1056 // TODO(user): Benchmark this against std::swap().
1057 if (!p(sequence)) insertion_bounds_[to++] = insertion_bounds_[from];
1058 ++from;
1059 }
1060 insertion_bounds_.resize(to);
1061 }
1062
1063 // Sorts sequences according to (cost, vehicle).
1064 // TODO(user): benchmark this against other ways to get insertion
1065 // sequence in order, for instance sorting by index, separating {cost, index},
1066 // making a heap.
1067 void Sort() { std::sort(insertion_bounds_.begin(), insertion_bounds_.end()); }
1068
1069 // Removes all sequences.
1070 void Clear() {
1071 insertions_.clear();
1072 insertion_bounds_.clear();
1073 }
1074
1075 private:
1076 std::vector<Insertion> insertions_;
1077 std::vector<InsertionBounds> insertion_bounds_;
1078};
1079
1080// Generates insertion positions respecting structural constraints.
1082 public:
1084
1103 int pickup, int delivery, int vehicle, const std::vector<int>& path,
1104 const std::vector<bool>& path_node_is_pickup,
1105 const std::vector<bool>& path_node_is_delivery,
1106 InsertionSequenceContainer& insertions);
1107
1108 private:
1109 // Information[i] describes the insertion between path[i] and path[i+1].
1110 std::vector<int> next_decrease_; // next position after a delivery.
1111 std::vector<int> next_increase_; // next position after a pickup.
1112 std::vector<int> prev_decrease_; // previous position after delivery.
1113 std::vector<int> prev_increase_; // previous position after pickup.
1114};
1115
1120 int64_t value;
1122
1123 bool operator<(const PickupDeliveryInsertion& other) const {
1124 return std::tie(neg_hint_weight, value, insert_pickup_after,
1126 std::tie(other.neg_hint_weight, other.value,
1128 other.vehicle);
1129 }
1130};
1131
1139 public:
1142 RoutingModel* model, std::function<bool()> stop_search,
1143 std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
1144 RoutingSearchParameters::PairInsertionStrategy pair_insertion_strategy,
1145 std::vector<RoutingSearchParameters::InsertionSortingProperty>
1146 insertion_sorting_properties,
1147 LocalSearchFilterManager* filter_manager, bool use_first_solution_hint,
1148 BinCapacities* bin_capacities = nullptr,
1149 std::function<bool(const std::vector<RoutingModel::VariableValuePair>&,
1150 std::vector<RoutingModel::VariableValuePair>*)>
1151 optimize_on_insertion = nullptr);
1153 bool BuildSolutionInternal() override;
1154 std::string DebugString() const override {
1155 return "LocalCheapestInsertionFilteredHeuristic";
1156 }
1157
1158 protected:
1159 void Initialize() override;
1160
1161 private:
1165 void ComputeInsertionOrder();
1169 std::vector<NodeInsertion> ComputeEvaluatorSortedPositions(int64_t node);
1174 std::vector<NodeInsertion> ComputeEvaluatorSortedPositionsOnRouteAfter(
1175 int64_t node, int64_t start, int64_t next_after_start, int vehicle);
1176
1180 std::vector<PickupDeliveryInsertion> ComputeEvaluatorSortedPairPositions(
1181 int pickup, int delivery);
1182
1183 // Tries to insert any alternative of the given pair,
1184 // ordered by cost of pickup insertion, then by cost of delivery insertion.
1185 void InsertBestPickupThenDelivery(const PickupDeliveryPair& pair);
1186 // Tries to insert any alternative of the given pair,
1187 // ordered by the sum of pickup and delivery insertion.
1188 void InsertBestPair(const PickupDeliveryPair& pair);
1189 // Tries to insert any alternative of the given pair,
1190 // at a position that preserves the multitour property,
1191 // ordered by the sum of pickup and delivery insertion.
1192 void InsertBestPairMultitour(const PickupDeliveryPair& pair);
1193 // Tries to insert a pair at the given location. Returns true iff inserted.
1194 bool InsertPair(int64_t pickup, int64_t insert_pickup_after, int64_t delivery,
1195 int64_t insert_delivery_after, int vehicle);
1196
1197 // Runs an internal optimization. Returns true if the solution was changed.
1198 bool OptimizeOnInsertion(std::vector<int> delta_indices);
1199
1200 // Returns true if bin capacities should be updated.
1201 // TODO(user): Allow updating bin capacities when we do internal
1202 // optimizations.
1203 bool MustUpdateBinCapacities() const {
1204 return bin_capacities_ != nullptr && optimize_on_insertion_ == nullptr;
1205 }
1206
1207 std::vector<Seed> insertion_order_;
1208 const RoutingSearchParameters::PairInsertionStrategy pair_insertion_strategy_;
1209 std::vector<RoutingSearchParameters::InsertionSortingProperty>
1210 insertion_sorting_properties_;
1211 InsertionSequenceContainer insertion_container_;
1212 InsertionSequenceGenerator insertion_generator_;
1213
1214 const bool use_first_solution_hint_;
1215
1216 BinCapacities* const bin_capacities_;
1217
1218 std::function<bool(const std::vector<RoutingModel::VariableValuePair>&,
1219 std::vector<RoutingModel::VariableValuePair>*)>
1220 optimize_on_insertion_;
1221 bool synchronize_insertion_optimizer_ = true;
1222};
1223
1227 public:
1229 std::function<bool()> stop_search,
1230 LocalSearchFilterManager* filter_manager);
1232 bool BuildSolutionInternal() override;
1233
1234 private:
1235 class PartialRoutesAndLargeVehicleIndicesFirst {
1236 public:
1237 explicit PartialRoutesAndLargeVehicleIndicesFirst(
1238 const CheapestAdditionFilteredHeuristic& builder)
1239 : builder_(builder) {}
1240 bool operator()(int vehicle1, int vehicle2) const;
1241
1242 private:
1243 const CheapestAdditionFilteredHeuristic& builder_;
1244 };
1246 template <typename Iterator>
1247 std::vector<int64_t> GetPossibleNextsFromIterator(int64_t node,
1248 Iterator start,
1249 Iterator end) const {
1250 const int size = model()->Size();
1251 std::vector<int64_t> nexts;
1252 for (Iterator it = start; it != end; ++it) {
1253 const int64_t next = *it;
1254 if (next != node && (next >= size || !Contains(next))) {
1255 nexts.push_back(next);
1256 }
1257 }
1258 return nexts;
1259 }
1261 virtual void SortSuccessors(int64_t node,
1262 std::vector<int64_t>* successors) = 0;
1263 virtual int64_t FindTopSuccessor(int64_t node,
1264 const std::vector<int64_t>& successors) = 0;
1265};
1266
1271 public:
1274 RoutingModel* model, std::function<bool()> stop_search,
1275 std::function<int64_t(int64_t, int64_t)> evaluator,
1276 LocalSearchFilterManager* filter_manager);
1278 std::string DebugString() const override {
1279 return "EvaluatorCheapestAdditionFilteredHeuristic";
1280 }
1281
1282 private:
1284 void SortSuccessors(int64_t node, std::vector<int64_t>* successors) override;
1285 int64_t FindTopSuccessor(int64_t node,
1286 const std::vector<int64_t>& successors) override;
1287
1288 std::function<int64_t(int64_t, int64_t)> evaluator_;
1289};
1290
1295 public:
1298 RoutingModel* model, std::function<bool()> stop_search,
1300 LocalSearchFilterManager* filter_manager);
1302 std::string DebugString() const override {
1303 return "ComparatorCheapestAdditionFilteredHeuristic";
1304 }
1305
1306 private:
1308 void SortSuccessors(int64_t node, std::vector<int64_t>* successors) override;
1309 int64_t FindTopSuccessor(int64_t node,
1310 const std::vector<int64_t>& successors) override;
1311
1313};
1314
1324 public:
1328 double neighbors_ratio = 1.0;
1334 bool add_reverse_arcs = false;
1337 double arc_coefficient = 1.0;
1338 };
1339
1340 SavingsFilteredHeuristic(RoutingModel* model,
1341 std::function<bool()> stop_search,
1342 SavingsParameters parameters,
1343 LocalSearchFilterManager* filter_manager);
1345 bool BuildSolutionInternal() override;
1346
1347 protected:
1348 struct Saving {
1349 int64_t saving;
1350 unsigned int vehicle_type : 20;
1351 unsigned int before_node : 22;
1352 unsigned int after_node : 22;
1353 bool operator<(const Saving& other) const {
1354 return std::tie(saving, vehicle_type, before_node, after_node) <
1355 std::tie(other.saving, other.vehicle_type, other.before_node,
1356 other.after_node);
1357 }
1358 };
1359
1360 template <typename S>
1361 class SavingsContainer;
1362
1363 virtual double ExtraSavingsMemoryMultiplicativeFactor() const = 0;
1364
1365 virtual void BuildRoutesFromSavings() = 0;
1366
1376 int StartNewRouteWithBestVehicleOfType(int type, int64_t before_node,
1377 int64_t after_node);
1378
1379 // clang-format off
1380 std::unique_ptr<SavingsContainer<Saving> > savings_container_;
1381 // clang-format on
1382 std::unique_ptr<VehicleTypeCurator> vehicle_type_curator_;
1383
1384 private:
1389 // clang-format off
1390 void AddSymmetricArcsToAdjacencyLists(
1391 std::vector<std::vector<int64_t> >* adjacency_lists);
1392 // clang-format on
1393
1402 bool ComputeSavings();
1404 Saving BuildSaving(int64_t saving, int vehicle_type, int before_node,
1405 int after_node) const {
1406 return {saving, static_cast<unsigned int>(vehicle_type),
1407 static_cast<unsigned int>(before_node),
1408 static_cast<unsigned int>(after_node)};
1409 }
1410
1414 int64_t MaxNumNeighborsPerNode(int num_vehicle_types) const;
1415
1416 const SavingsParameters savings_params_;
1417
1419};
1420
1422 public:
1424 std::function<bool()> stop_search,
1425 SavingsParameters parameters,
1426 LocalSearchFilterManager* filter_manager)
1427 : SavingsFilteredHeuristic(model, std::move(stop_search), parameters,
1428 filter_manager) {}
1430 std::string DebugString() const override {
1431 return "SequentialSavingsFilteredHeuristic";
1432 }
1433
1434 private:
1439 void BuildRoutesFromSavings() override;
1440 double ExtraSavingsMemoryMultiplicativeFactor() const override { return 1.0; }
1441};
1442
1444 public:
1446 std::function<bool()> stop_search,
1447 SavingsParameters parameters,
1448 LocalSearchFilterManager* filter_manager)
1449 : SavingsFilteredHeuristic(model, std::move(stop_search), parameters,
1450 filter_manager) {}
1452 std::string DebugString() const override {
1453 return "ParallelSavingsFilteredHeuristic";
1454 }
1455
1456 private:
1467 void BuildRoutesFromSavings() override;
1468
1469 double ExtraSavingsMemoryMultiplicativeFactor() const override { return 2.0; }
1470
1475 void MergeRoutes(int first_vehicle, int second_vehicle, int64_t before_node,
1476 int64_t after_node);
1477
1479 std::vector<int64_t> first_node_on_route_;
1480 std::vector<int64_t> last_node_on_route_;
1484 std::vector<int> vehicle_of_first_or_last_node_;
1485};
1486
1490
1492 public:
1494 std::function<bool()> stop_search,
1495 LocalSearchFilterManager* filter_manager,
1496 bool use_minimum_matching);
1498 bool BuildSolutionInternal() override;
1499 std::string DebugString() const override {
1500 return "ChristofidesFilteredHeuristic";
1501 }
1502
1503 private:
1504 const bool use_minimum_matching_;
1505};
1506
1510 public:
1511 explicit SweepArranger(absl::Span<const std::pair<int64_t, int64_t>> points);
1512
1513 // This type is neither copyable nor movable.
1516
1517 virtual ~SweepArranger() = default;
1518 void ArrangeIndices(std::vector<int64_t>* indices);
1519 void SetSectors(int sectors) { sectors_ = sectors; }
1520
1521 private:
1522 std::vector<int> coordinates_;
1523 int sectors_;
1524};
1525#endif // SWIG
1526
1527// Returns a DecisionBuilder building a first solution based on the Sweep
1528// heuristic. Mostly suitable when cost is proportional to distance.
1529DecisionBuilder* MakeSweepDecisionBuilder(RoutingModel* model,
1530 bool check_assignment);
1531
1532// Returns a DecisionBuilder making all nodes unperformed.
1533DecisionBuilder* MakeAllUnperformed(RoutingModel* model);
1534
1535} // namespace operations_research
1536
1537#endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_SEARCH_H_
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
CheapestAdditionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, LocalSearchFilterManager *filter_manager)
CheapestAdditionFilteredHeuristic.
int64_t GetInsertionCostForNodeAtPosition(int64_t node_to_insert, int64_t insert_after, int64_t insert_before, int vehicle) const
std::function< int64_t(int64_t, int64_t, int64_t)> evaluator_
std::vector< std::vector< StartEndValue > > ComputeStartEndDistanceForVehicles(absl::Span< const int > vehicles)
void InitializeSeedQueue(std::vector< std::vector< StartEndValue > > *start_end_distances_per_node, SeedQueue *sq)
CheapestInsertionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, std::function< int64_t(int64_t, int64_t, int64_t)> evaluator, std::function< int64_t(int64_t)> penalty_evaluator, LocalSearchFilterManager *filter_manager)
Takes ownership of evaluator.
void AppendInsertionPositionsAfter(int64_t node_to_insert, int64_t start, int64_t next_after_start, int vehicle, bool ignore_cost, std::vector< NodeInsertion > *node_insertions)
int64_t GetUnperformedValue(int64_t node_to_insert) const
void InsertBetween(int64_t node, int64_t predecessor, int64_t successor, int vehicle=-1)
void AddSeedNodeToQueue(int node, std::vector< StartEndValue > *start_end_distances, SeedQueue *sq)
clang-format on
ChristofidesFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, LocalSearchFilterManager *filter_manager, bool use_minimum_matching)
ChristofidesFilteredHeuristic.
ComparatorCheapestAdditionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, Solver::VariableValueComparator comparator, LocalSearchFilterManager *filter_manager)
Takes ownership of evaluator.
EvaluatorCheapestAdditionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, std::function< int64_t(int64_t, int64_t)> evaluator, LocalSearchFilterManager *filter_manager)
Takes ownership of evaluator.
GlobalCheapestInsertionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, std::function< int64_t(int64_t, int64_t, int64_t)> evaluator, std::function< int64_t(int64_t)> penalty_evaluator, LocalSearchFilterManager *filter_manager, GlobalCheapestInsertionParameters parameters)
Takes ownership of evaluators.
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
bool operator!=(const InsertionSequenceIterator &other) const
InsertionSequence(Insertion *data, InsertionBounds *bounds)
void RemoveIf(const std::function< bool(const InsertionSequence &)> &p)
void AddInsertionSequence(int vehicle, std::initializer_list< Insertion > insertion_sequence)
InsertionSequenceIterator begin()
InsertionSequenceContainer is a range over insertion sequences.
size_t Size() const
Returns the number of sequences of this container.
void AddInsertionSequence(int vehicle, absl::Span< const Insertion > insertion_sequence)
Adds an insertion sequence to the container.
void AppendPickupDeliveryMultitourInsertions(int pickup, int delivery, int vehicle, const std::vector< int > &path, const std::vector< bool > &path_node_is_pickup, const std::vector< bool > &path_node_is_delivery, InsertionSequenceContainer &insertions)
int64_t number_of_decisions() const
Returns statistics from its underlying heuristic.
std::string DebugString() const override
-------— Decision Builder -------—
IntVarFilteredDecisionBuilder(std::unique_ptr< IntVarFilteredHeuristic > heuristic)
— First solution decision builder —
Generic filter-based heuristic applied to IntVars.
bool HasSecondaryVars() const
Returns true if there are secondary variables.
void ResetSolution()
Resets the data members for a new solution.
IntVarFilteredHeuristic(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, LocalSearchFilterManager *filter_manager)
— First solution heuristics —
virtual bool BuildSolutionInternal()=0
Virtual method to redefine how to build a solution.
bool Contains(int64_t index) const
Returns true if the variable of index 'index' is in the current solution.
virtual bool StopSearch()
Returns true if the search must be stopped.
virtual void Initialize()
Initialize the heuristic; called before starting to build a new solution.
int64_t SecondaryVarIndex(int64_t index) const
Returns the index of a secondary var.
void SetValue(int64_t index, int64_t value)
virtual bool InitializeSolution()
Virtual method to initialize the solution.
const std::vector< int > & delta_indices() const
Returns the indices of the nodes currently in the insertion delta.
IntVar * Var(int64_t index) const
Returns the variable of index 'index'.
void SynchronizeFilters()
Synchronizes filters with an assignment (the current solution).
std::optional< int64_t > Evaluate(bool commit, bool ignore_upper_bound=false, bool update_upper_bound=true)
bool IsSecondaryVar(int64_t index) const
Returns true if 'index' is a secondary variable index.
void Initialize() override
Initialize the heuristic; called before starting to build a new solution.
LocalCheapestInsertionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, std::function< int64_t(int64_t, int64_t, int64_t)> evaluator, RoutingSearchParameters::PairInsertionStrategy pair_insertion_strategy, std::vector< RoutingSearchParameters::InsertionSortingProperty > insertion_sorting_properties, LocalSearchFilterManager *filter_manager, bool use_first_solution_hint, BinCapacities *bin_capacities=nullptr, std::function< bool(const std::vector< RoutingModel::VariableValuePair > &, std::vector< RoutingModel::VariableValuePair > *)> optimize_on_insertion=nullptr)
Takes ownership of evaluator.
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
ParallelSavingsFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, SavingsParameters parameters, LocalSearchFilterManager *filter_manager)
int GetEndChainStart(int vehicle) const
Returns the start of the end chain of vehicle,.
Assignment * BuildSolutionFromRoutes(const std::function< int64_t(int64_t)> &next_accessor)
Builds a solution starting from the routes formed by the next accessor.
void SetNext(int64_t node, int64_t next, int vehicle)
bool MakeUnassignedNodesUnperformed()
Make all unassigned nodes unperformed, always returns true.
RoutingFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, LocalSearchFilterManager *filter_manager)
RoutingFilteredHeuristic.
int GetStartChainEnd(int vehicle) const
Returns the end of the start chain of vehicle,.
bool StopSearch() override
Returns true if the search must be stopped.
void AddUnassignedNodesToEmptyVehicles()
Adds all unassigned nodes to empty vehicles.
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
SavingsFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, SavingsParameters parameters, LocalSearchFilterManager *filter_manager)
SavingsFilteredHeuristic.
virtual double ExtraSavingsMemoryMultiplicativeFactor() const =0
int StartNewRouteWithBestVehicleOfType(int type, int64_t before_node, int64_t after_node)
std::unique_ptr< SavingsContainer< Saving > > savings_container_
clang-format off
std::unique_ptr< VehicleTypeCurator > vehicle_type_curator_
clang-format on
SequentialSavingsFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, SavingsParameters parameters, LocalSearchFilterManager *filter_manager)
For the time being, Solver is neither MT_SAFE nor MT_HOT.
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
SweepArranger(absl::Span< const std::pair< int64_t, int64_t > > points)
SweepArranger(const SweepArranger &)=delete
This type is neither copyable nor movable.
void ArrangeIndices(std::vector< int64_t > *indices)
SweepArranger & operator=(const SweepArranger &)=delete
void Update(const std::function< bool(int)> &remove_vehicle)
bool HasCompatibleVehicleOfType(int type, const std::function< bool(int)> &vehicle_is_compatible) const
VehicleTypeCurator(const RoutingModel::VehicleTypeContainer &vehicle_type_container)
void ReinjectVehicleOfClass(int vehicle, int vehicle_class, int64_t fixed_cost)
int GetLowestFixedCostVehicleOfType(int type) const
std::pair< int, int > GetCompatibleVehicleOfType(int type, const std::function< bool(int)> &vehicle_is_compatible, const std::function< bool(int)> &stop_and_return_vehicle)
void Reset(const std::function< bool(int)> &store_vehicle)
— VehicleTypeCurator —
dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp
In SWIG mode, we don't want anything besides these top-level includes.
const Assignment * SolveFromAssignmentWithAlternativeSolversAndParameters(const Assignment *assignment, RoutingModel *primary_model, const RoutingSearchParameters &primary_parameters, const std::vector< RoutingModel * > &alternative_models, const std::vector< RoutingSearchParameters > &alternative_parameters, int max_non_improving_iterations)
Same as above but taking alternative parameters for each alternative model.
DecisionBuilder * MakeAllUnperformed(RoutingModel *model)
Returns a DecisionBuilder making all nodes unperformed.
FirstSolutionStrategy::Value AutomaticFirstSolutionStrategy(bool has_pickup_deliveries, bool has_node_precedences, bool has_single_vehicle_node)
std::vector< int64_t > ComputeVehicleEndChainStarts(const RoutingModel &model)
const Assignment * SolveFromAssignmentWithAlternativeSolvers(const Assignment *assignment, RoutingModel *primary_model, const std::vector< RoutingModel * > &alternative_models, const RoutingSearchParameters &parameters, int max_non_improving_iterations)
Same as above, but taking an initial solution.
DecisionBuilder * MakeSweepDecisionBuilder(RoutingModel *model, bool check_assignment)
const Assignment * SolveWithAlternativeSolvers(RoutingModel *primary_model, const std::vector< RoutingModel * > &alternative_models, const RoutingSearchParameters &parameters, int max_non_improving_iterations)
STL namespace.
bool Next()
trees with all degrees equal to
std::priority_queue< Seed, std::vector< Seed >, std::greater< Seed > > priority_queue
bool is_sequential
Whether the routes are constructed sequentially or in parallel.
bool operator<(const PickupDeliveryInsertion &other) const