344 template <
typename H>
351 std::vector<DimensionCost>
362 template <
typename H>
365 std::move(h), c.evaluator_index,
366 c.dimension_transit_evaluator_class_and_cost_coefficient);
410 class ResourceGroup {
422 return a.start_domain_ == b.start_domain_ &&
423 a.end_domain_ == b.end_domain_;
425 template <
typename H>
427 return H::combine(std::move(h), attributes.start_domain_,
428 attributes.end_domain_);
445 return index < dimension_attributes_per_index_.size()
446 ? attributes_[dimension_attributes_per_index_[index]]
447 : GetDefaultAttributes();
453 SetDimensionAttributes(std::move(attributes), dimension);
460 absl::flat_hash_map<DimensionIndex, int> dimension_attributes_;
462 dimension_attributes_per_index_;
463 std::vector<ResourceGroup::Attributes> attributes_;
478 return vehicles_requiring_resource_;
482 return vehicle_requires_resource_[vehicle];
486 int vehicle,
const std::vector<int>& allowed_resource_indices) {
487 DCHECK(!model_->closed_);
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());
499 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
500 vehicle_allowed_resources_[vehicle].clear();
504 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
505 return vehicle_allowed_resources_[vehicle];
508 DCHECK_LT(vehicle, vehicle_allowed_resources_.size());
509 return vehicle_allowed_resources_[vehicle].empty() ||
510 vehicle_allowed_resources_[vehicle].contains(resource);
513 const std::vector<Resource>&
GetResources()
const {
return resources_; }
515 DCHECK_LT(resource_index, resources_.size());
516 return resources_[resource_index];
520 return affected_dimension_indices_;
524 return resource_indices_per_class_.size();
528 DCHECK_LT(resource_class, resource_indices_per_class_.size());
529 return resource_indices_per_class_[resource_class];
534 return resource_indices_per_class_;
538 DCHECK_LT(resource_index, resource_class_indices_.size());
539 return resource_class_indices_[resource_index];
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(
551 int Size()
const {
return resources_.size(); }
552 int Index()
const {
return index_; }
558 vehicle_requires_resource_(model->
vehicles(), false),
559 vehicle_allowed_resources_(model->
vehicles()) {}
561 void ComputeResourceClasses();
565 std::vector<Resource> resources_;
568 std::vector<ResourceClassIndex> resource_class_indices_;
571 resource_indices_per_class_;
574 std::vector<bool> vehicle_requires_resource_;
575 std::vector<int> vehicles_requiring_resource_;
580 std::vector<absl::flat_hash_set<int> > vehicle_allowed_resources_;
583 absl::flat_hash_set<DimensionIndex> affected_dimension_indices_;
599 int64_t solve_period);
600 bool Solve(
const std::vector<RoutingModel::VariableValuePair>& in_state,
601 std::vector<RoutingModel::VariableValuePair>* out_state);
606 const int64_t solve_period_ = 0;
607 int64_t call_count_ = 0;
609 absl::flat_hash_map<operations_research::IntVar*, int> var_to_index_;
647 int RegisterUnaryTransitVector(std::vector<int64_t> values);
648 int RegisterUnaryTransitCallback(
649 TransitCallback1 callback,
650 TransitEvaluatorSign sign = kTransitEvaluatorSignUnknown);
652 int RegisterTransitMatrix(
653 std::vector<std::vector<int64_t> > values);
654 int RegisterTransitCallback(
655 TransitCallback2 callback,
656 TransitEvaluatorSign sign = kTransitEvaluatorSignUnknown);
657 int RegisterCumulDependentTransitCallback(
658 CumulDependentTransitCallback2 callback);
659 int RegisterStateDependentTransitCallback(VariableIndexEvaluator2 callback);
662 CHECK_LT(callback_index, transit_evaluators_.size());
663 return transit_evaluators_[callback_index];
666 CHECK_LT(callback_index, unary_transit_evaluators_.size());
667 return unary_transit_evaluators_[callback_index];
670 int callback_index)
const {
671 CHECK_LT(callback_index, cumul_dependent_transit_evaluators_.size());
672 return cumul_dependent_transit_evaluators_[callback_index];
675 int callback_index)
const {
676 CHECK_LT(callback_index, state_dependent_transit_evaluators_.size());
677 return state_dependent_transit_evaluators_[callback_index];
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);
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);
739 bool fix_start_cumul_to_zero,
740 const std::string& name) {
742 fix_start_cumul_to_zero, name);
753 std::pair<int, bool> AddVectorDimension(std::vector<int64_t> values,
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> > 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,
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);
787 bool AddDimensionDependentDimensionWithVehicleCapacity(
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(
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,
799 int64_t vehicle_capacity,
bool fix_start_cumul_to_zero,
800 const std::string& name);
804 const std::function<int64_t(int64_t)>& f, int64_t domain_start,
809 std::vector<std::string> GetAllDimensionNames()
const;
812 return dimensions_.get();
815 std::vector<RoutingDimension*> GetDimensionsWithSoftOrSpanCosts()
const;
817 std::vector<RoutingDimension*> GetUnaryDimensions()
const;
820 std::vector<const RoutingDimension*> GetDimensionsWithGlobalCumulOptimizers()
822 std::vector<const RoutingDimension*> GetDimensionsWithLocalCumulOptimizers()
827 return GetGlobalCumulOptimizerIndex(dimension) >= 0;
830 return GetLocalCumulOptimizerIndex(dimension) >= 0;
844 bool HasDimension(absl::string_view dimension_name)
const;
847 const std::string& dimension_name)
const;
851 const std::string& dimension_name)
const;
857 DCHECK(dimension_name.empty() ||
HasDimension(dimension_name));
858 primary_constrained_dimension_ = dimension_name;
862 return primary_constrained_dimension_;
866 ResourceGroup* AddResourceGroup();
870 return resource_groups_;
874 DCHECK_LT(rg_index, resource_groups_.size());
875 return resource_groups_[rg_index].get();
880 const std::vector<int>& GetDimensionResourceGroupIndices(
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];
929 template <
typename F>
930 void ForEachNodeInDisjunctionWithMaxCardinalityFromIndex(
931 int64_t index, int64_t max_cardinality, F f)
const {
933 if (disjunctions_[disjunction].value.max_cardinality == max_cardinality) {
934 for (
const int64_t d_index : disjunctions_[disjunction].indices) {
940#if !defined(SWIGPYTHON)
943 const std::vector<int64_t>& GetDisjunctionNodeIndices(
945 return disjunctions_[index].indices;
949 int64_t GetDisjunctionPenalty(DisjunctionIndex index) const {
950 return disjunctions_[index].value.penalty;
954 int64_t GetDisjunctionMaxCardinality(DisjunctionIndex index)
const {
955 return disjunctions_[index].value.max_cardinality;
959 PenaltyCostBehavior GetDisjunctionPenaltyCostBehavior(
961 return disjunctions_[index].value.penalty_cost_behavior;
964 int GetNumberOfDisjunctions()
const {
return disjunctions_.size(); }
991 return same_vehicle_costs_.size();
995 const std::vector<int64_t>& GetSoftSameVehicleIndices(
int index)
const {
996 return same_vehicle_costs_[index].indices;
999 int64_t GetSoftSameVehicleCost(
int index)
const {
1000 return same_vehicle_costs_[index].value;
1007 void SetAllowedVehiclesForIndex(absl::Span<const int> vehicles,
1011 bool IsVehicleAllowedForIndex(
int vehicle, int64_t index)
const {
1012 return allowed_vehicles_[index].empty() ||
1013 allowed_vehicles_[index].contains(vehicle);
1031 void AddPickupAndDelivery(int64_t pickup, int64_t delivery);
1035 void AddPickupAndDeliverySets(DisjunctionIndex pickup_disjunction,
1036 DisjunctionIndex delivery_disjunction);
1039 struct PickupDeliveryPosition {
1048 int64_t node_index)
const;
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;
1062 void SetPickupAndDeliveryPolicyOfAllVehicles(PickupAndDeliveryPolicy policy);
1063 void SetPickupAndDeliveryPolicyOfVehicle(PickupAndDeliveryPolicy policy,
1065 PickupAndDeliveryPolicy GetPickupAndDeliveryPolicyOfVehicle(
1070 int GetNumOfSingletonNodes()
const;
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_;
1085 const std::vector<PickupDeliveryPair>&
1086 GetImplicitUniquePickupAndDeliveryPairs()
const {
1088 return implicit_pickup_delivery_pairs_without_alternatives_;
1094 std::optional<int64_t> GetFirstMatchingPickupDeliverySibling(
1095 int64_t node,
const std::function<
bool(int64_t)>& is_match)
const;
1106 enum VisitTypePolicy {
1108 TYPE_ADDED_TO_VEHICLE,
1124 void SetVisitType(int64_t index,
int type, VisitTypePolicy type_policy);
1131 return visit_type_components_;
1136 const std::vector<std::vector<int>>& GetTopologicallySortedVisitTypes()
1139 return topologically_sorted_visit_types_;
1141 const std::vector<std::vector<std::vector<int>>>&
1142 GetTopologicallySortedNodePrecedences()
const {
1144 return topologically_sorted_node_precedences_;
1154 void AddHardTypeIncompatibility(int type1, int type2);
1164 return !hard_incompatible_types_per_type_index_.empty();
1166 bool HasTemporalTypeIncompatibilities()
const {
1167 return !temporal_incompatible_types_per_type_index_.empty();
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);
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> >&
1212 return !same_vehicle_required_type_alternatives_per_type_index_.empty();
1214 bool HasTemporalTypeRequirements()
const {
1215 return !required_type_alternatives_when_adding_type_index_.empty() ||
1216 !required_type_alternatives_when_removing_type_index_.empty();
1236 int64_t var_index)
const;
1247 max_active_vehicles_ = max_active_vehicles;
1250 int GetMaximumNumberOfActiveVehicles()
const {
return max_active_vehicles_; }
1274 const std::string& distance,
1275 int64_t cost_per_unit,
int vehicle);
1283 const std::string& distance,
1285 int64_t cost_per_unit_below_threshold,
1286 int64_t cost_per_unit_above_threshold,
1305 int64_t quadratic_cost_factor);
1308 int64_t quadratic_cost_factor,
1312 return linear_cost_factor_of_vehicle_;
1314 const std::vector<int64_t>& GetAmortizedQuadraticCostFactorOfVehicles()
1316 return quadratic_cost_factor_of_vehicle_;
1325 absl::AnyInvocable<std::optional<int64_t>(
const std::vector<int64_t>&)>
1327 bool costs_are_homogeneous_across_vehicles =
false);
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);
1339 void SetVehicleUsedWhenEmpty(
bool is_used,
int vehicle) {
1340 DCHECK_LT(vehicle, vehicles_);
1341 vehicle_used_when_empty_[vehicle] = is_used;
1344 bool IsVehicleUsedWhenEmpty(
int vehicle)
const {
1345 DCHECK_LT(vehicle, vehicles_);
1346 return vehicle_used_when_empty_[vehicle];
1353 return first_solution_evaluator_;
1358 first_solution_evaluator_ = std::move(evaluator);
1385 bool track_unchecked_neighbors =
false);
1412 int64_t target, int64_t cost);
1441 std::vector<const operations_research::Assignment*>* solutions =
nullptr);
1447 std::vector<const operations_research::Assignment*>* solutions =
nullptr);
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,
1462 std::vector<const operations_research::Assignment*>* solutions =
nullptr);
1491 const RoutingSearchStats& search_stats()
const {
return search_stats_; }
1493 bool enable_deep_serialization()
const {
return enable_deep_serialization_; }
1518 return preassignment_;
1521 return preassignment_;
1541 const std::vector<std::vector<int64_t>>& routes,
1542 bool ignore_inactive_indices);
1560 bool ignore_inactive_indices,
bool close_routes,
1566 std::vector<std::vector<int64_t>>* routes)
const;
1615 absl::Duration duration_limit,
bool* time_limit_was_reached =
nullptr);
1622 struct TransitionInfo {
1657 std::string
DebugString(std::string line_prefix =
"")
const;
1670 bool add_vehicle_starts_to_neighbors =
true;
1671 bool add_vehicle_ends_to_neighbors =
false;
1688 template <
typename H>
1696 class NodeNeighborsByCostClass {
1699 : routing_model_(*routing_model) {};
1708 int cost_class,
int node_index)
const {
1709 if (routing_model_.IsStart(node_index))
return empty_neighbors_;
1711 if (node_index_to_incoming_neighbors_by_cost_class_.empty()) {
1713 return all_incoming_nodes_;
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_;
1720 return node_index_to_incoming_neighbors[node_index];
1726 const std::vector<int>& GetOutgoingNeighborsOfNodeForCostClass(
1727 int cost_class,
int node_index)
const {
1728 if (routing_model_.IsEnd(node_index))
return empty_neighbors_;
1730 if (node_index_to_outgoing_neighbors_by_cost_class_.empty()) {
1731 DCHECK(IsFullNeighborhood());
1732 return all_outgoing_nodes_;
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_;
1739 return node_index_to_outgoing_neighbors[node_index];
1744 bool IsNeighborhoodArcForCostClass(
int cost_class, int64_t from,
1746 if (node_index_to_outgoing_neighbor_indicator_by_cost_class_.empty()) {
1747 DCHECK(full_neighborhood_);
1750 if (routing_model_.IsEnd(from)) {
1753 return node_index_to_outgoing_neighbor_indicator_by_cost_class_
1754 [cost_class][from][
to];
1757 bool IsFullNeighborhood()
const {
return full_neighborhood_; }
1760 const RoutingModel& routing_model_;
1761#if __cplusplus >= 202002L
1762 static constexpr std::vector<int> empty_neighbors_ = {};
1764 inline static const std::vector<int> empty_neighbors_ = {};
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_;
1774 std::vector<int> all_outgoing_nodes_;
1775 std::vector<int> all_incoming_nodes_;
1777 bool full_neighborhood_ =
false;
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);
1799 CHECK(filter !=
nullptr);
1801 LOG(WARNING) <<
"Model is closed, filter addition will be ignored.";
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); }
1815 bool IsEnd(int64_t index)
const {
return paths_metadata_.IsEnd(index); }
1819 return paths_metadata_.GetPath(index);
1825 int64_t index)
const;
1830#if !defined(SWIGPYTHON)
1833 const std::vector<operations_research::IntVar*>&
Nexts()
const {
1838 const std::vector<operations_research::IntVar*>& VehicleVars()
const {
1839 return vehicle_vars_;
1844 const std::vector<operations_research::IntVar*>&
ResourceVars(
1845 int resource_group)
const {
1846 return resource_vars_[resource_group];
1852 return nexts_[index];
1856 return active_[index];
1861 return vehicle_active_[vehicle];
1867 return vehicle_route_considered_[vehicle];
1872 return vehicle_vars_[index];
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];
1889 int64_t vehicle)
const;
1892 return costs_are_homogeneous_across_vehicles_;
1896 int64_t GetHomogeneousCost(int64_t from_index, int64_t to_index)
const {
1897 return GetArcCostForVehicle(from_index, to_index, 0);
1902 int64_t to_index)
const;
1910 int64_t cost_class_index)
const;
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];
1923 if (cost_class_index == kCostClassIndexOfZeroCost) {
1924 return has_vehicle_with_zero_cost_class_;
1926 return cost_class_index < cost_classes_.size();
1931 int GetNonZeroCostClassesCount()
const {
1932 return std::max(0, GetCostClassesCount() - 1);
1934 VehicleClassIndex GetVehicleClassIndexOfVehicle(int64_t vehicle)
const {
1936 return vehicle_class_index_of_vehicle_[vehicle];
1949 return vehicle_type_container
1954 int GetVehicleClassesCount()
const {
return num_vehicle_classes_; }
1956 const std::vector<int>& GetSameVehicleIndicesOfIndex(
int node)
const {
1958 return same_vehicle_groups_[same_vehicle_group_[node]];
1960 void AddSameActivityGroup(absl::Span<const int> nodes) {
1963 for (
auto it =
nodes.begin() + 1; it !=
nodes.end(); ++it) {
1964 solver_->AddConstraint(
1971 return same_active_var_groups_[same_active_var_group_[node]];
1974 int GetSameActivityGroupOfIndex(
int node)
const {
1976 return same_active_var_group_[node];
1979 const std::vector<int>& GetSameActivityGroups()
const {
1981 return same_active_var_group_;
1984 int GetSameActivityGroupsCount()
const {
1986 return same_active_var_groups_.size();
1989 const std::vector<int>& GetSameActivityIndicesOfGroup(
int group)
const {
1991 return same_active_var_groups_[group];
1996 void AddOrderedActivityGroup(std::vector<DisjunctionIndex> disjunctions) {
1998 if (disjunctions.size() <= 1)
return;
1999 ordered_activity_groups_.push_back(std::move(disjunctions));
2002 const std::vector<std::vector<DisjunctionIndex>>& GetOrderedActivityGroups()
2004 return ordered_activity_groups_;
2007 const VehicleTypeContainer& GetVehicleTypeContainer()
const {
2009 return vehicle_type_container_;
2037 const std::string& dimension_to_print)
const;
2044 std::vector<std::vector<std::pair<int64_t, int64_t>>>
GetCumulBounds(
2051 bool call_at_solution_monitors);
2058 bool CheckLimit(absl::Duration offset = absl::ZeroDuration()) {
2059 DCHECK(limit_ !=
nullptr);
2060 return limit_->CheckWithOffset(offset);
2065 DCHECK(limit_ !=
nullptr);
2066 return limit_->AbsoluteSolverDeadline() - solver_->Now();
2070 void UpdateTimeLimit(absl::Duration time_limit) {
2073 std::numeric_limits<int64_t>::max(),
2081 std::atomic<bool>* GetMutableCPSatInterrupt() {
return &interrupt_cp_sat_; }
2083 std::atomic<bool>* GetMutableCPInterrupt() {
return &interrupt_cp_; }
2085 void CancelSearch() {
2086 interrupt_cp_sat_ =
true;
2087 interrupt_cp_ =
true;
2092 int nodes()
const {
return nodes_; }
2094 int vehicles()
const {
return vehicles_; }
2096 int64_t Size()
const {
return nodes_ + vehicles_ - start_end_count_; }
2107 return automatic_first_solution_strategy_;
2111 bool IsMatchingModel()
const;
2121 std::function<std::vector<operations_research::IntVar*>(
RoutingModel*)>;
2141 std::function<int64_t(int64_t)> initializer);
2149 std::vector<operations_research::IntVar*> variables);
2173 BinCapacities* GetBinCapacities() {
return bin_capacities_.get(); }
2177 void SetSecondaryModel(RoutingModel* secondary_model,
2178 RoutingSearchParameters secondary_parameters) {
2180 secondary_model_ = secondary_model;
2181 secondary_parameters_ = std::move(secondary_parameters);
2195 int64_t from_index, int64_t to_index)
const;
2199 enum RoutingLocalSearchOperator {
2202 LIGHT_RELOCATE_PAIR,
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,
2223 RELOCATE_AND_MAKE_ACTIVE,
2224 MAKE_ACTIVE_AND_RELOCATE,
2225 EXCHANGE_AND_MAKE_ACTIVE,
2226 EXCHANGE_PATH_START_ENDS_AND_MAKE_ACTIVE,
2228 MAKE_CHAIN_INACTIVE,
2231 EXTENDED_SWAP_ACTIVE,
2232 SHORTEST_PATH_SWAP_ACTIVE,
2233 SHORTEST_PATH_TWO_OPT,
2239 EXCHANGE_RELOCATE_PAIR,
2242 LOCAL_SEARCH_OPERATOR_COUNTER
2248 template <
typename T>
2249 struct ValuedNodes {
2250 std::vector<int64_t> indices;
2253 struct DisjunctionValues {
2255 int64_t max_cardinality;
2256 PenaltyCostBehavior penalty_cost_behavior;
2258 typedef ValuedNodes<DisjunctionValues> Disjunction;
2262 struct CostCacheElement {
2269 CostClassIndex cost_class_index;
2275 template <
class DimensionCumulOptimizer>
2276 struct DimensionCumulOptimizers {
2277 std::unique_ptr<DimensionCumulOptimizer> lp_optimizer;
2278 std::unique_ptr<DimensionCumulOptimizer> mp_optimizer;
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,
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,
2301 DimensionIndex GetDimensionIndex(absl::string_view dimension_name)
const;
2337 void FinalizeAllowedVehicles();
2340 void ComputeVehicleClasses();
2348 void ComputeVehicleTypes();
2350 void ComputeResourceClasses();
2360 void FinalizeVisitTypes();
2361 void ComputeVisitTypesConnectedComponents();
2363 void TopologicallySortVisitTypes();
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,
2372 int64_t vehicle)
const {
2374 GetArcCostForVehicle(from_index, to_index, vehicle),
2375 solver()->GetGuidedLocalSearchPenalty(from_index, to_index, vehicle));
2377 std::function<int64_t(int64_t, int64_t, int64_t)>
2378 GetLocalSearchArcCostCallback(
2380 int64_t GetHomogeneousArcCostWithGuidedLocalSearchPenalties(
2381 int64_t from_index, int64_t to_index)
const {
2382 return GetArcCostWithGuidedLocalSearchPenalties(from_index, to_index,
2385 std::function<int64_t(int64_t, int64_t)>
2386 GetLocalSearchHomogeneousArcCostCallback(
2388 void AppendHomogeneousArcCosts(
2390 std::vector<operations_research::IntVar*>* cost_elements);
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)
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;
2417 bool RouteCanBeUsedByVehicle(
2418 const operations_research::Assignment& assignment,
int start_index,
2427 bool ReplaceUnusedVehicle(
2428 int unused_vehicle,
int active_vehicle,
2429 operations_research::Assignment* compact_assignment)
const;
2431 void QuietCloseModel();
2432 void QuietCloseModelWithParameters(
2435 CloseModelWithParameters(parameters);
2440 bool SolveMatchingModel(operations_research::Assignment* assignment,
2444 bool AppendAssignmentIfFeasible(
2445 const operations_research::Assignment& assignment,
2446 std::vector<std::unique_ptr<operations_research::Assignment>>*
2448 bool call_at_solution_monitors =
true);
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(
2466 void UpdateSearchFromParametersIfNeeded(
2470 operations_research::Assignment* GetOrCreateAssignment();
2471 operations_research::Assignment* GetOrCreateTmpAssignment();
2475 RegularLimit* GetOrCreateLargeNeighborhoodSearchLimit();
2476 RegularLimit* GetOrCreateFirstSolutionLargeNeighborhoodSearchLimit();
2482 const std::vector<LocalSearchOperator*>& operators)
const;
2485 const absl::flat_hash_set<RoutingLocalSearchOperator>&
2486 operators_to_consider)
const;
2488 struct FilterOptions {
2489 bool filter_objective;
2490 bool filter_with_cp_solver;
2492 bool operator==(
const FilterOptions& other)
const {
2493 return other.filter_objective == filter_objective &&
2494 other.filter_with_cp_solver == filter_with_cp_solver;
2496 template <
typename H>
2498 return H::combine(std::move(h), options.filter_objective,
2499 options.filter_with_cp_solver);
2502 std::vector<LocalSearchFilterManager::FilterEvent> CreateLocalSearchFilters(
2508 void CreateFirstSolutionDecisionBuilders(
2515 template <
typename Heuristic,
typename... Args>
2517 const Args&... args);
2525 void SetupAssignmentCollector(
2530 bool UsesLightPropagation(
2532 GetTabuVarsCallback tabu_var_callback_;
2538 void DetectImplicitPickupAndDeliveries();
2540 int GetVehicleStartClass(int64_t start)
const;
2542 void InitSameVehicleGroups(
int number_of_groups) {
2543 same_vehicle_group_.assign(Size(), 0);
2544 same_vehicle_groups_.assign(number_of_groups, {});
2546 void SetSameVehicleGroup(
int index,
int group) {
2547 same_vehicle_group_[index] = group;
2548 same_vehicle_groups_[group].push_back(index);
2551 void InitSameActiveVarGroups(
int number_of_groups) {
2552 same_active_var_group_.assign(Size(), 0);
2553 same_active_var_groups_.assign(number_of_groups, {});
2555 void SetSameActiveVarGroup(
int index,
int group) {
2556 same_active_var_group_[index] = group;
2557 same_active_var_groups_[group].push_back(index);
2566 std::unique_ptr<Solver> solver_;
2569 int max_active_vehicles_;
2572 std::vector<operations_research::IntVar*> nexts_;
2573 std::vector<operations_research::IntVar*> vehicle_vars_;
2574 std::vector<operations_research::IntVar*> active_;
2581 std::vector<std::vector<operations_research::IntVar*> > resource_vars_;
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_;
2600 std::vector<std::unique_ptr<ResourceGroup> > resource_groups_;
2602 util_intops::StrongVector<DimensionIndex, std::vector<int> >
2603 dimension_resource_group_indices_;
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_;
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>&)>>
2639 std::vector<bool> vehicle_used_when_empty_;
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_;
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_;
2654 VehicleTypeContainer vehicle_type_container_;
2655 std::function<int(int64_t)> vehicle_start_class_callback_;
2657 util_intops::StrongVector<DisjunctionIndex, Disjunction> disjunctions_;
2659 std::vector<std::vector<DisjunctionIndex> > index_to_disjunctions_;
2661 std::vector<ValuedNodes<int64_t> > same_vehicle_costs_;
2664 std::vector<absl::flat_hash_set<int>> allowed_vehicles_;
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_;
2676 std::vector<PickupDeliveryPosition> index_to_pickup_position_;
2678 std::vector<PickupDeliveryPosition> index_to_delivery_position_;
2680 std::vector<PickupAndDeliveryPolicy> vehicle_pickup_delivery_policy_;
2682 std::vector<int> same_vehicle_group_;
2684 std::vector<std::vector<int>> same_vehicle_groups_;
2686 std::vector<int> same_active_var_group_;
2688 std::vector<std::vector<int>> same_active_var_groups_;
2690 std::vector<std::vector<DisjunctionIndex>> ordered_activity_groups_;
2693 std::vector<int> index_to_visit_type_;
2695 std::vector<VisitTypePolicy> index_to_type_policy_;
2697 std::vector<std::vector<int> > single_nodes_of_type_;
2698 std::vector<std::vector<int> > pair_indices_of_type_;
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_;
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<int, absl::flat_hash_set<VisitTypePolicy> >
2714 trivially_infeasible_visit_types_to_policies_;
2731 std::vector<std::vector<int> > topologically_sorted_visit_types_;
2732 std::vector<std::vector<int>> visit_type_components_;
2734 int num_visit_types_;
2735 std::vector<std::vector<std::vector<int>>>
2736 topologically_sorted_node_precedences_;
2739 std::vector<int> index_to_equivalence_class_;
2744 int start_end_count_;
2746 bool closed_ =
false;
2748 bool enable_deep_serialization_ =
true;
2753 std::unique_ptr<SecondaryOptimizer> secondary_optimizer_;
2756 std::vector<DecisionBuilder*> first_solution_decision_builders_;
2757 std::vector<IntVarFilteredDecisionBuilder*>
2758 first_solution_filtered_decision_builders_;
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;
2772 bool local_optimum_reached_ =
false;
2774 int64_t objective_lower_bound_ =
kint64min;
2785 operations_research::Assignment* assignment_ =
nullptr;
2786 operations_research::Assignment* preassignment_ =
nullptr;
2787 operations_research::Assignment* tmp_assignment_ =
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_;
2801 std::unique_ptr<SweepArranger> sweep_arranger_;
2809 absl::Duration time_buffer_;
2813 std::atomic<bool> interrupt_cp_sat_;
2814 std::atomic<bool> interrupt_cp_;
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;
2829 std::vector<TransitCallback1> unary_transit_evaluators_;
2830 std::vector<TransitCallback2> transit_evaluators_;
2831 std::vector<TransitEvaluatorSign> transit_evaluator_sign_;
2833 std::vector<VariableIndexEvaluator2> state_dependent_transit_evaluators_;
2834 std::vector<std::unique_ptr<StateDependentTransitCallbackCache>>
2835 state_dependent_transit_evaluators_cache_;
2837 std::vector<CumulDependentTransitCallback2>
2838 cumul_dependent_transit_evaluators_;
2841 std::unique_ptr<BinCapacities> bin_capacities_;
2845 friend class ResourceGroup::Resource;
2852 static const char kLightElement[];
2853 static const char kLightElement2[];
2854 static const char kRemoveValues[];
3099 return cumuls_[
index];
3105 return fixed_transits_[index];
3108 return slacks_[index];
3122 int64_t GetCumulVarMax(int64_t index)
const {
return CumulVar(index)->Max(); }
3124#if !defined(SWIGPYTHON)
3127 const std::vector<operations_research::IntVar*>&
cumuls()
const {
3130 const std::vector<operations_research::IntVar*>& fixed_transits()
const {
3131 return fixed_transits_;
3133 const std::vector<operations_research::IntVar*>& transits()
const {
3136 const std::vector<operations_research::IntVar*>& slacks()
const {
3139#if !defined(SWIGCSHARP) && !defined(SWIGJAVA)
3142 return forbidden_intervals_;
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 =
3157 min_value >= first_forbidden_interval_it->start) {
3159 return CapAdd(first_forbidden_interval_it->end, 1);
3169 int64_t max_value)
const {
3170 DCHECK_LT(
index, forbidden_intervals_.size());
3172 forbidden_intervals_[
index];
3173 const auto last_forbidden_interval_it =
3176 max_value <= last_forbidden_interval_it->
end) {
3178 return CapSub(last_forbidden_interval_it->start, 1);
3184 const std::vector<int64_t>& vehicle_capacities()
const {
3185 return vehicle_capacities_;
3190 return model_->TransitCallback(
3191 class_evaluators_[vehicle_to_class_[vehicle]]);
3197 RoutingVehicleClassIndex vehicle_class)
const {
3198 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3199 DCHECK_NE(vehicle, -1);
3200 return transit_evaluator(vehicle);
3205 for (
int evaluator_index : class_evaluators_) {
3206 if (model_->UnaryTransitCallbackOrNull(evaluator_index) ==
nullptr) {
3217 int vehicle)
const {
3218 return model_->UnaryTransitCallbackOrNull(
3219 class_evaluators_[vehicle_to_class_[vehicle]]);
3222 int vehicle)
const {
3223 return model_->TransitCallback(
3224 class_evaluators_[vehicle_to_class_[vehicle]]);
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] ==
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];
3239 int vehicle_to_class(
int vehicle)
const {
return vehicle_to_class_[vehicle]; }
3241 if (vehicle_to_cumul_dependent_class_.empty()) {
3244 DCHECK_LT(vehicle, vehicle_to_cumul_dependent_class_.size());
3245 return vehicle_to_cumul_dependent_class_[vehicle];
3291 int64_t
index)
const;
3303 int64_t coefficient);
3326 int64_t coefficient);
3354#if !defined(SWIGPYTHON)
3356 int pre_travel_evaluator,
3357 int post_travel_evaluator);
3362 std::vector<int64_t> node_visit_transits);
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);
3389 const std::vector<std::pair<int64_t, int64_t> >&
3405 int64_t ShortestTransitionSlack(int64_t node)
const;
3408 operations_research::RoutingDimensionIndex index()
const {
3412 const std::string& name()
const {
return name_; }
3416 const ReverseArcListGraph<int, int>& GetPathPrecedenceGraph()
const {
3417 return path_precedence_graph_;
3438 int pickup_alternative_index,
3439 int delivery_alternative_index)
const;
3443 int64_t second_node;
3445 enum class PerformedConstraint {
3447 kFirstAndSecondIndependent,
3449 kSecondImpliesFirst,
3451 kFirstImpliesSecond,
3453 kFirstAndSecondEqual,
3455 PerformedConstraint performed_constraint;
3458 void AddNodePrecedence(NodePrecedence precedence) {
3459 node_precedences_.push_back(precedence);
3462 return node_precedences_;
3472 bool first_unperformed,
bool second_unperformed,
3476 if (first_unperformed || second_unperformed) {
3480 case NodePrecedence::PerformedConstraint::kSecondImpliesFirst:
3481 if (first_unperformed) {
3485 if (second_unperformed)
return PrecedenceStatus::kInactive;
3488 if (second_unperformed) {
3492 if (first_unperformed)
return PrecedenceStatus::kInactive;
3494 case NodePrecedence::PerformedConstraint::kFirstAndSecondEqual:
3495 if (first_unperformed != second_unperformed) {
3496 return PrecedenceStatus::kInvalid;
3498 if (first_unperformed)
return PrecedenceStatus::kInactive;
3501 return PrecedenceStatus::kActive;
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});
3510 void AddNodePrecedence(int64_t first_node, int64_t second_node,
3513 {first_node, second_node, offset,
3514 NodePrecedence::PerformedConstraint::kFirstAndSecondIndependent});
3518 int64_t GetSpanUpperBoundForVehicle(
int vehicle)
const {
3519 return vehicle_span_upper_bounds_[vehicle];
3522 const std::vector<int64_t>& vehicle_span_upper_bounds()
const {
3523 return vehicle_span_upper_bounds_;
3526 int64_t GetSpanCostCoefficientForVehicle(
int vehicle)
const {
3527 return vehicle_span_cost_coefficients_[vehicle];
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);
3539 return vehicle_span_cost_coefficients_;
3544 return vehicle_slack_cost_coefficients_;
3548 return vehicle_slack_cost_coefficients_[vehicle];
3552 RoutingVehicleClassIndex vehicle_class)
const {
3553 const int vehicle = model_->GetVehicleOfClass(vehicle_class);
3554 DCHECK_NE(vehicle, -1);
3559 return global_span_cost_coefficient_;
3562 int64_t GetGlobalOptimizerOffset()
const {
3563 DCHECK_GE(global_optimizer_offset_, 0);
3564 return global_optimizer_offset_;
3566 int64_t GetLocalOptimizerOffsetForVehicle(
int vehicle)
const {
3567 if (vehicle >= local_optimizer_offset_for_vehicle_.size()) {
3570 DCHECK_GE(local_optimizer_offset_for_vehicle_[vehicle], 0);
3571 return local_optimizer_offset_for_vehicle_[vehicle];
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});
3581 vehicle_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost;
3583 bool HasSoftSpanUpperBounds()
const {
3584 return vehicle_soft_span_upper_bound_ !=
nullptr;
3588 return vehicle_soft_span_upper_bound_->bound_cost(vehicle);
3592 void SetQuadraticCostSoftSpanUpperBoundForVehicle(
BoundCost bound_cost,
3594 if (!HasQuadraticCostSoftSpanUpperBounds()) {
3595 vehicle_quadratic_cost_soft_span_upper_bound_ =
3596 std::make_unique<SimpleBoundCosts>(model_->vehicles(),
3599 vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle) =
3602 bool HasQuadraticCostSoftSpanUpperBounds()
const {
3603 return vehicle_quadratic_cost_soft_span_upper_bound_ !=
nullptr;
3605 BoundCost GetQuadraticCostSoftSpanUpperBoundForVehicle(
int vehicle)
const {
3607 return vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle);
3614 int64_t coefficient;
3617 struct PiecewiseLinearCost {
3618 PiecewiseLinearCost() : var(
nullptr), cost(
nullptr) {}
3620 std::unique_ptr<PiecewiseLinearFunction> cost;
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,
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,
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);
3656 void SetOffsetForGlobalOptimizer(int64_t offset) {
3657 global_optimizer_offset_ = std::max(
Zero(), offset);
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);
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_;
3681 std::vector<int> cumul_dependent_class_evaluators_;
3682 std::vector<int> vehicle_to_cumul_dependent_class_;
3690 std::vector<NodePrecedence> node_precedences_;
3695 const RoutingDimension*
const base_dimension_;
3699 std::vector<int> state_dependent_class_evaluators_;
3700 std::vector<int> state_dependent_vehicle_to_class_;
3705 std::vector<PickupToDeliveryLimitFunction>
3706 pickup_to_delivery_limits_per_pair_index_;
3709 bool break_constraints_are_initialized_ =
false;
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_;
3718 std::vector<int> vehicle_pre_travel_evaluators_;
3719 std::vector<int> vehicle_post_travel_evaluators_;
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;
3748 const RoutingSearchParameters& search_parameters,