156#ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_H_
157#define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_H_
173#include "absl/container/flat_hash_map.h"
174#include "absl/container/flat_hash_set.h"
175#include "absl/hash/hash.h"
176#include "absl/log/check.h"
177#include "absl/strings/string_view.h"
178#include "absl/time/time.h"
179#include "absl/types/span.h"
186#include "ortools/constraint_solver/routing_enums.pb.h"
188#include "ortools/constraint_solver/routing_parameters.pb.h"
206class RoutingDimension;
208using util::ReverseArcListGraph;
214 explicit PathsMetadata(
const RoutingIndexManager& manager) {
215 const int num_indices = manager.num_indices();
216 const int num_paths = manager.num_vehicles();
217 path_of_node_.resize(num_indices, -1);
218 is_start_.resize(num_indices,
false);
219 is_end_.resize(num_indices,
false);
220 start_of_path_.resize(num_paths);
221 end_of_path_.resize(num_paths);
222 for (
int v = 0; v < num_paths; ++v) {
223 const int64_t start = manager.GetStartIndex(v);
224 start_of_path_[v] = start;
225 path_of_node_[start] = v;
226 is_start_[start] =
true;
227 const int64_t end = manager.GetEndIndex(v);
228 end_of_path_[v] = end;
229 path_of_node_[end] = v;
234 bool IsStart(int64_t node)
const {
return is_start_[node]; }
235 bool IsEnd(int64_t node)
const {
return is_end_[node]; }
236 int GetPath(int64_t start_or_end_node)
const {
237 return path_of_node_[start_or_end_node];
239 int NumPaths()
const {
return start_of_path_.size(); }
240 const std::vector<int64_t>& Paths()
const {
return path_of_node_; }
241 const std::vector<int64_t>& Starts()
const {
return start_of_path_; }
242 int64_t Start(
int path)
const {
return start_of_path_[path]; }
243 int64_t End(
int path)
const {
return end_of_path_[path]; }
244 const std::vector<int64_t>& Ends()
const {
return end_of_path_; }
247 std::vector<bool> is_start_;
248 std::vector<bool> is_end_;
249 std::vector<int64_t> start_of_path_;
250 std::vector<int64_t> end_of_path_;
251 std::vector<int64_t> path_of_node_;
254class OR_DLL RoutingModel {
257 enum PickupAndDeliveryPolicy {
259 PICKUP_AND_DELIVERY_NO_ORDER,
261 PICKUP_AND_DELIVERY_LIFO,
263 PICKUP_AND_DELIVERY_FIFO
265 typedef RoutingCostClassIndex CostClassIndex;
266 typedef RoutingDimensionIndex DimensionIndex;
267 typedef RoutingDisjunctionIndex DisjunctionIndex;
268 typedef RoutingVehicleClassIndex VehicleClassIndex;
269 typedef RoutingResourceClassIndex ResourceClassIndex;
287 struct StateDependentTransit {
288 RangeIntToIntFunction* transit;
289 RangeMinMaxIndexFunction* transit_plus_identity;
291 typedef std::function<StateDependentTransit(int64_t, int64_t)>
292 VariableIndexEvaluator2;
298 int evaluator_index = 0;
320 struct DimensionCost {
321 int64_t transit_evaluator_class;
324 int64_t span_cost_coefficient;
325 int64_t slack_cost_coefficient;
326 const RoutingDimension* dimension;
327 bool operator<(
const DimensionCost& cost)
const {
328 return std::tie(transit_evaluator_class, span_cost_coefficient,
329 slack_cost_coefficient) <
330 std::tie(cost.transit_evaluator_class,
331 cost.span_cost_coefficient,
332 cost.slack_cost_coefficient);
335 friend bool operator==(
const DimensionCost& c1,
const DimensionCost& c2) {
336 return c1.transit_evaluator_class == c2.transit_evaluator_class &&
337 c1.span_cost_coefficient == c2.span_cost_coefficient &&
338 c1.slack_cost_coefficient == c2.slack_cost_coefficient;
340 template <
typename H>
342 return H::combine(std::move(h), cost.transit_evaluator_class,
343 cost.span_cost_coefficient,
344 cost.slack_cost_coefficient);
347 std::vector<DimensionCost>
348 dimension_transit_evaluator_class_and_cost_coefficient;
350 explicit CostClass(
int evaluator_index)
351 : evaluator_index(evaluator_index) {}
353 friend bool operator==(
const CostClass& c1,
const CostClass& c2) {
354 return c1.evaluator_index == c2.evaluator_index &&
355 c1.dimension_transit_evaluator_class_and_cost_coefficient ==
356 c2.dimension_transit_evaluator_class_and_cost_coefficient;
358 template <
typename H>
361 std::move(h),
c.evaluator_index,
362 c.dimension_transit_evaluator_class_and_cost_coefficient);
370 struct VehicleTypeContainer {
371 struct VehicleClassEntry {
375 bool operator<(
const VehicleClassEntry& other)
const {
376 return std::tie(fixed_cost, vehicle_class) <
377 std::tie(other.fixed_cost, other.vehicle_class);
381 int NumTypes()
const {
return sorted_vehicle_classes_per_type.size(); }
383 int Type(
int vehicle)
const {
384 DCHECK_LT(vehicle, type_index_of_vehicle.size());
385 return type_index_of_vehicle[vehicle];
388 std::vector<int> type_index_of_vehicle;
390 std::vector<std::set<VehicleClassEntry> > sorted_vehicle_classes_per_type;
391 std::vector<std::deque<int> > vehicles_per_vehicle_class;
406 class ResourceGroup {
412 Attributes(Domain start_domain, Domain end_domain);
414 const Domain& start_domain()
const {
return start_domain_; }
415 const Domain& end_domain()
const {
return end_domain_; }
417 friend bool operator==(
const Attributes& a,
const Attributes& b) {
418 return a.start_domain_ ==
b.start_domain_ &&
419 a.end_domain_ ==
b.end_domain_;
421 template <
typename H>
423 return H::combine(std::move(h), attributes.start_domain_,
424 attributes.end_domain_);
431 Domain start_domain_;
439 const ResourceGroup::Attributes& GetDimensionAttributes(
440 const RoutingDimension* dimension)
const;
443 explicit Resource(
const RoutingModel* model) : model_(model) {}
445 void SetDimensionAttributes(ResourceGroup::Attributes attributes,
446 const RoutingDimension* dimension);
447 const ResourceGroup::Attributes& GetDefaultAttributes()
const;
449 const RoutingModel*
const model_;
450 absl::flat_hash_map<DimensionIndex, ResourceGroup::Attributes>
451 dimension_attributes_;
453 friend class ResourceGroup;
458 int AddResource(Attributes attributes,
const RoutingDimension* dimension);
463 void NotifyVehicleRequiresAResource(
int vehicle);
465 const std::vector<int>& GetVehiclesRequiringAResource()
const {
466 return vehicles_requiring_resource_;
469 bool VehicleRequiresAResource(
int vehicle)
const {
470 return vehicle_requires_resource_[vehicle];
473 void SetAllowedResourcesForVehicle(
474 int vehicle,
const std::vector<int>& allowed_resource_indices) {
475 DCHECK(!model_->closed_);
479 DCHECK(!allowed_resource_indices.empty());
480 DCHECK(vehicle_requires_resource_[vehicle]);
481 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
482 vehicle_allowed_resources_[vehicle].clear();
483 vehicle_allowed_resources_[vehicle].insert(
484 allowed_resource_indices.begin(), allowed_resource_indices.end());
486 void ClearAllowedResourcesForVehicle(
int vehicle) {
487 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
488 vehicle_allowed_resources_[vehicle].clear();
490 const absl::flat_hash_set<int>& GetResourcesMarkedAllowedForVehicle(
492 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
493 return vehicle_allowed_resources_[vehicle];
495 bool IsResourceAllowedForVehicle(
int resource,
int vehicle)
const {
496 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
497 return vehicle_allowed_resources_[vehicle].empty() ||
498 vehicle_allowed_resources_[vehicle].contains(resource);
501 const std::vector<Resource>& GetResources()
const {
return resources_; }
502 const Resource& GetResource(
int resource_index)
const {
503 DCHECK_LT(resource_index, resources_.size());
504 return resources_[resource_index];
506 const absl::flat_hash_set<DimensionIndex>& GetAffectedDimensionIndices()
508 return affected_dimension_indices_;
511 int GetResourceClassesCount()
const {
512 return resource_indices_per_class_.size();
514 const std::vector<int>& GetResourceIndicesInClass(
515 ResourceClassIndex resource_class)
const {
516 DCHECK_LT(resource_class, resource_indices_per_class_.size());
517 return resource_indices_per_class_[resource_class];
520 const util_intops::StrongVector<ResourceClassIndex, std::vector<int> >&
521 GetResourceIndicesPerClass()
const {
522 return resource_indices_per_class_;
525 ResourceClassIndex GetResourceClassIndex(
int resource_index)
const {
526 DCHECK_LT(resource_index, resource_class_indices_.size());
527 return resource_class_indices_[resource_index];
529 const Attributes& GetDimensionAttributesForClass(
530 const RoutingDimension* dimension, ResourceClassIndex rc_index)
const {
531 DCHECK_LT(rc_index, resource_indices_per_class_.size());
532 const std::vector<int>& resource_indices =
533 resource_indices_per_class_[rc_index];
534 DCHECK(!resource_indices.empty());
535 return resources_[resource_indices[0]].GetDimensionAttributes(dimension);
538 int Size()
const {
return resources_.size(); }
539 int Index()
const {
return index_; }
542 explicit ResourceGroup(
const RoutingModel* model)
543 : index_(model->GetResourceGroups().size()),
545 vehicle_requires_resource_(model->vehicles(),
false),
546 vehicle_allowed_resources_(model->vehicles()) {}
548 void ComputeResourceClasses();
551 const RoutingModel*
const model_;
552 std::vector<Resource> resources_;
555 std::vector<ResourceClassIndex> resource_class_indices_;
557 util_intops::StrongVector<ResourceClassIndex, std::vector<int> >
558 resource_indices_per_class_;
561 std::vector<bool> vehicle_requires_resource_;
562 std::vector<int> vehicles_requiring_resource_;
567 std::vector<absl::flat_hash_set<int> > vehicle_allowed_resources_;
570 absl::flat_hash_set<DimensionIndex> affected_dimension_indices_;
572 friend class RoutingModel;
576 struct VariableValuePair {
582 class SecondaryOptimizer {
584 SecondaryOptimizer(RoutingModel* model,
585 RoutingSearchParameters* search_parameters,
586 int64_t solve_period);
587 bool Solve(
const std::vector<RoutingModel::VariableValuePair>& in_state,
588 std::vector<RoutingModel::VariableValuePair>* out_state);
591 RoutingModel*
const model_;
592 const RoutingSearchParameters*
const search_parameters_;
593 const int64_t solve_period_ = 0;
594 int64_t call_count_ = 0;
595 Assignment* state_ =
nullptr;
596 absl::flat_hash_map<IntVar*, int> var_to_index_;
600 static const int64_t kNoPenalty;
604 static const DisjunctionIndex kNoDisjunction;
608 static const DimensionIndex kNoDimension;
613 explicit RoutingModel(
const RoutingIndexManager& index_manager);
614 RoutingModel(
const RoutingIndexManager& index_manager,
615 const RoutingModelParameters& parameters);
618 RoutingModel(
const RoutingModel&) =
delete;
619 RoutingModel& operator=(
const RoutingModel&) =
delete;
624 enum TransitEvaluatorSign {
625 kTransitEvaluatorSignUnknown = 0,
626 kTransitEvaluatorSignPositiveOrZero = 1,
627 kTransitEvaluatorSignNegativeOrZero = 2,
634 int RegisterUnaryTransitVector(std::vector<int64_t> values);
635 int RegisterUnaryTransitCallback(
636 TransitCallback1 callback,
637 TransitEvaluatorSign sign = kTransitEvaluatorSignUnknown);
639 int RegisterTransitMatrix(
640 std::vector<std::vector<int64_t> > values);
641 int RegisterTransitCallback(
642 TransitCallback2 callback,
643 TransitEvaluatorSign sign = kTransitEvaluatorSignUnknown);
644 int RegisterCumulDependentTransitCallback(
645 CumulDependentTransitCallback2 callback);
646 int RegisterStateDependentTransitCallback(VariableIndexEvaluator2 callback);
648 const TransitCallback2& TransitCallback(
int callback_index)
const {
649 CHECK_LT(callback_index, transit_evaluators_.size());
650 return transit_evaluators_[callback_index];
652 const TransitCallback1& UnaryTransitCallbackOrNull(
int callback_index)
const {
653 CHECK_LT(callback_index, unary_transit_evaluators_.size());
654 return unary_transit_evaluators_[callback_index];
656 const CumulDependentTransitCallback2& CumulDependentTransitCallback(
657 int callback_index)
const {
658 CHECK_LT(callback_index, cumul_dependent_transit_evaluators_.size());
659 return cumul_dependent_transit_evaluators_[callback_index];
661 const VariableIndexEvaluator2& StateDependentTransitCallback(
662 int callback_index)
const {
663 CHECK_LT(callback_index, state_dependent_transit_evaluators_.size());
664 return state_dependent_transit_evaluators_[callback_index];
689 bool AddDimension(
int evaluator_index, int64_t slack_max, int64_t capacity,
690 bool fix_start_cumul_to_zero,
const std::string& name);
691 bool AddDimensionWithVehicleTransits(
692 const std::vector<int>& evaluator_indices, int64_t slack_max,
693 int64_t capacity,
bool fix_start_cumul_to_zero,
const std::string& name);
694 bool AddDimensionWithVehicleCapacity(
int evaluator_index, int64_t slack_max,
695 std::vector<int64_t> vehicle_capacities,
696 bool fix_start_cumul_to_zero,
697 const std::string& name);
698 bool AddDimensionWithVehicleTransitAndCapacity(
699 const std::vector<int>& evaluator_indices, int64_t slack_max,
700 std::vector<int64_t> vehicle_capacities,
bool fix_start_cumul_to_zero,
701 const std::string& name);
708 bool AddDimensionWithCumulDependentVehicleTransitAndCapacity(
709 const std::vector<int>& fixed_evaluator_indices,
710 const std::vector<int>& cumul_dependent_evaluator_indices,
711 int64_t slack_max, std::vector<int64_t> vehicle_capacities,
712 bool fix_start_cumul_to_zero,
const std::string& name);
722 std::pair<int, bool> AddConstantDimensionWithSlack(
723 int64_t value, int64_t capacity, int64_t slack_max,
724 bool fix_start_cumul_to_zero,
const std::string& name);
725 std::pair<int, bool> AddConstantDimension(int64_t value, int64_t capacity,
726 bool fix_start_cumul_to_zero,
727 const std::string& name) {
728 return AddConstantDimensionWithSlack(value, capacity, 0,
729 fix_start_cumul_to_zero, name);
740 std::pair<int, bool> AddVectorDimension(std::vector<int64_t> values,
742 bool fix_start_cumul_to_zero,
743 const std::string& name);
753 std::pair<int, bool> AddMatrixDimension(
754 std::vector<std::vector<int64_t> > values,
755 int64_t capacity,
bool fix_start_cumul_to_zero,
const std::string& name);
762 bool AddDimensionDependentDimensionWithVehicleCapacity(
763 const std::vector<int>& pure_transits,
764 const std::vector<int>& dependent_transits,
765 const RoutingDimension* base_dimension, int64_t slack_max,
766 std::vector<int64_t> vehicle_capacities,
bool fix_start_cumul_to_zero,
767 const std::string& name) {
768 return AddDimensionDependentDimensionWithVehicleCapacityInternal(
769 pure_transits, dependent_transits, base_dimension, slack_max,
770 std::move(vehicle_capacities), fix_start_cumul_to_zero, name);
774 bool AddDimensionDependentDimensionWithVehicleCapacity(
775 const std::vector<int>& transits,
const RoutingDimension* base_dimension,
776 int64_t slack_max, std::vector<int64_t> vehicle_capacities,
777 bool fix_start_cumul_to_zero,
const std::string& name);
779 bool AddDimensionDependentDimensionWithVehicleCapacity(
780 int transit,
const RoutingDimension* base_dimension, int64_t slack_max,
781 int64_t vehicle_capacity,
bool fix_start_cumul_to_zero,
782 const std::string& name);
783 bool AddDimensionDependentDimensionWithVehicleCapacity(
784 int pure_transit,
int dependent_transit,
785 const RoutingDimension* base_dimension, int64_t slack_max,
786 int64_t vehicle_capacity,
bool fix_start_cumul_to_zero,
787 const std::string& name);
790 static RoutingModel::StateDependentTransit MakeStateDependentTransit(
791 const std::function<int64_t(int64_t)>& f, int64_t domain_start,
796 std::vector<std::string> GetAllDimensionNames()
const;
798 const std::vector<RoutingDimension*>& GetDimensions()
const {
799 return dimensions_.get();
802 std::vector<RoutingDimension*> GetDimensionsWithSoftOrSpanCosts()
const;
804 std::vector<RoutingDimension*> GetUnaryDimensions()
const;
807 std::vector<const RoutingDimension*> GetDimensionsWithGlobalCumulOptimizers()
809 std::vector<const RoutingDimension*> GetDimensionsWithLocalCumulOptimizers()
813 bool HasGlobalCumulOptimizer(
const RoutingDimension& dimension)
const {
814 return GetGlobalCumulOptimizerIndex(dimension) >= 0;
816 bool HasLocalCumulOptimizer(
const RoutingDimension& dimension)
const {
817 return GetLocalCumulOptimizerIndex(dimension) >= 0;
821 GlobalDimensionCumulOptimizer* GetMutableGlobalCumulLPOptimizer(
822 const RoutingDimension& dimension)
const;
823 GlobalDimensionCumulOptimizer* GetMutableGlobalCumulMPOptimizer(
824 const RoutingDimension& dimension)
const;
825 LocalDimensionCumulOptimizer* GetMutableLocalCumulLPOptimizer(
826 const RoutingDimension& dimension)
const;
827 LocalDimensionCumulOptimizer* GetMutableLocalCumulMPOptimizer(
828 const RoutingDimension& dimension)
const;
831 bool HasDimension(absl::string_view dimension_name)
const;
833 const RoutingDimension& GetDimensionOrDie(
834 const std::string& dimension_name)
const;
837 RoutingDimension* GetMutableDimension(
838 const std::string& dimension_name)
const;
843 void SetPrimaryConstrainedDimension(absl::string_view dimension_name) {
844 DCHECK(dimension_name.empty() || HasDimension(dimension_name));
845 primary_constrained_dimension_ = dimension_name;
848 const std::string& GetPrimaryConstrainedDimension()
const {
849 return primary_constrained_dimension_;
853 ResourceGroup* AddResourceGroup();
855 const std::vector<std::unique_ptr<ResourceGroup> >& GetResourceGroups()
857 return resource_groups_;
860 ResourceGroup* GetResourceGroup(
int rg_index)
const {
861 DCHECK_LT(rg_index, resource_groups_.size());
862 return resource_groups_[rg_index].get();
867 const std::vector<int>& GetDimensionResourceGroupIndices(
868 const RoutingDimension* dimension)
const;
872 int GetDimensionResourceGroupIndex(
const RoutingDimension* dimension)
const {
873 DCHECK_EQ(GetDimensionResourceGroupIndices(dimension).size(), 1);
874 return GetDimensionResourceGroupIndices(dimension)[0];
879 enum PenaltyCostBehavior { PENALIZE_ONCE, PENALIZE_PER_INACTIVE };
902 DisjunctionIndex AddDisjunction(
const std::vector<int64_t>& indices,
903 int64_t penalty = kNoPenalty,
904 int64_t max_cardinality = 1,
905 PenaltyCostBehavior penalty_cost_behavior =
906 PenaltyCostBehavior::PENALIZE_ONCE);
908 const std::vector<DisjunctionIndex>& GetDisjunctionIndices(
909 int64_t index)
const {
910 return index_to_disjunctions_[index];
915 template <
typename F>
916 void ForEachNodeInDisjunctionWithMaxCardinalityFromIndex(
917 int64_t index, int64_t max_cardinality, F f)
const {
918 for (
const DisjunctionIndex disjunction : GetDisjunctionIndices(index)) {
919 if (disjunctions_[disjunction].value.max_cardinality == max_cardinality) {
920 for (
const int64_t d_index : disjunctions_[disjunction].indices) {
926#if !defined(SWIGPYTHON)
929 const std::vector<int64_t>& GetDisjunctionNodeIndices(
930 DisjunctionIndex index)
const {
931 return disjunctions_[index].indices;
935 int64_t GetDisjunctionPenalty(DisjunctionIndex index) const {
936 return disjunctions_[index].value.penalty;
940 int64_t GetDisjunctionMaxCardinality(DisjunctionIndex index)
const {
941 return disjunctions_[index].value.max_cardinality;
945 PenaltyCostBehavior GetDisjunctionPenaltyCostBehavior(
946 DisjunctionIndex index)
const {
947 return disjunctions_[index].value.penalty_cost_behavior;
950 int GetNumberOfDisjunctions()
const {
return disjunctions_.size(); }
953 bool HasMandatoryDisjunctions()
const;
956 bool HasMaxCardinalityConstrainedDisjunctions()
const;
961 std::vector<std::pair<int64_t, int64_t>> GetPerfectBinaryDisjunctions()
const;
967 void IgnoreDisjunctionsAlreadyForcedToZero();
972 void AddSoftSameVehicleConstraint(std::vector<int64_t> indices, int64_t cost);
978 void SetAllowedVehiclesForIndex(
const std::vector<int>& vehicles,
982 bool IsVehicleAllowedForIndex(
int vehicle, int64_t index)
const {
983 return allowed_vehicles_[index].empty() ||
984 allowed_vehicles_[index].find(vehicle) !=
985 allowed_vehicles_[index].end();
1003 void AddPickupAndDelivery(int64_t pickup, int64_t delivery);
1007 void AddPickupAndDeliverySets(DisjunctionIndex pickup_disjunction,
1008 DisjunctionIndex delivery_disjunction);
1011 struct PickupDeliveryPosition {
1013 int pd_pair_index = -1;
1016 int alternative_index = -1;
1019 std::optional<PickupDeliveryPosition> GetPickupPosition(
1020 int64_t node_index)
const;
1022 std::optional<PickupDeliveryPosition> GetDeliveryPosition(
1023 int64_t node_index)
const;
1025 bool IsPickup(int64_t node_index)
const {
1026 return index_to_pickup_position_[node_index].pd_pair_index != -1;
1028 bool IsDelivery(int64_t node_index)
const {
1029 return index_to_delivery_position_[node_index].pd_pair_index != -1;
1034 void SetPickupAndDeliveryPolicyOfAllVehicles(PickupAndDeliveryPolicy policy);
1035 void SetPickupAndDeliveryPolicyOfVehicle(PickupAndDeliveryPolicy policy,
1037 PickupAndDeliveryPolicy GetPickupAndDeliveryPolicyOfVehicle(
1042 int GetNumOfSingletonNodes()
const;
1046 const std::vector<PickupDeliveryPair>& GetPickupAndDeliveryPairs()
const {
1047 return pickup_delivery_pairs_;
1049 const std::vector<std::pair<DisjunctionIndex, DisjunctionIndex>>&
1050 GetPickupAndDeliveryDisjunctions()
const {
1051 return pickup_delivery_disjunctions_;
1057 const std::vector<PickupDeliveryPair>&
1058 GetImplicitUniquePickupAndDeliveryPairs()
const {
1060 return implicit_pickup_delivery_pairs_without_alternatives_;
1066 std::optional<int64_t> GetFirstMatchingPickupDeliverySibling(
1067 int64_t node,
const std::function<
bool(int64_t)>& is_match)
const;
1080 enum VisitTypePolicy {
1082 TYPE_ADDED_TO_VEHICLE,
1087 ADDED_TYPE_REMOVED_FROM_VEHICLE,
1090 TYPE_ON_VEHICLE_UP_TO_VISIT,
1095 TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED
1098 void SetVisitType(int64_t index,
int type, VisitTypePolicy type_policy);
1099 int GetVisitType(int64_t index)
const;
1100 const std::vector<int>& GetSingleNodesOfType(
int type)
const;
1101 const std::vector<int>& GetPairIndicesOfType(
int type)
const;
1102 VisitTypePolicy GetVisitTypePolicy(int64_t index)
const;
1104 int GetNumberOfVisitTypes()
const {
return num_visit_types_; }
1106 const std::vector<std::vector<int>>& GetTopologicallySortedVisitTypes()
1109 return topologically_sorted_visit_types_;
1119 void AddHardTypeIncompatibility(int type1, int type2);
1120 void AddTemporalTypeIncompatibility(
int type1,
int type2);
1122 const absl::flat_hash_set<int>& GetHardTypeIncompatibilitiesOfType(
1124 const absl::flat_hash_set<int>& GetTemporalTypeIncompatibilitiesOfType(
1128 bool HasHardTypeIncompatibilities()
const {
1129 return !hard_incompatible_types_per_type_index_.empty();
1131 bool HasTemporalTypeIncompatibilities()
const {
1132 return !temporal_incompatible_types_per_type_index_.empty();
1147 void AddSameVehicleRequiredTypeAlternatives(
1148 int dependent_type, absl::flat_hash_set<int> required_type_alternatives);
1153 void AddRequiredTypeAlternativesWhenAddingType(
1154 int dependent_type, absl::flat_hash_set<int> required_type_alternatives);
1160 void AddRequiredTypeAlternativesWhenRemovingType(
1161 int dependent_type, absl::flat_hash_set<int> required_type_alternatives);
1165 const std::vector<absl::flat_hash_set<int> >&
1166 GetSameVehicleRequiredTypeAlternativesOfType(
int type)
const;
1168 const std::vector<absl::flat_hash_set<int> >&
1169 GetRequiredTypeAlternativesWhenAddingType(
int type)
const;
1171 const std::vector<absl::flat_hash_set<int> >&
1172 GetRequiredTypeAlternativesWhenRemovingType(
int type)
const;
1176 bool HasSameVehicleTypeRequirements()
const {
1177 return !same_vehicle_required_type_alternatives_per_type_index_.empty();
1179 bool HasTemporalTypeRequirements()
const {
1180 return !required_type_alternatives_when_adding_type_index_.empty() ||
1181 !required_type_alternatives_when_removing_type_index_.empty();
1186 bool HasTypeRegulations()
const {
1187 return HasTemporalTypeIncompatibilities() ||
1188 HasHardTypeIncompatibilities() || HasSameVehicleTypeRequirements() ||
1189 HasTemporalTypeRequirements();
1196 int64_t UnperformedPenalty(int64_t var_index)
const;
1200 int64_t UnperformedPenaltyOrValue(int64_t default_value,
1201 int64_t var_index)
const;
1205 int64_t GetDepot()
const;
1211 void SetMaximumNumberOfActiveVehicles(
int max_active_vehicles) {
1212 max_active_vehicles_ = max_active_vehicles;
1215 int GetMaximumNumberOfActiveVehicles()
const {
return max_active_vehicles_; }
1219 void SetArcCostEvaluatorOfAllVehicles(
int evaluator_index);
1221 void SetArcCostEvaluatorOfVehicle(
int evaluator_index,
int vehicle);
1224 void SetFixedCostOfAllVehicles(int64_t cost);
1226 void SetFixedCostOfVehicle(int64_t cost,
int vehicle);
1230 int64_t GetFixedCostOfVehicle(
int vehicle)
const;
1238 void SetPathEnergyCostOfVehicle(
const std::string& force,
1239 const std::string& distance,
1240 int64_t cost_per_unit,
int vehicle);
1247 void SetPathEnergyCostsOfVehicle(
const std::string& force,
1248 const std::string& distance,
1250 int64_t cost_per_unit_below_threshold,
1251 int64_t cost_per_unit_above_threshold,
1269 void SetAmortizedCostFactorsOfAllVehicles(int64_t linear_cost_factor,
1270 int64_t quadratic_cost_factor);
1272 void SetAmortizedCostFactorsOfVehicle(int64_t linear_cost_factor,
1273 int64_t quadratic_cost_factor,
1276 const std::vector<int64_t>& GetAmortizedLinearCostFactorOfVehicles()
const {
1277 return linear_cost_factor_of_vehicle_;
1279 const std::vector<int64_t>& GetAmortizedQuadraticCostFactorOfVehicles()
1281 return quadratic_cost_factor_of_vehicle_;
1288 void AddRouteConstraint(
1289 std::function<std::optional<int64_t>(
const std::vector<int64_t>&)>
1291 bool costs_are_homogeneous_across_vehicles =
false);
1292 std::optional<int64_t> GetRouteCost(
const std::vector<int64_t>& route)
const {
1293 int64_t route_cost = 0;
1294 for (
const auto& evaluator : route_evaluators_) {
1295 std::optional<int64_t> cost = evaluator(route);
1296 if (!cost.has_value())
return std::nullopt;
1297 CapAddTo(cost.value(), &route_cost);
1302 void SetVehicleUsedWhenEmpty(
bool is_used,
int vehicle) {
1303 DCHECK_LT(vehicle, vehicles_);
1304 vehicle_used_when_empty_[vehicle] = is_used;
1307 bool IsVehicleUsedWhenEmpty(
int vehicle)
const {
1308 DCHECK_LT(vehicle, vehicles_);
1309 return vehicle_used_when_empty_[vehicle];
1316 return first_solution_evaluator_;
1321 first_solution_evaluator_ = std::move(evaluator);
1327 void SetFirstSolutionHint(
const Assignment* hint) { hint_ = hint; }
1329 const Assignment* GetFirstSolutionHint()
const {
return hint_; }
1336 void AddEnterSearchCallback(std::function<
void()> callback);
1343 void AddAtSolutionCallback(std::function<
void()> callback,
1344 bool track_unchecked_neighbors =
false);
1347 void AddRestoreDimensionValuesResetCallback(std::function<
void()> callback);
1352 void AddVariableMinimizedByFinalizer(
IntVar* var);
1355 void AddVariableMaximizedByFinalizer(
IntVar* var);
1358 void AddWeightedVariableMinimizedByFinalizer(
IntVar* var, int64_t cost);
1361 void AddWeightedVariableMaximizedByFinalizer(
IntVar* var, int64_t cost);
1364 void AddVariableTargetToFinalizer(
IntVar* var, int64_t target);
1367 void AddWeightedVariableTargetToFinalizer(
IntVar* var, int64_t target,
1378 void CloseModelWithParameters(
1379 const RoutingSearchParameters& search_parameters);
1395 const RoutingSearchParameters& search_parameters,
1396 std::vector<const Assignment*>* solutions =
nullptr);
1399 const Assignment* SolveFromAssignmentWithParameters(
1401 const RoutingSearchParameters& search_parameters,
1402 std::vector<const Assignment*>* solutions =
nullptr);
1407 const Assignment* FastSolveFromAssignmentWithParameters(
1409 const RoutingSearchParameters& search_parameters,
1410 bool check_solution_in_cp,
1411 absl::flat_hash_set<IntVar*>* touched =
nullptr);
1414 const Assignment* SolveFromAssignmentsWithParameters(
1415 const std::vector<const Assignment*>& assignments,
1416 const RoutingSearchParameters& search_parameters,
1417 std::vector<const Assignment*>* solutions =
nullptr);
1420 const Assignment* SolveWithIteratedLocalSearch(
1421 const RoutingSearchParameters& search_parameters);
1427 void SetAssignmentFromOtherModelAssignment(
1428 Assignment* target_assignment,
const RoutingModel* source_model,
1436 int64_t ComputeLowerBound();
1439 int64_t objective_lower_bound()
const {
return objective_lower_bound_; }
1441 RoutingSearchStatus::Value status()
const {
return status_; }
1443 bool enable_deep_serialization()
const {
return enable_deep_serialization_; }
1452 IntVar* ApplyLocks(
const std::vector<int64_t>& locks);
1461 bool ApplyLocksToAllVehicles(
const std::vector<std::vector<int64_t>>& locks,
1467 const Assignment* PreAssignment()
const {
return preassignment_; }
1468 Assignment* MutablePreAssignment() {
return preassignment_; }
1472 bool WriteAssignment(
const std::string& file_name)
const;
1476 Assignment* ReadAssignment(
const std::string& file_name);
1486 const std::vector<std::vector<int64_t>>& routes,
1487 bool ignore_inactive_indices);
1504 bool RoutesToAssignment(
const std::vector<std::vector<int64_t>>& routes,
1505 bool ignore_inactive_indices,
bool close_routes,
1510 void AssignmentToRoutes(
const Assignment& assignment,
1511 std::vector<std::vector<int64_t>>* routes)
const;
1517 std::vector<std::vector<int64_t>> GetRoutesFromAssignment(
1543 void AddToAssignment(
IntVar* var);
1544 void AddIntervalToAssignment(
IntervalVar* interval);
1555 const Assignment* PackCumulsOfOptimizerDimensionsFromAssignment(
1556 const Assignment* original_assignment, absl::Duration duration_limit,
1557 bool* time_limit_was_reached =
nullptr);
1562 struct RouteDimensionTravelInfo {
1564 struct TransitionInfo {
1567 FloatSlopePiecewiseLinearFunction travel_start_dependent_travel;
1572 FloatSlopePiecewiseLinearFunction travel_compression_cost;
1577 int64_t pre_travel_transit_value;
1578 int64_t post_travel_transit_value;
1582 int64_t compressed_travel_value_lower_bound;
1588 int64_t travel_value_upper_bound;
1590 std::string DebugString(std::string line_prefix =
"")
const;
1595 std::vector<TransitionInfo> transition_info;
1597 int64_t travel_cost_coefficient;
1599 std::string DebugString(std::string line_prefix =
"")
const;
1610 struct NodeNeighborsParameters {
1612 bool add_vehicle_starts_to_neighbors =
true;
1613 bool add_vehicle_ends_to_neighbors =
false;
1619 bool only_sort_neighbors_for_partial_neighborhoods =
true;
1621 bool operator==(
const NodeNeighborsParameters& other)
const {
1622 return num_neighbors == other.num_neighbors &&
1623 add_vehicle_starts_to_neighbors ==
1624 other.add_vehicle_starts_to_neighbors &&
1625 add_vehicle_ends_to_neighbors ==
1626 other.add_vehicle_ends_to_neighbors &&
1627 only_sort_neighbors_for_partial_neighborhoods ==
1628 other.only_sort_neighbors_for_partial_neighborhoods;
1630 template <
typename H>
1631 friend H
AbslHashValue(H h,
const NodeNeighborsParameters& params) {
1632 return H::combine(std::move(h), params.num_neighbors,
1633 params.add_vehicle_starts_to_neighbors,
1634 params.add_vehicle_ends_to_neighbors,
1635 params.only_sort_neighbors_for_partial_neighborhoods);
1638 class NodeNeighborsByCostClass {
1640 explicit NodeNeighborsByCostClass(
const RoutingModel* routing_model)
1641 : routing_model_(*routing_model) {};
1645 void ComputeNeighbors(
const NodeNeighborsParameters& params);
1649 const std::vector<int>& GetIncomingNeighborsOfNodeForCostClass(
1650 int cost_class,
int node_index)
const {
1651 if (routing_model_.IsStart(node_index))
return empty_neighbors_;
1653 if (node_index_to_incoming_neighbors_by_cost_class_.empty()) {
1654 return all_incoming_nodes_;
1656 const std::vector<std::vector<int>>& node_index_to_incoming_neighbors =
1657 node_index_to_incoming_neighbors_by_cost_class_[cost_class];
1658 if (node_index_to_incoming_neighbors.empty()) {
1659 return empty_neighbors_;
1661 return node_index_to_incoming_neighbors[node_index];
1667 const std::vector<int>& GetOutgoingNeighborsOfNodeForCostClass(
1668 int cost_class,
int node_index)
const {
1669 if (routing_model_.IsEnd(node_index))
return empty_neighbors_;
1671 if (node_index_to_outgoing_neighbors_by_cost_class_.empty()) {
1672 return all_outgoing_nodes_;
1674 const std::vector<std::vector<int>>& node_index_to_outgoing_neighbors =
1675 node_index_to_outgoing_neighbors_by_cost_class_[cost_class];
1676 if (node_index_to_outgoing_neighbors.empty()) {
1677 return empty_neighbors_;
1679 return node_index_to_outgoing_neighbors[node_index];
1684 bool IsNeighborhoodArcForCostClass(
int cost_class, int64_t from,
1686 if (node_index_to_outgoing_neighbor_indicator_by_cost_class_.empty()) {
1689 if (routing_model_.IsEnd(from)) {
1692 return node_index_to_outgoing_neighbor_indicator_by_cost_class_
1693 [cost_class][from][
to];
1697 const RoutingModel& routing_model_;
1698#if __cplusplus >= 202002L
1699 static constexpr std::vector<int> empty_neighbors_ = {};
1701 inline static const std::vector<int> empty_neighbors_ = {};
1704 std::vector<std::vector<std::vector<int>>>
1705 node_index_to_incoming_neighbors_by_cost_class_;
1706 std::vector<std::vector<std::vector<int>>>
1707 node_index_to_outgoing_neighbors_by_cost_class_;
1708 std::vector<std::vector<std::vector<bool>>>
1709 node_index_to_outgoing_neighbor_indicator_by_cost_class_;
1711 std::vector<int> all_outgoing_nodes_;
1712 std::vector<int> all_incoming_nodes_;
1719 const NodeNeighborsByCostClass* GetOrCreateNodeNeighborsByCostClass(
1720 double neighbors_ratio, int64_t min_neighbors,
1721 double& neighbors_ratio_used,
bool add_vehicle_starts_to_neighbors =
true,
1722 bool add_vehicle_ends_to_neighbors =
false,
1723 bool only_sort_neighbors_for_partial_neighborhoods =
true);
1726 const NodeNeighborsByCostClass* GetOrCreateNodeNeighborsByCostClass(
1727 const NodeNeighborsParameters& params);
1734 CHECK(filter !=
nullptr);
1736 LOG(WARNING) <<
"Model is closed, filter addition will be ignored.";
1744 int64_t Start(
int vehicle)
const {
return paths_metadata_.Starts()[vehicle]; }
1746 int64_t End(
int vehicle)
const {
return paths_metadata_.Ends()[vehicle]; }
1748 bool IsStart(int64_t index)
const {
return paths_metadata_.IsStart(index); }
1750 bool IsEnd(int64_t index)
const {
return paths_metadata_.IsEnd(index); }
1753 int VehicleIndex(int64_t index)
const {
1754 return paths_metadata_.GetPath(index);
1761 bool IsVehicleUsed(
const Assignment& assignment,
int vehicle)
const;
1763#if !defined(SWIGPYTHON)
1766 const std::vector<IntVar*>& Nexts()
const {
return nexts_; }
1769 const std::vector<IntVar*>& VehicleVars()
const {
return vehicle_vars_; }
1773 const std::vector<IntVar*>& ResourceVars(
int resource_group)
const {
1774 return resource_vars_[resource_group];
1779 IntVar* NextVar(int64_t index)
const {
return nexts_[index]; }
1781 IntVar* ActiveVar(int64_t index)
const {
return active_[index]; }
1784 IntVar* ActiveVehicleVar(
int vehicle)
const {
1785 return vehicle_active_[vehicle];
1790 IntVar* VehicleRouteConsideredVar(
int vehicle)
const {
1791 return vehicle_route_considered_[vehicle];
1795 IntVar* VehicleVar(int64_t index)
const {
return vehicle_vars_[index]; }
1799 IntVar* ResourceVar(
int vehicle,
int resource_group)
const {
1800 DCHECK_LT(resource_group, resource_vars_.size());
1801 DCHECK_LT(vehicle, resource_vars_[resource_group].size());
1802 return resource_vars_[resource_group][vehicle];
1805 IntVar* CostVar()
const {
return cost_; }
1809 int64_t GetArcCostForVehicle(int64_t from_index, int64_t to_index,
1810 int64_t vehicle)
const;
1812 bool CostsAreHomogeneousAcrossVehicles()
const {
1813 return costs_are_homogeneous_across_vehicles_;
1817 int64_t GetHomogeneousCost(int64_t from_index, int64_t to_index)
const {
1818 return GetArcCostForVehicle(from_index, to_index, 0);
1822 int64_t GetArcCostForFirstSolution(int64_t from_index,
1823 int64_t to_index)
const;
1830 int64_t GetArcCostForClass(int64_t from_index, int64_t to_index,
1831 int64_t cost_class_index)
const;
1833 CostClassIndex GetCostClassIndexOfVehicle(int64_t vehicle)
const {
1835 DCHECK_GE(vehicle, 0);
1836 DCHECK_LT(vehicle, cost_class_index_of_vehicle_.size());
1837 DCHECK_GE(cost_class_index_of_vehicle_[vehicle], 0);
1838 return cost_class_index_of_vehicle_[vehicle];
1842 bool HasVehicleWithCostClassIndex(CostClassIndex cost_class_index)
const {
1844 if (cost_class_index == kCostClassIndexOfZeroCost) {
1845 return has_vehicle_with_zero_cost_class_;
1847 return cost_class_index < cost_classes_.size();
1850 int GetCostClassesCount()
const {
return cost_classes_.size(); }
1852 int GetNonZeroCostClassesCount()
const {
1853 return std::max(0, GetCostClassesCount() - 1);
1855 VehicleClassIndex GetVehicleClassIndexOfVehicle(int64_t vehicle)
const {
1857 return vehicle_class_index_of_vehicle_[vehicle];
1861 int GetVehicleOfClass(VehicleClassIndex vehicle_class)
const {
1863 const RoutingModel::VehicleTypeContainer& vehicle_type_container =
1864 GetVehicleTypeContainer();
1865 if (vehicle_class.value() >= GetVehicleClassesCount() ||
1866 vehicle_type_container.vehicles_per_vehicle_class[vehicle_class.value()]
1870 return vehicle_type_container
1871 .vehicles_per_vehicle_class[vehicle_class.value()]
1875 int GetVehicleClassesCount()
const {
return num_vehicle_classes_; }
1877 const std::vector<int>& GetSameVehicleIndicesOfIndex(
int node)
const {
1879 return same_vehicle_groups_[same_vehicle_group_[node]];
1882 const std::vector<int>& GetSameActivityIndicesOfIndex(
int node)
const {
1884 return same_active_var_groups_[same_active_var_group_[node]];
1887 int GetSameActivityGroupOfIndex(
int node)
const {
1889 return same_active_var_group_[node];
1892 int GetSameActivityGroupsCount()
const {
1894 return same_active_var_groups_.size();
1897 const std::vector<int>& GetSameActivityIndicesOfGroup(
int group)
const {
1899 return same_active_var_groups_[group];
1902 const VehicleTypeContainer& GetVehicleTypeContainer()
const {
1904 return vehicle_type_container_;
1925 bool ArcIsMoreConstrainedThanArc(int64_t from, int64_t to1, int64_t to2);
1930 std::string DebugOutputAssignment(
1932 const std::string& dimension_to_print)
const;
1939 std::vector<std::vector<std::pair<int64_t, int64_t>>> GetCumulBounds(
1940 const Assignment& solution_assignment,
const RoutingDimension& dimension);
1943 bool CheckIfAssignmentIsFeasible(
const Assignment& assignment,
1944 bool call_at_solution_monitors);
1947 Solver* solver()
const {
return solver_.get(); }
1951 bool CheckLimit(absl::Duration offset = absl::ZeroDuration()) {
1952 DCHECK(limit_ !=
nullptr);
1953 return limit_->CheckWithOffset(offset);
1957 absl::Duration RemainingTime()
const {
1958 DCHECK(limit_ !=
nullptr);
1959 return limit_->AbsoluteSolverDeadline() - solver_->Now();
1963 void UpdateTimeLimit(absl::Duration
time_limit) {
1965 limit->UpdateLimits(
time_limit, std::numeric_limits<int64_t>::max(),
1966 std::numeric_limits<int64_t>::max(),
1967 limit->solutions());
1971 absl::Duration TimeBuffer()
const {
return time_buffer_; }
1974 std::atomic<bool>* GetMutableCPSatInterrupt() {
return &interrupt_cp_sat_; }
1976 std::atomic<bool>* GetMutableCPInterrupt() {
return &interrupt_cp_; }
1978 void CancelSearch() {
1979 interrupt_cp_sat_ =
true;
1980 interrupt_cp_ =
true;
1985 int nodes()
const {
return nodes_; }
1987 int vehicles()
const {
return vehicles_; }
1989 int64_t Size()
const {
return nodes_ + vehicles_ - start_end_count_; }
1993 int64_t GetNumberOfDecisionsInFirstSolution(
1994 const RoutingSearchParameters& search_parameters)
const;
1995 int64_t GetNumberOfRejectsInFirstSolution(
1996 const RoutingSearchParameters& search_parameters)
const;
1998 operations_research::FirstSolutionStrategy::Value
1999 GetAutomaticFirstSolutionStrategy()
const {
2000 return automatic_first_solution_strategy_;
2004 bool IsMatchingModel()
const;
2008 bool AreRoutesInterdependent(
const RoutingSearchParameters& parameters)
const;
2013 using GetTabuVarsCallback =
2014 std::function<std::vector<operations_research::IntVar*>(RoutingModel*)>;
2016 void SetTabuVarsCallback(GetTabuVarsCallback tabu_var_callback);
2033 const RoutingDimension* dimension,
2034 std::function<int64_t(int64_t)> initializer);
2041 static std::unique_ptr<LocalSearchOperator> MakeGreedyDescentLSOperator(
2042 std::vector<IntVar*> variables);
2044 const std::vector<SearchMonitor*>& GetSearchMonitors()
const {
2062 const RoutingDimension* dimension);
2064 const PathsMetadata& GetPathsMetadata()
const {
return paths_metadata_; }
2066 BinCapacities* GetBinCapacities() {
return bin_capacities_.get(); }
2070 void SetSecondaryModel(RoutingModel* secondary_model,
2071 RoutingSearchParameters secondary_parameters) {
2073 secondary_model_ = secondary_model;
2074 secondary_parameters_ = std::move(secondary_parameters);
2080 const std::deque<int>& GetVehiclesOfSameClass(int64_t start_end_index)
const;
2087 std::vector<std::pair<int64_t, int64_t>> GetSameVehicleClassArcs(
2088 int64_t from_index, int64_t to_index)
const;
2092 enum RoutingLocalSearchOperator {
2095 LIGHT_RELOCATE_PAIR,
2103 GLOBAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS,
2104 LOCAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS,
2105 GLOBAL_CHEAPEST_INSERTION_PATH_LNS,
2106 LOCAL_CHEAPEST_INSERTION_PATH_LNS,
2107 RELOCATE_PATH_GLOBAL_CHEAPEST_INSERTION_INSERT_UNPERFORMED,
2108 GLOBAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS,
2109 LOCAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS,
2110 RELOCATE_EXPENSIVE_CHAIN,
2114 RELOCATE_AND_MAKE_ACTIVE,
2115 MAKE_ACTIVE_AND_RELOCATE,
2116 EXCHANGE_AND_MAKE_ACTIVE,
2117 EXCHANGE_PATH_START_ENDS_AND_MAKE_ACTIVE,
2119 MAKE_CHAIN_INACTIVE,
2122 EXTENDED_SWAP_ACTIVE,
2123 SHORTEST_PATH_SWAP_ACTIVE,
2124 SHORTEST_PATH_TWO_OPT,
2130 EXCHANGE_RELOCATE_PAIR,
2133 LOCAL_SEARCH_OPERATOR_COUNTER
2139 template <
typename T>
2140 struct ValuedNodes {
2141 std::vector<int64_t> indices;
2144 struct DisjunctionValues {
2146 int64_t max_cardinality;
2147 PenaltyCostBehavior penalty_cost_behavior;
2149 typedef ValuedNodes<DisjunctionValues> Disjunction;
2153 struct CostCacheElement {
2160 CostClassIndex cost_class_index;
2166 template <
class DimensionCumulOptimizer>
2167 struct DimensionCumulOptimizers {
2168 std::unique_ptr<DimensionCumulOptimizer> lp_optimizer;
2169 std::unique_ptr<DimensionCumulOptimizer> mp_optimizer;
2174 void AddNoCycleConstraintInternal();
2175 bool AddDimensionWithCapacityInternal(
2176 const std::vector<int>& evaluator_indices,
2177 const std::vector<int>& cumul_dependent_evaluator_indices,
2178 int64_t slack_max, std::vector<int64_t> vehicle_capacities,
2179 bool fix_start_cumul_to_zero,
const std::string& name);
2180 bool AddDimensionDependentDimensionWithVehicleCapacityInternal(
2181 const std::vector<int>& pure_transits,
2182 const std::vector<int>& dependent_transits,
2183 const RoutingDimension* base_dimension, int64_t slack_max,
2184 std::vector<int64_t> vehicle_capacities,
bool fix_start_cumul_to_zero,
2185 const std::string& name);
2186 bool InitializeDimensionInternal(
2187 const std::vector<int>& evaluator_indices,
2188 const std::vector<int>& cumul_dependent_evaluator_indices,
2189 const std::vector<int>& state_dependent_evaluator_indices,
2190 int64_t slack_max,
bool fix_start_cumul_to_zero,
2191 RoutingDimension* dimension);
2192 DimensionIndex GetDimensionIndex(
const std::string& dimension_name)
const;
2221 void StoreDimensionCumulOptimizers(
const RoutingSearchParameters& parameters);
2228 void FinalizeAllowedVehicles();
2230 void ComputeCostClasses(
const RoutingSearchParameters& parameters);
2231 void ComputeVehicleClasses();
2239 void ComputeVehicleTypes();
2241 void ComputeResourceClasses();
2251 void FinalizeVisitTypes();
2253 void TopologicallySortVisitTypes();
2254 int64_t GetArcCostForClassInternal(int64_t from_index, int64_t to_index,
2255 CostClassIndex cost_class_index)
const;
2256 int64_t GetArcCostWithGuidedLocalSearchPenalties(int64_t from_index,
2258 int64_t vehicle)
const {
2260 GetArcCostForVehicle(from_index, to_index, vehicle),
2261 solver()->GetGuidedLocalSearchPenalty(from_index, to_index, vehicle));
2263 std::function<int64_t(int64_t, int64_t, int64_t)>
2264 GetLocalSearchArcCostCallback(
2265 const RoutingSearchParameters& parameters)
const;
2266 int64_t GetHomogeneousArcCostWithGuidedLocalSearchPenalties(
2267 int64_t from_index, int64_t to_index)
const {
2268 return GetArcCostWithGuidedLocalSearchPenalties(from_index, to_index,
2271 std::function<int64_t(int64_t, int64_t)>
2272 GetLocalSearchHomogeneousArcCostCallback(
2273 const RoutingSearchParameters& parameters)
const;
2274 void AppendHomogeneousArcCosts(
const RoutingSearchParameters& parameters,
2276 std::vector<IntVar*>* cost_elements);
2277 void AppendArcCosts(
const RoutingSearchParameters& parameters,
int node_index,
2278 std::vector<IntVar*>* cost_elements);
2280 static const CostClassIndex kCostClassIndexOfZeroCost;
2281 int64_t SafeGetCostClassInt64OfVehicle(int64_t vehicle)
const {
2282 DCHECK_LT(0, vehicles_);
2283 return (vehicle >= 0 ? GetCostClassIndexOfVehicle(vehicle)
2284 : kCostClassIndexOfZeroCost)
2287 int64_t GetDimensionTransitCostSum(int64_t i, int64_t j,
2288 const CostClass& cost_class)
const;
2290 IntVar* CreateDisjunction(DisjunctionIndex disjunction);
2292 void AddPickupAndDeliverySetsInternal(
const std::vector<int64_t>& pickups,
2293 const std::vector<int64_t>& deliveries);
2296 IntVar* CreateSameVehicleCost(
int vehicle_index);
2299 int FindNextActive(
int index, absl::Span<const int64_t> indices)
const;
2303 bool RouteCanBeUsedByVehicle(
const Assignment& assignment,
int start_index,
2312 bool ReplaceUnusedVehicle(
int unused_vehicle,
int active_vehicle,
2315 void QuietCloseModel();
2316 void QuietCloseModelWithParameters(
2317 const RoutingSearchParameters& parameters) {
2319 CloseModelWithParameters(parameters);
2324 bool SolveMatchingModel(
Assignment* assignment,
2325 const RoutingSearchParameters& parameters);
2328 bool AppendAssignmentIfFeasible(
2330 std::vector<std::unique_ptr<Assignment>>* assignments,
2331 bool call_at_solution_monitors =
true);
2334 void LogSolution(
const RoutingSearchParameters& parameters,
2335 absl::string_view description, int64_t solution_cost,
2336 int64_t start_time_ms);
2340 bool check_compact_assignment)
const;
2343 std::string FindErrorInSearchParametersForModel(
2344 const RoutingSearchParameters& search_parameters)
const;
2346 void SetupSearch(
const RoutingSearchParameters& search_parameters);
2348 void UpdateSearchFromParametersIfNeeded(
2349 const RoutingSearchParameters& search_parameters);
2357 RegularLimit* GetOrCreateLargeNeighborhoodSearchLimit();
2358 RegularLimit* GetOrCreateFirstSolutionLargeNeighborhoodSearchLimit();
2361 void CreateNeighborhoodOperators(
const RoutingSearchParameters& parameters);
2363 const RoutingSearchParameters& search_parameters,
2364 const std::vector<LocalSearchOperator*>& operators)
const;
2366 const RoutingSearchParameters& search_parameters,
2367 const absl::flat_hash_set<RoutingLocalSearchOperator>&
2368 operators_to_consider)
const;
2370 struct FilterOptions {
2371 bool filter_objective;
2372 bool filter_with_cp_solver;
2374 bool operator==(
const FilterOptions& other)
const {
2375 return other.filter_objective == filter_objective &&
2376 other.filter_with_cp_solver == filter_with_cp_solver;
2378 template <
typename H>
2380 return H::combine(std::move(h), options.filter_objective,
2381 options.filter_with_cp_solver);
2384 std::vector<LocalSearchFilterManager::FilterEvent> CreateLocalSearchFilters(
2385 const RoutingSearchParameters& parameters,
const FilterOptions& options);
2387 const RoutingSearchParameters& parameters,
const FilterOptions& options);
2389 const RoutingSearchParameters& parameters,
SearchLimit* lns_limit);
2390 void CreateFirstSolutionDecisionBuilders(
2391 const RoutingSearchParameters& search_parameters);
2393 const RoutingSearchParameters& search_parameters)
const;
2395 const RoutingSearchParameters& parameters)
const;
2397 template <
typename Heuristic,
typename... Args>
2399 const Args&... args);
2402 const RoutingSearchParameters& search_parameters,
bool secondary_ls);
2404 const RoutingSearchParameters& search_parameters);
2405 void SetupDecisionBuilders(
const RoutingSearchParameters& search_parameters);
2406 void SetupMetaheuristics(
const RoutingSearchParameters& search_parameters);
2407 void SetupAssignmentCollector(
2408 const RoutingSearchParameters& search_parameters);
2409 void SetupTrace(
const RoutingSearchParameters& search_parameters);
2410 void SetupImprovementLimit(
const RoutingSearchParameters& search_parameters);
2411 void SetupSearchMonitors(
const RoutingSearchParameters& search_parameters);
2412 bool UsesLightPropagation(
2413 const RoutingSearchParameters& search_parameters)
const;
2414 GetTabuVarsCallback tabu_var_callback_;
2420 void DetectImplicitPickupAndDeliveries();
2422 int GetVehicleStartClass(int64_t start)
const;
2424 void InitSameVehicleGroups(
int number_of_groups) {
2425 same_vehicle_group_.assign(Size(), 0);
2426 same_vehicle_groups_.assign(number_of_groups, {});
2428 void SetSameVehicleGroup(
int index,
int group) {
2429 same_vehicle_group_[index] = group;
2430 same_vehicle_groups_[group].push_back(index);
2433 void InitSameActiveVarGroups(
int number_of_groups) {
2434 same_active_var_group_.assign(Size(), 0);
2435 same_active_var_groups_.assign(number_of_groups, {});
2437 void SetSameActiveVarGroup(
int index,
int group) {
2438 same_active_var_group_[index] = group;
2439 same_active_var_groups_[group].push_back(index);
2444 int GetGlobalCumulOptimizerIndex(
const RoutingDimension& dimension)
const;
2445 int GetLocalCumulOptimizerIndex(
const RoutingDimension& dimension)
const;
2448 std::unique_ptr<Solver> solver_;
2451 int max_active_vehicles_;
2454 std::vector<IntVar*> nexts_;
2455 std::vector<IntVar*> vehicle_vars_;
2456 std::vector<IntVar*> active_;
2463 std::vector<std::vector<IntVar*> > resource_vars_;
2466 std::vector<IntVar*> vehicle_active_;
2467 std::vector<IntVar*> vehicle_route_considered_;
2472 std::vector<IntVar*> is_bound_to_end_;
2473 mutable RevSwitch is_bound_to_end_ct_added_;
2475 absl::flat_hash_map<std::string, DimensionIndex> dimension_name_to_index_;
2476 util_intops::StrongVector<DimensionIndex, RoutingDimension*> dimensions_;
2482 std::vector<std::unique_ptr<ResourceGroup> > resource_groups_;
2484 util_intops::StrongVector<DimensionIndex, std::vector<int> >
2485 dimension_resource_group_indices_;
2490 std::vector<DimensionCumulOptimizers<GlobalDimensionCumulOptimizer> >
2491 global_dimension_optimizers_;
2492 util_intops::StrongVector<DimensionIndex, int> global_optimizer_index_;
2493 std::vector<DimensionCumulOptimizers<LocalDimensionCumulOptimizer> >
2494 local_dimension_optimizers_;
2495 util_intops::StrongVector<DimensionIndex, int> local_optimizer_index_;
2497 std::string primary_constrained_dimension_;
2500 std::vector<int> vehicle_to_transit_cost_;
2501 std::vector<int64_t> fixed_cost_of_vehicle_;
2502 std::vector<CostClassIndex> cost_class_index_of_vehicle_;
2503 bool has_vehicle_with_zero_cost_class_;
2504 std::vector<int64_t> linear_cost_factor_of_vehicle_;
2505 std::vector<int64_t> quadratic_cost_factor_of_vehicle_;
2506 bool vehicle_amortized_cost_factors_set_;
2508 std::function<std::optional<int64_t>(
const std::vector<int64_t>&)>>
2521 std::vector<bool> vehicle_used_when_empty_;
2523 absl::flat_hash_map<
2524 std::pair<std::string, std::string>,
2525 std::vector<Solver::PathEnergyCostConstraintSpecification::EnergyCost>,
2526 absl::Hash<std::pair<std::string, std::string>>>
2527 force_distance_to_energy_costs_;
2528 util_intops::StrongVector<CostClassIndex, CostClass> cost_classes_;
2530 bool costs_are_homogeneous_across_vehicles_;
2531 bool cache_callbacks_;
2532 mutable std::vector<CostCacheElement> cost_cache_;
2533 std::vector<VehicleClassIndex> vehicle_class_index_of_vehicle_;
2534 int num_vehicle_classes_;
2536 VehicleTypeContainer vehicle_type_container_;
2537 std::function<int(int64_t)> vehicle_start_class_callback_;
2539 util_intops::StrongVector<DisjunctionIndex, Disjunction> disjunctions_;
2541 std::vector<std::vector<DisjunctionIndex> > index_to_disjunctions_;
2543 std::vector<ValuedNodes<int64_t> > same_vehicle_costs_;
2546 std::vector<absl::flat_hash_set<int>> allowed_vehicles_;
2549 std::vector<PickupDeliveryPair> pickup_delivery_pairs_;
2550 std::vector<PickupDeliveryPair>
2551 implicit_pickup_delivery_pairs_without_alternatives_;
2552 std::vector<std::pair<DisjunctionIndex, DisjunctionIndex> >
2553 pickup_delivery_disjunctions_;
2558 std::vector<PickupDeliveryPosition> index_to_pickup_position_;
2560 std::vector<PickupDeliveryPosition> index_to_delivery_position_;
2562 std::vector<PickupAndDeliveryPolicy> vehicle_pickup_delivery_policy_;
2564 std::vector<int> same_vehicle_group_;
2566 std::vector<std::vector<int>> same_vehicle_groups_;
2568 std::vector<int> same_active_var_group_;
2570 std::vector<std::vector<int>> same_active_var_groups_;
2573 std::vector<int> index_to_visit_type_;
2575 std::vector<VisitTypePolicy> index_to_type_policy_;
2577 std::vector<std::vector<int> > single_nodes_of_type_;
2578 std::vector<std::vector<int> > pair_indices_of_type_;
2580 std::vector<absl::flat_hash_set<int> >
2581 hard_incompatible_types_per_type_index_;
2582 std::vector<absl::flat_hash_set<int> >
2583 temporal_incompatible_types_per_type_index_;
2584 const absl::flat_hash_set<int> empty_incompatibility_set_;
2586 std::vector<std::vector<absl::flat_hash_set<int> > >
2587 same_vehicle_required_type_alternatives_per_type_index_;
2588 std::vector<std::vector<absl::flat_hash_set<int> > >
2589 required_type_alternatives_when_adding_type_index_;
2590 std::vector<std::vector<absl::flat_hash_set<int> > >
2591 required_type_alternatives_when_removing_type_index_;
2592 const std::vector<absl::flat_hash_set<int>> empty_required_type_alternatives_;
2593 absl::flat_hash_map<int, absl::flat_hash_set<VisitTypePolicy> >
2594 trivially_infeasible_visit_types_to_policies_;
2611 std::vector<std::vector<int> > topologically_sorted_visit_types_;
2613 int num_visit_types_;
2616 std::vector<int> index_to_equivalence_class_;
2617 const PathsMetadata paths_metadata_;
2621 int start_end_count_;
2623 bool closed_ =
false;
2624 RoutingSearchStatus::Value status_ = RoutingSearchStatus::ROUTING_NOT_SOLVED;
2625 bool enable_deep_serialization_ =
true;
2628 RoutingModel* secondary_model_ =
nullptr;
2629 RoutingSearchParameters secondary_parameters_;
2630 std::unique_ptr<SecondaryOptimizer> secondary_optimizer_;
2633 std::vector<DecisionBuilder*> first_solution_decision_builders_;
2634 std::vector<IntVarFilteredDecisionBuilder*>
2635 first_solution_filtered_decision_builders_;
2637 FirstSolutionStrategy::Value automatic_first_solution_strategy_ =
2638 FirstSolutionStrategy::UNSET;
2640 std::vector<LocalSearchOperator*> local_search_operators_;
2641 std::vector<SearchMonitor*> monitors_;
2642 std::vector<SearchMonitor*> secondary_ls_monitors_;
2643 std::vector<SearchMonitor*> at_solution_monitors_;
2644 std::vector<std::function<void()>> restore_dimension_values_reset_callbacks_;
2645 int monitors_before_setup_ = 0;
2646 int monitors_after_setup_ = 0;
2649 bool local_optimum_reached_ =
false;
2651 int64_t objective_lower_bound_ =
kint64min;
2656 RoutingSearchParameters search_parameters_;
2667 std::vector<IntVar*> extra_vars_;
2668 std::vector<IntervalVar*> extra_intervals_;
2669 std::vector<LocalSearchOperator*> extra_operators_;
2670 absl::flat_hash_map<FilterOptions, LocalSearchFilterManager*>
2671 local_search_filter_managers_;
2672 std::vector<LocalSearchFilterManager::FilterEvent> extra_filters_;
2673 absl::flat_hash_map<NodeNeighborsParameters,
2674 std::unique_ptr<NodeNeighborsByCostClass>>
2675 node_neighbors_by_cost_class_per_size_;
2676 std::unique_ptr<FinalizerVariables> finalizer_variables_;
2678 std::unique_ptr<SweepArranger> sweep_arranger_;
2686 absl::Duration time_buffer_;
2688 std::atomic<bool> interrupt_cp_sat_;
2689 std::atomic<bool> interrupt_cp_;
2691 typedef std::pair<int64_t, int64_t> CacheKey;
2692 typedef absl::flat_hash_map<CacheKey, int64_t> TransitCallbackCache;
2693 typedef absl::flat_hash_map<CacheKey, StateDependentTransit>
2694 StateDependentTransitCallbackCache;
2704 std::vector<TransitCallback1> unary_transit_evaluators_;
2705 std::vector<TransitCallback2> transit_evaluators_;
2706 std::vector<TransitEvaluatorSign> transit_evaluator_sign_;
2708 std::vector<VariableIndexEvaluator2> state_dependent_transit_evaluators_;
2709 std::vector<std::unique_ptr<StateDependentTransitCallbackCache>>
2710 state_dependent_transit_evaluators_cache_;
2712 std::vector<CumulDependentTransitCallback2>
2713 cumul_dependent_transit_evaluators_;
2716 std::unique_ptr<BinCapacities> bin_capacities_;
2718 friend class RoutingDimension;
2720 friend class ResourceGroup::Resource;
2724class OR_DLL RoutingModelVisitor :
public BaseObject {
2727 static const char kLightElement[];
2728 static const char kLightElement2[];
2729 static const char kRemoveValues[];
2735class DisjunctivePropagator {
2743 int num_chain_tasks = 0;
2744 std::vector<int64_t> start_min;
2745 std::vector<int64_t> start_max;
2746 std::vector<int64_t> duration_min;
2747 std::vector<int64_t> duration_max;
2748 std::vector<int64_t> end_min;
2749 std::vector<int64_t> end_max;
2750 std::vector<bool> is_preemptible;
2751 std::vector<const SortedDisjointIntervalList*> forbidden_intervals;
2752 std::vector<std::pair<int64_t, int64_t>> distance_duration;
2753 int64_t span_min = 0;
2759 duration_min.clear();
2760 duration_max.clear();
2763 is_preemptible.clear();
2764 forbidden_intervals.clear();
2765 distance_duration.clear();
2768 num_chain_tasks = 0;
2774 bool Propagate(Tasks* tasks);
2777 bool Precedences(Tasks* tasks);
2780 bool MirrorTasks(Tasks* tasks);
2782 bool EdgeFinding(Tasks* tasks);
2785 bool DetectablePrecedencesWithChain(Tasks* tasks);
2787 bool ForbiddenIntervals(Tasks* tasks);
2789 bool DistanceDuration(Tasks* tasks);
2792 bool ChainSpanMin(Tasks* tasks);
2797 bool ChainSpanMinDynamic(Tasks* tasks);
2802 sat::ThetaLambdaTree<int64_t> theta_lambda_tree_;
2804 std::vector<int> tasks_by_start_min_;
2805 std::vector<int> tasks_by_end_max_;
2806 std::vector<int> event_of_task_;
2807 std::vector<int> nonchain_tasks_by_start_max_;
2809 std::vector<int64_t> total_duration_before_;
2812struct TravelBounds {
2813 std::vector<int64_t> min_travels;
2814 std::vector<int64_t> max_travels;
2815 std::vector<int64_t> pre_travels;
2816 std::vector<int64_t> post_travels;
2820 const TravelBounds& travel_bounds,
2821 const RoutingDimension& dimension,
2822 DisjunctivePropagator::Tasks* tasks);
2824 DisjunctivePropagator::Tasks* tasks);
2826 const RoutingModel::TransitCallback2& evaluator,
2827 std::vector<int64_t>* values);
2829 const RoutingDimension& dimension,
2830 TravelBounds* travel_bounds);
2843class GlobalVehicleBreaksConstraint :
public Constraint {
2845 explicit GlobalVehicleBreaksConstraint(
const RoutingDimension* dimension);
2847 return "GlobalVehicleBreaksConstraint";
2850 void Post()
override;
2851 void InitialPropagate()
override;
2854 void PropagateNode(
int node);
2855 void PropagateVehicle(
int vehicle);
2857 const RoutingModel* model_;
2858 const RoutingDimension*
const dimension_;
2859 std::vector<Demon*> vehicle_demons_;
2860 std::vector<int64_t> path_;
2866 void FillPartialPathOfVehicle(
int vehicle);
2867 void FillPathTravels(absl::Span<const int64_t> path);
2879 class TaskTranslator {
2881 TaskTranslator(IntVar* start, int64_t before_start, int64_t after_start)
2883 before_start_(before_start),
2884 after_start_(after_start) {}
2885 explicit TaskTranslator(IntervalVar* interval) : interval_(interval) {}
2886 TaskTranslator() =
default;
2888 void SetStartMin(int64_t value) {
2889 if (start_ !=
nullptr) {
2890 start_->SetMin(
CapAdd(before_start_, value));
2891 }
else if (interval_ !=
nullptr) {
2892 interval_->SetStartMin(value);
2895 void SetStartMax(int64_t value) {
2896 if (start_ !=
nullptr) {
2897 start_->SetMax(
CapAdd(before_start_, value));
2898 }
else if (interval_ !=
nullptr) {
2899 interval_->SetStartMax(value);
2902 void SetDurationMin(int64_t value) {
2903 if (interval_ !=
nullptr) {
2904 interval_->SetDurationMin(value);
2907 void SetEndMin(int64_t value) {
2908 if (start_ !=
nullptr) {
2909 start_->SetMin(
CapSub(value, after_start_));
2910 }
else if (interval_ !=
nullptr) {
2911 interval_->SetEndMin(value);
2914 void SetEndMax(int64_t value) {
2915 if (start_ !=
nullptr) {
2916 start_->SetMax(
CapSub(value, after_start_));
2917 }
else if (interval_ !=
nullptr) {
2918 interval_->SetEndMax(value);
2923 IntVar* start_ =
nullptr;
2924 int64_t before_start_;
2925 int64_t after_start_;
2926 IntervalVar* interval_ =
nullptr;
2930 std::vector<TaskTranslator> task_translators_;
2933 DisjunctivePropagator disjunctive_propagator_;
2934 DisjunctivePropagator::Tasks tasks_;
2937 TravelBounds travel_bounds_;
2940class TypeRegulationsChecker {
2942 explicit TypeRegulationsChecker(
const RoutingModel& model);
2943 virtual ~TypeRegulationsChecker() =
default;
2945 bool CheckVehicle(
int vehicle,
2946 const std::function<int64_t(int64_t)>& next_accessor);
2950 using VisitTypePolicy = RoutingModel::VisitTypePolicy;
2953 struct TypePolicyOccurrence {
2957 int num_type_added_to_vehicle = 0;
2963 int num_type_removed_from_vehicle = 0;
2968 int position_of_last_type_on_vehicle_up_to_visit = -1;
2975 bool TypeOccursOnRoute(
int type)
const;
2982 bool TypeCurrentlyOnRoute(
int type,
int pos)
const;
2984 void InitializeCheck(
int vehicle,
2985 const std::function<int64_t(int64_t)>& next_accessor);
2986 virtual void OnInitializeCheck() {}
2987 virtual bool HasRegulationsToCheck()
const = 0;
2988 virtual bool CheckTypeRegulations(
int type, VisitTypePolicy policy,
2990 virtual bool FinalizeCheck()
const {
return true; }
2992 const RoutingModel& model_;
2995 std::vector<TypePolicyOccurrence> occurrences_of_type_;
2996 std::vector<int64_t> current_route_visits_;
3000class TypeIncompatibilityChecker :
public TypeRegulationsChecker {
3002 TypeIncompatibilityChecker(
const RoutingModel& model,
3003 bool check_hard_incompatibilities);
3004 ~TypeIncompatibilityChecker()
override =
default;
3007 bool HasRegulationsToCheck()
const override;
3008 bool CheckTypeRegulations(
int type, VisitTypePolicy policy,
int pos)
override;
3012 bool check_hard_incompatibilities_;
3016class TypeRequirementChecker :
public TypeRegulationsChecker {
3018 explicit TypeRequirementChecker(
const RoutingModel& model)
3019 : TypeRegulationsChecker(model) {}
3020 ~TypeRequirementChecker()
override =
default;
3023 bool HasRegulationsToCheck()
const override;
3024 void OnInitializeCheck()
override {
3025 types_with_same_vehicle_requirements_on_route_.clear();
3030 bool CheckRequiredTypesCurrentlyOnRoute(
3031 const std::vector<absl::flat_hash_set<int> >& required_type_alternatives,
3034 bool CheckTypeRegulations(
int type, VisitTypePolicy policy,
int pos)
override;
3035 bool FinalizeCheck()
const override;
3037 absl::flat_hash_set<int> types_with_same_vehicle_requirements_on_route_;
3080class TypeRegulationsConstraint :
public Constraint {
3082 explicit TypeRegulationsConstraint(
const RoutingModel& model);
3084 void Post()
override;
3085 void InitialPropagate()
override;
3088 void PropagateNodeRegulations(
int node);
3089 void CheckRegulationsOnVehicle(
int vehicle);
3091 const RoutingModel& model_;
3092 TypeIncompatibilityChecker incompatibility_checker_;
3093 TypeRequirementChecker requirement_checker_;
3094 std::vector<Demon*> vehicle_demons_;
3112 BoundCost() :
bound(0), cost(0) {}
3113 BoundCost(int64_t bound, int64_t cost) :
bound(
bound), cost(cost) {}
3116class SimpleBoundCosts {
3118 SimpleBoundCosts(
int num_bounds, BoundCost default_bound_cost)
3119 : bound_costs_(num_bounds, default_bound_cost) {}
3121 BoundCost& bound_cost(
int element) {
return bound_costs_[element]; }
3123 BoundCost bound_cost(
int element)
const {
return bound_costs_[element]; }
3124 int Size() {
return bound_costs_.size(); }
3125 SimpleBoundCosts(
const SimpleBoundCosts&) =
delete;
3126 SimpleBoundCosts operator=(
const SimpleBoundCosts&) =
delete;
3129 std::vector<BoundCost> bound_costs_;
3152class RoutingDimension {
3155 RoutingDimension(
const RoutingDimension&) =
delete;
3156 RoutingDimension& operator=(
const RoutingDimension&) =
delete;
3158 ~RoutingDimension();
3160 RoutingModel* model()
const {
return model_; }
3164 int64_t GetTransitValue(int64_t from_index, int64_t to_index,
3165 int64_t vehicle)
const;
3168 int64_t GetTransitValueFromClass(int64_t from_index, int64_t to_index,
3169 int64_t vehicle_class)
const {
3170 return model_->TransitCallback(class_evaluators_[vehicle_class])(from_index,
3175 IntVar* CumulVar(int64_t index)
const {
return cumuls_[index]; }
3176 IntVar* TransitVar(int64_t index)
const {
return transits_[index]; }
3177 IntVar* FixedTransitVar(int64_t index)
const {
3178 return fixed_transits_[index];
3180 IntVar* SlackVar(int64_t index)
const {
return slacks_[index]; }
3187 void SetCumulVarRange(int64_t index, int64_t min, int64_t max) {
3188 CumulVar(index)->SetRange(min, max);
3191 int64_t GetCumulVarMin(int64_t index)
const {
return CumulVar(index)->Min(); }
3193 int64_t GetCumulVarMax(int64_t index)
const {
return CumulVar(index)->Max(); }
3195#if !defined(SWIGPYTHON)
3198 const std::vector<IntVar*>& cumuls()
const {
return cumuls_; }
3199 const std::vector<IntVar*>& fixed_transits()
const {
return fixed_transits_; }
3200 const std::vector<IntVar*>& transits()
const {
return transits_; }
3201 const std::vector<IntVar*>& slacks()
const {
return slacks_; }
3202#if !defined(SWIGCSHARP) && !defined(SWIGJAVA)
3204 const std::vector<SortedDisjointIntervalList>& forbidden_intervals()
const {
3205 return forbidden_intervals_;
3208 SortedDisjointIntervalList GetAllowedIntervalsInRange(
3209 int64_t index, int64_t min_value, int64_t max_value)
const;
3212 int64_t GetFirstPossibleGreaterOrEqualValueForNode(int64_t index,
3213 int64_t min_value)
const {
3214 DCHECK_LT(index, forbidden_intervals_.size());
3215 const SortedDisjointIntervalList& forbidden_intervals =
3216 forbidden_intervals_[index];
3217 const auto first_forbidden_interval_it =
3218 forbidden_intervals.FirstIntervalGreaterOrEqual(min_value);
3219 if (first_forbidden_interval_it != forbidden_intervals.end() &&
3220 min_value >= first_forbidden_interval_it->start) {
3222 return CapAdd(first_forbidden_interval_it->end, 1);
3231 int64_t GetLastPossibleLessOrEqualValueForNode(int64_t index,
3232 int64_t max_value)
const {
3233 DCHECK_LT(index, forbidden_intervals_.size());
3234 const SortedDisjointIntervalList& forbidden_intervals =
3235 forbidden_intervals_[index];
3236 const auto last_forbidden_interval_it =
3237 forbidden_intervals.LastIntervalLessOrEqual(max_value);
3238 if (last_forbidden_interval_it != forbidden_intervals.end() &&
3239 max_value <= last_forbidden_interval_it->end) {
3241 return CapSub(last_forbidden_interval_it->start, 1);
3247 const std::vector<int64_t>& vehicle_capacities()
const {
3248 return vehicle_capacities_;
3252 const RoutingModel::TransitCallback2& transit_evaluator(
int vehicle)
const {
3253 return model_->TransitCallback(
3254 class_evaluators_[vehicle_to_class_[vehicle]]);
3259 const RoutingModel::TransitCallback2& class_transit_evaluator(
3260 RoutingVehicleClassIndex vehicle_class)
const {
3261 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3262 DCHECK_NE(vehicle, -1);
3263 return transit_evaluator(vehicle);
3267 bool IsUnary()
const {
3268 for (
int evaluator_index : class_evaluators_) {
3269 if (model_->UnaryTransitCallbackOrNull(evaluator_index) ==
nullptr) {
3279 const RoutingModel::TransitCallback1& GetUnaryTransitEvaluator(
3280 int vehicle)
const {
3281 return model_->UnaryTransitCallbackOrNull(
3282 class_evaluators_[vehicle_to_class_[vehicle]]);
3284 const RoutingModel::TransitCallback2& GetBinaryTransitEvaluator(
3285 int vehicle)
const {
3286 return model_->TransitCallback(
3287 class_evaluators_[vehicle_to_class_[vehicle]]);
3291 bool AreVehicleTransitsPositive(
int vehicle)
const {
3292 const int evaluator_index = class_evaluators_[vehicle_to_class_[vehicle]];
3293 return model()->transit_evaluator_sign_[evaluator_index] ==
3294 RoutingModel::kTransitEvaluatorSignPositiveOrZero;
3296 bool AllTransitEvaluatorSignsAreUnknown()
const;
3297 RoutingModel::TransitEvaluatorSign GetTransitEvaluatorSign(
3298 int vehicle)
const {
3299 const int evaluator_index = class_evaluators_[vehicle_to_class_[vehicle]];
3300 return model()->transit_evaluator_sign_[evaluator_index];
3302 int vehicle_to_class(
int vehicle)
const {
return vehicle_to_class_[vehicle]; }
3303 int vehicle_to_cumul_dependent_class(
int vehicle)
const {
3304 if (vehicle_to_cumul_dependent_class_.empty()) {
3307 DCHECK_LT(vehicle, vehicle_to_cumul_dependent_class_.size());
3308 return vehicle_to_cumul_dependent_class_[vehicle];
3315 void SetSpanUpperBoundForVehicle(int64_t upper_bound,
int vehicle);
3322 void SetSpanCostCoefficientForVehicle(int64_t coefficient,
int vehicle);
3323 void SetSpanCostCoefficientForAllVehicles(int64_t coefficient);
3331 void SetSlackCostCoefficientForVehicle(int64_t coefficient,
int vehicle);
3332 void SetSlackCostCoefficientForAllVehicles(int64_t coefficient);
3339 void SetGlobalSpanCostCoefficient(int64_t coefficient);
3346 void SetCumulVarPiecewiseLinearCost(int64_t index,
3347 const PiecewiseLinearFunction& cost);
3350 bool HasCumulVarPiecewiseLinearCost(int64_t index)
const;
3353 const PiecewiseLinearFunction* GetCumulVarPiecewiseLinearCost(
3354 int64_t index)
const;
3365 void SetCumulVarSoftUpperBound(int64_t index, int64_t upper_bound,
3366 int64_t coefficient);
3369 bool HasCumulVarSoftUpperBound(int64_t index)
const;
3373 int64_t GetCumulVarSoftUpperBound(int64_t index)
const;
3377 int64_t GetCumulVarSoftUpperBoundCoefficient(int64_t index)
const;
3388 void SetCumulVarSoftLowerBound(int64_t index, int64_t lower_bound,
3389 int64_t coefficient);
3392 bool HasCumulVarSoftLowerBound(int64_t index)
const;
3396 int64_t GetCumulVarSoftLowerBound(int64_t index)
const;
3400 int64_t GetCumulVarSoftLowerBoundCoefficient(int64_t index)
const;
3417#if !defined(SWIGPYTHON)
3418 void SetBreakIntervalsOfVehicle(std::vector<IntervalVar*> breaks,
int vehicle,
3419 int pre_travel_evaluator,
3420 int post_travel_evaluator);
3424 void SetBreakIntervalsOfVehicle(std::vector<IntervalVar*> breaks,
int vehicle,
3425 std::vector<int64_t> node_visit_transits);
3431 void SetBreakDistanceDurationOfVehicle(int64_t distance, int64_t duration,
3435 void InitializeBreaks();
3437 bool HasBreakConstraints()
const;
3438#if !defined(SWIGPYTHON)
3441 void SetBreakIntervalsOfVehicle(
3442 std::vector<IntervalVar*> breaks,
int vehicle,
3443 std::vector<int64_t> node_visit_transits,
3444 std::function<int64_t(int64_t, int64_t)> delays);
3447 const std::vector<IntervalVar*>& GetBreakIntervalsOfVehicle(
3452 const std::vector<std::pair<int64_t, int64_t> >&
3453 GetBreakDistanceDurationOfVehicle(
int vehicle)
const;
3456 int GetPreTravelEvaluatorOfVehicle(
int vehicle)
const;
3457 int GetPostTravelEvaluatorOfVehicle(
int vehicle)
const;
3460 const RoutingDimension* base_dimension()
const {
return base_dimension_; }
3468 int64_t ShortestTransitionSlack(int64_t node)
const;
3471 const std::string& name()
const {
return name_; }
3475 const ReverseArcListGraph<int, int>& GetPathPrecedenceGraph()
const {
3476 return path_precedence_graph_;
3489 typedef std::function<int64_t(
int,
int)> PickupToDeliveryLimitFunction;
3491 void SetPickupToDeliveryLimitFunctionForPair(
3492 PickupToDeliveryLimitFunction limit_function,
int pair_index);
3494 bool HasPickupToDeliveryLimits()
const;
3496 int64_t GetPickupToDeliveryLimitForPair(
int pair_index,
3497 int pickup_alternative_index,
3498 int delivery_alternative_index)
const;
3500 struct NodePrecedence {
3502 int64_t second_node;
3504 enum class PerformedConstraint {
3506 kFirstAndSecondIndependent,
3508 kSecondImpliesFirst,
3510 kFirstAndSecondEqual,
3512 PerformedConstraint performed_constraint;
3515 void AddNodePrecedence(NodePrecedence precedence) {
3516 node_precedences_.push_back(precedence);
3518 const std::vector<NodePrecedence>& GetNodePrecedences()
const {
3519 return node_precedences_;
3523 enum class PrecedenceStatus {
3528 static PrecedenceStatus GetPrecedenceStatus(
3529 bool first_unperformed,
bool second_unperformed,
3530 NodePrecedence::PerformedConstraint performed_constraint) {
3531 switch (performed_constraint) {
3532 case NodePrecedence::PerformedConstraint::kFirstAndSecondIndependent:
3533 if (first_unperformed || second_unperformed) {
3534 return PrecedenceStatus::kInactive;
3537 case NodePrecedence::PerformedConstraint::kSecondImpliesFirst:
3538 if (first_unperformed) {
3539 if (!second_unperformed)
return PrecedenceStatus::kInvalid;
3540 return PrecedenceStatus::kInactive;
3542 if (second_unperformed)
return PrecedenceStatus::kInactive;
3544 case NodePrecedence::PerformedConstraint::kFirstAndSecondEqual:
3545 if (first_unperformed != second_unperformed) {
3546 return PrecedenceStatus::kInvalid;
3548 if (first_unperformed)
return PrecedenceStatus::kInactive;
3551 return PrecedenceStatus::kActive;
3553 void AddNodePrecedence(
3554 int64_t first_node, int64_t second_node, int64_t offset,
3555 NodePrecedence::PerformedConstraint performed_constraint =
3556 NodePrecedence::PerformedConstraint::kFirstAndSecondIndependent) {
3557 AddNodePrecedence({first_node, second_node, offset, performed_constraint});
3560 void AddNodePrecedence(int64_t first_node, int64_t second_node,
3563 {first_node, second_node, offset,
3564 NodePrecedence::PerformedConstraint::kFirstAndSecondIndependent});
3568 int64_t GetSpanUpperBoundForVehicle(
int vehicle)
const {
3569 return vehicle_span_upper_bounds_[vehicle];
3572 const std::vector<int64_t>& vehicle_span_upper_bounds()
const {
3573 return vehicle_span_upper_bounds_;
3576 int64_t GetSpanCostCoefficientForVehicle(
int vehicle)
const {
3577 return vehicle_span_cost_coefficients_[vehicle];
3580 int64_t GetSpanCostCoefficientForVehicleClass(
3581 RoutingVehicleClassIndex vehicle_class)
const {
3582 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3583 DCHECK_NE(vehicle, -1);
3584 return GetSpanCostCoefficientForVehicle(vehicle);
3588 const std::vector<int64_t>& vehicle_span_cost_coefficients()
const {
3589 return vehicle_span_cost_coefficients_;
3593 const std::vector<int64_t>& vehicle_slack_cost_coefficients()
const {
3594 return vehicle_slack_cost_coefficients_;
3597 int64_t GetSlackCostCoefficientForVehicle(
int vehicle)
const {
3598 return vehicle_slack_cost_coefficients_[vehicle];
3601 int64_t GetSlackCostCoefficientForVehicleClass(
3602 RoutingVehicleClassIndex vehicle_class)
const {
3603 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3604 DCHECK_NE(vehicle, -1);
3605 return GetSlackCostCoefficientForVehicle(vehicle);
3608 int64_t global_span_cost_coefficient()
const {
3609 return global_span_cost_coefficient_;
3612 int64_t GetGlobalOptimizerOffset()
const {
3613 DCHECK_GE(global_optimizer_offset_, 0);
3614 return global_optimizer_offset_;
3616 int64_t GetLocalOptimizerOffsetForVehicle(
int vehicle)
const {
3617 if (vehicle >= local_optimizer_offset_for_vehicle_.size()) {
3620 DCHECK_GE(local_optimizer_offset_for_vehicle_[vehicle], 0);
3621 return local_optimizer_offset_for_vehicle_[vehicle];
3626 void SetSoftSpanUpperBoundForVehicle(BoundCost bound_cost,
int vehicle) {
3627 if (!HasSoftSpanUpperBounds()) {
3628 vehicle_soft_span_upper_bound_ = std::make_unique<SimpleBoundCosts>(
3629 model_->vehicles(), BoundCost{kint64max, 0});
3631 vehicle_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost;
3633 bool HasSoftSpanUpperBounds()
const {
3634 return vehicle_soft_span_upper_bound_ !=
nullptr;
3636 BoundCost GetSoftSpanUpperBoundForVehicle(
int vehicle)
const {
3637 DCHECK(HasSoftSpanUpperBounds());
3638 return vehicle_soft_span_upper_bound_->bound_cost(vehicle);
3642 void SetQuadraticCostSoftSpanUpperBoundForVehicle(BoundCost bound_cost,
3644 if (!HasQuadraticCostSoftSpanUpperBounds()) {
3645 vehicle_quadratic_cost_soft_span_upper_bound_ =
3646 std::make_unique<SimpleBoundCosts>(model_->vehicles(),
3647 BoundCost{kint64max, 0});
3649 vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle) =
3652 bool HasQuadraticCostSoftSpanUpperBounds()
const {
3653 return vehicle_quadratic_cost_soft_span_upper_bound_ !=
nullptr;
3655 BoundCost GetQuadraticCostSoftSpanUpperBoundForVehicle(
int vehicle)
const {
3656 DCHECK(HasQuadraticCostSoftSpanUpperBounds());
3657 return vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle);
3664 int64_t coefficient;
3667 struct PiecewiseLinearCost {
3668 PiecewiseLinearCost() : var(nullptr), cost(nullptr) {}
3670 std::unique_ptr<PiecewiseLinearFunction> cost;
3674 RoutingDimension(RoutingModel* model, std::vector<int64_t> vehicle_capacities,
3675 const std::string& name,
3676 const RoutingDimension* base_dimension);
3677 RoutingDimension(RoutingModel* model, std::vector<int64_t> vehicle_capacities,
3678 const std::string& name, SelfBased);
3679 void Initialize(
const std::vector<int>& transit_evaluators,
3680 const std::vector<int>& cumul_dependent_transit_evaluators,
3681 const std::vector<int>& state_dependent_transit_evaluators,
3683 void InitializeCumuls();
3684 void InitializeTransits(
3685 absl::Span<const int> transit_evaluators,
3686 absl::Span<const int> cumul_dependent_transit_evaluators,
3687 absl::Span<const int> state_dependent_transit_evaluators,
3689 void InitializeTransitVariables(int64_t slack_max);
3691 void SetupCumulVarSoftUpperBoundCosts(
3692 std::vector<IntVar*>* cost_elements)
const;
3694 void SetupCumulVarSoftLowerBoundCosts(
3695 std::vector<IntVar*>* cost_elements)
const;
3696 void SetupCumulVarPiecewiseLinearCosts(
3697 std::vector<IntVar*>* cost_elements)
const;
3700 void SetupGlobalSpanCost(std::vector<IntVar*>* cost_elements)
const;
3701 void SetupSlackAndDependentTransitCosts()
const;
3703 void CloseModel(
bool use_light_propagation);
3705 void SetOffsetForGlobalOptimizer(int64_t offset) {
3706 global_optimizer_offset_ = std::max(
Zero(), offset);
3709 void SetVehicleOffsetsForLocalOptimizer(std::vector<int64_t> offsets) {
3711 std::transform(offsets.begin(), offsets.end(), offsets.begin(),
3712 [](int64_t offset) { return std::max(Zero(), offset); });
3713 local_optimizer_offset_for_vehicle_ = std::move(offsets);
3716 std::vector<IntVar*> cumuls_;
3717 std::vector<SortedDisjointIntervalList> forbidden_intervals_;
3718 std::vector<IntVar*> capacity_vars_;
3719 const std::vector<int64_t> vehicle_capacities_;
3720 std::vector<IntVar*> transits_;
3721 std::vector<IntVar*> fixed_transits_;
3724 std::vector<int> class_evaluators_;
3725 std::vector<int> vehicle_to_class_;
3730 std::vector<int> cumul_dependent_class_evaluators_;
3731 std::vector<int> vehicle_to_cumul_dependent_class_;
3733 ReverseArcListGraph<int, int> path_precedence_graph_;
3739 std::vector<NodePrecedence> node_precedences_;
3744 const RoutingDimension*
const base_dimension_;
3748 std::vector<int> state_dependent_class_evaluators_;
3749 std::vector<int> state_dependent_vehicle_to_class_;
3754 std::vector<PickupToDeliveryLimitFunction>
3755 pickup_to_delivery_limits_per_pair_index_;
3758 bool break_constraints_are_initialized_ =
false;
3760 std::vector<std::vector<IntervalVar*> > vehicle_break_intervals_;
3761 std::vector<std::vector<std::pair<int64_t, int64_t> > >
3762 vehicle_break_distance_duration_;
3767 std::vector<int> vehicle_pre_travel_evaluators_;
3768 std::vector<int> vehicle_post_travel_evaluators_;
3770 std::vector<IntVar*> slacks_;
3771 std::vector<IntVar*> dependent_transits_;
3772 std::vector<int64_t> vehicle_span_upper_bounds_;
3773 int64_t global_span_cost_coefficient_;
3774 std::vector<int64_t> vehicle_span_cost_coefficients_;
3775 std::vector<int64_t> vehicle_slack_cost_coefficients_;
3776 std::vector<SoftBound> cumul_var_soft_upper_bound_;
3777 std::vector<SoftBound> cumul_var_soft_lower_bound_;
3778 std::vector<PiecewiseLinearCost> cumul_var_piecewise_linear_cost_;
3779 RoutingModel*
const model_;
3780 const std::string name_;
3781 int64_t global_optimizer_offset_;
3782 std::vector<int64_t> local_optimizer_offset_for_vehicle_;
3784 std::unique_ptr<SimpleBoundCosts> vehicle_soft_span_upper_bound_;
3785 std::unique_ptr<SimpleBoundCosts>
3786 vehicle_quadratic_cost_soft_span_upper_bound_;
3787 friend class RoutingModel;
3788 friend class RoutingModelInspector;
3796 const RoutingSearchParameters& search_parameters,
3797 const Assignment* initial_solution,
3798 Assignment* solution);
3802 const RoutingModel& routing_model,
const RoutingDimension& dimension);
-------— Local Search Phase Parameters -------—
A reversible switch that can switch once from false to true.
Base class of all search limits.
A search monitor is a simple set of callbacks to monitor all search events.
For the time being, Solver is neither MT_SAFE nor MT_HOT.
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
bool operator==(const ProtoEnumIterator< E > &a, const ProtoEnumIterator< E > &b)
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
H AbslHashValue(H h, std::shared_ptr< Variable > i)
dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp
CpSolverResponse SolveWithParameters(const CpModelProto &model_proto, const SatParameters ¶ms)
Solves the given CpModelProto with the given parameters.
In SWIG mode, we don't want anything besides these top-level includes.
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)
IntVarLocalSearchFilter * MakeVehicleBreaksFilter(const RoutingModel &routing_model, const RoutingDimension &dimension)
std::function< const FloatSlopePiecewiseLinearFunction *(int64_t, int64_t)> RoutingCumulDependentTransitCallback2
std::function< int64_t(int64_t)> RoutingTransitCallback1
void FillTravelBoundsOfVehicle(int vehicle, absl::Span< const int64_t > path, const RoutingDimension &dimension, TravelBounds *travel_bounds)
void AppendTasksFromPath(absl::Span< const int64_t > path, const TravelBounds &travel_bounds, const RoutingDimension &dimension, DisjunctivePropagator::Tasks *tasks)
std::function< int64_t(int64_t, int64_t)> RoutingTransitCallback2
bool SolveModelWithSat(RoutingModel *model, const RoutingSearchParameters &search_parameters, const Assignment *initial_solution, Assignment *solution)
void FillPathEvaluation(absl::Span< const int64_t > path, const RoutingModel::TransitCallback2 &evaluator, std::vector< int64_t > *values)
void AppendTasksFromIntervals(const std::vector< IntervalVar * > &intervals, DisjunctivePropagator::Tasks *tasks)
trees with all degrees equal to
std::string DebugString() const
--— Constraint --—
static const int64_t kint64max
static const int64_t kint64min