OR-Tools  9.6
routing_search.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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 <deque>
21 #include <functional>
22 #include <iterator>
23 #include <limits>
24 #include <map>
25 #include <memory>
26 #include <optional>
27 #include <set>
28 #include <string>
29 #include <tuple>
30 #include <type_traits>
31 #include <utility>
32 #include <vector>
33 
34 #include "absl/container/flat_hash_set.h"
37 #include "ortools/base/logging.h"
38 #include "ortools/base/macros.h"
39 #include "ortools/base/mathutil.h"
44 #include "ortools/util/bitset.h"
45 
46 namespace operations_research {
47 
48 class IntVarFilteredHeuristic;
49 #ifndef SWIG
54  public:
56  const RoutingModel::VehicleTypeContainer& vehicle_type_container)
57  : vehicle_type_container_(&vehicle_type_container) {}
58 
59  int NumTypes() const { return vehicle_type_container_->NumTypes(); }
60 
61  int Type(int vehicle) const { return vehicle_type_container_->Type(vehicle); }
62 
65  void Reset(const std::function<bool(int)>& store_vehicle);
66 
69  void Update(const std::function<bool(int)>& remove_vehicle);
70 
71  int GetLowestFixedCostVehicleOfType(int type) const {
72  DCHECK_LT(type, NumTypes());
73  const std::set<VehicleClassEntry>& vehicle_classes =
74  sorted_vehicle_classes_per_type_[type];
75  if (vehicle_classes.empty()) {
76  return -1;
77  }
78  const int vehicle_class = (vehicle_classes.begin())->vehicle_class;
79  DCHECK(!vehicles_per_vehicle_class_[vehicle_class].empty());
80  return vehicles_per_vehicle_class_[vehicle_class][0];
81  }
82 
83  void ReinjectVehicleOfClass(int vehicle, int vehicle_class,
84  int64_t fixed_cost) {
85  std::vector<int>& vehicles = vehicles_per_vehicle_class_[vehicle_class];
86  if (vehicles.empty()) {
89  std::set<VehicleClassEntry>& vehicle_classes =
90  sorted_vehicle_classes_per_type_[Type(vehicle)];
91  const auto& insertion =
92  vehicle_classes.insert({vehicle_class, fixed_cost});
93  DCHECK(insertion.second);
94  }
95  vehicles.push_back(vehicle);
96  }
97 
101  int type, const std::function<bool(int)>& vehicle_is_compatible) const;
110  std::pair<int, int> GetCompatibleVehicleOfType(
111  int type, const std::function<bool(int)>& vehicle_is_compatible,
112  const std::function<bool(int)>& stop_and_return_vehicle);
113 
114  private:
115  using VehicleClassEntry =
117  const RoutingModel::VehicleTypeContainer* const vehicle_type_container_;
118  // clang-format off
119  std::vector<std::set<VehicleClassEntry> > sorted_vehicle_classes_per_type_;
120  std::vector<std::vector<int> > vehicles_per_vehicle_class_;
121  // clang-format on
122 };
123 
127 AutomaticFirstSolutionStrategy(bool has_pickup_deliveries,
128  bool has_node_precedences,
129  bool has_single_vehicle_node);
130 
133 std::vector<int64_t> ComputeVehicleEndChainStarts(const RoutingModel& model);
134 
147 
149 // TODO(user): Eventually move this to the core CP solver library
152  public:
154  std::unique_ptr<IntVarFilteredHeuristic> heuristic);
155 
157 
158  Decision* Next(Solver* solver) override;
159 
160  std::string DebugString() const override;
161 
163  int64_t number_of_decisions() const;
164  int64_t number_of_rejects() const;
165 
166  private:
167  const std::unique_ptr<IntVarFilteredHeuristic> heuristic_;
168 };
169 
172  public:
173  IntVarFilteredHeuristic(Solver* solver, const std::vector<IntVar*>& vars,
174  const std::vector<IntVar*>& secondary_vars,
175  LocalSearchFilterManager* filter_manager);
176 
177  virtual ~IntVarFilteredHeuristic() = default;
178 
181  Assignment* const BuildSolution();
182 
185  int64_t number_of_decisions() const { return number_of_decisions_; }
186  int64_t number_of_rejects() const { return number_of_rejects_; }
187 
188  virtual std::string DebugString() const { return "IntVarFilteredHeuristic"; }
189 
190  protected:
192  void ResetSolution();
194  virtual void Initialize() {}
196  virtual bool InitializeSolution() { return true; }
198  virtual bool BuildSolutionInternal() = 0;
206  std::optional<int64_t> Evaluate(bool commit);
208  virtual bool StopSearch() { return false; }
211  void SetValue(int64_t index, int64_t value) {
212  if (!is_in_delta_[index]) {
213  delta_->FastAdd(vars_[index])->SetValue(value);
214  delta_indices_.push_back(index);
215  is_in_delta_[index] = true;
216  } else {
217  delta_->SetValue(vars_[index], value);
218  }
219  }
222  int64_t Value(int64_t index) const {
224  }
226  bool Contains(int64_t index) const {
227  return assignment_->IntVarContainer().Element(index).Var() != nullptr;
228  }
231  int Size() const { return vars_.size(); }
233  IntVar* Var(int64_t index) const { return vars_[index]; }
235  int64_t SecondaryVarIndex(int64_t index) const {
236  DCHECK(HasSecondaryVars());
237  return index + base_vars_size_;
238  }
240  bool HasSecondaryVars() const { return base_vars_size_ != vars_.size(); }
242  bool IsSecondaryVar(int64_t index) const { return index >= base_vars_size_; }
244  void SynchronizeFilters();
245 
247 
248  private:
251  bool FilterAccept();
252 
253  Solver* solver_;
254  std::vector<IntVar*> vars_;
255  const int base_vars_size_;
256  Assignment* const delta_;
257  std::vector<int> delta_indices_;
258  std::vector<bool> is_in_delta_;
259  Assignment* const empty_;
260  LocalSearchFilterManager* filter_manager_;
261  int64_t objective_upper_bound_;
263  int64_t number_of_decisions_;
264  int64_t number_of_rejects_;
265 };
266 
269  public:
271  std::function<bool()> stop_search,
272  LocalSearchFilterManager* filter_manager,
273  bool omit_secondary_vars = true);
274  ~RoutingFilteredHeuristic() override = default;
277  const std::function<int64_t(int64_t)>& next_accessor);
278  RoutingModel* model() const { return model_; }
280  int GetStartChainEnd(int vehicle) const { return start_chain_ends_[vehicle]; }
282  int GetEndChainStart(int vehicle) const { return end_chain_starts_[vehicle]; }
285  void MakeDisjunctionNodesUnperformed(int64_t node);
293 
294  protected:
295  bool StopSearch() override { return stop_search_(); }
296  virtual void SetVehicleIndex(int64_t /*node*/, int /*vehicle*/) {}
297  virtual void ResetVehicleIndices() {}
298  bool VehicleIsEmpty(int vehicle) const {
299  return Value(model()->Start(vehicle)) == model()->End(vehicle);
300  }
301 
302  private:
304  bool InitializeSolution() override;
305 
306  RoutingModel* const model_;
307  std::function<bool()> stop_search_;
308  std::vector<int64_t> start_chain_ends_;
309  std::vector<int64_t> end_chain_starts_;
310 };
311 
313  public:
316  RoutingModel* model, std::function<bool()> stop_search,
317  std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
318  std::function<int64_t(int64_t)> penalty_evaluator,
319  LocalSearchFilterManager* filter_manager);
321 
322  protected:
323  struct NodeInsertion {
324  int64_t insert_after;
325  int vehicle;
326  int64_t value;
327 
328  bool operator<(const NodeInsertion& other) const {
329  return std::tie(value, insert_after, vehicle) <
330  std::tie(other.value, other.insert_after, other.vehicle);
331  }
332  };
333  struct StartEndValue {
335  int64_t distance;
336  int vehicle;
337 
338  bool operator<(const StartEndValue& other) const {
339  return std::tie(num_allowed_vehicles, distance, vehicle) <
340  std::tie(other.num_allowed_vehicles, other.distance,
341  other.vehicle);
342  }
343  };
344  typedef std::pair<StartEndValue, /*seed_node*/ int> Seed;
345 
351  // clang-format off
352  std::vector<std::vector<StartEndValue> >
353  ComputeStartEndDistanceForVehicles(const std::vector<int>& vehicles);
354 
359  template <class Queue>
361  std::vector<std::vector<StartEndValue> >* start_end_distances_per_node,
362  Queue* priority_queue);
363  // clang-format on
364 
370  void InsertBetween(int64_t node, int64_t predecessor, int64_t successor,
371  int vehicle = -1);
377  int64_t node_to_insert, int64_t start, int64_t next_after_start,
378  int vehicle, bool ignore_cost,
379  std::vector<NodeInsertion>* node_insertions);
384  // TODO(user): Replace 'insert_before' and 'insert_after' by 'predecessor'
385  // and 'successor' in the code.
386  int64_t GetInsertionCostForNodeAtPosition(int64_t node_to_insert,
387  int64_t insert_after,
388  int64_t insert_before,
389  int vehicle) const;
392  int64_t GetUnperformedValue(int64_t node_to_insert) const;
393 
394  std::function<int64_t(int64_t, int64_t, int64_t)> evaluator_;
395  std::function<int64_t(int64_t)> penalty_evaluator_;
396 };
397 
407  public:
420  int64_t min_neighbors;
430  };
431 
434  RoutingModel* model, std::function<bool()> stop_search,
435  std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
436  std::function<int64_t(int64_t)> penalty_evaluator,
437  LocalSearchFilterManager* filter_manager,
440  bool BuildSolutionInternal() override;
441  std::string DebugString() const override {
442  return "GlobalCheapestInsertionFilteredHeuristic";
443  }
444 
445  private:
447  class NodeEntryQueue;
448 
450  class PairEntry {
451  public:
452  PairEntry(int pickup_to_insert, int pickup_insert_after,
453  int delivery_to_insert, int delivery_insert_after, int vehicle,
454  int64_t bucket)
455  : value_(std::numeric_limits<int64_t>::max()),
456  heap_index_(-1),
457  pickup_to_insert_(pickup_to_insert),
458  pickup_insert_after_(pickup_insert_after),
459  delivery_to_insert_(delivery_to_insert),
460  delivery_insert_after_(delivery_insert_after),
461  vehicle_(vehicle),
462  bucket_(bucket) {}
463  // Note: for compatibility reasons, comparator follows tie-breaking rules
464  // used in the first version of GlobalCheapestInsertion.
465  bool operator<(const PairEntry& other) const {
466  // We give higher priority to insertions from lower buckets.
467  if (bucket_ != other.bucket_) {
468  return bucket_ > other.bucket_;
469  }
470  // We then compare by value, then we favor insertions (vehicle != -1).
471  // The rest of the tie-breaking is done with std::tie.
472  if (value_ != other.value_) {
473  return value_ > other.value_;
474  }
475  if ((vehicle_ == -1) ^ (other.vehicle_ == -1)) {
476  return vehicle_ == -1;
477  }
478  return std::tie(pickup_insert_after_, pickup_to_insert_,
479  delivery_insert_after_, delivery_to_insert_, vehicle_) >
480  std::tie(other.pickup_insert_after_, other.pickup_to_insert_,
481  other.delivery_insert_after_, other.delivery_to_insert_,
482  other.vehicle_);
483  }
484  void SetHeapIndex(int h) { heap_index_ = h; }
485  int GetHeapIndex() const { return heap_index_; }
486  void set_value(int64_t value) { value_ = value; }
487  int pickup_to_insert() const { return pickup_to_insert_; }
488  int pickup_insert_after() const { return pickup_insert_after_; }
489  void set_pickup_insert_after(int pickup_insert_after) {
490  pickup_insert_after_ = pickup_insert_after;
491  }
492  int delivery_to_insert() const { return delivery_to_insert_; }
493  int delivery_insert_after() const { return delivery_insert_after_; }
494  int vehicle() const { return vehicle_; }
495  void set_vehicle(int vehicle) { vehicle_ = vehicle; }
496 
497  private:
498  int64_t value_;
499  int heap_index_;
500  int pickup_to_insert_;
501  int pickup_insert_after_;
502  int delivery_to_insert_;
503  int delivery_insert_after_;
504  int vehicle_;
505  int64_t bucket_;
506  };
507 
508  typedef absl::flat_hash_set<PairEntry*> PairEntries;
509 
511  template <typename T>
512  class EntryAllocator {
513  public:
514  EntryAllocator() {}
515  void Clear() {
516  entries_.clear();
517  free_entries_.clear();
518  }
519  template <typename... Args>
520  T* NewEntry(const Args&... args) {
521  if (!free_entries_.empty()) {
522  auto* entry = free_entries_.back();
523  free_entries_.pop_back();
524  *entry = T(args...);
525  return entry;
526  } else {
527  entries_.emplace_back(args...);
528  return &entries_.back();
529  }
530  }
531  void FreeEntry(T* entry) { free_entries_.push_back(entry); }
532 
533  private:
535  std::deque<T> entries_;
536  std::vector<T*> free_entries_;
537  };
538 
545  bool InsertPairsAndNodesByRequirementTopologicalOrder();
546 
553  bool InsertPairs(
554  const std::map<int64_t, std::vector<int>>& pair_indices_by_bucket);
555 
559  bool UseEmptyVehicleTypeCuratorForVehicle(int vehicle,
560  bool all_vehicles = true) {
561  return vehicle >= 0 && VehicleIsEmpty(vehicle) && all_vehicles;
562  }
563 
570  bool InsertPairEntryUsingEmptyVehicleTypeCurator(
571  const absl::flat_hash_set<int>& pair_indices, PairEntry* const pair_entry,
572  AdjustablePriorityQueue<PairEntry>* priority_queue,
573  std::vector<PairEntries>* pickup_to_entries,
574  std::vector<PairEntries>* delivery_to_entries);
575 
583  bool InsertNodesOnRoutes(
584  const std::map<int64_t, std::vector<int>>& nodes_by_bucket,
585  const absl::flat_hash_set<int>& vehicles);
586 
594  bool InsertNodeEntryUsingEmptyVehicleTypeCurator(
595  const std::vector<bool>& nodes, bool all_vehicles, NodeEntryQueue* queue);
596 
602  bool SequentialInsertNodes(
603  const std::map<int64_t, std::vector<int>>& nodes_by_bucket);
604 
608  void DetectUsedVehicles(std::vector<bool>* is_vehicle_used,
609  std::vector<int>* unused_vehicles,
610  absl::flat_hash_set<int>* used_vehicles);
611 
615  void InsertFarthestNodesAsSeeds();
616 
625  template <class Queue>
626  int InsertSeedNode(
627  std::vector<std::vector<StartEndValue>>* start_end_distances_per_node,
628  Queue* priority_queue, std::vector<bool>* is_vehicle_used);
629  // clang-format on
630 
633  bool InitializePairPositions(
634  const absl::flat_hash_set<int>& pair_indices,
635  AdjustablePriorityQueue<PairEntry>* priority_queue,
636  std::vector<PairEntries>* pickup_to_entries,
637  std::vector<PairEntries>* delivery_to_entries);
643  void InitializeInsertionEntriesPerformingPair(
644  int64_t pickup, int64_t delivery,
645  AdjustablePriorityQueue<PairEntry>* priority_queue,
646  std::vector<PairEntries>* pickup_to_entries,
647  std::vector<PairEntries>* delivery_to_entries);
651  bool UpdateAfterPairInsertion(
652  const absl::flat_hash_set<int>& pair_indices, int vehicle, int64_t pickup,
653  int64_t pickup_position, int64_t delivery, int64_t delivery_position,
654  AdjustablePriorityQueue<PairEntry>* priority_queue,
655  std::vector<PairEntries>* pickup_to_entries,
656  std::vector<PairEntries>* delivery_to_entries);
660  bool UpdateExistingPairEntriesOnChain(
661  int64_t insert_after_start, int64_t insert_after_end,
662  AdjustablePriorityQueue<PairEntry>* priority_queue,
663  std::vector<PairEntries>* pickup_to_entries,
664  std::vector<PairEntries>* delivery_to_entries);
670  bool AddPairEntriesAfter(const absl::flat_hash_set<int>& pair_indices,
671  int vehicle, int64_t insert_after,
672  int64_t skip_entries_inserting_delivery_after,
673  AdjustablePriorityQueue<PairEntry>* priority_queue,
674  std::vector<PairEntries>* pickup_to_entries,
675  std::vector<PairEntries>* delivery_to_entries) {
676  return AddPairEntriesWithDeliveryAfter(pair_indices, vehicle, insert_after,
677  priority_queue, pickup_to_entries,
678  delivery_to_entries) &&
679  AddPairEntriesWithPickupAfter(pair_indices, vehicle, insert_after,
680  skip_entries_inserting_delivery_after,
681  priority_queue, pickup_to_entries,
682  delivery_to_entries);
683  }
690  bool AddPairEntriesWithPickupAfter(
691  const absl::flat_hash_set<int>& pair_indices, int vehicle,
692  int64_t insert_after, int64_t skip_entries_inserting_delivery_after,
693  AdjustablePriorityQueue<PairEntry>* priority_queue,
694  std::vector<PairEntries>* pickup_to_entries,
695  std::vector<PairEntries>* delivery_to_entries);
699  bool AddPairEntriesWithDeliveryAfter(
700  const absl::flat_hash_set<int>& pair_indices, int vehicle,
701  int64_t insert_after, AdjustablePriorityQueue<PairEntry>* priority_queue,
702  std::vector<PairEntries>* pickup_to_entries,
703  std::vector<PairEntries>* delivery_to_entries);
706  void DeletePairEntry(PairEntry* entry,
707  AdjustablePriorityQueue<PairEntry>* priority_queue,
708  std::vector<PairEntries>* pickup_to_entries,
709  std::vector<PairEntries>* delivery_to_entries);
714  void AddPairEntry(int64_t pickup, int64_t pickup_insert_after,
715  int64_t delivery, int64_t delivery_insert_after,
716  int vehicle,
717  AdjustablePriorityQueue<PairEntry>* priority_queue,
718  std::vector<PairEntries>* pickup_entries,
719  std::vector<PairEntries>* delivery_entries) const;
722  void UpdatePairEntry(
723  PairEntry* const pair_entry,
724  AdjustablePriorityQueue<PairEntry>* priority_queue) const;
728  int64_t GetInsertionValueForPairAtPositions(int64_t pickup,
729  int64_t pickup_insert_after,
730  int64_t delivery,
731  int64_t delivery_insert_after,
732  int vehicle) const;
733 
736  bool InitializePositions(const std::vector<bool>& nodes,
737  const absl::flat_hash_set<int>& vehicles,
738  NodeEntryQueue* queue);
744  void InitializeInsertionEntriesPerformingNode(
745  int64_t node, const absl::flat_hash_set<int>& vehicles,
746  NodeEntryQueue* queue);
749  bool UpdateAfterNodeInsertion(const std::vector<bool>& nodes, int vehicle,
750  int64_t node, int64_t insert_after,
751  bool all_vehicles, NodeEntryQueue* queue);
755  bool UpdateExistingNodeEntriesOnChain(const std::vector<bool>& nodes,
756  int vehicle, int64_t insert_after_start,
757  int64_t insert_after_end,
758  bool all_vehicles,
759  NodeEntryQueue* queue);
762  bool AddNodeEntriesAfter(const std::vector<bool>& nodes, int vehicle,
763  int64_t insert_after, bool all_vehicles,
764  NodeEntryQueue* queue);
765 
769  void AddNodeEntry(int64_t node, int64_t insert_after, int vehicle,
770  bool all_vehicles, NodeEntryQueue* queue) const;
771 
772  int64_t NumNonStartEndNodes() const {
773  return model()->Size() - model()->vehicles();
774  }
775 
776  int64_t NumNeighbors() const {
777  return std::max(gci_params_.min_neighbors,
779  NumNonStartEndNodes()));
780  }
781 
782  void ResetVehicleIndices() override {
783  node_index_to_vehicle_.assign(node_index_to_vehicle_.size(), -1);
784  }
785 
786  void SetVehicleIndex(int64_t node, int vehicle) override {
787  DCHECK_LT(node, node_index_to_vehicle_.size());
788  node_index_to_vehicle_[node] = vehicle;
789  }
790 
793  bool CheckVehicleIndices() const;
794 
796  int64_t GetBucketOfNode(int node) const {
797  return model()->VehicleVar(node)->Size();
798  }
799 
801  int64_t GetBucketOfPair(const RoutingModel::IndexPair& index_pair) const {
802  int64_t max_pickup_bucket = 0;
803  for (int64_t pickup : index_pair.first) {
804  max_pickup_bucket = std::max(max_pickup_bucket, GetBucketOfNode(pickup));
805  }
806  int64_t max_delivery_bucket = 0;
807  for (int64_t delivery : index_pair.second) {
808  max_delivery_bucket =
809  std::max(max_delivery_bucket, GetBucketOfNode(delivery));
810  }
811  return std::min(max_pickup_bucket, max_delivery_bucket);
812  }
813 
816  template <typename T>
817  bool StopSearchAndCleanup(AdjustablePriorityQueue<T>* priority_queue) {
818  if (!StopSearch()) return false;
819  if constexpr (std::is_same_v<T, PairEntry>) {
820  pair_entry_allocator_.Clear();
821  }
822  priority_queue->Clear();
823  return true;
824  }
825 
826  GlobalCheapestInsertionParameters gci_params_;
828  std::vector<int> node_index_to_vehicle_;
829 
830  const RoutingModel::NodeNeighborsByCostClass*
831  node_index_to_neighbors_by_cost_class_;
832 
833  std::unique_ptr<VehicleTypeCurator> empty_vehicle_type_curator_;
834 
835  mutable EntryAllocator<PairEntry> pair_entry_allocator_;
836 };
837 
838 // Generates insertion positions respecting structural constraints.
840  public:
841  InsertionGenerator() = default;
842 
846  int64_t value;
847  int vehicle;
848 
849  bool operator<(const PickupDeliveryInsertion& other) const {
851  vehicle) <
852  std::tie(other.value, other.insert_pickup_after,
853  other.insert_delivery_after, other.vehicle);
854  }
855  };
874  int pickup, const std::vector<int>& path,
875  const std::vector<bool>& node_is_pickup,
876  const std::vector<bool>& node_is_delivery,
877  std::vector<PickupDeliveryInsertion>& insertions);
878 
879  private:
880  // Information[i] describes the insertion between path[i] and path[i+1].
881  std::vector<int> next_decrease_; // next position after a delivery.
882  std::vector<int> next_increase_; // next position after a pickup.
883  std::vector<int> prev_decrease_; // previous position after delivery.
884  std::vector<int> prev_increase_; // previous position after pickup.
885 };
886 
894  public:
897  RoutingModel* model, std::function<bool()> stop_search,
898  std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
899  RoutingSearchParameters::PairInsertionStrategy pair_insertion_strategy,
900  LocalSearchFilterManager* filter_manager);
902  bool BuildSolutionInternal() override;
903  std::string DebugString() const override {
904  return "LocalCheapestInsertionFilteredHeuristic";
905  }
906 
907  protected:
908  void Initialize() override;
909 
910  private:
914  std::vector<NodeInsertion> ComputeEvaluatorSortedPositions(int64_t node);
919  std::vector<NodeInsertion> ComputeEvaluatorSortedPositionsOnRouteAfter(
920  int64_t node, int64_t start, int64_t next_after_start, int vehicle);
921 
925  std::optional<std::vector<InsertionGenerator::PickupDeliveryInsertion>>
926  ComputeEvaluatorSortedPairPositions(int64_t pickup, int64_t delivery);
927 
928  // Tries to insert any alternative of the given pair,
929  // ordered by cost of pickup insertion, then by cost of delivery insertion.
930  void InsertBestPickupThenDelivery(const RoutingModel::IndexPair& index_pair);
931  // Tries to insert any alternative of the given pair,
932  // ordered by the sum of pickup and delivery insertion.
933  void InsertBestPair(const RoutingModel::IndexPair& index_pair);
934  // Tries to insert any alternative of the given pair,
935  // at a position that preserves the multitour property,
936  // ordered by the sum of pickup and delivery insertion.
937  void InsertBestPairMultitour(const RoutingModel::IndexPair& index_pair,
938  const std::vector<bool>& node_is_pickup,
939  const std::vector<bool>& node_is_delivery);
940  // Tries to insert a pair at the given location. Returns true iff inserted.
941  bool InsertPair(int64_t pickup, int64_t insert_pickup_after, int64_t delivery,
942  int64_t insert_delivery_after, int vehicle);
943  // Sets all nodes of pair alternatives as visited.
944  void SetIndexPairVisited(const RoutingModel::IndexPair& index_pair);
945 
946  bool update_start_end_distances_per_node_;
947  std::vector<std::vector<StartEndValue>> start_end_distances_per_node_;
948  const RoutingSearchParameters::PairInsertionStrategy pair_insertion_strategy_;
949  InsertionGenerator insertion_generator_;
950 
951  // Marks whether a node has already been tried for insertion.
952  std::vector<bool> visited_;
953 };
954 
958  public:
960  std::function<bool()> stop_search,
961  LocalSearchFilterManager* filter_manager);
963  bool BuildSolutionInternal() override;
964 
965  private:
966  class PartialRoutesAndLargeVehicleIndicesFirst {
967  public:
968  explicit PartialRoutesAndLargeVehicleIndicesFirst(
969  const CheapestAdditionFilteredHeuristic& builder)
970  : builder_(builder) {}
971  bool operator()(int vehicle1, int vehicle2) const;
972 
973  private:
974  const CheapestAdditionFilteredHeuristic& builder_;
975  };
977  template <typename Iterator>
978  std::vector<int64_t> GetPossibleNextsFromIterator(int64_t node,
979  Iterator start,
980  Iterator end) const {
981  const int size = model()->Size();
982  std::vector<int64_t> nexts;
983  for (Iterator it = start; it != end; ++it) {
984  const int64_t next = *it;
985  if (next != node && (next >= size || !Contains(next))) {
986  nexts.push_back(next);
987  }
988  }
989  return nexts;
990  }
992  virtual void SortSuccessors(int64_t node,
993  std::vector<int64_t>* successors) = 0;
994  virtual int64_t FindTopSuccessor(int64_t node,
995  const std::vector<int64_t>& successors) = 0;
996 };
997 
1002  public:
1005  RoutingModel* model, std::function<bool()> stop_search,
1006  std::function<int64_t(int64_t, int64_t)> evaluator,
1007  LocalSearchFilterManager* filter_manager);
1009  std::string DebugString() const override {
1010  return "EvaluatorCheapestAdditionFilteredHeuristic";
1011  }
1012 
1013  private:
1015  void SortSuccessors(int64_t node, std::vector<int64_t>* successors) override;
1016  int64_t FindTopSuccessor(int64_t node,
1017  const std::vector<int64_t>& successors) override;
1018 
1019  std::function<int64_t(int64_t, int64_t)> evaluator_;
1020 };
1021 
1026  public:
1029  RoutingModel* model, std::function<bool()> stop_search,
1031  LocalSearchFilterManager* filter_manager);
1033  std::string DebugString() const override {
1034  return "ComparatorCheapestAdditionFilteredHeuristic";
1035  }
1036 
1037  private:
1039  void SortSuccessors(int64_t node, std::vector<int64_t>* successors) override;
1040  int64_t FindTopSuccessor(int64_t node,
1041  const std::vector<int64_t>& successors) override;
1042 
1043  Solver::VariableValueComparator comparator_;
1044 };
1045 
1055  public:
1059  double neighbors_ratio = 1.0;
1065  bool add_reverse_arcs = false;
1068  double arc_coefficient = 1.0;
1069  };
1070 
1072  std::function<bool()> stop_search,
1074  LocalSearchFilterManager* filter_manager);
1075  ~SavingsFilteredHeuristic() override;
1076  bool BuildSolutionInternal() override;
1077 
1078  protected:
1079  typedef std::pair</*saving*/ int64_t, /*saving index*/ int64_t> Saving;
1080 
1081  template <typename S>
1082  class SavingsContainer;
1083 
1084  virtual double ExtraSavingsMemoryMultiplicativeFactor() const = 0;
1085 
1086  virtual void BuildRoutesFromSavings() = 0;
1087 
1089  int64_t GetVehicleTypeFromSaving(const Saving& saving) const {
1090  return saving.second / size_squared_;
1091  }
1093  int64_t GetBeforeNodeFromSaving(const Saving& saving) const {
1094  return (saving.second % size_squared_) / Size();
1095  }
1097  int64_t GetAfterNodeFromSaving(const Saving& saving) const {
1098  return (saving.second % size_squared_) % Size();
1099  }
1101  int64_t GetSavingValue(const Saving& saving) const { return saving.first; }
1102 
1112  int StartNewRouteWithBestVehicleOfType(int type, int64_t before_node,
1113  int64_t after_node);
1114 
1115  // clang-format off
1116  std::unique_ptr<SavingsContainer<Saving> > savings_container_;
1117  // clang-format on
1118  std::unique_ptr<VehicleTypeCurator> vehicle_type_curator_;
1119 
1120  private:
1125  // clang-format off
1126  void AddSymmetricArcsToAdjacencyLists(
1127  std::vector<std::vector<int64_t> >* adjacency_lists);
1128  // clang-format on
1129 
1138  bool ComputeSavings();
1140  Saving BuildSaving(int64_t saving, int vehicle_type, int before_node,
1141  int after_node) const {
1142  return std::make_pair(saving, vehicle_type * size_squared_ +
1143  before_node * Size() + after_node);
1144  }
1145 
1149  int64_t MaxNumNeighborsPerNode(int num_vehicle_types) const;
1150 
1151  const SavingsParameters savings_params_;
1152  int64_t size_squared_;
1153 
1155 };
1156 
1158  public:
1160  std::function<bool()> stop_search,
1162  LocalSearchFilterManager* filter_manager)
1163  : SavingsFilteredHeuristic(model, std::move(stop_search), parameters,
1164  filter_manager) {}
1166  std::string DebugString() const override {
1167  return "SequentialSavingsFilteredHeuristic";
1168  }
1169 
1170  private:
1175  void BuildRoutesFromSavings() override;
1176  double ExtraSavingsMemoryMultiplicativeFactor() const override { return 1.0; }
1177 };
1178 
1180  public:
1182  std::function<bool()> stop_search,
1184  LocalSearchFilterManager* filter_manager)
1185  : SavingsFilteredHeuristic(model, std::move(stop_search), parameters,
1186  filter_manager) {}
1188  std::string DebugString() const override {
1189  return "ParallelSavingsFilteredHeuristic";
1190  }
1191 
1192  private:
1203  void BuildRoutesFromSavings() override;
1204 
1205  double ExtraSavingsMemoryMultiplicativeFactor() const override { return 2.0; }
1206 
1211  void MergeRoutes(int first_vehicle, int second_vehicle, int64_t before_node,
1212  int64_t after_node);
1213 
1215  std::vector<int64_t> first_node_on_route_;
1216  std::vector<int64_t> last_node_on_route_;
1220  std::vector<int> vehicle_of_first_or_last_node_;
1221 };
1222 
1226 
1228  public:
1230  std::function<bool()> stop_search,
1231  LocalSearchFilterManager* filter_manager,
1232  bool use_minimum_matching);
1233  ~ChristofidesFilteredHeuristic() override = default;
1234  bool BuildSolutionInternal() override;
1235  std::string DebugString() const override {
1236  return "ChristofidesFilteredHeuristic";
1237  }
1238 
1239  private:
1240  const bool use_minimum_matching_;
1241 };
1242 
1246  public:
1247  explicit SweepArranger(
1248  const std::vector<std::pair<int64_t, int64_t>>& points);
1249  virtual ~SweepArranger() {}
1250  void ArrangeIndices(std::vector<int64_t>* indices);
1251  void SetSectors(int sectors) { sectors_ = sectors; }
1252 
1253  private:
1254  std::vector<int> coordinates_;
1255  int sectors_;
1256 
1257  DISALLOW_COPY_AND_ASSIGN(SweepArranger);
1258 };
1259 #endif // SWIG
1260 
1261 // Returns a DecisionBuilder building a first solution based on the Sweep
1262 // heuristic. Mostly suitable when cost is proportional to distance.
1263 DecisionBuilder* MakeSweepDecisionBuilder(RoutingModel* model,
1264  bool check_assignment);
1265 
1266 // Returns a DecisionBuilder making all nodes unperformed.
1267 DecisionBuilder* MakeAllUnperformed(RoutingModel* model);
1268 
1269 } // namespace operations_research
1270 
1271 #endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_SEARCH_H_
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
const E & Element(const V *const var) const
An Assignment is a variable -> domains mapping, used to report solutions to the user.
const IntContainer & IntVarContainer() const
void SetValue(const IntVar *const var, int64_t value)
IntVarElement * FastAdd(IntVar *const var)
Adds without checking if variable has been previously added.
Filtered-base decision builder based on the addition heuristic, extending a path from its start node ...
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
CheapestAdditionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, LocalSearchFilterManager *filter_manager)
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)
Helper method to the ComputeEvaluatorSortedPositions* methods.
std::vector< std::vector< StartEndValue > > ComputeStartEndDistanceForVehicles(const std::vector< int > &vehicles)
Computes and returns the distance of each uninserted node to every vehicle in "vehicles" as a std::ve...
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.
std::function< int64_t(int64_t, int64_t, int64_t)> evaluator_
void InitializePriorityQueue(std::vector< std::vector< StartEndValue > > *start_end_distances_per_node, Queue *priority_queue)
Initializes the priority_queue by inserting the best entry corresponding to each node,...
int64_t GetInsertionCostForNodeAtPosition(int64_t node_to_insert, int64_t insert_after, int64_t insert_before, int vehicle) const
Returns the cost of inserting 'node_to_insert' between 'insert_after' and 'insert_before' on the 'veh...
int64_t GetUnperformedValue(int64_t node_to_insert) const
Returns the cost of unperforming node 'node_to_insert'.
void InsertBetween(int64_t node, int64_t predecessor, int64_t successor, int vehicle=-1)
Inserts 'node' just after 'predecessor', and just before 'successor' on the route of 'vehicle',...
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
ChristofidesFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, LocalSearchFilterManager *filter_manager, bool use_minimum_matching)
A CheapestAdditionFilteredHeuristic where the notion of 'cheapest arc' comes from an arc comparator.
ComparatorCheapestAdditionFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, Solver::VariableValueComparator comparator, LocalSearchFilterManager *filter_manager)
Takes ownership of evaluator.
A DecisionBuilder is responsible for creating the search tree.
A Decision represents a choice point in the search tree.
A CheapestAdditionFilteredHeuristic where the notion of 'cheapest arc' comes from an arc 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.
Filter-based decision builder which builds a solution by inserting nodes at their cheapest position o...
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
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.
void AppendPickupDeliveryMultitourInsertions(int pickup, const std::vector< int > &path, const std::vector< bool > &node_is_pickup, const std::vector< bool > &node_is_delivery, std::vector< PickupDeliveryInsertion > &insertions)
Generates insertions for a pickup and delivery pair in a multitour path:
Decision builder building a solution using heuristics with local search filters to evaluate its feasi...
Decision * Next(Solver *solver) override
This is the main method of the decision builder class.
int64_t number_of_decisions() const
Returns statistics from its underlying heuristic.
IntVarFilteredDecisionBuilder(std::unique_ptr< IntVarFilteredHeuristic > heuristic)
Generic filter-based heuristic applied to IntVars.
void SetValue(int64_t index, int64_t value)
Modifies the current solution by setting the variable of index 'index' to value 'value'.
virtual bool BuildSolutionInternal()=0
Virtual method to redefine how to build a solution.
int64_t SecondaryVarIndex(int64_t index) const
Returns the index of a secondary var.
int Size() const
Returns the number of variables the decision builder is trying to instantiate.
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.
void ResetSolution()
Resets the data members for a new solution.
void SynchronizeFilters()
Synchronizes filters with an assignment (the current solution).
bool HasSecondaryVars() const
Returns true if there are secondary variables.
virtual bool InitializeSolution()
Virtual method to initialize the solution.
int64_t number_of_decisions() const
Returns statistics on search, number of decisions sent to filters, number of decisions rejected by fi...
virtual void Initialize()
Initialize the heuristic; called before starting to build a new solution.
int64_t Value(int64_t index) const
Returns the value of the variable of index 'index' in the last committed solution.
IntVar * Var(int64_t index) const
Returns the variable of index 'index'.
bool IsSecondaryVar(int64_t index) const
Returns true if 'index' is a secondary variable index.
std::optional< int64_t > Evaluate(bool commit)
Evaluates the modifications to the current solution.
Assignment *const BuildSolution()
Builds a solution.
IntVarFilteredHeuristic(Solver *solver, const std::vector< IntVar * > &vars, const std::vector< IntVar * > &secondary_vars, LocalSearchFilterManager *filter_manager)
The class IntVar is a subset of IntExpr.
virtual uint64_t Size() const =0
This method returns the number of values in the domain of the variable.
Filter-base decision builder which builds a solution by inserting nodes at their cheapest position.
void Initialize() override
Initialize the heuristic; called before starting to build a new solution.
bool BuildSolutionInternal() override
Virtual method to redefine how to build a 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, LocalSearchFilterManager *filter_manager)
Takes ownership of evaluator.
Filter manager: when a move is made, filters are executed to decide whether the solution is feasible ...
static int64_t FastInt64Round(double x)
Definition: mathutil.h:138
ParallelSavingsFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, SavingsParameters parameters, LocalSearchFilterManager *filter_manager)
Filter-based heuristic dedicated to routing.
bool MakeUnassignedNodesUnperformed()
Make all unassigned nodes unperformed, always returns true.
RoutingFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, LocalSearchFilterManager *filter_manager, bool omit_secondary_vars=true)
int GetStartChainEnd(int vehicle) const
Returns the end of the start chain of vehicle,.
int GetEndChainStart(int vehicle) const
Returns the start of the end chain of vehicle,.
void MakeDisjunctionNodesUnperformed(int64_t node)
Make nodes in the same disjunction as 'node' unperformed.
bool StopSearch() override
Returns true if the search must be stopped.
void MakePartiallyPerformedPairsUnperformed()
Make all partially performed pickup and delivery pairs unperformed.
const Assignment * BuildSolutionFromRoutes(const std::function< int64_t(int64_t)> &next_accessor)
Builds a solution starting from the routes formed by the next accessor.
RoutingIndexPair IndexPair
Definition: routing.h:286
IntVar * VehicleVar(int64_t index) const
Returns the vehicle variable of the node corresponding to index.
Definition: routing.h:1501
int64_t Size() const
Returns the number of next variables in the model.
Definition: routing.h:1654
int vehicles() const
Returns the number of vehicle routes in the model.
Definition: routing.h:1652
int64_t End(int vehicle) const
Returns the variable index of the ending node of a vehicle route.
Definition: routing.h:1452
Filter-based decision builder which builds a solution by using Clarke & Wright's Savings heuristic.
int64_t GetVehicleTypeFromSaving(const Saving &saving) const
Returns the cost class from a saving.
std::unique_ptr< VehicleTypeCurator > vehicle_type_curator_
bool BuildSolutionInternal() override
Virtual method to redefine how to build a solution.
int64_t GetAfterNodeFromSaving(const Saving &saving) const
Returns the "after node" from a saving.
int64_t GetSavingValue(const Saving &saving) const
Returns the saving value from a saving.
std::unique_ptr< SavingsContainer< Saving > > savings_container_
virtual double ExtraSavingsMemoryMultiplicativeFactor() const =0
int64_t GetBeforeNodeFromSaving(const Saving &saving) const
Returns the "before node" from a saving.
SavingsFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, SavingsParameters parameters, LocalSearchFilterManager *filter_manager)
int StartNewRouteWithBestVehicleOfType(int type, int64_t before_node, int64_t after_node)
Finds the best available vehicle of type "type" to start a new route to serve the arc before_node-->a...
SequentialSavingsFilteredHeuristic(RoutingModel *model, std::function< bool()> stop_search, SavingsParameters parameters, LocalSearchFilterManager *filter_manager)
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
Class to arrange indices by their distance and their angle from the depot.
void ArrangeIndices(std::vector< int64_t > *indices)
SweepArranger(const std::vector< std::pair< int64_t, int64_t >> &points)
Helper class that manages vehicles.
void Update(const std::function< bool(int)> &remove_vehicle)
Goes through all the currently stored vehicles and removes vehicles for which remove_vehicle() return...
bool HasCompatibleVehicleOfType(int type, const std::function< bool(int)> &vehicle_is_compatible) const
Searches a compatible vehicle of the given type; returns false if none was found.
VehicleTypeCurator(const RoutingModel::VehicleTypeContainer &vehicle_type_container)
void Reset(const std::function< bool(int)> &store_vehicle)
Resets the vehicles stored, storing only vehicles from the vehicle_type_container_ for which store_ve...
std::pair< int, int > GetCompatibleVehicleOfType(int type, const std::function< bool(int)> &vehicle_is_compatible, const std::function< bool(int)> &stop_and_return_vehicle)
Searches for the best compatible vehicle of the given type, i.e.
void ReinjectVehicleOfClass(int vehicle, int vehicle_class, int64_t fixed_cost)
int GetLowestFixedCostVehicleOfType(int type) const
Block * next
SatParameters parameters
int64_t value
GRBmodel * model
int index
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1795
Collection of objects used to extend the Constraint Solver library.
DecisionBuilder * MakeAllUnperformed(RoutingModel *model)
FirstSolutionStrategy::Value AutomaticFirstSolutionStrategy(bool has_pickup_deliveries, bool has_node_precedences, bool has_single_vehicle_node)
Returns the best value for the automatic first solution strategy, based on the given model parameters...
DecisionBuilder * MakeSweepDecisionBuilder(RoutingModel *model, bool check_assignment)
std::vector< int64_t > ComputeVehicleEndChainStarts(const RoutingModel &model)
Computes and returns the first node in the end chain of each vehicle in the model,...
int vehicle_class
int nodes
std::optional< int64_t > end
int64_t start
double neighbors_ratio
If neighbors_ratio < 1 then for each node only this ratio of its neighbors leading to the smallest ar...
bool is_sequential
Whether the routes are constructed sequentially or in parallel.
double farthest_seeds_ratio
The ratio of routes on which to insert farthest nodes as seeds before starting the cheapest insertion...
bool use_neighbors_ratio_for_initialization
If true, only closest neighbors (see neighbors_ratio and min_neighbors) are considered as insertion p...
bool add_unperformed_entries
If true, entries are created for making the nodes/pairs unperformed, and when the cost of making a no...
bool operator<(const PickupDeliveryInsertion &other) const
Definition: routing.h:402
Struct used to sort and store vehicles by their type.
Definition: routing.h:401
double neighbors_ratio
If neighbors_ratio < 1 then for each node only this ratio of its neighbors leading to the smallest ar...
double arc_coefficient
arc_coefficient is a strictly positive parameter indicating the coefficient of the arc being consider...
double max_memory_usage_bytes
The number of neighbors considered for each node is also adapted so that the stored Savings don't use...
bool add_reverse_arcs
If add_reverse_arcs is true, the neighborhood relationships are considered symmetrically.