Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
routing.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
151
152#ifndef ORTOOLS_CONSTRAINT_SOLVER_ROUTING_H_
153#define ORTOOLS_CONSTRAINT_SOLVER_ROUTING_H_
154
155#include <algorithm>
156#include <atomic>
157#include <cstdint>
158#include <deque>
159#include <functional>
160#include <limits>
161#include <memory>
162#include <optional>
163#include <set>
164#include <string>
165#include <tuple>
166#include <utility>
167#include <vector>
168
169#include "absl/container/flat_hash_map.h"
170#include "absl/container/flat_hash_set.h"
171#include "absl/functional/any_invocable.h"
172#include "absl/hash/hash.h"
173#include "absl/log/check.h"
174#include "absl/strings/string_view.h"
175#include "absl/time/time.h"
176#include "absl/types/span.h"
177#include "ortools/base/logging.h"
179#include "ortools/base/types.h"
188#include "ortools/graph/graph.h"
193
194namespace operations_research {
195
199#ifndef SWIG
201#endif
202class RoutingDimension;
203#ifndef SWIG
204using util::ReverseArcListGraph;
205class SweepArranger;
206#endif
207
209 public:
210 explicit PathsMetadata(const RoutingIndexManager& manager) {
211 const int num_indices = manager.num_indices();
212 const int num_paths = manager.num_vehicles();
213 path_of_node_.resize(num_indices, -1);
214 is_start_.resize(num_indices, false);
215 is_end_.resize(num_indices, false);
216 start_of_path_.resize(num_paths);
217 end_of_path_.resize(num_paths);
218 for (int v = 0; v < num_paths; ++v) {
219 const int64_t start = manager.GetStartIndex(v);
220 start_of_path_[v] = start;
221 path_of_node_[start] = v;
222 is_start_[start] = true;
223 const int64_t end = manager.GetEndIndex(v);
224 end_of_path_[v] = end;
225 path_of_node_[end] = v;
226 is_end_[end] = true;
227 }
228 }
229
230 bool IsStart(int64_t node) const { return is_start_[node]; }
231 bool IsEnd(int64_t node) const { return is_end_[node]; }
232 int GetPath(int64_t start_or_end_node) const {
233 return path_of_node_[start_or_end_node];
234 }
235 int NumPaths() const { return start_of_path_.size(); }
236 const std::vector<int64_t>& Paths() const { return path_of_node_; }
237 const std::vector<int64_t>& Starts() const { return start_of_path_; }
238 int64_t Start(int path) const { return start_of_path_[path]; }
239 int64_t End(int path) const { return end_of_path_[path]; }
240 const std::vector<int64_t>& Ends() const { return end_of_path_; }
241
242 private:
243 std::vector<bool> is_start_;
244 std::vector<bool> is_end_;
245 std::vector<int64_t> start_of_path_;
246 std::vector<int64_t> end_of_path_;
247 std::vector<int64_t> path_of_node_;
248};
249
257
259 public:
269 typedef RoutingCostClassIndex CostClassIndex;
270 typedef RoutingDimensionIndex DimensionIndex;
271 typedef RoutingDisjunctionIndex DisjunctionIndex;
272 typedef RoutingVehicleClassIndex VehicleClassIndex;
273 typedef RoutingResourceClassIndex ResourceClassIndex;
277
278#if !defined(SWIG)
295 typedef std::function<StateDependentTransit(int64_t, int64_t)>
297#endif // SWIG
298
299#if !defined(SWIG)
300 struct CostClass {
303
318
326 // TODO(user): replace span_cost_coefficient by
327 // transit_cost_coefficient and add the span coefficient to the slack one.
331 bool operator<(const DimensionCost& cost) const {
334 std::tie(cost.transit_evaluator_class,
337 }
338
344 template <typename H>
345 friend H AbslHashValue(H h, const DimensionCost& cost) {
346 return H::combine(std::move(h), cost.transit_evaluator_class,
349 }
350 };
351 std::vector<DimensionCost>
353
356
362 template <typename H>
363 friend H AbslHashValue(H h, const CostClass& c) {
364 return H::combine(
365 std::move(h), c.evaluator_index,
366 c.dimension_transit_evaluator_class_and_cost_coefficient);
367 }
368 };
369#endif // defined(SWIG)
370
377 int64_t fixed_cost;
378
379 bool operator<(const VehicleClassEntry& other) const {
380 return std::tie(fixed_cost, vehicle_class) <
381 std::tie(other.fixed_cost, other.vehicle_class);
382 }
383 };
384
385 int NumTypes() const { return sorted_vehicle_classes_per_type.size(); }
386
387 int Type(int vehicle) const {
388 DCHECK_LT(vehicle, type_index_of_vehicle.size());
389 return type_index_of_vehicle[vehicle];
390 }
391
392 std::vector<int> type_index_of_vehicle;
393 // clang-format off
394 std::vector<std::set<VehicleClassEntry> > sorted_vehicle_classes_per_type;
395 std::vector<std::deque<int> > vehicles_per_vehicle_class;
396 // clang-format on
397 };
398
410 class ResourceGroup {
411 public:
414 public:
415 Attributes();
417
418 const Domain& start_domain() const { return start_domain_; }
419 const Domain& end_domain() const { return end_domain_; }
420
421 friend bool operator==(const Attributes& a, const Attributes& b) {
422 return a.start_domain_ == b.start_domain_ &&
423 a.end_domain_ == b.end_domain_;
424 }
425 template <typename H>
426 friend H AbslHashValue(H h, const Attributes& attributes) {
427 return H::combine(std::move(h), attributes.start_domain_,
428 attributes.end_domain_);
429 }
430
431 private:
435 Domain start_domain_;
437 Domain end_domain_;
438 };
439
441 class Resource {
442 public:
444 DimensionIndex index) const {
445 return index < dimension_attributes_per_index_.size()
446 ? attributes_[dimension_attributes_per_index_[index]]
447 : GetDefaultAttributes();
448 }
449
450 private:
452 const RoutingDimension* dimension) {
453 SetDimensionAttributes(std::move(attributes), dimension);
454 }
455
456 void SetDimensionAttributes(ResourceGroup::Attributes attributes,
457 const RoutingDimension* dimension);
458 const ResourceGroup::Attributes& GetDefaultAttributes() const;
459
460 absl::flat_hash_map<DimensionIndex, int> dimension_attributes_;
462 dimension_attributes_per_index_;
463 std::vector<ResourceGroup::Attributes> attributes_;
464
465 friend class ResourceGroup;
466 };
467
470 int AddResource(Attributes attributes, const RoutingDimension* dimension);
471
475 void NotifyVehicleRequiresAResource(int vehicle);
476
477 const std::vector<int>& GetVehiclesRequiringAResource() const {
478 return vehicles_requiring_resource_;
479 }
480
481 bool VehicleRequiresAResource(int vehicle) const {
482 return vehicle_requires_resource_[vehicle];
483 }
484
486 int vehicle, const std::vector<int>& allowed_resource_indices) {
487 DCHECK(!model_->closed_);
488 // NOTE: As of 12/2023, an empty set of allowed resources means "all
489 // resources allowed", so we make sure the empty set isn't used here
490 // explicitly by the user to mark a vehicle as "unusable".
491 DCHECK(!allowed_resource_indices.empty());
492 DCHECK(vehicle_requires_resource_[vehicle]);
493 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
494 vehicle_allowed_resources_[vehicle].clear();
495 vehicle_allowed_resources_[vehicle].insert(
496 allowed_resource_indices.begin(), allowed_resource_indices.end());
497 }
499 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
500 vehicle_allowed_resources_[vehicle].clear();
501 }
502 const absl::flat_hash_set<int>& GetResourcesMarkedAllowedForVehicle(
503 int vehicle) const {
504 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
505 return vehicle_allowed_resources_[vehicle];
506 }
507 bool IsResourceAllowedForVehicle(int resource, int vehicle) const {
508 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
509 return vehicle_allowed_resources_[vehicle].empty() ||
510 vehicle_allowed_resources_[vehicle].contains(resource);
511 }
512
513 const std::vector<Resource>& GetResources() const { return resources_; }
514 const Resource& GetResource(int resource_index) const {
515 DCHECK_LT(resource_index, resources_.size());
516 return resources_[resource_index];
517 }
518 const absl::flat_hash_set<DimensionIndex>& GetAffectedDimensionIndices()
519 const {
520 return affected_dimension_indices_;
521 }
522
524 return resource_indices_per_class_.size();
525 }
526 const std::vector<int>& GetResourceIndicesInClass(
527 ResourceClassIndex resource_class) const {
528 DCHECK_LT(resource_class, resource_indices_per_class_.size());
529 return resource_indices_per_class_[resource_class];
530 }
531 // clang-format off
534 return resource_indices_per_class_;
535 }
536 // clang-format on
537 ResourceClassIndex GetResourceClassIndex(int resource_index) const {
538 DCHECK_LT(resource_index, resource_class_indices_.size());
539 return resource_class_indices_[resource_index];
540 }
542 DimensionIndex dimension_index, ResourceClassIndex rc_index) const {
543 DCHECK_LT(rc_index, resource_indices_per_class_.size());
544 const std::vector<int>& resource_indices =
545 resource_indices_per_class_[rc_index];
546 DCHECK(!resource_indices.empty());
547 return resources_[resource_indices[0]].GetDimensionAttributes(
548 dimension_index);
549 }
550
551 int Size() const { return resources_.size(); }
552 int Index() const { return index_; }
553
554 private:
555 explicit ResourceGroup(const RoutingModel* model)
556 : index_(model->GetResourceGroups().size()),
557 model_(model),
558 vehicle_requires_resource_(model->vehicles(), false),
559 vehicle_allowed_resources_(model->vehicles()) {}
560
561 void ComputeResourceClasses();
562
563 const int index_;
564 const RoutingModel* const model_;
565 std::vector<Resource> resources_;
566 // Stores the ResourceClassIndex of each resource (See implementation of
567 // ComputeResourceClasses()).
568 std::vector<ResourceClassIndex> resource_class_indices_;
569 // clang-format off
571 resource_indices_per_class_;
572 // clang-format on
573
574 std::vector<bool> vehicle_requires_resource_;
575 std::vector<int> vehicles_requiring_resource_;
576 // For each vehicle, stores the set of allowed resource indices if it's
577 // restricted for that vehicle. If the set is empty for a vehicle, then any
578 // resource from this group can be assigned to it.
579 // clang-format off
580 std::vector<absl::flat_hash_set<int> > vehicle_allowed_resources_;
581 // clang-format on
583 absl::flat_hash_set<DimensionIndex> affected_dimension_indices_;
584
585 friend class RoutingModel;
586 };
587
591 int64_t value;
592 };
593
596 public:
598 RoutingSearchParameters* search_parameters,
599 int64_t solve_period);
600 bool Solve(const std::vector<RoutingModel::VariableValuePair>& in_state,
601 std::vector<RoutingModel::VariableValuePair>* out_state);
602
603 private:
604 RoutingModel* const model_;
605 const RoutingSearchParameters* const search_parameters_;
606 const int64_t solve_period_ = 0;
607 int64_t call_count_ = 0;
608 operations_research::Assignment* state_ = nullptr;
609 absl::flat_hash_map<operations_research::IntVar*, int> var_to_index_;
610 };
611
613 static const int64_t kNoPenalty;
614
618
622
626 explicit RoutingModel(const RoutingIndexManager& index_manager);
627 RoutingModel(const RoutingIndexManager& index_manager,
628 const RoutingModelParameters& parameters);
629
630 // This type is neither copyable nor movable.
631 RoutingModel(const RoutingModel&) = delete;
633
635
642
647 int RegisterUnaryTransitVector(std::vector<int64_t> values);
648 int RegisterUnaryTransitCallback(
649 TransitCallback1 callback,
650 TransitEvaluatorSign sign = kTransitEvaluatorSignUnknown);
651
652 int RegisterTransitMatrix(
653 std::vector<std::vector<int64_t> /*needed_for_swig*/> values);
654 int RegisterTransitCallback(
655 TransitCallback2 callback,
656 TransitEvaluatorSign sign = kTransitEvaluatorSignUnknown);
657 int RegisterCumulDependentTransitCallback(
658 CumulDependentTransitCallback2 callback);
659 int RegisterStateDependentTransitCallback(VariableIndexEvaluator2 callback);
660
661 const TransitCallback2& TransitCallback(int callback_index) const {
662 CHECK_LT(callback_index, transit_evaluators_.size());
663 return transit_evaluators_[callback_index];
664 }
665 const TransitCallback1& UnaryTransitCallbackOrNull(int callback_index) const {
666 CHECK_LT(callback_index, unary_transit_evaluators_.size());
667 return unary_transit_evaluators_[callback_index];
668 }
670 int callback_index) const {
671 CHECK_LT(callback_index, cumul_dependent_transit_evaluators_.size());
672 return cumul_dependent_transit_evaluators_[callback_index];
673 }
675 int callback_index) const {
676 CHECK_LT(callback_index, state_dependent_transit_evaluators_.size());
677 return state_dependent_transit_evaluators_[callback_index];
678 }
679
681
693
702 bool AddDimension(int evaluator_index, int64_t slack_max, int64_t capacity,
703 bool fix_start_cumul_to_zero, const std::string& name);
704 bool AddDimensionWithVehicleTransits(
705 const std::vector<int>& evaluator_indices, int64_t slack_max,
706 int64_t capacity, bool fix_start_cumul_to_zero, const std::string& name);
707 bool AddDimensionWithVehicleCapacity(int evaluator_index, int64_t slack_max,
708 std::vector<int64_t> vehicle_capacities,
709 bool fix_start_cumul_to_zero,
710 const std::string& name);
711 bool AddDimensionWithVehicleTransitAndCapacity(
712 const std::vector<int>& evaluator_indices, int64_t slack_max,
713 std::vector<int64_t> vehicle_capacities, bool fix_start_cumul_to_zero,
714 const std::string& name);
721 bool AddDimensionWithCumulDependentVehicleTransitAndCapacity(
722 const std::vector<int>& fixed_evaluator_indices,
723 const std::vector<int>& cumul_dependent_evaluator_indices,
724 int64_t slack_max, std::vector<int64_t> vehicle_capacities,
725 bool fix_start_cumul_to_zero, const std::string& name);
726
735 std::pair<int, bool> AddConstantDimensionWithSlack(
736 int64_t value, int64_t capacity, int64_t slack_max,
737 bool fix_start_cumul_to_zero, const std::string& name);
738 std::pair<int, bool> AddConstantDimension(int64_t value, int64_t capacity,
739 bool fix_start_cumul_to_zero,
740 const std::string& name) {
741 return AddConstantDimensionWithSlack(value, capacity, 0,
742 fix_start_cumul_to_zero, name);
743 }
744
753 std::pair<int, bool> AddVectorDimension(std::vector<int64_t> values,
754 int64_t capacity,
755 bool fix_start_cumul_to_zero,
756 const std::string& name);
766 std::pair<int, bool> AddMatrixDimension(
767 std::vector<std::vector<int64_t> /*needed_for_swig*/> values,
768 int64_t capacity, bool fix_start_cumul_to_zero, const std::string& name);
776 const std::vector<int>& pure_transits,
777 const std::vector<int>& dependent_transits,
778 const RoutingDimension* base_dimension, int64_t slack_max,
779 std::vector<int64_t> vehicle_capacities, bool fix_start_cumul_to_zero,
780 const std::string& name) {
781 return AddDimensionDependentDimensionWithVehicleCapacityInternal(
782 pure_transits, dependent_transits, base_dimension, slack_max,
783 std::move(vehicle_capacities), fix_start_cumul_to_zero, name);
784 }
785
787 bool AddDimensionDependentDimensionWithVehicleCapacity(
788 const std::vector<int>& transits, const RoutingDimension* base_dimension,
789 int64_t slack_max, std::vector<int64_t> vehicle_capacities,
790 bool fix_start_cumul_to_zero, const std::string& name);
792 bool AddDimensionDependentDimensionWithVehicleCapacity(
793 int transit, const RoutingDimension* base_dimension, int64_t slack_max,
794 int64_t vehicle_capacity, bool fix_start_cumul_to_zero,
795 const std::string& name);
796 bool AddDimensionDependentDimensionWithVehicleCapacity(
797 int pure_transit, int dependent_transit,
798 const RoutingDimension* base_dimension, int64_t slack_max,
799 int64_t vehicle_capacity, bool fix_start_cumul_to_zero,
800 const std::string& name);
801
803 static RoutingModel::StateDependentTransit MakeStateDependentTransit(
804 const std::function<int64_t(int64_t)>& f, int64_t domain_start,
805 int64_t domain_end);
806
808 // TODO(user): rename.
809 std::vector<std::string> GetAllDimensionNames() const;
811 const std::vector<RoutingDimension*>& GetDimensions() const {
812 return dimensions_.get();
813 }
814
815 std::vector<RoutingDimension*> GetDimensionsWithSoftOrSpanCosts() const;
817 std::vector<RoutingDimension*> GetUnaryDimensions() const;
818
820 std::vector<const RoutingDimension*> GetDimensionsWithGlobalCumulOptimizers()
821 const;
822 std::vector<const RoutingDimension*> GetDimensionsWithLocalCumulOptimizers()
823 const;
824
826 bool HasGlobalCumulOptimizer(const RoutingDimension& dimension) const {
827 return GetGlobalCumulOptimizerIndex(dimension) >= 0;
828 }
829 bool HasLocalCumulOptimizer(const RoutingDimension& dimension) const {
830 return GetLocalCumulOptimizerIndex(dimension) >= 0;
831 }
832
834 GlobalDimensionCumulOptimizer* GetMutableGlobalCumulLPOptimizer(
835 const RoutingDimension& dimension) const;
836 GlobalDimensionCumulOptimizer* GetMutableGlobalCumulMPOptimizer(
837 const RoutingDimension& dimension) const;
838 LocalDimensionCumulOptimizer* GetMutableLocalCumulLPOptimizer(
839 const RoutingDimension& dimension) const;
840 LocalDimensionCumulOptimizer* GetMutableLocalCumulMPOptimizer(
841 const RoutingDimension& dimension) const;
842
844 bool HasDimension(absl::string_view dimension_name) const;
846 const RoutingDimension& GetDimensionOrDie(
847 const std::string& dimension_name) const;
850 RoutingDimension* GetMutableDimension(
851 const std::string& dimension_name) const;
856 void SetPrimaryConstrainedDimension(absl::string_view dimension_name) {
857 DCHECK(dimension_name.empty() || HasDimension(dimension_name));
858 primary_constrained_dimension_ = dimension_name;
859 }
860
861 const std::string& GetPrimaryConstrainedDimension() const {
862 return primary_constrained_dimension_;
863 }
864
866 ResourceGroup* AddResourceGroup();
867 // clang-format off
868 const std::vector<std::unique_ptr<ResourceGroup> >& GetResourceGroups()
869 const {
870 return resource_groups_;
871 }
872 // clang-format on
873 ResourceGroup* GetResourceGroup(int rg_index) const {
874 DCHECK_LT(rg_index, resource_groups_.size());
875 return resource_groups_[rg_index].get();
876 }
877
880 const std::vector<int>& GetDimensionResourceGroupIndices(
881 const RoutingDimension* dimension) const;
882
886 DCHECK_EQ(GetDimensionResourceGroupIndices(dimension).size(), 1);
887 return GetDimensionResourceGroupIndices(dimension)[0];
888 }
889
893
916 DisjunctionIndex AddDisjunction(const std::vector<int64_t>& indices,
917 int64_t penalty = kNoPenalty,
918 int64_t max_cardinality = 1,
919 PenaltyCostBehavior penalty_cost_behavior =
920 PenaltyCostBehavior::PENALIZE_ONCE);
922 const std::vector<DisjunctionIndex>& GetDisjunctionIndices(
923 int64_t index) const {
924 return index_to_disjunctions_[index];
925 }
927
929 template <typename F>
930 void ForEachNodeInDisjunctionWithMaxCardinalityFromIndex(
931 int64_t index, int64_t max_cardinality, F f) const {
932 for (const DisjunctionIndex disjunction : GetDisjunctionIndices(index)) {
933 if (disjunctions_[disjunction].value.max_cardinality == max_cardinality) {
934 for (const int64_t d_index : disjunctions_[disjunction].indices) {
935 f(d_index);
936 }
937 }
938 }
939 }
940#if !defined(SWIGPYTHON)
941
943 const std::vector<int64_t>& GetDisjunctionNodeIndices(
944 DisjunctionIndex index) const {
945 return disjunctions_[index].indices;
946 }
947#endif // !defined(SWIGPYTHON)
948
949 int64_t GetDisjunctionPenalty(DisjunctionIndex index) const {
950 return disjunctions_[index].value.penalty;
951 }
953
954 int64_t GetDisjunctionMaxCardinality(DisjunctionIndex index) const {
955 return disjunctions_[index].value.max_cardinality;
956 }
958
959 PenaltyCostBehavior GetDisjunctionPenaltyCostBehavior(
960 DisjunctionIndex index) const {
961 return disjunctions_[index].value.penalty_cost_behavior;
962 }
964 int GetNumberOfDisjunctions() const { return disjunctions_.size(); }
967 bool HasMandatoryDisjunctions() const;
975 std::vector<std::pair<int64_t, int64_t>> GetPerfectBinaryDisjunctions() const;
982
988 void AddSoftSameVehicleConstraint(std::vector<int64_t> indices, int64_t cost);
991 return same_vehicle_costs_.size();
992 }
994
995 const std::vector<int64_t>& GetSoftSameVehicleIndices(int index) const {
996 return same_vehicle_costs_[index].indices;
997 }
999 int64_t GetSoftSameVehicleCost(int index) const {
1000 return same_vehicle_costs_[index].value;
1001 }
1002
1003
1007 void SetAllowedVehiclesForIndex(absl::Span<const int> vehicles,
1008 int64_t index);
1009
1011 bool IsVehicleAllowedForIndex(int vehicle, int64_t index) const {
1012 return allowed_vehicles_[index].empty() ||
1013 allowed_vehicles_[index].contains(vehicle);
1014 }
1015
1016
1030 // TODO(user): Remove this when model introspection detects linked nodes.
1031 void AddPickupAndDelivery(int64_t pickup, int64_t delivery);
1035 void AddPickupAndDeliverySets(DisjunctionIndex pickup_disjunction,
1036 DisjunctionIndex delivery_disjunction);
1037
1039 struct PickupDeliveryPosition {
1044 int alternative_index = -1;
1045 };
1047 std::optional<PickupDeliveryPosition> GetPickupPosition(
1048 int64_t node_index) const;
1050 std::optional<PickupDeliveryPosition> GetDeliveryPosition(
1051 int64_t node_index) const;
1053 bool IsPickup(int64_t node_index) const {
1054 return index_to_pickup_position_[node_index].pd_pair_index != -1;
1056 bool IsDelivery(int64_t node_index) const {
1057 return index_to_delivery_position_[node_index].pd_pair_index != -1;
1059
1061
1062 void SetPickupAndDeliveryPolicyOfAllVehicles(PickupAndDeliveryPolicy policy);
1063 void SetPickupAndDeliveryPolicyOfVehicle(PickupAndDeliveryPolicy policy,
1064 int vehicle);
1065 PickupAndDeliveryPolicy GetPickupAndDeliveryPolicyOfVehicle(
1066 int vehicle) const;
1069
1070 int GetNumOfSingletonNodes() const;
1071
1072#ifndef SWIG
1074 const std::vector<PickupDeliveryPair>& GetPickupAndDeliveryPairs() const {
1075 return pickup_delivery_pairs_;
1077 const std::vector<std::pair<DisjunctionIndex, DisjunctionIndex>>&
1078 GetPickupAndDeliveryDisjunctions() const {
1079 return pickup_delivery_disjunctions_;
1083
1085 const std::vector<PickupDeliveryPair>&
1086 GetImplicitUniquePickupAndDeliveryPairs() const {
1087 DCHECK(closed_);
1088 return implicit_pickup_delivery_pairs_without_alternatives_;
1089 }
1090#endif // SWIG
1091
1092 // Returns the first pickup or delivery sibling of the given node matching
1093 // the given predicate.
1094 std::optional<int64_t> GetFirstMatchingPickupDeliverySibling(
1095 int64_t node, const std::function<bool(int64_t)>& is_match) const;
1096
1106 enum VisitTypePolicy {
1108 TYPE_ADDED_TO_VEHICLE,
1110 /// (TYPE_ADDED_TO_VEHICLE), if any, is removed from the vehicle.
1111 /// If the type was not previously added to the route or all added instances
1112 /// have already been removed, this visit has no effect on the types.
1122 };
1123 // TODO(user): Support multiple visit types per node?
1124 void SetVisitType(int64_t index, int type, VisitTypePolicy type_policy);
1125 int GetVisitType(int64_t index) const;
1126 const std::vector<int>& GetSingleNodesOfType(int type) const;
1127 const std::vector<int>& GetPairIndicesOfType(int type) const;
1128 VisitTypePolicy GetVisitTypePolicy(int64_t index) const;
1129#ifndef SWIG
1130 const std::vector<std::vector<int>>& GetVisitTypeComponents() const {
1131 return visit_type_components_;
1132 }
1133#endif // SWIG
1134 int GetNumberOfVisitTypes() const { return num_visit_types_; }
1135#ifndef SWIG
1136 const std::vector<std::vector<int>>& GetTopologicallySortedVisitTypes()
1137 const {
1138 DCHECK(closed_);
1139 return topologically_sorted_visit_types_;
1141 const std::vector<std::vector<std::vector<int>>>&
1142 GetTopologicallySortedNodePrecedences() const {
1143 DCHECK(closed_);
1144 return topologically_sorted_node_precedences_;
1145 }
1146#endif // SWIG
1150
1154 void AddHardTypeIncompatibility(int type1, int type2);
1155 void AddTemporalTypeIncompatibility(int type1, int type2);
1157 const absl::flat_hash_set<int>& GetHardTypeIncompatibilitiesOfType(
1158 int type) const;
1159 const absl::flat_hash_set<int>& GetTemporalTypeIncompatibilitiesOfType(
1160 int type) const;
1163 bool HasHardTypeIncompatibilities() const {
1164 return !hard_incompatible_types_per_type_index_.empty();
1165 }
1166 bool HasTemporalTypeIncompatibilities() const {
1167 return !temporal_incompatible_types_per_type_index_.empty();
1168 }
1170
1170 /// NOTE: As of 2019-04, cycles in the requirement graph are not supported,
1171 /// and lead to the dependent nodes being skipped if possible (otherwise
1172 /// the model is considered infeasible).
1173 /// The following functions specify that "dependent_type" requires at least
1174 /// one of the types in "required_type_alternatives".
1175 ///
1176 /// For same-vehicle requirements, a node of dependent type type_D requires at
1177 /// least one node of type type_R among the required alternatives on the same
1178 /// route.
1179 /// NOTE: To avoid unnecessary memory reallocations, it is recommended to only
1180 /// add requirements once all the existing types have been set with
1181 /// SetVisitType().
1183 int dependent_type, absl::flat_hash_set<int> required_type_alternatives);
1189 int dependent_type, absl::flat_hash_set<int> required_type_alternatives);
1196 int dependent_type, absl::flat_hash_set<int> required_type_alternatives);
1197 // clang-format off
1200 const std::vector<absl::flat_hash_set<int> >&
1203 const std::vector<absl::flat_hash_set<int> >&
1206 const std::vector<absl::flat_hash_set<int> >&
1208 // clang-format on
1211 bool HasSameVehicleTypeRequirements() const {
1212 return !same_vehicle_required_type_alternatives_per_type_index_.empty();
1213 }
1214 bool HasTemporalTypeRequirements() const {
1215 return !required_type_alternatives_when_adding_type_index_.empty() ||
1216 !required_type_alternatives_when_removing_type_index_.empty();
1217 }
1218
1219
1219 /// Returns true iff the model has any incompatibilities or requirements set
1220 /// on node types.
1221 bool HasTypeRegulations() const {
1225 }
1231 int64_t UnperformedPenalty(int64_t var_index) const;
1235 int64_t UnperformedPenaltyOrValue(int64_t default_value,
1236 int64_t var_index) const;
1240 int64_t GetDepot() const;
1241
1246 void SetMaximumNumberOfActiveVehicles(int max_active_vehicles) {
1247 max_active_vehicles_ = max_active_vehicles;
1248 }
1250 int GetMaximumNumberOfActiveVehicles() const { return max_active_vehicles_; }
1251 /// Sets the cost function of the model such that the cost of a segment of a
1252 /// route between node 'from' and 'to' is evaluator(from, to), whatever the
1253 /// route or vehicle performing the route.
1254 void SetArcCostEvaluatorOfAllVehicles(int evaluator_index);
1256 void SetArcCostEvaluatorOfVehicle(int evaluator_index, int vehicle);
1259 void SetFixedCostOfAllVehicles(int64_t cost);
1261 void SetFixedCostOfVehicle(int64_t cost, int vehicle);
1265 int64_t GetFixedCostOfVehicle(int vehicle) const;
1266 // Sets the energy cost of a vehicle.
1267 // The energy used by a vehicle is defined as the integral of the
1268 // force dimension over the distance dimension:
1269 // it is the sum over nodes visited by the vehicle of
1270 // force.CumulVar(Next(node)) * distance.TransitVar(node).
1271 // The energy cost of a vehicle is linear in the energy used by the vehicle,
1272 // this call sets the coefficient to cost_per_unit. The cost is zero if unset.
1273 void SetPathEnergyCostOfVehicle(const std::string& force,
1274 const std::string& distance,
1275 int64_t cost_per_unit, int vehicle);
1276 // Sets the energy cost of a vehicle, relative to a threshold.
1277 // The cost per unit of energy is cost_per_unit_below_threshold until the
1278 // force reaches the threshold, then it is cost_per_unit_above_threshold:
1279 // min(threshold, force.CumulVar(Next(node))) * distance.TransitVar(node) *
1280 // cost_per_unit_below_threshold + max(0, force.CumulVar(Next(node)) -
1281 // threshold) * distance.TransitVar(node) * cost_per_unit_above_threshold.
1282 void SetPathEnergyCostsOfVehicle(const std::string& force,
1283 const std::string& distance,
1284 int64_t threshold,
1285 int64_t cost_per_unit_below_threshold,
1286 int64_t cost_per_unit_above_threshold,
1287 int vehicle);
1288
1304 void SetAmortizedCostFactorsOfAllVehicles(int64_t linear_cost_factor,
1305 int64_t quadratic_cost_factor);
1307 void SetAmortizedCostFactorsOfVehicle(int64_t linear_cost_factor,
1308 int64_t quadratic_cost_factor,
1309 int vehicle);
1310
1311 const std::vector<int64_t>& GetAmortizedLinearCostFactorOfVehicles() const {
1312 return linear_cost_factor_of_vehicle_;
1313 }
1314 const std::vector<int64_t>& GetAmortizedQuadraticCostFactorOfVehicles()
1315 const {
1316 return quadratic_cost_factor_of_vehicle_;
1317 }
1319 // Adds a custom route constraint based on a route evaluation callback. The
1320 // callback must not return a value if the route vector is invalid, and
1321 // returns the value of the route otherwise.
1322 // The callback must always return the same value for a given route.
1323#ifndef SWIG
1324 void AddRouteConstraint(
1325 absl::AnyInvocable<std::optional<int64_t>(const std::vector<int64_t>&)>
1326 route_evaluator,
1327 bool costs_are_homogeneous_across_vehicles = false);
1328#endif
1329 std::optional<int64_t> GetRouteCost(const std::vector<int64_t>& route) const {
1330 int64_t route_cost = 0;
1331 for (auto& evaluator : route_evaluators_) {
1332 std::optional<int64_t> cost = evaluator(route);
1333 if (!cost.has_value()) return std::nullopt;
1334 CapAddTo(cost.value(), &route_cost);
1335 }
1336 return route_cost;
1337 }
1338
1339 void SetVehicleUsedWhenEmpty(bool is_used, int vehicle) {
1340 DCHECK_LT(vehicle, vehicles_);
1341 vehicle_used_when_empty_[vehicle] = is_used;
1342 }
1343
1344 bool IsVehicleUsedWhenEmpty(int vehicle) const {
1345 DCHECK_LT(vehicle, vehicles_);
1346 return vehicle_used_when_empty_[vehicle];
1347 }
1348
1350
1351#ifndef SWIG
1353 return first_solution_evaluator_;
1354 }
1355#endif
1357 void SetFirstSolutionEvaluator(Solver::IndexEvaluator2 evaluator) {
1358 first_solution_evaluator_ = std::move(evaluator);
1362
1365 hint_ = hint;
1366 }
1367
1368 const operations_research::Assignment* GetFirstSolutionHint() const {
1369 return hint_;
1370 }
1371 /// Adds a local search operator to the set of operators used to solve the
1372 /// vehicle routing problem.
1374
1376 // Adds a callback called at the beginning of the search.
1377 void AddEnterSearchCallback(std::function<void()> callback);
1378
1384 void AddAtSolutionCallback(std::function<void()> callback,
1385 bool track_unchecked_neighbors = false);
1386 // Internal-only: Adds a callback to reset
1387 // RestoreDimensionValuesForUnchangedRoutes at the beginning of the search.
1388 void AddRestoreDimensionValuesResetCallback(std::function<void()> callback);
1400 int64_t cost);
1404 int64_t cost);
1408 int64_t target);
1412 int64_t target, int64_t cost);
1419 void CloseModel();
1423 const RoutingSearchParameters& search_parameters);
1431 const operations_research::Assignment* assignment = nullptr);
1440 const RoutingSearchParameters& search_parameters,
1441 std::vector<const operations_research::Assignment*>* solutions = nullptr);
1445 const operations_research::Assignment* assignment,
1446 const RoutingSearchParameters& search_parameters,
1447 std::vector<const operations_research::Assignment*>* solutions = nullptr);
1453 const operations_research::Assignment* assignment,
1454 const RoutingSearchParameters& search_parameters,
1455 bool check_solution_in_cp,
1456 absl::flat_hash_set<operations_research::IntVar*>* touched = nullptr);
1460 const std::vector<const operations_research::Assignment*>& assignments,
1461 const RoutingSearchParameters& search_parameters,
1462 std::vector<const operations_research::Assignment*>* solutions = nullptr);
1466 const RoutingSearchParameters& search_parameters);
1473 operations_research::Assignment* target_assignment,
1474 const RoutingModel* source_model,
1475 const operations_research::Assignment* source_assignment);
1483 // TODO(user): Add support for non-homogeneous costs and disjunctions.
1484 int64_t ComputeLowerBound();
1487 int64_t objective_lower_bound() const { return objective_lower_bound_; }
1489 RoutingSearchStatus::Value status() const { return status_; }
1491 const RoutingSearchStats& search_stats() const { return search_stats_; }
1493 bool enable_deep_serialization() const { return enable_deep_serialization_; }
1502 operations_research::IntVar* ApplyLocks(absl::Span<const int64_t> locks);
1511 bool ApplyLocksToAllVehicles(const std::vector<std::vector<int64_t>>& locks,
1512 bool close_routes);
1518 return preassignment_;
1519 }
1520 operations_research::Assignment* MutablePreAssignment() {
1521 return preassignment_;
1522 }
1525 /// solution.
1526 bool WriteAssignment(const std::string& file_name) const;
1528
1528 /// Returns nullptr if the file cannot be opened or if the assignment is not
1529 /// valid.
1530 operations_research::Assignment* ReadAssignment(const std::string& file_name);
1531
1541 const std::vector<std::vector<int64_t>>& routes,
1542 bool ignore_inactive_indices);
1559 bool RoutesToAssignment(const std::vector<std::vector<int64_t>>& routes,
1560 bool ignore_inactive_indices, bool close_routes,
1561 operations_research::Assignment* assignment) const;
1566 std::vector<std::vector<int64_t>>* routes) const;
1571#ifndef SWIG
1572 std::vector<std::vector<int64_t>> GetRoutesFromAssignment(
1573 const operations_research::Assignment& assignment);
1574#endif
1593 const operations_research::Assignment& assignment) const;
1598 const operations_research::Assignment& assignment) const;
1601 void AddIntervalToAssignment(IntervalVar* interval);
1614 const operations_research::Assignment* original_assignment,
1615 absl::Duration duration_limit, bool* time_limit_was_reached = nullptr);
1616
1617#ifndef SWIG
1622 struct TransitionInfo {
1625 FloatSlopePiecewiseLinearFunction travel_start_dependent_travel;
1626
1628 /// (real) travel value Táµ£ given by travel_start_dependent_travel and the
1629 /// compressed travel value considered in the scheduling.
1631
1637
1641
1647
1648 std::string DebugString(std::string line_prefix = "") const;
1649 };
1650
1653 std::vector<TransitionInfo> transition_info;
1656
1657 std::string DebugString(std::string line_prefix = "") const;
1658 };
1659
1660#endif // SWIG
1662#ifndef SWIG
1663 // TODO(user): Revisit if coordinates are added to the RoutingModel class.
1667#endif
1669 int num_neighbors;
1670 bool add_vehicle_starts_to_neighbors = true;
1671 bool add_vehicle_ends_to_neighbors = false;
1672 // In NodeNeighborsByCostClass, neighbors for each node are sorted by
1673 // increasing "cost" for each node. The following parameter determines if
1674 // neighbors are sorted based on distance only when the neighborhood is
1675 // partial, i.e. when num_neighbors entails that not all nodes are
1676 // neighbors.
1679 bool operator==(const NodeNeighborsParameters& other) const {
1680 return num_neighbors == other.num_neighbors &&
1688 template <typename H>
1689 friend H AbslHashValue(H h, const NodeNeighborsParameters& params) {
1690 return H::combine(std::move(h), params.num_neighbors,
1694 }
1695 };
1696 class NodeNeighborsByCostClass {
1697 public:
1698 explicit NodeNeighborsByCostClass(const RoutingModel* routing_model)
1699 : routing_model_(*routing_model) {};
1700
1703 void ComputeNeighbors(const NodeNeighborsParameters& params);
1704
1704 /// Returns the incoming neighbors of the given node for the given
1705 /// cost_class, i.e. all 'neighbor' indices such that neighbor -> node_index
1706 /// is a neighborhood arc for 'cost_class'.
1707 const std::vector<int>& GetIncomingNeighborsOfNodeForCostClass(
1708 int cost_class, int node_index) const {
1709 if (routing_model_.IsStart(node_index)) return empty_neighbors_;
1710
1711 if (node_index_to_incoming_neighbors_by_cost_class_.empty()) {
1712 DCHECK(IsFullNeighborhood());
1713 return all_incoming_nodes_;
1714 }
1715 const std::vector<std::vector<int>>& node_index_to_incoming_neighbors =
1716 node_index_to_incoming_neighbors_by_cost_class_[cost_class];
1717 if (node_index_to_incoming_neighbors.empty()) {
1718 return empty_neighbors_;
1719 }
1720 return node_index_to_incoming_neighbors[node_index];
1721 }
1722
1726 const std::vector<int>& GetOutgoingNeighborsOfNodeForCostClass(
1727 int cost_class, int node_index) const {
1728 if (routing_model_.IsEnd(node_index)) return empty_neighbors_;
1729
1730 if (node_index_to_outgoing_neighbors_by_cost_class_.empty()) {
1731 DCHECK(IsFullNeighborhood());
1732 return all_outgoing_nodes_;
1733 }
1734 const std::vector<std::vector<int>>& node_index_to_outgoing_neighbors =
1735 node_index_to_outgoing_neighbors_by_cost_class_[cost_class];
1736 if (node_index_to_outgoing_neighbors.empty()) {
1737 return empty_neighbors_;
1738 }
1739 return node_index_to_outgoing_neighbors[node_index];
1740 }
1744 bool IsNeighborhoodArcForCostClass(int cost_class, int64_t from,
1745 int64_t to) const {
1746 if (node_index_to_outgoing_neighbor_indicator_by_cost_class_.empty()) {
1747 DCHECK(full_neighborhood_);
1748 return true;
1749 }
1750 if (routing_model_.IsEnd(from)) {
1751 return false;
1753 return node_index_to_outgoing_neighbor_indicator_by_cost_class_
1754 [cost_class][from][to];
1755 }
1756
1757 bool IsFullNeighborhood() const { return full_neighborhood_; }
1758
1759 private:
1760 const RoutingModel& routing_model_;
1761#if __cplusplus >= 202002L
1762 static constexpr std::vector<int> empty_neighbors_ = {};
1763#else
1764 inline static const std::vector<int> empty_neighbors_ = {};
1765#endif
1766
1767 std::vector<std::vector<std::vector<int>>>
1768 node_index_to_incoming_neighbors_by_cost_class_;
1769 std::vector<std::vector<std::vector<int>>>
1770 node_index_to_outgoing_neighbors_by_cost_class_;
1771 std::vector<std::vector<std::vector<bool>>>
1772 node_index_to_outgoing_neighbor_indicator_by_cost_class_;
1773
1774 std::vector<int> all_outgoing_nodes_;
1775 std::vector<int> all_incoming_nodes_;
1776
1777 bool full_neighborhood_ = false;
1778 };
1779
1785 double neighbors_ratio, int64_t min_neighbors,
1786 double& neighbors_ratio_used, bool add_vehicle_starts_to_neighbors = true,
1787 bool add_vehicle_ends_to_neighbors = false,
1788 bool only_sort_neighbors_for_partial_neighborhoods = true);
1792 const NodeNeighborsParameters& params);
1799 CHECK(filter != nullptr);
1800 if (closed_) {
1801 LOG(WARNING) << "Model is closed, filter addition will be ignored.";
1802 }
1803 extra_filters_.push_back({filter, LocalSearchFilterManager::kRelax});
1804 extra_filters_.push_back({filter, LocalSearchFilterManager::kAccept});
1805 }
1809 int64_t Start(int vehicle) const { return paths_metadata_.Starts()[vehicle]; }
1811 int64_t End(int vehicle) const { return paths_metadata_.Ends()[vehicle]; }
1813 bool IsStart(int64_t index) const { return paths_metadata_.IsStart(index); }
1814
1815 bool IsEnd(int64_t index) const { return paths_metadata_.IsEnd(index); }
1818 int VehicleIndex(int64_t index) const {
1819 return paths_metadata_.GetPath(index);
1820 }
1824 int64_t Next(const operations_research::Assignment& assignment,
1825 int64_t index) const;
1826 /// Returns true if the route of 'vehicle' is non empty in 'assignment'.
1827 bool IsVehicleUsed(const operations_research::Assignment& assignment,
1828 int vehicle) const;
1829
1830#if !defined(SWIGPYTHON)
1833 const std::vector<operations_research::IntVar*>& Nexts() const {
1834 return nexts_;
1835 }
1838 const std::vector<operations_research::IntVar*>& VehicleVars() const {
1839 return vehicle_vars_;
1840 }
1841 /// Returns vehicle resource variables for a given resource group, such that
1842 /// ResourceVars(r_g)[v] is the resource variable for vehicle 'v' in resource
1843 /// group 'r_g'.
1844 const std::vector<operations_research::IntVar*>& ResourceVars(
1845 int resource_group) const {
1846 return resource_vars_[resource_group];
1847 }
1848#endif
1849
1851 operations_research::IntVar* NextVar(int64_t index) const {
1852 return nexts_[index];
1853 }
1855 operations_research::IntVar* ActiveVar(int64_t index) const {
1856 return active_[index];
1857 }
1859 /// route of the vehicle is not empty, 0 otherwise.
1860 operations_research::IntVar* ActiveVehicleVar(int vehicle) const {
1861 return vehicle_active_[vehicle];
1862 }
1863 /// Returns the variable specifying whether or not the given vehicle route is
1864 /// considered for costs and constraints. It will be equal to 1 iff the route
1865 /// of the vehicle is not empty OR vehicle_used_when_empty_[vehicle] is true.
1867 return vehicle_route_considered_[vehicle];
1871 operations_research::IntVar* VehicleVar(int64_t index) const {
1872 return vehicle_vars_[index];
1873 }
1874 /// Returns the resource variable for the given vehicle index in the given
1875 /// resource group. If a vehicle doesn't require a resource from the
1876 /// corresponding resource group, then ResourceVar(v, r_g) == -1.
1878 int resource_group) const {
1879 DCHECK_LT(resource_group, resource_vars_.size());
1880 DCHECK_LT(vehicle, resource_vars_[resource_group].size());
1881 return resource_vars_[resource_group][vehicle];
1882 }
1884 operations_research::IntVar* CostVar() const { return cost_; }
1888 int64_t GetArcCostForVehicle(int64_t from_index, int64_t to_index,
1889 int64_t vehicle) const;
1892 return costs_are_homogeneous_across_vehicles_;
1893 }
1896 int64_t GetHomogeneousCost(int64_t from_index, int64_t to_index) const {
1897 return GetArcCostForVehicle(from_index, to_index, /*vehicle=*/0);
1898 }
1899 /// Returns the cost of the arc in the context of the first solution strategy.
1900 /// This is typically a simplification of the actual cost; see the .cc.
1901 int64_t GetArcCostForFirstSolution(int64_t from_index,
1902 int64_t to_index) const;
1904 /// class. Input are variable indices of nodes and the cost class.
1905 /// Unlike GetArcCostForVehicle(), if cost_class is kNoCost, then the
1906 /// returned cost won't necessarily be zero: only some of the components
1907 /// of the cost that depend on the cost class will be omited. See the code
1908 /// for details.
1909 int64_t GetArcCostForClass(int64_t from_index, int64_t to_index,
1910 int64_t /*CostClassIndex*/ cost_class_index) const;
1912 CostClassIndex GetCostClassIndexOfVehicle(int64_t vehicle) const {
1913 DCHECK(closed_);
1914 DCHECK_GE(vehicle, 0);
1915 DCHECK_LT(vehicle, cost_class_index_of_vehicle_.size());
1916 DCHECK_GE(cost_class_index_of_vehicle_[vehicle], 0);
1917 return cost_class_index_of_vehicle_[vehicle];
1918 }
1920 /// cost_class_index.
1921 bool HasVehicleWithCostClassIndex(CostClassIndex cost_class_index) const {
1922 DCHECK(closed_);
1923 if (cost_class_index == kCostClassIndexOfZeroCost) {
1924 return has_vehicle_with_zero_cost_class_;
1925 }
1926 return cost_class_index < cost_classes_.size();
1927 }
1929 int GetCostClassesCount() const { return cost_classes_.size(); }
1931 int GetNonZeroCostClassesCount() const {
1932 return std::max(0, GetCostClassesCount() - 1);
1933 }
1934 VehicleClassIndex GetVehicleClassIndexOfVehicle(int64_t vehicle) const {
1935 DCHECK(closed_);
1936 return vehicle_class_index_of_vehicle_[vehicle];
1939 /// vehicles for this class.
1940 int GetVehicleOfClass(VehicleClassIndex vehicle_class) const {
1941 DCHECK(closed_);
1942 const RoutingModel::VehicleTypeContainer& vehicle_type_container =
1944 if (vehicle_class.value() >= GetVehicleClassesCount() ||
1945 vehicle_type_container.vehicles_per_vehicle_class[vehicle_class.value()]
1946 .empty()) {
1947 return -1;
1949 return vehicle_type_container
1950 .vehicles_per_vehicle_class[vehicle_class.value()]
1951 .front();
1952 }
1954 int GetVehicleClassesCount() const { return num_vehicle_classes_; }
1956 const std::vector<int>& GetSameVehicleIndicesOfIndex(int node) const {
1957 DCHECK(closed_);
1958 return same_vehicle_groups_[same_vehicle_group_[node]];
1959 }
1960 void AddSameActivityGroup(absl::Span<const int> nodes) {
1961 DCHECK(!closed_);
1962 if (nodes.size() <= 1) return;
1963 for (auto it = nodes.begin() + 1; it != nodes.end(); ++it) {
1964 solver_->AddConstraint(
1965 solver_->MakeEquality(ActiveVar(*it), ActiveVar(*(it - 1))));
1966 }
1967 }
1968
1968 /// Returns variable indices of nodes constrained to have the same activity.
1969 const std::vector<int>& GetSameActivityIndicesOfIndex(int node) const {
1970 DCHECK(closed_);
1971 return same_active_var_groups_[same_active_var_group_[node]];
1972 }
1974 int GetSameActivityGroupOfIndex(int node) const {
1975 DCHECK(closed_);
1976 return same_active_var_group_[node];
1979 const std::vector<int>& GetSameActivityGroups() const {
1980 DCHECK(closed_);
1981 return same_active_var_group_;
1984 int GetSameActivityGroupsCount() const {
1985 DCHECK(closed_);
1986 return same_active_var_groups_.size();
1989 const std::vector<int>& GetSameActivityIndicesOfGroup(int group) const {
1990 DCHECK(closed_);
1991 return same_active_var_groups_[group];
1993#ifndef SWIG
1996 void AddOrderedActivityGroup(std::vector<DisjunctionIndex> disjunctions) {
1997 DCHECK(!closed_);
1998 if (disjunctions.size() <= 1) return;
1999 ordered_activity_groups_.push_back(std::move(disjunctions));
2000 }
2001
2002 const std::vector<std::vector<DisjunctionIndex>>& GetOrderedActivityGroups()
2003 const {
2004 return ordered_activity_groups_;
2005 }
2006#endif // SWIG
2007 const VehicleTypeContainer& GetVehicleTypeContainer() const {
2008 DCHECK(closed_);
2009 return vehicle_type_container_;
2011
2014
2015 /// - whether the destination node is mandatory
2016 /// - whether the destination node is bound to the same vehicle as the source
2017 /// - the "primary constrained" dimension (see SetPrimaryConstrainedDimension)
2018 /// It then breaks ties using, in order:
2019 /// - the arc cost (taking unperformed penalties into account)
2020 /// - the size of the vehicle vars of "to1" and "to2" (lowest size wins)
2021 /// - the value: the lowest value of the indices to1 and to2 wins.
2022 /// See the .cc for details.
2023 /// The more constrained arc is typically preferable when building a
2024 /// first solution. This method is intended to be used as a callback for the
2025 /// BestValueByComparisonSelector value selector.
2026 /// Args:
2027 /// from: the variable index of the source node
2028 /// to1: the variable index of the first candidate destination node.
2029 /// to2: the variable index of the second candidate destination node.
2030 bool ArcIsMoreConstrainedThanArc(int64_t from, int64_t to1, int64_t to2);
2035 std::string DebugOutputAssignment(
2036 const operations_research::Assignment& solution_assignment,
2037 const std::string& dimension_to_print) const;
2043#ifndef SWIG
2044 std::vector<std::vector<std::pair<int64_t, int64_t>>> GetCumulBounds(
2045 const operations_research::Assignment& solution_assignment,
2046 const RoutingDimension& dimension);
2047#endif
2050 const operations_research::Assignment& assignment,
2051 bool call_at_solution_monitors);
2054 Solver* solver() const { return solver_.get(); }
2055
2058 bool CheckLimit(absl::Duration offset = absl::ZeroDuration()) {
2059 DCHECK(limit_ != nullptr);
2060 return limit_->CheckWithOffset(offset);
2061 }
2064 absl::Duration RemainingTime() const {
2065 DCHECK(limit_ != nullptr);
2066 return limit_->AbsoluteSolverDeadline() - solver_->Now();
2067 }
2068
2070 void UpdateTimeLimit(absl::Duration time_limit) {
2071 RegularLimit* limit = GetOrCreateLimit();
2072 limit->UpdateLimits(time_limit, std::numeric_limits<int64_t>::max(),
2073 std::numeric_limits<int64_t>::max(),
2074 limit->solutions());
2075 }
2076
2078 absl::Duration TimeBuffer() const { return time_buffer_; }
2079
2081 std::atomic<bool>* GetMutableCPSatInterrupt() { return &interrupt_cp_sat_; }
2083 std::atomic<bool>* GetMutableCPInterrupt() { return &interrupt_cp_; }
2084
2085 void CancelSearch() {
2086 interrupt_cp_sat_ = true;
2087 interrupt_cp_ = true;
2088 }
2092 int nodes() const { return nodes_; }
2093 /// Returns the number of vehicle routes in the model.
2094 int vehicles() const { return vehicles_; }
2096 int64_t Size() const { return nodes_ + vehicles_ - start_end_count_; }
2097
2101 const RoutingSearchParameters& search_parameters) const;
2103 const RoutingSearchParameters& search_parameters) const;
2107 return automatic_first_solution_strategy_;
2108 }
2109
2111 bool IsMatchingModel() const;
2112
2114 /// modification to a route might impact another.
2115 bool AreRoutesInterdependent(const RoutingSearchParameters& parameters) const;
2116
2117#ifndef SWIG
2120 using GetTabuVarsCallback =
2121 std::function<std::vector<operations_research::IntVar*>(RoutingModel*)>;
2122
2123 void SetTabuVarsCallback(GetTabuVarsCallback tabu_var_callback);
2124#endif // SWIG
2125
2127 // TODO(user): Find a way to test and restrict the access at the same time.
2140 const RoutingDimension* dimension,
2141 std::function<int64_t(int64_t)> initializer);
2142#ifndef SWIG
2143 // TODO(user): MakeGreedyDescentLSOperator is too general for routing.h.
2148 static std::unique_ptr<LocalSearchOperator> MakeGreedyDescentLSOperator(
2149 std::vector<operations_research::IntVar*> variables);
2150 // Read access to currently registered search monitors.
2151 const std::vector<SearchMonitor*>& GetSearchMonitors() const {
2152 return monitors_;
2153 }
2154#endif
2160 /// of the start of each route and a guided slack finalizer. Provided there
2161 /// are no time windows and the maximum slacks are large enough, once the
2162 /// cumul of the start of route is fixed, the guided finalizer can find
2163 /// optimal values of the slacks for the rest of the route in time
2164 /// proportional to the length of the route. Therefore the composed finalizer
2165 /// generally works in time O(log(t)*n*m), where t is the latest possible
2166 /// departute time, n is the number of nodes in the network and m is the
2167 /// number of vehicles.
2169 const RoutingDimension* dimension);
2170
2171 const PathsMetadata& GetPathsMetadata() const { return paths_metadata_; }
2172#ifndef SWIG
2173 BinCapacities* GetBinCapacities() { return bin_capacities_.get(); }
2174
2177 void SetSecondaryModel(RoutingModel* secondary_model,
2178 RoutingSearchParameters secondary_parameters) {
2179 DCHECK(!closed_);
2180 secondary_model_ = secondary_model;
2181 secondary_parameters_ = std::move(secondary_parameters);
2183#endif // SWIG
2184
2186 /// vehicle starting or ending at start_end_index.
2187 const std::deque<int>& GetVehiclesOfSameClass(int64_t start_end_index) const;
2188
2192
2194 std::vector<std::pair<int64_t, int64_t>> GetSameVehicleClassArcs(
2195 int64_t from_index, int64_t to_index) const;
2196
2197 private:
2199 enum RoutingLocalSearchOperator {
2200 RELOCATE = 0,
2201 RELOCATE_PAIR,
2202 LIGHT_RELOCATE_PAIR,
2203 RELOCATE_NEIGHBORS,
2204 EXCHANGE,
2205 EXCHANGE_PAIR,
2206 CROSS,
2207 CROSS_EXCHANGE,
2208 TWO_OPT,
2209 OR_OPT,
2210 GLOBAL_CHEAPEST_INSERTION_VISIT_TYPES_LNS,
2211 LOCAL_CHEAPEST_INSERTION_VISIT_TYPES_LNS,
2212 GLOBAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS,
2213 LOCAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS,
2214 GLOBAL_CHEAPEST_INSERTION_PATH_LNS,
2215 LOCAL_CHEAPEST_INSERTION_PATH_LNS,
2216 RELOCATE_PATH_GLOBAL_CHEAPEST_INSERTION_INSERT_UNPERFORMED,
2217 GLOBAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS,
2218 LOCAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS,
2219 RELOCATE_EXPENSIVE_CHAIN,
2220 LIN_KERNIGHAN,
2221 TSP_OPT,
2222 MAKE_ACTIVE,
2223 RELOCATE_AND_MAKE_ACTIVE,
2224 MAKE_ACTIVE_AND_RELOCATE,
2225 EXCHANGE_AND_MAKE_ACTIVE,
2226 EXCHANGE_PATH_START_ENDS_AND_MAKE_ACTIVE,
2227 MAKE_INACTIVE,
2228 MAKE_CHAIN_INACTIVE,
2229 SWAP_ACTIVE,
2230 SWAP_ACTIVE_CHAIN,
2231 EXTENDED_SWAP_ACTIVE,
2232 SHORTEST_PATH_SWAP_ACTIVE,
2233 SHORTEST_PATH_TWO_OPT,
2234 NODE_PAIR_SWAP,
2235 PATH_LNS,
2236 FULL_PATH_LNS,
2237 TSP_LNS,
2238 INACTIVE_LNS,
2239 EXCHANGE_RELOCATE_PAIR,
2240 RELOCATE_SUBTRIP,
2241 EXCHANGE_SUBTRIP,
2242 LOCAL_SEARCH_OPERATOR_COUNTER
2243 };
2244
2248 template <typename T>
2249 struct ValuedNodes {
2250 std::vector<int64_t> indices;
2251 T value;
2252 };
2253 struct DisjunctionValues {
2254 int64_t penalty;
2255 int64_t max_cardinality;
2256 PenaltyCostBehavior penalty_cost_behavior;
2257 };
2258 typedef ValuedNodes<DisjunctionValues> Disjunction;
2259
2262 struct CostCacheElement {
2268 int index;
2269 CostClassIndex cost_class_index;
2270 int64_t cost;
2271 };
2272
2275 template <class DimensionCumulOptimizer>
2276 struct DimensionCumulOptimizers {
2277 std::unique_ptr<DimensionCumulOptimizer> lp_optimizer;
2278 std::unique_ptr<DimensionCumulOptimizer> mp_optimizer;
2279 };
2280
2282 void Initialize();
2283 void AddNoCycleConstraintInternal();
2284 bool AddDimensionWithCapacityInternal(
2285 const std::vector<int>& evaluator_indices,
2286 const std::vector<int>& cumul_dependent_evaluator_indices,
2287 int64_t slack_max, std::vector<int64_t> vehicle_capacities,
2288 bool fix_start_cumul_to_zero, const std::string& name);
2289 bool AddDimensionDependentDimensionWithVehicleCapacityInternal(
2290 const std::vector<int>& pure_transits,
2291 const std::vector<int>& dependent_transits,
2292 const RoutingDimension* base_dimension, int64_t slack_max,
2293 std::vector<int64_t> vehicle_capacities, bool fix_start_cumul_to_zero,
2294 const std::string& name);
2295 bool InitializeDimensionInternal(
2296 const std::vector<int>& evaluator_indices,
2297 const std::vector<int>& cumul_dependent_evaluator_indices,
2298 const std::vector<int>& state_dependent_evaluator_indices,
2299 int64_t slack_max, bool fix_start_cumul_to_zero,
2300 RoutingDimension* dimension);
2301 DimensionIndex GetDimensionIndex(absl::string_view dimension_name) const;
2302
2330 void StoreDimensionCumulOptimizers(const RoutingSearchParameters& parameters);
2331
2337 void FinalizeAllowedVehicles();
2338
2339 void ComputeCostClasses(const RoutingSearchParameters& parameters);
2340 void ComputeVehicleClasses();
2348 void ComputeVehicleTypes();
2350 void ComputeResourceClasses();
2360 void FinalizeVisitTypes();
2361 void ComputeVisitTypesConnectedComponents();
2362 // Called by FinalizeVisitTypes() to setup topologically_sorted_visit_types_.
2363 void TopologicallySortVisitTypes();
2364 // This method updates topologically_sorted_node_precedences_ which contains
2365 // nodes in topological order based on precedence constraints for
2366 // dimensions of the model.
2367 void FinalizePrecedences();
2368 int64_t GetArcCostForClassInternal(int64_t from_index, int64_t to_index,
2369 CostClassIndex cost_class_index) const;
2370 int64_t GetArcCostWithGuidedLocalSearchPenalties(int64_t from_index,
2371 int64_t to_index,
2372 int64_t vehicle) const {
2373 return CapAdd(
2374 GetArcCostForVehicle(from_index, to_index, vehicle),
2375 solver()->GetGuidedLocalSearchPenalty(from_index, to_index, vehicle));
2376 }
2377 std::function<int64_t(int64_t, int64_t, int64_t)>
2378 GetLocalSearchArcCostCallback(
2379 const RoutingSearchParameters& parameters) const;
2380 int64_t GetHomogeneousArcCostWithGuidedLocalSearchPenalties(
2381 int64_t from_index, int64_t to_index) const {
2382 return GetArcCostWithGuidedLocalSearchPenalties(from_index, to_index,
2383 /*vehicle=*/0);
2384 }
2385 std::function<int64_t(int64_t, int64_t)>
2386 GetLocalSearchHomogeneousArcCostCallback(
2387 const RoutingSearchParameters& parameters) const;
2388 void AppendHomogeneousArcCosts(
2389 const RoutingSearchParameters& parameters, int node_index,
2390 std::vector<operations_research::IntVar*>* cost_elements);
2391 void AppendArcCosts(const RoutingSearchParameters& parameters, int node_index,
2392 std::vector<operations_research::IntVar*>* cost_elements);
2393 operations_research::Assignment* DoRestoreAssignment();
2394 static const CostClassIndex kCostClassIndexOfZeroCost;
2395 int64_t SafeGetCostClassInt64OfVehicle(int64_t vehicle) const {
2396 DCHECK_LT(0, vehicles_);
2397 return (vehicle >= 0 ? GetCostClassIndexOfVehicle(vehicle)
2398 : kCostClassIndexOfZeroCost)
2399 .value();
2400 }
2401 int64_t GetDimensionTransitCostSum(int64_t i, int64_t j,
2402 const CostClass& cost_class) const;
2404 operations_research::IntVar* CreateDisjunction(DisjunctionIndex disjunction);
2406 void AddPickupAndDeliverySetsInternal(const std::vector<int64_t>& pickups,
2407 const std::vector<int64_t>& deliveries);
2410 operations_research::IntVar* CreateSameVehicleCost(int vehicle_index);
2413 int FindNextActive(int index, absl::Span<const int64_t> indices) const;
2414
2417 bool RouteCanBeUsedByVehicle(
2418 const operations_research::Assignment& assignment, int start_index,
2419 int vehicle) const;
2427 bool ReplaceUnusedVehicle(
2428 int unused_vehicle, int active_vehicle,
2429 operations_research::Assignment* compact_assignment) const;
2430
2431 void QuietCloseModel();
2432 void QuietCloseModelWithParameters(
2433 const RoutingSearchParameters& parameters) {
2434 if (!closed_) {
2435 CloseModelWithParameters(parameters);
2436 }
2437 }
2438
2440 bool SolveMatchingModel(operations_research::Assignment* assignment,
2441 const RoutingSearchParameters& parameters);
2442#ifndef SWIG
2444 bool AppendAssignmentIfFeasible(
2445 const operations_research::Assignment& assignment,
2446 std::vector<std::unique_ptr<operations_research::Assignment>>*
2447 assignments,
2448 bool call_at_solution_monitors = true);
2449#endif
2451 void LogSolution(const RoutingSearchParameters& parameters,
2452 absl::string_view description, int64_t solution_cost,
2453 int64_t start_time_ms);
2456 operations_research::Assignment* CompactAssignmentInternal(
2457 const operations_research::Assignment& assignment,
2458 bool check_compact_assignment) const;
2461 std::string FindErrorInSearchParametersForModel(
2462 const RoutingSearchParameters& search_parameters) const;
2464 void SetupSearch(const RoutingSearchParameters& search_parameters);
2466 void UpdateSearchFromParametersIfNeeded(
2467 const RoutingSearchParameters& search_parameters);
2469 // TODO(user): Document each auxiliary method.
2470 operations_research::Assignment* GetOrCreateAssignment();
2471 operations_research::Assignment* GetOrCreateTmpAssignment();
2472 RegularLimit* GetOrCreateLimit();
2473 RegularLimit* GetOrCreateCumulativeLimit();
2474 RegularLimit* GetOrCreateLocalSearchLimit();
2475 RegularLimit* GetOrCreateLargeNeighborhoodSearchLimit();
2476 RegularLimit* GetOrCreateFirstSolutionLargeNeighborhoodSearchLimit();
2477 LocalSearchOperator* CreateInsertionOperator();
2478 LocalSearchOperator* CreateMakeInactiveOperator();
2479 void CreateNeighborhoodOperators(const RoutingSearchParameters& parameters);
2480 LocalSearchOperator* ConcatenateOperators(
2481 const RoutingSearchParameters& search_parameters,
2482 const std::vector<LocalSearchOperator*>& operators) const;
2483 LocalSearchOperator* GetNeighborhoodOperators(
2484 const RoutingSearchParameters& search_parameters,
2485 const absl::flat_hash_set<RoutingLocalSearchOperator>&
2486 operators_to_consider) const;
2487
2488 struct FilterOptions {
2489 bool filter_objective;
2490 bool filter_with_cp_solver;
2491
2492 bool operator==(const FilterOptions& other) const {
2493 return other.filter_objective == filter_objective &&
2494 other.filter_with_cp_solver == filter_with_cp_solver;
2495 }
2496 template <typename H>
2497 friend H AbslHashValue(H h, const FilterOptions& options) {
2498 return H::combine(std::move(h), options.filter_objective,
2499 options.filter_with_cp_solver);
2500 }
2501 };
2502 std::vector<LocalSearchFilterManager::FilterEvent> CreateLocalSearchFilters(
2503 const RoutingSearchParameters& parameters, const FilterOptions& options);
2504 LocalSearchFilterManager* GetOrCreateLocalSearchFilterManager(
2505 const RoutingSearchParameters& parameters, const FilterOptions& options);
2506 DecisionBuilder* CreateSolutionFinalizer(
2507 const RoutingSearchParameters& parameters);
2508 void CreateFirstSolutionDecisionBuilders(
2509 const RoutingSearchParameters& search_parameters);
2510 DecisionBuilder* GetFirstSolutionDecisionBuilder(
2511 const RoutingSearchParameters& search_parameters) const;
2512 IntVarFilteredDecisionBuilder* GetFilteredFirstSolutionDecisionBuilderOrNull(
2513 const RoutingSearchParameters& parameters) const;
2514#ifndef SWIG
2515 template <typename Heuristic, typename... Args>
2516 IntVarFilteredDecisionBuilder* CreateIntVarFilteredDecisionBuilder(
2517 const Args&... args);
2518#endif
2519 LocalSearchPhaseParameters* CreateLocalSearchParameters(
2520 const RoutingSearchParameters& search_parameters, bool secondary_ls);
2521 DecisionBuilder* CreatePrimaryLocalSearchDecisionBuilder(
2522 const RoutingSearchParameters& search_parameters);
2523 void SetupDecisionBuilders(const RoutingSearchParameters& search_parameters);
2524 void SetupMetaheuristics(const RoutingSearchParameters& search_parameters);
2525 void SetupAssignmentCollector(
2526 const RoutingSearchParameters& search_parameters);
2527 void SetupTrace(const RoutingSearchParameters& search_parameters);
2528 void SetupImprovementLimit(const RoutingSearchParameters& search_parameters);
2529 void SetupSearchMonitors(const RoutingSearchParameters& search_parameters);
2530 bool UsesLightPropagation(
2531 const RoutingSearchParameters& search_parameters) const;
2532 GetTabuVarsCallback tabu_var_callback_;
2533
2534 // Detects implicit pickup delivery pairs. These pairs are
2535 // non-pickup/delivery pairs for which there exists a unary dimension such
2536 // that the demand d of the implicit pickup is positive and the demand of the
2537 // implicit delivery is equal to -d.
2538 void DetectImplicitPickupAndDeliveries();
2539
2540 int GetVehicleStartClass(int64_t start) const;
2541
2542 void InitSameVehicleGroups(int number_of_groups) {
2543 same_vehicle_group_.assign(Size(), 0);
2544 same_vehicle_groups_.assign(number_of_groups, {});
2545 }
2546 void SetSameVehicleGroup(int index, int group) {
2547 same_vehicle_group_[index] = group;
2548 same_vehicle_groups_[group].push_back(index);
2549 }
2550
2551 void InitSameActiveVarGroups(int number_of_groups) {
2552 same_active_var_group_.assign(Size(), 0);
2553 same_active_var_groups_.assign(number_of_groups, {});
2554 }
2555 void SetSameActiveVarGroup(int index, int group) {
2556 same_active_var_group_[index] = group;
2557 same_active_var_groups_[group].push_back(index);
2558 }
2559
2562 int GetGlobalCumulOptimizerIndex(const RoutingDimension& dimension) const;
2563 int GetLocalCumulOptimizerIndex(const RoutingDimension& dimension) const;
2564
2566 std::unique_ptr<Solver> solver_;
2567 int nodes_;
2568 int vehicles_;
2569 int max_active_vehicles_;
2570 Constraint* no_cycle_constraint_ = nullptr;
2572 std::vector<operations_research::IntVar*> nexts_;
2573 std::vector<operations_research::IntVar*> vehicle_vars_;
2574 std::vector<operations_research::IntVar*> active_;
2580 // clang-format off
2581 std::vector<std::vector<operations_research::IntVar*> > resource_vars_;
2582 // clang-format on
2583 // The following vectors are indexed by vehicle index.
2584 std::vector<operations_research::IntVar*> vehicle_active_;
2585 std::vector<operations_research::IntVar*> vehicle_route_considered_;
2590 std::vector<operations_research::IntVar*> is_bound_to_end_;
2591 mutable RevSwitch is_bound_to_end_ct_added_;
2593 absl::flat_hash_map<std::string, DimensionIndex> dimension_name_to_index_;
2594 util_intops::StrongVector<DimensionIndex, RoutingDimension*> dimensions_;
2599 // clang-format off
2600 std::vector<std::unique_ptr<ResourceGroup> > resource_groups_;
2602 util_intops::StrongVector<DimensionIndex, std::vector<int> >
2603 dimension_resource_group_indices_;
2604
2608 std::vector<DimensionCumulOptimizers<GlobalDimensionCumulOptimizer> >
2609 global_dimension_optimizers_;
2610 util_intops::StrongVector<DimensionIndex, int> global_optimizer_index_;
2611 std::vector<DimensionCumulOptimizers<LocalDimensionCumulOptimizer> >
2612 local_dimension_optimizers_;
2613 util_intops::StrongVector<DimensionIndex, int> local_optimizer_index_;
2614 // clang-format on
2615 std::string primary_constrained_dimension_;
2617 operations_research::IntVar* cost_ = nullptr;
2618 std::vector<int> vehicle_to_transit_cost_;
2619 std::vector<int64_t> fixed_cost_of_vehicle_;
2620 std::vector<CostClassIndex> cost_class_index_of_vehicle_;
2621 bool has_vehicle_with_zero_cost_class_;
2622 std::vector<int64_t> linear_cost_factor_of_vehicle_;
2623 std::vector<int64_t> quadratic_cost_factor_of_vehicle_;
2624 bool vehicle_amortized_cost_factors_set_;
2625 mutable std::vector<
2626 absl::AnyInvocable<std::optional<int64_t>(const std::vector<int64_t>&)>>
2627 route_evaluators_;
2639 std::vector<bool> vehicle_used_when_empty_;
2640#ifndef SWIG
2641 absl::flat_hash_map<
2642 std::pair<std::string, std::string>,
2643 std::vector<Solver::PathEnergyCostConstraintSpecification::EnergyCost>,
2644 absl::Hash<std::pair<std::string, std::string>>>
2645 force_distance_to_energy_costs_;
2646 util_intops::StrongVector<CostClassIndex, CostClass> cost_classes_;
2647#endif // SWIG
2648 bool costs_are_homogeneous_across_vehicles_;
2649 bool cache_callbacks_;
2650 mutable std::vector<CostCacheElement> cost_cache_;
2651 std::vector<VehicleClassIndex> vehicle_class_index_of_vehicle_;
2652 int num_vehicle_classes_;
2653
2654 VehicleTypeContainer vehicle_type_container_;
2655 std::function<int(int64_t)> vehicle_start_class_callback_;
2657 util_intops::StrongVector<DisjunctionIndex, Disjunction> disjunctions_;
2658 // clang-format off
2659 std::vector<std::vector<DisjunctionIndex> > index_to_disjunctions_;
2661 std::vector<ValuedNodes<int64_t> > same_vehicle_costs_;
2663#ifndef SWIG
2664 std::vector<absl::flat_hash_set<int>> allowed_vehicles_;
2665#endif // SWIG
2667 std::vector<PickupDeliveryPair> pickup_delivery_pairs_;
2668 std::vector<PickupDeliveryPair>
2669 implicit_pickup_delivery_pairs_without_alternatives_;
2670 std::vector<std::pair<DisjunctionIndex, DisjunctionIndex> >
2671 pickup_delivery_disjunctions_;
2672 // If node_index is a pickup, index_to_pickup_position_[node_index] contains
2673 // the PickupDeliveryPosition {pickup_delivery_index, alternative_index}
2674 // such that (pickup_delivery_pairs_[pickup_delivery_index]
2675 // .pickup_alternatives)[alternative_index] == node_index
2676 std::vector<PickupDeliveryPosition> index_to_pickup_position_;
2677 // Same as above for deliveries.
2678 std::vector<PickupDeliveryPosition> index_to_delivery_position_;
2679 // clang-format on
2680 std::vector<PickupAndDeliveryPolicy> vehicle_pickup_delivery_policy_;
2681 // Same vehicle group to which a node belongs.
2682 std::vector<int> same_vehicle_group_;
2683 // Same vehicle node groups.
2684 std::vector<std::vector<int>> same_vehicle_groups_;
2685 // Same active var group to which a node belongs.
2686 std::vector<int> same_active_var_group_;
2687 // Same active var groups.
2688 std::vector<std::vector<int>> same_active_var_groups_;
2689 // Ordered activity groups.
2690 std::vector<std::vector<DisjunctionIndex>> ordered_activity_groups_;
2691 // Node visit types
2692 // Variable index to visit type index.
2693 std::vector<int> index_to_visit_type_;
2694 // Variable index to VisitTypePolicy.
2695 std::vector<VisitTypePolicy> index_to_type_policy_;
2696 // clang-format off
2697 std::vector<std::vector<int> > single_nodes_of_type_;
2698 std::vector<std::vector<int> > pair_indices_of_type_;
2699
2700 std::vector<absl::flat_hash_set<int> >
2701 hard_incompatible_types_per_type_index_;
2702 std::vector<absl::flat_hash_set<int> >
2703 temporal_incompatible_types_per_type_index_;
2704 const absl::flat_hash_set<int> empty_incompatibility_set_;
2705
2706 std::vector<std::vector<absl::flat_hash_set<int> > >
2707 same_vehicle_required_type_alternatives_per_type_index_;
2708 std::vector<std::vector<absl::flat_hash_set<int> > >
2709 required_type_alternatives_when_adding_type_index_;
2710 std::vector<std::vector<absl::flat_hash_set<int> > >
2711 required_type_alternatives_when_removing_type_index_;
2712 const std::vector<absl::flat_hash_set<int>> empty_required_type_alternatives_;
2713 absl::flat_hash_map</*type*/int, absl::flat_hash_set<VisitTypePolicy> >
2714 trivially_infeasible_visit_types_to_policies_;
2715
2716 // Visit types sorted topologically based on required-->dependent requirement
2717 // arcs between the types (if the requirement/dependency graph is acyclic).
2718 // Visit types of the same topological level are sorted in each sub-vector
2719 // by decreasing requirement "tightness", computed as the pair of the two
2720 // following criteria:
2721 //
2722 // 1) How highly *dependent* this type is, determined by
2723 // (total number of required alternative sets for that type)
2724 // / (average number of types in the required alternative sets)
2725 // 2) How highly *required* this type t is, computed as
2726 // SUM_{S required set containing t} ( 1 / |S| ),
2727 // i.e. the sum of reverse number of elements of all required sets
2728 // containing the type t.
2729 //
2730 // The higher these two numbers, the tighter the type is wrt requirements.
2731 std::vector<std::vector<int> > topologically_sorted_visit_types_;
2732 std::vector<std::vector<int>> visit_type_components_;
2733 // clang-format on
2734 int num_visit_types_;
2735 std::vector<std::vector<std::vector<int>>>
2736 topologically_sorted_node_precedences_;
2737 // Two indices are equivalent if they correspond to the same node (as given
2738 // to the constructors taking a RoutingIndexManager).
2739 std::vector<int> index_to_equivalence_class_;
2740 const PathsMetadata paths_metadata_;
2741 // TODO(user): b/62478706 Once the port is done, this shouldn't be needed
2742 // anymore.
2743 RoutingIndexManager manager_;
2744 int start_end_count_;
2745 // Model status
2746 bool closed_ = false;
2748 bool enable_deep_serialization_ = true;
2749
2750 // Secondary routing solver
2751 RoutingModel* secondary_model_ = nullptr;
2752 RoutingSearchParameters secondary_parameters_;
2753 std::unique_ptr<SecondaryOptimizer> secondary_optimizer_;
2754
2755 // Search data
2756 std::vector<DecisionBuilder*> first_solution_decision_builders_;
2757 std::vector<IntVarFilteredDecisionBuilder*>
2758 first_solution_filtered_decision_builders_;
2759 Solver::IndexEvaluator2 first_solution_evaluator_;
2760 FirstSolutionStrategy::Value automatic_first_solution_strategy_ =
2762 const operations_research::Assignment* hint_ = nullptr;
2763 std::vector<LocalSearchOperator*> local_search_operators_;
2764 std::vector<SearchMonitor*> monitors_;
2765 std::vector<SearchMonitor*> secondary_ls_monitors_;
2766 std::vector<SearchMonitor*> at_solution_monitors_;
2767 std::vector<std::function<void()>> restore_dimension_values_reset_callbacks_;
2768 int monitors_before_setup_ = 0;
2769 int monitors_after_setup_ = 0;
2770 SearchMonitor* metaheuristic_ = nullptr;
2771 SearchMonitor* search_log_ = nullptr;
2772 bool local_optimum_reached_ = false;
2773 // Best lower bound found during the search.
2774 int64_t objective_lower_bound_ = kint64min;
2775 SolutionCollector* collect_assignments_ = nullptr;
2776 SolutionCollector* collect_secondary_ls_assignments_ = nullptr;
2777 SolutionCollector* collect_one_assignment_ = nullptr;
2778 SolutionCollector* optimized_dimensions_assignment_collector_ = nullptr;
2779 RoutingSearchParameters search_parameters_;
2780 DecisionBuilder* solve_db_ = nullptr;
2781 DecisionBuilder* improve_db_ = nullptr;
2782 DecisionBuilder* secondary_ls_db_ = nullptr;
2783 DecisionBuilder* restore_assignment_ = nullptr;
2784 DecisionBuilder* restore_tmp_assignment_ = nullptr;
2785 operations_research::Assignment* assignment_ = nullptr;
2786 operations_research::Assignment* preassignment_ = nullptr;
2787 operations_research::Assignment* tmp_assignment_ = nullptr;
2788 LocalSearchOperator* primary_ls_operator_ = nullptr;
2789 LocalSearchOperator* secondary_ls_operator_ = nullptr;
2790 std::vector<operations_research::IntVar*> extra_vars_;
2791 std::vector<IntervalVar*> extra_intervals_;
2792 std::vector<LocalSearchOperator*> extra_operators_;
2793 absl::flat_hash_map<FilterOptions, LocalSearchFilterManager*>
2794 local_search_filter_managers_;
2795 std::vector<LocalSearchFilterManager::FilterEvent> extra_filters_;
2796 absl::flat_hash_map<NodeNeighborsParameters,
2797 std::unique_ptr<NodeNeighborsByCostClass>>
2798 node_neighbors_by_cost_class_per_size_;
2799 std::unique_ptr<FinalizerVariables> finalizer_variables_;
2800#ifndef SWIG
2801 std::unique_ptr<SweepArranger> sweep_arranger_;
2802#endif
2803
2804 RegularLimit* limit_ = nullptr;
2805 RegularLimit* cumulative_limit_ = nullptr;
2806 RegularLimit* ls_limit_ = nullptr;
2807 RegularLimit* lns_limit_ = nullptr;
2808 RegularLimit* first_solution_lns_limit_ = nullptr;
2809 absl::Duration time_buffer_;
2810
2811 RoutingSearchStats search_stats_;
2812
2813 std::atomic<bool> interrupt_cp_sat_;
2814 std::atomic<bool> interrupt_cp_;
2815
2816 typedef std::pair<int64_t, int64_t> CacheKey;
2817 typedef absl::flat_hash_map<CacheKey, int64_t> TransitCallbackCache;
2818 typedef absl::flat_hash_map<CacheKey, StateDependentTransit>
2819 StateDependentTransitCallbackCache;
2820
2821 // All transit callbacks are stored in transit_evaluators_,
2822 // we refer to callbacks by the index in this vector.
2823 // We maintain unary_transit_evaluators_[] (with the same size) to store
2824 // callbacks that are unary:
2825 // - if a callback is unary, it is in unary_transit_evaluators_[i],
2826 // and a binary version is stored at transit_evaluators_[i].
2827 // - if a callback is binary, it is stored at transit_evaluators_[i],
2828 // and unary_transit_evaluators_[i] is nullptr.
2829 std::vector<TransitCallback1> unary_transit_evaluators_;
2830 std::vector<TransitCallback2> transit_evaluators_;
2831 std::vector<TransitEvaluatorSign> transit_evaluator_sign_;
2832
2833 std::vector<VariableIndexEvaluator2> state_dependent_transit_evaluators_;
2834 std::vector<std::unique_ptr<StateDependentTransitCallbackCache>>
2835 state_dependent_transit_evaluators_cache_;
2836
2837 std::vector<CumulDependentTransitCallback2>
2838 cumul_dependent_transit_evaluators_;
2839
2840 // Returns global BinCapacities state, may be nullptr.
2841 std::unique_ptr<BinCapacities> bin_capacities_;
2842
2843 friend class RoutingDimension;
2844 friend class RoutingModelInspector;
2845 friend class ResourceGroup::Resource;
2846};
2847
2849class OR_DLL RoutingModelVisitor : public operations_research::BaseObject {
2850 public:
2852 static const char kLightElement[];
2853 static const char kLightElement2[];
2854 static const char kRemoveValues[];
2855};
2857#if !defined(SWIG)
2858void FillPathEvaluation(absl::Span<const int64_t> path,
2859 const RoutingModel::TransitCallback2& evaluator,
2860 std::vector<int64_t>* values);
2861#endif // !defined(SWIG)
2864 public:
2865 explicit TypeRegulationsChecker(const RoutingModel& model);
2866 virtual ~TypeRegulationsChecker() = default;
2868 bool CheckVehicle(int vehicle,
2869 const std::function<int64_t(int64_t)>& next_accessor);
2870
2871 protected:
2872#ifndef SWIG
2873 using VisitTypePolicy = RoutingModel::VisitTypePolicy;
2874#endif // SWIG
2875
2880 int num_type_added_to_vehicle = 0;
2886 int num_type_removed_from_vehicle = 0;
2889 /// If positive, the type is considered on the vehicle from the start of the
2890 /// route until this position.
2892 };
2898 bool TypeOccursOnRoute(int type) const;
2905 bool TypeCurrentlyOnRoute(int type, int pos) const;
2906
2907 void InitializeCheck(int vehicle,
2908 const std::function<int64_t(int64_t)>& next_accessor);
2909 virtual void OnInitializeCheck() {}
2910 virtual bool HasRegulationsToCheck() const = 0;
2911 virtual bool CheckTypeRegulations(int type, VisitTypePolicy policy,
2912 int pos) = 0;
2913 virtual bool FinalizeCheck() const { return true; }
2914
2915 const RoutingModel& model_;
2916
2917 private:
2918 std::vector<TypePolicyOccurrence> occurrences_of_type_;
2919 std::vector<int64_t> current_route_visits_;
2920};
2921
2924 public:
2926 bool check_hard_incompatibilities);
2927 ~TypeIncompatibilityChecker() override = default;
2929 private:
2930 bool HasRegulationsToCheck() const override;
2931 bool CheckTypeRegulations(int type, VisitTypePolicy policy, int pos) override;
2934
2935 bool check_hard_incompatibilities_;
2937
2940 public:
2941 explicit TypeRequirementChecker(const RoutingModel& model)
2942 : TypeRegulationsChecker(model) {}
2943 ~TypeRequirementChecker() override = default;
2944
2945 private:
2946 bool HasRegulationsToCheck() const override;
2947 void OnInitializeCheck() override {
2948 types_with_same_vehicle_requirements_on_route_.clear();
2949 }
2950 // clang-format off
2952 /// the required types is on the route at position 'pos'.
2953 bool CheckRequiredTypesCurrentlyOnRoute(
2954 absl::Span<const absl::flat_hash_set<int>> required_type_alternatives,
2955 int pos);
2956 // clang-format on
2957 bool CheckTypeRegulations(int type, VisitTypePolicy policy, int pos) override;
2958 bool FinalizeCheck() const override;
2959
2960 absl::flat_hash_set<int> types_with_same_vehicle_requirements_on_route_;
2961};
2962
2975
3004 public:
3005 explicit TypeRegulationsConstraint(const RoutingModel& model);
3006
3007 void Post() override;
3008 void InitialPropagate() override;
3009
3010 private:
3011 void PropagateNodeRegulations(int node);
3012 void CheckRegulationsOnVehicle(int vehicle);
3013
3014 const RoutingModel& model_;
3015 TypeIncompatibilityChecker incompatibility_checker_;
3016 TypeRequirementChecker requirement_checker_;
3017 std::vector<Demon*> vehicle_demons_;
3018};
3032struct BoundCost {
3033 int64_t bound;
3034 int64_t cost;
3035 BoundCost() : bound(0), cost(0) {}
3036 BoundCost(int64_t bound, int64_t cost) : bound(bound), cost(cost) {}
3037};
3038
3039class SimpleBoundCosts {
3040 public:
3041 SimpleBoundCosts(int num_bounds, BoundCost default_bound_cost)
3042 : bound_costs_(num_bounds, default_bound_cost) {}
3043#ifndef SWIG
3044 BoundCost& bound_cost(int element) { return bound_costs_[element]; }
3045#endif
3046 BoundCost bound_cost(int element) const { return bound_costs_[element]; }
3047 int Size() { return bound_costs_.size(); }
3049 SimpleBoundCosts operator=(const SimpleBoundCosts&) = delete;
3051 private:
3052 std::vector<BoundCost> bound_costs_;
3053};
3054
3055/// Dimensions represent quantities accumulated at nodes along the routes. They
3056/// represent quantities such as weights or volumes carried along the route, or
3057/// distance or times.
3058///
3059/// Quantities at a node are represented by "cumul" variables and the increase
3060/// or decrease of quantities between nodes are represented by "transit"
3061/// variables. These variables are linked as follows:
3063/// if j == next(i),
3064/// cumuls(j) = cumuls(i) + transits(i) + slacks(i) +
3065/// state_dependent_transits(i)
3066///
3067/// where slack is a positive slack variable (can represent waiting times for
3068/// a time dimension), and state_dependent_transits is a non-purely functional
3069/// version of transits_. Favour transits over state_dependent_transits when
3070/// possible, because purely functional callbacks allow more optimisations and
3071/// make the model faster and easier to solve.
3072// TODO(user): Break constraints need to know the service time of nodes
3075class RoutingDimension {
3076 public:
3077 // This type is neither copyable nor movable.
3078 RoutingDimension(const RoutingDimension&) = delete;
3080
3083 RoutingModel* model() const { return model_; }
3087 int64_t GetTransitValue(int64_t from_index, int64_t to_index,
3088 int64_t vehicle) const;
3091 int64_t GetTransitValueFromClass(int64_t from_index, int64_t to_index,
3092 int64_t vehicle_class) const {
3093 return model_->TransitCallback(class_evaluators_[vehicle_class])(from_index,
3094 to_index);
3095 }
3099 return cumuls_[index];
3100 }
3101 operations_research::IntVar* TransitVar(int64_t index) const {
3102 return transits_[index];
3103 }
3104 operations_research::IntVar* FixedTransitVar(int64_t index) const {
3105 return fixed_transits_[index];
3106 }
3107 operations_research::IntVar* SlackVar(int64_t index) const {
3108 return slacks_[index];
3109 }
3113 // TODO(user): Routing should not store its data in a CP model.
3114
3115
3116 void SetCumulVarRange(int64_t index, int64_t min, int64_t max) {
3118 }
3120 int64_t GetCumulVarMin(int64_t index) const { return CumulVar(index)->Min(); }
3122 int64_t GetCumulVarMax(int64_t index) const { return CumulVar(index)->Max(); }
3124#if !defined(SWIGPYTHON)
3126
3126 /// vectors instead (indexed by int64_t var index).
3127 const std::vector<operations_research::IntVar*>& cumuls() const {
3128 return cumuls_;
3129 }
3130 const std::vector<operations_research::IntVar*>& fixed_transits() const {
3131 return fixed_transits_;
3132 }
3133 const std::vector<operations_research::IntVar*>& transits() const {
3134 return transits_;
3136 const std::vector<operations_research::IntVar*>& slacks() const {
3137 return slacks_;
3138 }
3139#if !defined(SWIGCSHARP) && !defined(SWIGJAVA)
3141 const std::vector<SortedDisjointIntervalList>& forbidden_intervals() const {
3142 return forbidden_intervals_;
3143 }
3145 SortedDisjointIntervalList GetAllowedIntervalsInRange(
3146 int64_t index, int64_t min_value, int64_t max_value) const;
3150 int64_t min_value) const {
3151 DCHECK_LT(index, forbidden_intervals_.size());
3153 forbidden_intervals_[index];
3154 const auto first_forbidden_interval_it =
3155 forbidden_intervals.FirstIntervalGreaterOrEqual(min_value);
3156 if (first_forbidden_interval_it != forbidden_intervals.end() &&
3157 min_value >= first_forbidden_interval_it->start) {
3158
3159 return CapAdd(first_forbidden_interval_it->end, 1);
3162 return min_value;
3163 }
3169 int64_t max_value) const {
3170 DCHECK_LT(index, forbidden_intervals_.size());
3172 forbidden_intervals_[index];
3173 const auto last_forbidden_interval_it =
3174 forbidden_intervals.LastIntervalLessOrEqual(max_value);
3175 if (last_forbidden_interval_it != forbidden_intervals.end() &&
3176 max_value <= last_forbidden_interval_it->end) {
3178 return CapSub(last_forbidden_interval_it->start, 1);
3179 }
3181 return max_value;
3182 }
3183
3184 const std::vector<int64_t>& vehicle_capacities() const {
3185 return vehicle_capacities_;
3186 }
3187 /// Returns the callback evaluating the transit value between two node indices
3188 /// for a given vehicle.
3189 const RoutingModel::TransitCallback2& transit_evaluator(int vehicle) const {
3190 return model_->TransitCallback(
3191 class_evaluators_[vehicle_to_class_[vehicle]]);
3192 }
3193
3196 const RoutingModel::TransitCallback2& class_transit_evaluator(
3197 RoutingVehicleClassIndex vehicle_class) const {
3198 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3199 DCHECK_NE(vehicle, -1);
3200 return transit_evaluator(vehicle);
3201 }
3202
3203 /// Returns true iff all transit evaluators for this dimension are unary.
3204 bool IsUnary() const {
3205 for (int evaluator_index : class_evaluators_) {
3206 if (model_->UnaryTransitCallbackOrNull(evaluator_index) == nullptr) {
3207 return false;
3209 }
3210 return true;
3211 }
3212
3215 /// returns a null callback.
3217 int vehicle) const {
3218 return model_->UnaryTransitCallbackOrNull(
3219 class_evaluators_[vehicle_to_class_[vehicle]]);
3220 }
3221 const RoutingModel::TransitCallback2& GetBinaryTransitEvaluator(
3222 int vehicle) const {
3223 return model_->TransitCallback(
3224 class_evaluators_[vehicle_to_class_[vehicle]]);
3225 }
3228 bool AreVehicleTransitsPositive(int vehicle) const {
3229 const int evaluator_index = class_evaluators_[vehicle_to_class_[vehicle]];
3230 return model()->transit_evaluator_sign_[evaluator_index] ==
3232 }
3233 bool AllTransitEvaluatorSignsAreUnknown() const;
3234 RoutingModel::TransitEvaluatorSign GetTransitEvaluatorSign(
3235 int vehicle) const {
3236 const int evaluator_index = class_evaluators_[vehicle_to_class_[vehicle]];
3237 return model()->transit_evaluator_sign_[evaluator_index];
3238 }
3239 int vehicle_to_class(int vehicle) const { return vehicle_to_class_[vehicle]; }
3240 int vehicle_to_cumul_dependent_class(int vehicle) const {
3241 if (vehicle_to_cumul_dependent_class_.empty()) {
3242 return -1;
3243 }
3244 DCHECK_LT(vehicle, vehicle_to_cumul_dependent_class_.size());
3245 return vehicle_to_cumul_dependent_class_[vehicle];
3246 }
3247#endif
3248#endif
3252 void SetSpanUpperBoundForVehicle(int64_t upper_bound, int vehicle);
3253 /// Sets a cost proportional to the dimension span on a given vehicle,
3254 /// or on all vehicles at once. "coefficient" must be nonnegative.
3255 /// This is handy to model costs proportional to idle time when the dimension
3256 /// represents time.
3257 /// The cost for a vehicle is
3258 /// span_cost = coefficient * (dimension end value - dimension start value).
3259 void SetSpanCostCoefficientForVehicle(int64_t coefficient, int vehicle);
3260 void SetSpanCostCoefficientForAllVehicles(int64_t coefficient);
3266
3268 void SetSlackCostCoefficientForVehicle(int64_t coefficient, int vehicle);
3269 void SetSlackCostCoefficientForAllVehicles(int64_t coefficient);
3276 void SetGlobalSpanCostCoefficient(int64_t coefficient);
3277
3278#ifndef SWIG
3284 const PiecewiseLinearFunction& cost);
3287 bool HasCumulVarPiecewiseLinearCost(int64_t index) const;
3291 int64_t index) const;
3292#endif
3293
3302 void SetCumulVarSoftUpperBound(int64_t index, int64_t upper_bound,
3303 int64_t coefficient);
3306 bool HasCumulVarSoftUpperBound(int64_t index) const;
3310 int64_t GetCumulVarSoftUpperBound(int64_t index) const;
3314 int64_t GetCumulVarSoftUpperBoundCoefficient(int64_t index) const;
3315
3325 void SetCumulVarSoftLowerBound(int64_t index, int64_t lower_bound,
3326 int64_t coefficient);
3329 bool HasCumulVarSoftLowerBound(int64_t index) const;
3333 int64_t GetCumulVarSoftLowerBound(int64_t index) const;
3337 int64_t GetCumulVarSoftLowerBoundCoefficient(int64_t index) const;
3353 // TODO(user): Remove if !defined when routing.swig is repaired.
3354#if !defined(SWIGPYTHON)
3355 void SetBreakIntervalsOfVehicle(std::vector<IntervalVar*> breaks, int vehicle,
3356 int pre_travel_evaluator,
3357 int post_travel_evaluator);
3358#endif // !defined(SWIGPYTHON)
3359
3361 void SetBreakIntervalsOfVehicle(std::vector<IntervalVar*> breaks, int vehicle,
3362 std::vector<int64_t> node_visit_transits);
3363
3368 void SetBreakDistanceDurationOfVehicle(int64_t distance, int64_t duration,
3369 int vehicle);
3372 void InitializeBreaks();
3374 bool HasBreakConstraints() const;
3375#if !defined(SWIGPYTHON)
3379 std::vector<IntervalVar*> breaks, int vehicle,
3380 std::vector<int64_t> node_visit_transits,
3381 std::function<int64_t(int64_t, int64_t)> delays);
3382
3384 const std::vector<IntervalVar*>& GetBreakIntervalsOfVehicle(
3385 int vehicle) const;
3388 // clang-format off
3389 const std::vector<std::pair<int64_t, int64_t> >&
3390 GetBreakDistanceDurationOfVehicle(int vehicle) const;
3391 // clang-format on
3392#endif
3393 int GetPreTravelEvaluatorOfVehicle(int vehicle) const;
3394 int GetPostTravelEvaluatorOfVehicle(int vehicle) const;
3395
3397 const RoutingDimension* base_dimension() const { return base_dimension_; }
3405 int64_t ShortestTransitionSlack(int64_t node) const;
3406
3408 operations_research::RoutingDimensionIndex index() const {
3409 return index_;
3410 }
3412 const std::string& name() const { return name_; }
3413
3415#ifndef SWIG
3416 const ReverseArcListGraph<int, int>& GetPathPrecedenceGraph() const {
3417 return path_precedence_graph_;
3418 }
3419#endif // SWIG
3420
3428 /// each pickup (delivery) index is in a single pickup/delivery pair.first
3429 /// (pair.second).
3430 typedef std::function<int64_t(int, int)> PickupToDeliveryLimitFunction;
3431
3433 PickupToDeliveryLimitFunction limit_function, int pair_index);
3434
3435 bool HasPickupToDeliveryLimits() const;
3436#ifndef SWIG
3437 int64_t GetPickupToDeliveryLimitForPair(int pair_index,
3438 int pickup_alternative_index,
3439 int delivery_alternative_index) const;
3440
3441 struct NodePrecedence {
3442 int64_t first_node;
3443 int64_t second_node;
3444 int64_t offset;
3445 enum class PerformedConstraint {
3446 // first_node and/or second_node can be unperformed.
3447 kFirstAndSecondIndependent,
3448 // if second_node is performed, first_node must be performed.
3449 kSecondImpliesFirst,
3450 // if first_node is performed, second_node must be performed.
3451 kFirstImpliesSecond,
3452 // first_node is performed iff second_node is performed.
3453 kFirstAndSecondEqual,
3454 };
3455 PerformedConstraint performed_constraint;
3456 };
3457
3458 void AddNodePrecedence(NodePrecedence precedence) {
3459 node_precedences_.push_back(precedence);
3460 }
3461 const std::vector<NodePrecedence>& GetNodePrecedences() const {
3462 return node_precedences_;
3465 /// the performed status of the first and second node of a precedence.
3466 enum class PrecedenceStatus {
3467 kActive,
3468 kInactive,
3469 kInvalid,
3470 };
3472 bool first_unperformed, bool second_unperformed,
3474 switch (performed_constraint) {
3476 if (first_unperformed || second_unperformed) {
3479 break;
3480 case NodePrecedence::PerformedConstraint::kSecondImpliesFirst:
3481 if (first_unperformed) {
3482 if (!second_unperformed) return PrecedenceStatus::kInvalid;
3484 }
3485 if (second_unperformed) return PrecedenceStatus::kInactive;
3486 break;
3488 if (second_unperformed) {
3489 if (!first_unperformed) return PrecedenceStatus::kInvalid;
3492 if (first_unperformed) return PrecedenceStatus::kInactive;
3493 break;
3494 case NodePrecedence::PerformedConstraint::kFirstAndSecondEqual:
3495 if (first_unperformed != second_unperformed) {
3496 return PrecedenceStatus::kInvalid;
3497 }
3498 if (first_unperformed) return PrecedenceStatus::kInactive;
3499 break;
3500 }
3501 return PrecedenceStatus::kActive;
3502 }
3503 void AddNodePrecedence(
3504 int64_t first_node, int64_t second_node, int64_t offset,
3505 NodePrecedence::PerformedConstraint performed_constraint =
3506 NodePrecedence::PerformedConstraint::kFirstAndSecondIndependent) {
3507 AddNodePrecedence({first_node, second_node, offset, performed_constraint});
3508 }
3509#else
3510 void AddNodePrecedence(int64_t first_node, int64_t second_node,
3511 int64_t offset) {
3512 AddNodePrecedence(
3513 {first_node, second_node, offset,
3514 NodePrecedence::PerformedConstraint::kFirstAndSecondIndependent});
3515 }
3516#endif // SWIG
3517
3518 int64_t GetSpanUpperBoundForVehicle(int vehicle) const {
3519 return vehicle_span_upper_bounds_[vehicle];
3520 }
3521#ifndef SWIG
3522 const std::vector<int64_t>& vehicle_span_upper_bounds() const {
3523 return vehicle_span_upper_bounds_;
3524 }
3525#endif // SWIG
3526 int64_t GetSpanCostCoefficientForVehicle(int vehicle) const {
3527 return vehicle_span_cost_coefficients_[vehicle];
3528 }
3529#ifndef SWIG
3530 int64_t GetSpanCostCoefficientForVehicleClass(
3531 RoutingVehicleClassIndex vehicle_class) const {
3532 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3533 DCHECK_NE(vehicle, -1);
3534 return GetSpanCostCoefficientForVehicle(vehicle);
3535 }
3536#endif // SWIG
3537#ifndef SWIG
3538 const std::vector<int64_t>& vehicle_span_cost_coefficients() const {
3539 return vehicle_span_cost_coefficients_;
3540 }
3541#endif // SWIG
3542#ifndef SWIG
3543 const std::vector<int64_t>& vehicle_slack_cost_coefficients() const {
3544 return vehicle_slack_cost_coefficients_;
3545 }
3546#endif // SWIG
3547 int64_t GetSlackCostCoefficientForVehicle(int vehicle) const {
3548 return vehicle_slack_cost_coefficients_[vehicle];
3549 }
3550#ifndef SWIG
3552 RoutingVehicleClassIndex vehicle_class) const {
3553 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3554 DCHECK_NE(vehicle, -1);
3555 return GetSlackCostCoefficientForVehicle(vehicle);
3556 }
3557#endif // SWIG
3559 return global_span_cost_coefficient_;
3560 }
3561
3562 int64_t GetGlobalOptimizerOffset() const {
3563 DCHECK_GE(global_optimizer_offset_, 0);
3564 return global_optimizer_offset_;
3565 }
3566 int64_t GetLocalOptimizerOffsetForVehicle(int vehicle) const {
3567 if (vehicle >= local_optimizer_offset_for_vehicle_.size()) {
3568 return 0;
3569 }
3570 DCHECK_GE(local_optimizer_offset_for_vehicle_[vehicle], 0);
3571 return local_optimizer_offset_for_vehicle_[vehicle];
3572 }
3573
3576 void SetSoftSpanUpperBoundForVehicle(BoundCost bound_cost, int vehicle) {
3577 if (!HasSoftSpanUpperBounds()) {
3578 vehicle_soft_span_upper_bound_ = std::make_unique<SimpleBoundCosts>(
3579 model_->vehicles(), BoundCost{kint64max, 0});
3580 }
3581 vehicle_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost;
3583 bool HasSoftSpanUpperBounds() const {
3584 return vehicle_soft_span_upper_bound_ != nullptr;
3585 }
3587 DCHECK(HasSoftSpanUpperBounds());
3588 return vehicle_soft_span_upper_bound_->bound_cost(vehicle);
3589 }
3592 void SetQuadraticCostSoftSpanUpperBoundForVehicle(BoundCost bound_cost,
3593 int vehicle) {
3594 if (!HasQuadraticCostSoftSpanUpperBounds()) {
3595 vehicle_quadratic_cost_soft_span_upper_bound_ =
3596 std::make_unique<SimpleBoundCosts>(model_->vehicles(),
3597 BoundCost{kint64max, 0});
3598 }
3599 vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle) =
3600 bound_cost;
3601 }
3602 bool HasQuadraticCostSoftSpanUpperBounds() const {
3603 return vehicle_quadratic_cost_soft_span_upper_bound_ != nullptr;
3604 }
3605 BoundCost GetQuadraticCostSoftSpanUpperBoundForVehicle(int vehicle) const {
3607 return vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle);
3608 }
3609
3610 private:
3611 struct SoftBound {
3613 int64_t bound;
3614 int64_t coefficient;
3615 };
3616
3617 struct PiecewiseLinearCost {
3618 PiecewiseLinearCost() : var(nullptr), cost(nullptr) {}
3620 std::unique_ptr<PiecewiseLinearFunction> cost;
3621 };
3623 class SelfBased {};
3624 RoutingDimension(RoutingModel* model, std::vector<int64_t> vehicle_capacities,
3625 const std::string& name,
3628 const std::string& name, SelfBased);
3629 void Initialize(absl::Span<const int> transit_evaluators,
3630 absl::Span<const int> cumul_dependent_transit_evaluators,
3631 absl::Span<const int> state_dependent_transit_evaluators,
3632 int64_t slack_max);
3633 void InitializeCumuls();
3634 void InitializeTransits(
3635 absl::Span<const int> transit_evaluators,
3636 absl::Span<const int> cumul_dependent_transit_evaluators,
3637 absl::Span<const int> state_dependent_transit_evaluators,
3638 int64_t slack_max);
3639 void InitializeTransitVariables(int64_t slack_max);
3641 void SetupCumulVarSoftUpperBoundCosts(
3642 std::vector<operations_research::IntVar*>* cost_elements) const;
3644 void SetupCumulVarSoftLowerBoundCosts(
3645 std::vector<operations_research::IntVar*>* cost_elements) const;
3646 void SetupCumulVarPiecewiseLinearCosts(
3647 std::vector<operations_research::IntVar*>* cost_elements) const;
3650 void SetupGlobalSpanCost(
3651 std::vector<operations_research::IntVar*>* cost_elements) const;
3652 void SetupSlackAndDependentTransitCosts() const;
3654 void CloseModel(bool use_light_propagation);
3655
3656 void SetOffsetForGlobalOptimizer(int64_t offset) {
3657 global_optimizer_offset_ = std::max(Zero(), offset);
3658 }
3660 void SetVehicleOffsetsForLocalOptimizer(std::vector<int64_t> offsets) {
3662 std::transform(offsets.begin(), offsets.end(), offsets.begin(),
3663 [](int64_t offset) { return std::max(Zero(), offset); });
3664 local_optimizer_offset_for_vehicle_ = std::move(offsets);
3665 }
3666
3667 std::vector<operations_research::IntVar*> cumuls_;
3668 std::vector<SortedDisjointIntervalList> forbidden_intervals_;
3669 std::vector<operations_research::IntVar*> capacity_vars_;
3670 const std::vector<int64_t> vehicle_capacities_;
3671 std::vector<operations_research::IntVar*> transits_;
3672 std::vector<operations_research::IntVar*> fixed_transits_;
3675 std::vector<int> class_evaluators_;
3676 std::vector<int> vehicle_to_class_;
3677
3681 std::vector<int> cumul_dependent_class_evaluators_;
3682 std::vector<int> vehicle_to_cumul_dependent_class_;
3683#ifndef SWIG
3684 ReverseArcListGraph<int, int> path_precedence_graph_;
3685#endif
3686 // For every {first_node, second_node, offset} element in node_precedences_,
3687 // if both first_node and second_node are performed, then
3688 // cumuls_[second_node] must be greater than (or equal to)
3689 // cumuls_[first_node] + offset.
3690 std::vector<NodePrecedence> node_precedences_;
3691
3692 // The transits of a dimension may depend on its cumuls or the cumuls of
3693 // another dimension. There can be no cycles, except for self loops, a
3694 // typical example for this is a time dimension.
3695 const RoutingDimension* const base_dimension_;
3696 // Values in state_dependent_class_evaluators_ correspond to the evaluators
3697 // in RoutingModel::state_dependent_transit_evaluators_ for each vehicle
3698 // class.
3699 std::vector<int> state_dependent_class_evaluators_;
3700 std::vector<int> state_dependent_vehicle_to_class_;
3701
3702 // For each pickup/delivery pair_index for which limits have been set,
3703 // pickup_to_delivery_limits_per_pair_index_[pair_index] contains the
3704 // PickupToDeliveryLimitFunction for the pickup and deliveries in this pair.
3705 std::vector<PickupToDeliveryLimitFunction>
3706 pickup_to_delivery_limits_per_pair_index_;
3707
3708 // Used if some vehicle has breaks in this dimension, typically time.
3709 bool break_constraints_are_initialized_ = false;
3710 // clang-format off
3711 std::vector<std::vector<IntervalVar*> > vehicle_break_intervals_;
3712 std::vector<std::vector<std::pair<int64_t, int64_t> > >
3713 vehicle_break_distance_duration_;
3714 // clang-format on
3715 // For each vehicle, stores the part of travel that is made directly
3716 // after (before) the departure (arrival) node of the travel.
3717 // These parts of the travel are non-interruptible, in particular by a break.
3718 std::vector<int> vehicle_pre_travel_evaluators_;
3719 std::vector<int> vehicle_post_travel_evaluators_;
3720
3721 std::vector<operations_research::IntVar*> slacks_;
3722 std::vector<operations_research::IntVar*> dependent_transits_;
3723 std::vector<int64_t> vehicle_span_upper_bounds_;
3724 int64_t global_span_cost_coefficient_;
3725 std::vector<int64_t> vehicle_span_cost_coefficients_;
3726 std::vector<int64_t> vehicle_slack_cost_coefficients_;
3727 std::vector<SoftBound> cumul_var_soft_upper_bound_;
3728 std::vector<SoftBound> cumul_var_soft_lower_bound_;
3729 std::vector<PiecewiseLinearCost> cumul_var_piecewise_linear_cost_;
3730 RoutingModel* const model_;
3731 const operations_research::RoutingDimensionIndex index_;
3732 const std::string name_;
3733 int64_t global_optimizer_offset_;
3734 std::vector<int64_t> local_optimizer_offset_for_vehicle_;
3736 std::unique_ptr<SimpleBoundCosts> vehicle_soft_span_upper_bound_;
3737 std::unique_ptr<SimpleBoundCosts>
3738 vehicle_quadratic_cost_soft_span_upper_bound_;
3739 friend class RoutingModel;
3740 friend class RoutingModelInspector;
3741};
3742
3747bool SolveModelWithSat(RoutingModel* model, RoutingSearchStats* search_stats,
3748 const RoutingSearchParameters& search_parameters,
3749 const operations_research::Assignment* initial_solution,
3751
3752} // namespace operations_research
3753#endif // ORTOOLS_CONSTRAINT_SOLVER_ROUTING_H_
#define OR_DLL
Definition base_export.h:27
virtual void SetRange(int64_t l, int64_t u)
This method sets both the min and the max of the expression.
Generic filter-based decision builder using an IntVarFilteredHeuristic.
The base class for all local search operators.
bool IsStart(int64_t node) const
Definition routing.h:230
const std::vector< int64_t > & Paths() const
Definition routing.h:236
bool IsEnd(int64_t node) const
Definition routing.h:231
const std::vector< int64_t > & Ends() const
Definition routing.h:240
int64_t End(int path) const
Definition routing.h:239
PathsMetadata(const RoutingIndexManager &manager)
Definition routing.h:210
int GetPath(int64_t start_or_end_node) const
Definition routing.h:232
int64_t Start(int path) const
Definition routing.h:238
const std::vector< int64_t > & Starts() const
Definition routing.h:237
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
Definition search.cc:4675
A reversible switch that can switch once from false to true.
void SetCumulVarSoftUpperBound(int64_t index, int64_t upper_bound, int64_t coefficient)
Definition routing.cc:7392
bool HasBreakConstraints() const
Returns true if any break interval or break distance was defined.
Definition routing.cc:7617
int64_t GetCumulVarSoftUpperBoundCoefficient(int64_t index) const
Definition routing.cc:7415
const RoutingDimension * base_dimension() const
Returns the parent in the dependency tree if any or nullptr otherwise.
Definition routing.h:3417
int vehicle_to_cumul_dependent_class(int vehicle) const
Definition routing.h:3259
int64_t GetCumulVarMin(int64_t index) const
Gets the current minimum of the cumul variable associated to index.
Definition routing.h:3139
void SetCumulVarRange(int64_t index, int64_t min, int64_t max)
Restricts the range of the cumul variable associated to index.
Definition routing.h:3135
const std::vector< operations_research::IntVar * > & cumuls() const
Definition routing.h:3146
int64_t GetPickupToDeliveryLimitForPair(int pair_index, int pickup_alternative_index, int delivery_alternative_index) const
Definition routing.cc:7676
const std::vector< int64_t > & vehicle_slack_cost_coefficients() const
Definition routing.h:3563
void SetSpanCostCoefficientForAllVehicles(int64_t coefficient)
Definition routing.cc:7302
int64_t GetCumulVarSoftUpperBound(int64_t index) const
Definition routing.cc:7407
void SetSpanUpperBoundForVehicle(int64_t upper_bound, int vehicle)
Definition routing.cc:7286
const std::string & name() const
Returns the name of the dimension.
Definition routing.h:3432
void SetBreakIntervalsOfVehicle(std::vector< IntervalVar * > breaks, int vehicle, int pre_travel_evaluator, int post_travel_evaluator)
Definition routing.cc:7578
void SetSlackCostCoefficientForAllVehicles(int64_t coefficient)
Definition routing.cc:7320
const std::vector< IntervalVar * > & GetBreakIntervalsOfVehicle(int vehicle) const
Returns the break intervals set by SetBreakIntervalsOfVehicle().
Definition routing.cc:7621
bool HasCumulVarSoftUpperBound(int64_t index) const
Definition routing.cc:7402
void SetCumulVarSoftLowerBound(int64_t index, int64_t lower_bound, int64_t coefficient)
Definition routing.cc:7444
int64_t GetSlackCostCoefficientForVehicleClass(RoutingVehicleClassIndex vehicle_class) const
Definition routing.h:3571
int64_t GetSlackCostCoefficientForVehicle(int vehicle) const
Definition routing.h:3567
void SetPickupToDeliveryLimitFunctionForPair(PickupToDeliveryLimitFunction limit_function, int pair_index)
Definition routing.cc:7662
int64_t GetLastPossibleLessOrEqualValueForNode(int64_t index, int64_t max_value) const
Definition routing.h:3187
bool HasCumulVarPiecewiseLinearCost(int64_t index) const
Definition routing.cc:7345
const std::vector< NodePrecedence > & GetNodePrecedences() const
Definition routing.h:3481
bool HasQuadraticCostSoftSpanUpperBounds() const
Definition routing.h:3622
int64_t GetCumulVarSoftLowerBound(int64_t index) const
Definition routing.cc:7459
bool IsUnary() const
Returns true iff all transit evaluators for this dimension are unary.
Definition routing.h:3223
int GetPostTravelEvaluatorOfVehicle(int vehicle) const
Definition routing.cc:7634
RoutingModel * model() const
Returns the model on which the dimension was created.
Definition routing.h:3102
const RoutingModel::TransitCallback1 & GetUnaryTransitEvaluator(int vehicle) const
Definition routing.h:3235
const std::vector< SortedDisjointIntervalList > & forbidden_intervals() const
Returns forbidden intervals for each node.
Definition routing.h:3160
const PiecewiseLinearFunction * GetCumulVarPiecewiseLinearCost(int64_t index) const
Definition routing.cc:7350
operations_research::RoutingDimensionIndex index() const
Returns the index of the dimension in the model.
Definition routing.h:3428
const RoutingModel::TransitCallback2 & transit_evaluator(int vehicle) const
Definition routing.h:3208
bool HasCumulVarSoftLowerBound(int64_t index) const
Definition routing.cc:7454
const std::vector< int64_t > & vehicle_capacities() const
Returns the capacities for all vehicles.
Definition routing.h:3203
std::function< int64_t(int, int)> PickupToDeliveryLimitFunction
Definition routing.h:3450
RoutingDimension(const RoutingDimension &)=delete
operations_research::IntVar * CumulVar(int64_t index) const
Definition routing.h:3117
static PrecedenceStatus GetPrecedenceStatus(bool first_unperformed, bool second_unperformed, NodePrecedence::PerformedConstraint performed_constraint)
Definition routing.h:3491
void SetBreakDistanceDurationOfVehicle(int64_t distance, int64_t duration, int vehicle)
Definition routing.cc:7640
BoundCost GetSoftSpanUpperBoundForVehicle(int vehicle) const
Definition routing.h:3606
int64_t GetCumulVarSoftLowerBoundCoefficient(int64_t index) const
Definition routing.cc:7467
void SetCumulVarPiecewiseLinearCost(int64_t index, const PiecewiseLinearFunction &cost)
Definition routing.cc:7326
const std::vector< int64_t > & vehicle_span_cost_coefficients() const
Definition routing.h:3558
int64_t GetFirstPossibleGreaterOrEqualValueForNode(int64_t index, int64_t min_value) const
Definition routing.h:3168
void SetSlackCostCoefficientForVehicle(int64_t coefficient, int vehicle)
Definition routing.cc:7313
const std::vector< std::pair< int64_t, int64_t > > & GetBreakDistanceDurationOfVehicle(int vehicle) const
Definition routing.cc:7656
int GetPreTravelEvaluatorOfVehicle(int vehicle) const
!defined(SWIGPYTHON)
Definition routing.cc:7628
void SetGlobalSpanCostCoefficient(int64_t coefficient)
Definition routing.cc:7308
void SetSpanCostCoefficientForVehicle(int64_t coefficient, int vehicle)
Definition routing.cc:7294
int64_t global_span_cost_coefficient() const
Definition routing.h:3578
Manager for any NodeIndex <-> variable index conversion.
const std::vector< int > & GetIncomingNeighborsOfNodeForCostClass(int cost_class, int node_index) const
Definition routing.h:1715
friend H AbslHashValue(H h, const Attributes &attributes)
Definition routing.h:426
friend bool operator==(const Attributes &a, const Attributes &b)
Definition routing.h:421
A Resource sets attributes (costs/constraints) for a set of dimensions.
Definition routing.h:441
const ResourceGroup::Attributes & GetDimensionAttributes(DimensionIndex index) const
Definition routing.h:443
int AddResource(Attributes attributes, const RoutingDimension *dimension)
Definition routing.cc:1155
const util_intops::StrongVector< ResourceClassIndex, std::vector< int > > & GetResourceIndicesPerClass() const
Definition routing.h:533
void SetAllowedResourcesForVehicle(int vehicle, const std::vector< int > &allowed_resource_indices)
Definition routing.h:485
bool IsResourceAllowedForVehicle(int resource, int vehicle) const
Definition routing.h:507
const Attributes & GetDimensionAttributesForClass(DimensionIndex dimension_index, ResourceClassIndex rc_index) const
Definition routing.h:541
bool VehicleRequiresAResource(int vehicle) const
Definition routing.h:481
const std::vector< int > & GetVehiclesRequiringAResource() const
Definition routing.h:477
const Resource & GetResource(int resource_index) const
Definition routing.h:514
const absl::flat_hash_set< int > & GetResourcesMarkedAllowedForVehicle(int vehicle) const
Definition routing.h:502
const std::vector< int > & GetResourceIndicesInClass(ResourceClassIndex resource_class) const
Definition routing.h:526
const std::vector< Resource > & GetResources() const
Definition routing.h:513
ResourceClassIndex GetResourceClassIndex(int resource_index) const
Definition routing.h:537
const absl::flat_hash_set< DimensionIndex > & GetAffectedDimensionIndices() const
Definition routing.h:518
SecondaryOptimizer(RoutingModel *model, RoutingSearchParameters *search_parameters, int64_t solve_period)
Definition routing.cc:1239
bool Solve(const std::vector< RoutingModel::VariableValuePair > &in_state, std::vector< RoutingModel::VariableValuePair > *out_state)
Definition routing.cc:1261
void SetPathEnergyCostOfVehicle(const std::string &force, const std::string &distance, int64_t cost_per_unit, int vehicle)
Definition routing.cc:1321
bool HasHardTypeIncompatibilities() const
Definition routing.h:1167
operations_research::FirstSolutionStrategy::Value GetAutomaticFirstSolutionStrategy() const
Returns the automatic first solution strategy selected.
Definition routing.h:2114
void AddSameVehicleRequiredTypeAlternatives(int dependent_type, absl::flat_hash_set< int > required_type_alternatives)
Definition routing.cc:4521
bool HasLocalCumulOptimizer(const RoutingDimension &dimension) const
Definition routing.h:829
bool ApplyLocksToAllVehicles(const std::vector< std::vector< int64_t > > &locks, bool close_routes)
Definition routing.cc:3974
RoutingModel(const RoutingModel &)=delete
void AddWeightedVariableMaximizedByFinalizer(operations_research::IntVar *var, int64_t cost)
Definition routing.cc:6601
bool HasTemporalTypeRequirements() const
Definition routing.h:1219
operations_research::IntVar * ApplyLocks(absl::Span< const int64_t > locks)
Definition routing.cc:3953
std::pair< int, bool > AddConstantDimensionWithSlack(int64_t value, int64_t capacity, int64_t slack_max, bool fix_start_cumul_to_zero, const std::string &name)
Definition routing.cc:836
RoutingModel(const RoutingIndexManager &index_manager)
Definition routing.cc:514
CostClassIndex GetCostClassIndexOfVehicle(int64_t vehicle) const
Get the cost class index of the given vehicle.
Definition routing.h:1920
operations_research::IntVar * VehicleRouteConsideredVar(int vehicle) const
Definition routing.h:1874
bool HasMaxCardinalityConstrainedDisjunctions() const
Definition routing.cc:1954
std::optional< PickupDeliveryPosition > GetPickupPosition(int64_t node_index) const
Returns the pickup and delivery positions where the node is a pickup.
Definition routing.cc:2099
void AddLocalSearchFilter(LocalSearchFilter *filter)
Definition routing.h:1806
bool HasVehicleWithCostClassIndex(CostClassIndex cost_class_index) const
Definition routing.h:1929
int GetVisitType(int64_t index) const
Definition routing.cc:4458
const std::vector< SearchMonitor * > & GetSearchMonitors() const
Definition routing.h:2160
bool AreRoutesInterdependent(const RoutingSearchParameters &parameters) const
Definition routing.cc:5817
bool HasTemporalTypeIncompatibilities() const
Definition routing.h:1170
const operations_research::Assignment * SolveWithIteratedLocalSearch(const RoutingSearchParameters &search_parameters)
Definition routing.cc:3542
int64_t GetNumberOfDecisionsInFirstSolution(const RoutingSearchParameters &search_parameters) const
Definition routing.cc:3980
int64_t Start(int vehicle) const
Definition routing.h:1817
const operations_research::Assignment * PackCumulsOfOptimizerDimensionsFromAssignment(const operations_research::Assignment *original_assignment, absl::Duration duration_limit, bool *time_limit_was_reached=nullptr)
Definition routing.cc:126
const VehicleTypeContainer & GetVehicleTypeContainer() const
Definition routing.h:2015
RoutingDisjunctionIndex DisjunctionIndex
Definition routing.h:271
void AddSearchMonitor(SearchMonitor *monitor)
Adds a search monitor to the search used to solve the routing model.
Definition routing.cc:3098
operations_research::IntVar * ActiveVar(int64_t index) const
Returns the active variable of the node corresponding to index.
Definition routing.h:1863
int64_t GetArcCostForClass(int64_t from_index, int64_t to_index, int64_t cost_class_index) const
Definition routing.cc:4308
void SetAssignmentFromOtherModelAssignment(operations_research::Assignment *target_assignment, const RoutingModel *source_model, const operations_research::Assignment *source_assignment)
Definition routing.cc:3669
const operations_research::Assignment * Solve(const operations_research::Assignment *assignment=nullptr)
Definition routing.cc:3169
void SetAmortizedCostFactorsOfVehicle(int64_t linear_cost_factor, int64_t quadratic_cost_factor, int vehicle)
Sets the linear and quadratic cost factor of the given vehicle.
Definition routing.cc:1363
const std::vector< int64_t > & GetAmortizedLinearCostFactorOfVehicles() const
Definition routing.h:1318
void AddIntervalToAssignment(IntervalVar *interval)
Definition routing.cc:6654
bool CostsAreHomogeneousAcrossVehicles() const
Whether costs are homogeneous across all vehicles.
Definition routing.h:1899
operations_research::Assignment * CompactAssignment(const operations_research::Assignment &assignment) const
Definition routing.cc:3862
operations_research::Assignment * CompactAndCheckAssignment(const operations_research::Assignment &assignment) const
Definition routing.cc:3867
void AddVariableMinimizedByFinalizer(operations_research::IntVar *var)
Definition routing.cc:6614
const std::vector< int > & GetPairIndicesOfType(int type) const
Definition routing.cc:4468
static const DimensionIndex kNoDimension
Definition routing.h:621
int GetVehicleClassesCount() const
Returns the number of different vehicle classes in the model.
Definition routing.h:1962
const std::vector< absl::flat_hash_set< int > > & GetRequiredTypeAlternativesWhenRemovingType(int type) const
Returns the set of requirement alternatives when removing the given type.
Definition routing.cc:4615
RoutingTransitCallback2 TransitCallback2
Definition routing.h:275
void AddLocalSearchOperator(LocalSearchOperator *ls_operator)
Definition routing.cc:2209
int GetCostClassesCount() const
Returns the number of different cost classes in the model.
Definition routing.h:1937
int GetDimensionResourceGroupIndex(const RoutingDimension *dimension) const
Definition routing.h:885
void AddToAssignment(operations_research::IntVar *var)
Adds an extra variable to the vehicle routing assignment.
Definition routing.cc:6650
const std::string & GetPrimaryConstrainedDimension() const
Get the primary constrained dimension, or an empty string if it is unset.
Definition routing.h:861
const CumulDependentTransitCallback2 & CumulDependentTransitCallback(int callback_index) const
Definition routing.h:669
const std::vector< RoutingDimension * > & GetDimensions() const
Returns all dimensions of the model.
Definition routing.h:811
const absl::flat_hash_set< int > & GetTemporalTypeIncompatibilitiesOfType(int type) const
Definition routing.cc:4510
absl::Duration TimeBuffer() const
Returns the time buffer to safely return a solution.
Definition routing.h:2086
DecisionBuilder * MakeSelfDependentDimensionFinalizer(const RoutingDimension *dimension)
const absl::flat_hash_set< int > & GetHardTypeIncompatibilitiesOfType(int type) const
Returns visit types incompatible with a given type.
Definition routing.cc:4500
std::function< StateDependentTransit(int64_t, int64_t)> VariableIndexEvaluator2
Definition routing.h:296
void SetAmortizedCostFactorsOfAllVehicles(int64_t linear_cost_factor, int64_t quadratic_cost_factor)
Sets the linear and quadratic cost factor of all vehicles.
Definition routing.cc:1355
void CloseModelWithParameters(const RoutingSearchParameters &search_parameters)
Definition routing.cc:2550
const operations_research::Assignment * SolveFromAssignmentsWithParameters(const std::vector< const operations_research::Assignment * > &assignments, const RoutingSearchParameters &search_parameters, std::vector< const operations_research::Assignment * > *solutions=nullptr)
Definition routing.cc:3300
void SetPrimaryConstrainedDimension(absl::string_view dimension_name)
Definition routing.h:856
operations_research::Assignment * RestoreAssignment(const operations_research::Assignment &solution)
Definition routing.cc:4014
int GetVehicleOfClass(VehicleClassIndex vehicle_class) const
Definition routing.h:1948
void AddRequiredTypeAlternativesWhenAddingType(int dependent_type, absl::flat_hash_set< int > required_type_alternatives)
Definition routing.cc:4546
RoutingDimensionIndex DimensionIndex
Definition routing.h:270
const NodeNeighborsByCostClass * GetOrCreateNodeNeighborsByCostClass(double neighbors_ratio, int64_t min_neighbors, double &neighbors_ratio_used, bool add_vehicle_starts_to_neighbors=true, bool add_vehicle_ends_to_neighbors=false, bool only_sort_neighbors_for_partial_neighborhoods=true)
Definition routing.cc:462
int64_t UnperformedPenaltyOrValue(int64_t default_value, int64_t var_index) const
Definition routing.cc:4628
bool AddDimensionDependentDimensionWithVehicleCapacity(const std::vector< int > &pure_transits, const std::vector< int > &dependent_transits, const RoutingDimension *base_dimension, int64_t slack_max, std::vector< int64_t > vehicle_capacities, bool fix_start_cumul_to_zero, const std::string &name)
Definition routing.h:775
int64_t GetNumberOfRejectsInFirstSolution(const RoutingSearchParameters &search_parameters) const
Definition routing.cc:3988
const operations_research::Assignment * SolveWithParameters(const RoutingSearchParameters &search_parameters, std::vector< const operations_research::Assignment * > *solutions=nullptr)
Definition routing.cc:3174
ResourceGroup * GetResourceGroup(int rg_index) const
Definition routing.h:873
void SetFixedCostOfAllVehicles(int64_t cost)
Definition routing.cc:1304
bool IsPickup(int64_t node_index) const
Returns whether the node is a pickup (resp. delivery).
Definition routing.h:1055
void SetMaximumNumberOfActiveVehicles(int max_active_vehicles)
Definition routing.h:1251
int64_t UnperformedPenalty(int64_t var_index) const
Definition routing.cc:4624
const std::vector< absl::flat_hash_set< int > > & GetSameVehicleRequiredTypeAlternativesOfType(int type) const
Definition routing.cc:4595
const std::vector< std::unique_ptr< ResourceGroup > > & GetResourceGroups() const
Definition routing.h:868
int vehicles() const
Returns the number of vehicle routes in the model.
Definition routing.h:2102
void AddWeightedVariableMinimizedByFinalizer(operations_research::IntVar *var, int64_t cost)
Definition routing.cc:6596
static const int64_t kNoPenalty
Constant used to express a hard constraint instead of a soft penalty.
Definition routing.h:613
const std::vector< int > & GetDimensionResourceGroupIndices(const RoutingDimension *dimension) const
Definition routing.cc:1233
const VariableIndexEvaluator2 & StateDependentTransitCallback(int callback_index) const
Definition routing.h:674
RoutingResourceClassIndex ResourceClassIndex
Definition routing.h:273
const operations_research::Assignment * FastSolveFromAssignmentWithParameters(const operations_research::Assignment *assignment, const RoutingSearchParameters &search_parameters, bool check_solution_in_cp, absl::flat_hash_set< operations_research::IntVar * > *touched=nullptr)
Definition routing.cc:3251
int64_t GetArcCostForFirstSolution(int64_t from_index, int64_t to_index) const
Definition routing.cc:4319
std::vector< std::pair< int64_t, int64_t > > GetPerfectBinaryDisjunctions() const
Definition routing.cc:1962
void SetArcCostEvaluatorOfVehicle(int evaluator_index, int vehicle)
Sets the cost function for a given vehicle route.
Definition routing.cc:1297
void SetFixedCostOfVehicle(int64_t cost, int vehicle)
Sets the fixed cost of one vehicle route.
Definition routing.cc:1315
bool CheckIfAssignmentIsFeasible(const operations_research::Assignment &assignment, bool call_at_solution_monitors)
Checks if an assignment is feasible.
Definition routing.cc:3203
void AssignmentToRoutes(const operations_research::Assignment &assignment, std::vector< std::vector< int64_t > > *routes) const
Definition routing.cc:4162
VisitTypePolicy GetVisitTypePolicy(int64_t index) const
Definition routing.cc:4473
const Solver::IndexEvaluator2 & first_solution_evaluator() const
Definition routing.h:1359
std::optional< PickupDeliveryPosition > GetDeliveryPosition(int64_t node_index) const
Returns the pickup and delivery positions where the node is a delivery.
Definition routing.cc:2106
int GetNumberOfSoftSameVehicleConstraints() const
Returns the number of soft same vehicle constraints in the model.
Definition routing.h:991
const std::vector< operations_research::IntVar * > & ResourceVars(int resource_group) const
Definition routing.h:1852
bool RoutesToAssignment(const std::vector< std::vector< int64_t > > &routes, bool ignore_inactive_indices, bool close_routes, operations_research::Assignment *assignment) const
Definition routing.cc:4036
const std::vector< absl::flat_hash_set< int > > & GetRequiredTypeAlternativesWhenAddingType(int type) const
Returns the set of requirement alternatives when adding the given type.
Definition routing.cc:4605
const operations_research::Assignment * SolveFromAssignmentWithParameters(const operations_research::Assignment *assignment, const RoutingSearchParameters &search_parameters, std::vector< const operations_research::Assignment * > *solutions=nullptr)
Definition routing.cc:3244
const TransitCallback1 & UnaryTransitCallbackOrNull(int callback_index) const
Definition routing.h:665
bool WriteAssignment(const std::string &file_name) const
Definition routing.cc:3996
int64_t GetArcCostForVehicle(int64_t from_index, int64_t to_index, int64_t vehicle) const
Definition routing.cc:4298
const TransitCallback2 & TransitCallback(int callback_index) const
Definition routing.h:661
bool ArcIsMoreConstrainedThanArc(int64_t from, int64_t to1, int64_t to2)
Definition routing.cc:4354
operations_research::Assignment * ReadAssignmentFromRoutes(const std::vector< std::vector< int64_t > > &routes, bool ignore_inactive_indices)
Definition routing.cc:4149
absl::Duration RemainingTime() const
Returns the time left in the search limit.
Definition routing.h:2072
static std::unique_ptr< LocalSearchOperator > MakeGreedyDescentLSOperator(std::vector< operations_research::IntVar * > variables)
static const DisjunctionIndex kNoDisjunction
Definition routing.h:617
bool HasGlobalCumulOptimizer(const RoutingDimension &dimension) const
Returns whether the given dimension has global/local cumul optimizers.
Definition routing.h:826
std::string DebugOutputAssignment(const operations_research::Assignment &solution_assignment, const std::string &dimension_to_print) const
Definition routing.cc:4642
PickupAndDeliveryPolicy
Types of precedence policy applied to pickup and delivery pairs.
Definition routing.h:261
@ PICKUP_AND_DELIVERY_NO_ORDER
Any precedence is accepted.
Definition routing.h:263
@ PICKUP_AND_DELIVERY_FIFO
Deliveries must be performed in the same order as pickups.
Definition routing.h:267
@ PICKUP_AND_DELIVERY_LIFO
Deliveries must be performed in reverse order of pickups.
Definition routing.h:265
const std::vector< int > & GetSameActivityIndicesOfIndex(int node) const
Returns variable indices of nodes constrained to have the same activity.
Definition routing.h:1977
SweepArranger * sweep_arranger() const
Returns the sweep arranger to be used by routing heuristics.
Definition routing.cc:211
operations_research::Assignment * ReadAssignment(const std::string &file_name)
Definition routing.cc:4005
std::pair< int, bool > AddConstantDimension(int64_t value, int64_t capacity, bool fix_start_cumul_to_zero, const std::string &name)
Definition routing.h:738
int64_t GetFixedCostOfVehicle(int vehicle) const
Definition routing.cc:1310
const std::deque< int > & GetVehiclesOfSameClass(int64_t start_end_index) const
Definition routing.cc:2293
RoutingModel & operator=(const RoutingModel &)=delete
void SetArcCostEvaluatorOfAllVehicles(int evaluator_index)
Definition routing.cc:1290
operations_research::IntVar * ActiveVehicleVar(int vehicle) const
Definition routing.h:1868
void SetPathEnergyCostsOfVehicle(const std::string &force, const std::string &distance, int64_t threshold, int64_t cost_per_unit_below_threshold, int64_t cost_per_unit_above_threshold, int vehicle)
Definition routing.cc:1331
void AddVariableTargetToFinalizer(operations_research::IntVar *var, int64_t target)
Definition routing.cc:6606
std::vector< std::vector< int64_t > > GetRoutesFromAssignment(const operations_research::Assignment &assignment)
Definition routing.cc:4196
void SetTabuVarsCallback(GetTabuVarsCallback tabu_var_callback)
Definition routing.cc:6438
bool HasDimension(absl::string_view dimension_name) const
Returns true if a dimension exists for a given dimension name.
Definition routing.cc:1077
std::function< std::vector< operations_research::IntVar * >(RoutingModel *)> GetTabuVarsCallback
Definition routing.h:2128
const operations_research::Assignment * PreAssignment() const
Definition routing.h:1525
void AddRouteConstraint(absl::AnyInvocable< std::optional< int64_t >(const std::vector< int64_t > &)> route_evaluator, bool costs_are_homogeneous_across_vehicles=false)
Definition routing.cc:1375
void AddVariableMaximizedByFinalizer(operations_research::IntVar *var)
Definition routing.cc:6610
RoutingCumulDependentTransitCallback2 CumulDependentTransitCallback2
Definition routing.h:276
void AddRestoreDimensionValuesResetCallback(std::function< void()> callback)
Definition routing.cc:3103
RoutingTransitCallback1 TransitCallback1
Definition routing.h:274
void SetFirstSolutionHint(const operations_research::Assignment *hint)
Definition routing.h:1371
const std::vector< DisjunctionIndex > & GetDisjunctionIndices(int64_t index) const
Returns the indices of the disjunctions to which an index belongs.
Definition routing.h:923
const PathsMetadata & GetPathsMetadata() const
Definition routing.h:2180
bool HasSameVehicleTypeRequirements() const
Definition routing.h:1216
void AddEnterSearchCallback(std::function< void()> callback)
Definition routing.cc:3154
bool IsVehicleUsed(const operations_research::Assignment &assignment, int vehicle) const
Returns true if the route of 'vehicle' is non empty in 'assignment'.
Definition routing.cc:4280
const std::vector< operations_research::IntVar * > & Nexts() const
Definition routing.h:1841
void SetSweepArranger(SweepArranger *sweep_arranger)
Definition routing.cc:207
void AddAtSolutionCallback(std::function< void()> callback, bool track_unchecked_neighbors=false)
Definition routing.cc:3160
void AddRequiredTypeAlternativesWhenRemovingType(int dependent_type, absl::flat_hash_set< int > required_type_alternatives)
Definition routing.cc:4569
const std::vector< int > & GetSingleNodesOfType(int type) const
Definition routing.cc:4463
std::vector< std::vector< std::pair< int64_t, int64_t > > > GetCumulBounds(const operations_research::Assignment &solution_assignment, const RoutingDimension &dimension)
Definition routing.cc:4716
RoutingVehicleClassIndex VehicleClassIndex
Definition routing.h:272
operations_research::SubSolverStatistics GetSubSolverStatistics() const
Returns detailed search statistics.
Definition routing.cc:3697
std::vector< std::pair< int64_t, int64_t > > GetSameVehicleClassArcs(int64_t from_index, int64_t to_index) const
Definition routing.cc:2301
DecisionBuilder * MakeGuidedSlackFinalizer(const RoutingDimension *dimension, std::function< int64_t(int64_t)> initializer)
The next few members are in the public section only for testing purposes.
void AddWeightedVariableTargetToFinalizer(operations_research::IntVar *var, int64_t target, int64_t cost)
Definition routing.cc:6590
TransitEvaluatorSign
Represents the sign of values returned by a transit evaluator.
Definition routing.h:637
operations_research::IntVar * ResourceVar(int vehicle, int resource_group) const
Definition routing.h:1885
void AddSoftSameVehicleConstraint(std::vector< int64_t > indices, int64_t cost)
Definition routing.cc:2037
std::optional< int64_t > GetRouteCost(const std::vector< int64_t > &route) const
Definition routing.h:1336
int VehicleIndex(int64_t index) const
Definition routing.h:1826
void AddTemporalTypeIncompatibility(int type1, int type2)
Definition routing.cc:4489
RoutingCostClassIndex CostClassIndex
Definition routing.h:269
const std::vector< std::vector< int > > & GetVisitTypeComponents() const
Definition routing.h:1134
int64_t objective_lower_bound() const
Definition routing.h:1494
A search monitor is a simple set of callbacks to monitor all search events.
SimpleBoundCosts operator=(const SimpleBoundCosts &)=delete
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
Checker for type incompatibilities.
Definition routing.h:2936
TypeRegulationsChecker(const RoutingModel &model)
Definition routing.cc:6903
virtual bool HasRegulationsToCheck() const =0
void InitializeCheck(int vehicle, const std::function< int64_t(int64_t)> &next_accessor)
Definition routing.cc:6950
RoutingModel::VisitTypePolicy VisitTypePolicy
Definition routing.h:2886
virtual bool CheckTypeRegulations(int type, VisitTypePolicy policy, int pos)=0
bool TypeCurrentlyOnRoute(int type, int pos) const
Definition routing.cc:6981
Checker for type requirements.
Definition routing.h:2952
bool operator==(const ProtoEnumIterator< E > &a, const ProtoEnumIterator< E > &b)
H AbslHashValue(H h, std::shared_ptr< Variable > i)
OR-Tools root namespace.
H AbslHashValue(H h, const StrongIndex< StrongIndexName > &i)
int64_t CapAdd(int64_t x, int64_t y)
void CapAddTo(int64_t x, int64_t *y)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
int64_t CapSub(int64_t x, int64_t y)
std::function< const FloatSlopePiecewiseLinearFunction *(int64_t, int64_t)> RoutingCumulDependentTransitCallback2
ClosedInterval::Iterator end(ClosedInterval interval)
std::function< int64_t(int64_t)> RoutingTransitCallback1
bool SolveModelWithSat(RoutingModel *model, RoutingSearchStats *search_stats, const RoutingSearchParameters &search_parameters, const operations_research::Assignment *initial_solution, operations_research::Assignment *solution)
std::function< int64_t(int64_t, int64_t)> RoutingTransitCallback2
void FillPathEvaluation(absl::Span< const int64_t > path, const RoutingModel::TransitCallback2 &evaluator, std::vector< int64_t > *values)
Definition routing.cc:6893
bool Next()
trees with all degrees equal to
bool operator<(const DimensionCost &cost) const
Definition routing.h:331
friend bool operator==(const DimensionCost &c1, const DimensionCost &c2)
Definition routing.h:339
friend H AbslHashValue(H h, const DimensionCost &cost)
Definition routing.h:345
friend bool operator==(const CostClass &c1, const CostClass &c2)
Definition routing.h:357
std::vector< DimensionCost > dimension_transit_evaluator_class_and_cost_coefficient
Definition routing.h:352
friend H AbslHashValue(H h, const CostClass &c)
Definition routing.h:363
int evaluator_index
Index of the arc cost evaluator, registered in the RoutingModel class.
Definition routing.h:302
bool operator==(const NodeNeighborsParameters &other) const
Definition routing.h:1687
int pd_pair_index
The index of the pickup and delivery pair within which the node appears.
Definition routing.h:1043
std::string DebugString(std::string line_prefix="") const
Definition routing.cc:114
int64_t travel_cost_coefficient
The cost per unit of travel for this vehicle.
Definition routing.h:1663
RangeMinMaxIndexFunction * transit_plus_identity
f(x)
Definition routing.h:293
Struct used to store a variable value.
Definition routing.h:589
std::vector< std::deque< int > > vehicles_per_vehicle_class
Definition routing.h:395
std::vector< std::set< VehicleClassEntry > > sorted_vehicle_classes_per_type
Definition routing.h:394
static const int64_t kint64min
Definition types.h:31