1 // Copyright 2010-2021 Google LLC 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 /// The vehicle routing library lets one model and solve generic vehicle routing 15 /// problems ranging from the Traveling Salesman Problem to more complex 16 /// problems such as the Capacitated Vehicle Routing Problem with Time Windows. 17 /// 18 /// The objective of a vehicle routing problem is to build routes covering a set 19 /// of nodes minimizing the overall cost of the routes (usually proportional to 20 /// the sum of the lengths of each segment of the routes) while respecting some 21 /// problem-specific constraints (such as the length of a route). A route is 22 /// equivalent to a path connecting nodes, starting/ending at specific 23 /// starting/ending nodes. 24 /// 25 /// The term "vehicle routing" is historical and the category of problems solved 26 /// is not limited to the routing of vehicles: any problem involving finding 27 /// routes visiting a given number of nodes optimally falls under this category 28 /// of problems, such as finding the optimal sequence in a playlist. 29 /// The literature around vehicle routing problems is extremely dense but one 30 /// can find some basic introductions in the following links: 31 /// - http://en.wikipedia.org/wiki/Travelling_salesman_problem 32 /// - http://www.tsp.gatech.edu/history/index.html 33 /// - http://en.wikipedia.org/wiki/Vehicle_routing_problem 34 /// 35 /// The vehicle routing library is a vertical layer above the constraint 36 /// programming library (ortools/constraint_programming:cp). 37 /// One has access to all underlying constrained variables of the vehicle 38 /// routing model which can therefore be enriched by adding any constraint 39 /// available in the constraint programming library. 40 /// 41 /// There are two sets of variables available: 42 /// - path variables: 43 /// * "next(i)" variables representing the immediate successor of the node 44 /// corresponding to i; use IndexToNode() to get the node corresponding to 45 /// a "next" variable value; note that node indices are strongly typed 46 /// integers (cf. ortools/base/int_type.h); 47 /// * "vehicle(i)" variables representing the vehicle route to which the 48 /// node corresponding to i belongs; 49 /// * "active(i)" boolean variables, true if the node corresponding to i is 50 /// visited and false if not; this can be false when nodes are either 51 /// optional or part of a disjunction; 52 /// * The following relationships hold for all i: 53 /// active(i) == 0 <=> next(i) == i <=> vehicle(i) == -1, 54 /// next(i) == j => vehicle(j) == vehicle(i). 55 /// - dimension variables, used when one is accumulating quantities along 56 /// routes, such as weight or volume carried, distance or time: 57 /// * "cumul(i,d)" variables representing the quantity of dimension d when 58 /// arriving at the node corresponding to i; 59 /// * "transit(i,d)" variables representing the quantity of dimension d added 60 /// after visiting the node corresponding to i. 61 /// * The following relationship holds for all (i,d): 62 /// next(i) == j => cumul(j,d) == cumul(i,d) + transit(i,d). 63 /// Solving the vehicle routing problems is mainly done using approximate 64 /// methods (namely local search, 65 /// cf. http://en.wikipedia.org/wiki/Local_search_(optimization) ), potentially 66 /// combined with exact techniques based on dynamic programming and exhaustive 67 /// tree search. 68 // TODO(user): Add a section on costs (vehicle arc costs, span costs, 69 // disjunctions costs). 70 // 71 /// Advanced tips: Flags are available to tune the search used to solve routing 72 /// problems. Here is a quick overview of the ones one might want to modify: 73 /// - Limiting the search for solutions: 74 /// * routing_solution_limit (default: kint64max): stop the search after 75 /// finding 'routing_solution_limit' improving solutions; 76 /// * routing_time_limit (default: kint64max): stop the search after 77 /// 'routing_time_limit' milliseconds; 78 /// - Customizing search: 79 /// * routing_first_solution (default: select the first node with an unbound 80 /// successor and connect it to the first available node): selects the 81 /// heuristic to build a first solution which will then be improved by local 82 /// search; possible values are GlobalCheapestArc (iteratively connect two 83 /// nodes which produce the cheapest route segment), LocalCheapestArc 84 /// (select the first node with an unbound successor and connect it to the 85 /// node which produces the cheapest route segment), PathCheapestArc 86 /// (starting from a route "start" node, connect it to the node which 87 /// produces the cheapest route segment, then extend the route by iterating 88 /// on the last node added to the route). 89 /// * Local search neighborhoods: 90 /// - routing_no_lns (default: false): forbids the use of Large Neighborhood 91 /// Search (LNS); LNS can find good solutions but is usually very slow. 92 /// Refer to the description of PATHLNS in the LocalSearchOperators enum 93 /// in constraint_solver.h for more information. 94 /// - routing_no_tsp (default: true): forbids the use of exact methods to 95 /// solve "sub"-traveling salesman problems (TSPs) of the current model 96 /// (such as sub-parts of a route, or one route in a multiple route 97 /// problem). Uses dynamic programming to solve such TSPs with a maximum 98 /// size (in number of nodes) up to cp_local_search_tsp_opt_size (flag 99 /// with a default value of 13 nodes). It is not activated by default 100 /// because it can slow down the search. 101 /// * Meta-heuristics: used to guide the search out of local minima found by 102 /// local search. Note that, in general, a search with metaheuristics 103 /// activated never stops, therefore one must specify a search limit. 104 /// Several types of metaheuristics are provided: 105 /// - routing_guided_local_search (default: false): activates guided local 106 /// search (cf. http://en.wikipedia.org/wiki/Guided_Local_Search); 107 /// this is generally the most efficient metaheuristic for vehicle 108 /// routing; 109 /// - routing_simulated_annealing (default: false): activates simulated 110 /// annealing (cf. http://en.wikipedia.org/wiki/Simulated_annealing); 111 /// - routing_tabu_search (default: false): activates tabu search (cf. 112 /// http://en.wikipedia.org/wiki/Tabu_search). 113 /// 114 /// Code sample: 115 /// Here is a simple example solving a traveling salesman problem given a cost 116 /// function callback (returns the cost of a route segment): 117 /// 118 /// - Define a custom distance/cost function from an index to another; in this 119 /// example just returns the sum of the indices: 120 /// 121 /// int64_t MyDistance(int64_t from, int64_t to) { 122 /// return from + to; 123 /// } 124 /// 125 /// - Create a routing model for a given problem size (int number of nodes) and 126 /// number of routes (here, 1): 127 /// 128 /// RoutingIndexManager manager(...number of nodes..., 1); 129 /// RoutingModel routing(manager); 130 /// 131 /// - Set the cost function by registering an std::function<int64_t(int64_t, 132 /// int64_t)> in the model and passing its index as the vehicle cost. 133 /// 134 /// const int cost = routing.RegisterTransitCallback(MyDistance); 135 /// routing.SetArcCostEvaluatorOfAllVehicles(cost); 136 /// 137 /// - Find a solution using Solve(), returns a solution if any (owned by 138 /// routing): 139 /// 140 /// const Assignment* solution = routing.Solve(); 141 /// CHECK(solution != nullptr); 142 /// 143 /// - Inspect the solution cost and route (only one route here): 144 /// 145 /// LOG(INFO) << "Cost " << solution->ObjectiveValue(); 146 /// const int route_number = 0; 147 /// for (int64_t node = routing.Start(route_number); 148 /// !routing.IsEnd(node); 149 /// node = solution->Value(routing.NextVar(node))) { 150 /// LOG(INFO) << manager.IndexToNode(node); 151 /// } 152 /// 153 /// 154 /// Keywords: Vehicle Routing, Traveling Salesman Problem, TSP, VRP, CVRPTW, 155 /// PDP. 156 157 #ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_H_ 158 #define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_H_ 159 160 #include <algorithm> 161 #include <deque> 162 #include <functional> 163 #include <memory> 164 #include <set> 165 #include <string> 166 #include <tuple> 167 #include <utility> 168 #include <vector> 169 170 #include "absl/container/flat_hash_map.h" 171 #include "absl/container/flat_hash_set.h" 172 #include "absl/functional/bind_front.h" 173 #include "absl/memory/memory.h" 174 #include "absl/time/time.h" 175 #include "ortools/base/int_type.h" 176 #include "ortools/base/integral_types.h" 177 #include "ortools/base/logging.h" 178 #include "ortools/base/macros.h" 179 #include "ortools/base/map_util.h" 180 #include "ortools/base/strong_vector.h" 181 #include "ortools/constraint_solver/constraint_solver.h" 182 #include "ortools/constraint_solver/constraint_solveri.h" 183 #include "ortools/constraint_solver/routing_enums.pb.h" 184 #include "ortools/constraint_solver/routing_index_manager.h" 185 #include "ortools/constraint_solver/routing_parameters.pb.h" 186 #include "ortools/constraint_solver/routing_types.h" 187 #include "ortools/graph/graph.h" 188 #include "ortools/sat/theta_tree.h" 189 #include "ortools/util/bitset.h" 190 #include "ortools/util/piecewise_linear_function.h" 191 #include "ortools/util/range_query_function.h" 192 #include "ortools/util/saturated_arithmetic.h" 193 #include "ortools/util/sorted_interval_list.h" 194 195 namespace operations_research { 196 197 class GlobalDimensionCumulOptimizer; 198 class LocalDimensionCumulOptimizer; 199 class LocalSearchPhaseParameters; 200 #ifndef SWIG 201 class IndexNeighborFinder; 202 class IntVarFilteredDecisionBuilder; 203 #endif 204 class RoutingDimension; 205 #ifndef SWIG 206 using util::ReverseArcListGraph; 207 class SweepArranger; 208 #endif 209 210 class RoutingModel { 211 public: 212 /// Status of the search. 213 enum Status { 214 /// Problem not solved yet (before calling RoutingModel::Solve()). 215 ROUTING_NOT_SOLVED, 216 /// Problem solved successfully after calling RoutingModel::Solve(). 217 ROUTING_SUCCESS, 218 /// No solution found to the problem after calling RoutingModel::Solve(). 219 ROUTING_FAIL, 220 /// Time limit reached before finding a solution with RoutingModel::Solve(). 221 ROUTING_FAIL_TIMEOUT, 222 /// Model, model parameters or flags are not valid. 223 ROUTING_INVALID 224 }; 225 226 /// Types of precedence policy applied to pickup and delivery pairs. 227 enum PickupAndDeliveryPolicy { 228 /// Any precedence is accepted. 229 PICKUP_AND_DELIVERY_NO_ORDER, 230 /// Deliveries must be performed in reverse order of pickups. 231 PICKUP_AND_DELIVERY_LIFO, 232 /// Deliveries must be performed in the same order as pickups. 233 PICKUP_AND_DELIVERY_FIFO 234 }; 235 typedef RoutingCostClassIndex CostClassIndex; 236 typedef RoutingDimensionIndex DimensionIndex; 237 typedef RoutingDisjunctionIndex DisjunctionIndex; 238 typedef RoutingVehicleClassIndex VehicleClassIndex; 239 typedef RoutingTransitCallback1 TransitCallback1; 240 typedef RoutingTransitCallback2 TransitCallback2; 241 242 // TODO(user): Remove all SWIG guards by adding the @ignore in .i. 243 #if !defined(SWIG) 244 typedef RoutingIndexPair IndexPair; 245 typedef RoutingIndexPairs IndexPairs; 246 #endif // SWIG 247 248 #if !defined(SWIG) 249 /// What follows is relevant for models with time/state dependent transits. 250 /// Such transits, say from node A to node B, are functions f: 251 /// int64_t->int64_t of the cumuls of a dimension. The user is free to 252 /// implement the abstract RangeIntToIntFunction interface, but it is expected 253 /// that the implementation of each method is quite fast. For 254 /// performance-related reasons, StateDependentTransit keeps an additional 255 /// pointer to a RangeMinMaxIndexFunction, with similar functionality to 256 /// RangeIntToIntFunction, for g(x) = f(x)+x, where f is the transit from A to 257 /// B. In most situations the best solutions are problem-specific, but in case 258 /// of doubt the user may use the MakeStateDependentTransit function from the 259 /// routing library, which works out-of-the-box, with very good running time, 260 /// but memory inefficient in some situations. 261 struct StateDependentTransit { 262 RangeIntToIntFunction* transit; /// f(x) 263 RangeMinMaxIndexFunction* transit_plus_identity; /// g(x) = f(x) + x 264 }; 265 typedef std::function<StateDependentTransit(int64_t, int64_t)> 266 VariableIndexEvaluator2; 267 #endif // SWIG 268 269 #if !defined(SWIG) 270 struct CostClass { 271 /// Index of the arc cost evaluator, registered in the RoutingModel class. 272 int evaluator_index = 0; 273 274 /// SUBTLE: 275 /// The vehicle's fixed cost is skipped on purpose here, because we 276 /// can afford to do so: 277 /// - We don't really care about creating "strict" equivalence classes; 278 /// all we care about is to: 279 /// 1) compress the space of cost callbacks so that 280 /// we can cache them more efficiently. 281 /// 2) have a smaller IntVar domain thanks to using a "cost class var" 282 /// instead of the vehicle var, so that we reduce the search space. 283 /// Both of these are an incentive for *fewer* cost classes. Ignoring 284 /// the fixed costs can only be good in that regard. 285 /// - The fixed costs are only needed when evaluating the cost of the 286 /// first arc of the route, in which case we know the vehicle, since we 287 /// have the route's start node. 288 289 /// Only dimensions that have non-zero cost evaluator and a non-zero cost 290 /// coefficient (in this cost class) are listed here. Since we only need 291 /// their transit evaluator (the raw version that takes var index, not Node 292 /// Index) and their span cost coefficient, we just store those. 293 /// This is sorted by the natural operator < (and *not* by DimensionIndex). 294 struct DimensionCost { 295 int64_t transit_evaluator_class; 296 int64_t cost_coefficient; 297 const RoutingDimension* dimension; 298 bool operator<(const DimensionCost& cost) const { 299 if (transit_evaluator_class != cost.transit_evaluator_class) { 300 return transit_evaluator_class < cost.transit_evaluator_class; 301 } 302 return cost_coefficient < cost.cost_coefficient; 303 } 304 }; 305 std::vector<DimensionCost> 306 dimension_transit_evaluator_class_and_cost_coefficient; 307 CostClassCostClass308 explicit CostClass(int evaluator_index) 309 : evaluator_index(evaluator_index) {} 310 311 /// Comparator for STL containers and algorithms. LessThanCostClass312 static bool LessThan(const CostClass& a, const CostClass& b) { 313 if (a.evaluator_index != b.evaluator_index) { 314 return a.evaluator_index < b.evaluator_index; 315 } 316 return a.dimension_transit_evaluator_class_and_cost_coefficient < 317 b.dimension_transit_evaluator_class_and_cost_coefficient; 318 } 319 }; 320 321 struct VehicleClass { 322 /// The cost class of the vehicle. 323 CostClassIndex cost_class_index; 324 /// Contrarily to CostClass, here we need strict equivalence. 325 int64_t fixed_cost; 326 /// Whether or not the vehicle is used when empty. 327 bool used_when_empty; 328 /// Vehicle start and end equivalence classes. Currently if two vehicles 329 /// have different start/end nodes which are "physically" located at the 330 /// same place, these two vehicles will be considered as non-equivalent 331 /// unless the two indices are in the same class. 332 // TODO(user): Find equivalent start/end nodes wrt dimensions and 333 // callbacks. 334 int start_equivalence_class; 335 int end_equivalence_class; 336 /// Bounds of cumul variables at start and end vehicle nodes. 337 /// dimension_{start,end}_cumuls_{min,max}[d] is the bound for dimension d. 338 absl::StrongVector<DimensionIndex, int64_t> dimension_start_cumuls_min; 339 absl::StrongVector<DimensionIndex, int64_t> dimension_start_cumuls_max; 340 absl::StrongVector<DimensionIndex, int64_t> dimension_end_cumuls_min; 341 absl::StrongVector<DimensionIndex, int64_t> dimension_end_cumuls_max; 342 absl::StrongVector<DimensionIndex, int64_t> dimension_capacities; 343 /// dimension_evaluators[d]->Run(from, to) is the transit value of arc 344 /// from->to for a dimension d. 345 absl::StrongVector<DimensionIndex, int64_t> dimension_evaluator_classes; 346 /// Fingerprint of unvisitable non-start/end nodes. 347 uint64_t unvisitable_nodes_fprint; 348 /// Sorted set of resource groups for which the vehicle requires a resource. 349 std::vector<int> required_resource_group_indices; 350 351 /// Comparator for STL containers and algorithms. 352 static bool LessThan(const VehicleClass& a, const VehicleClass& b); 353 }; 354 #endif // defined(SWIG) 355 356 /// Struct used to sort and store vehicles by their type. Two vehicles have 357 /// the same "vehicle type" iff they have the same cost class and start/end 358 /// nodes. 359 struct VehicleTypeContainer { 360 struct VehicleClassEntry { 361 int vehicle_class; 362 int64_t fixed_cost; 363 364 bool operator<(const VehicleClassEntry& other) const { 365 return std::tie(fixed_cost, vehicle_class) < 366 std::tie(other.fixed_cost, other.vehicle_class); 367 } 368 }; 369 NumTypesVehicleTypeContainer370 int NumTypes() const { return sorted_vehicle_classes_per_type.size(); } 371 TypeVehicleTypeContainer372 int Type(int vehicle) const { 373 DCHECK_LT(vehicle, type_index_of_vehicle.size()); 374 return type_index_of_vehicle[vehicle]; 375 } 376 377 std::vector<int> type_index_of_vehicle; 378 // clang-format off 379 std::vector<std::set<VehicleClassEntry> > sorted_vehicle_classes_per_type; 380 std::vector<std::deque<int> > vehicles_per_vehicle_class; 381 // clang-format on 382 }; 383 384 /// A ResourceGroup defines a set of available Resources with attributes on 385 /// one or multiple dimensions. 386 /// For every ResourceGroup in the model, each (used) vehicle in the solution 387 /// which requires a resource (see NotifyVehicleRequiresResource()) from this 388 /// group must be assigned to exactly 1 resource, and each resource can in 389 /// turn be assigned to at most 1 vehicle requiring it. This 390 /// vehicle-to-resource assignment will apply the corresponding Attributes to 391 /// the dimensions affected by the resource group. NOTE: As of 2021/07, each 392 /// ResourceGroup can only affect a single RoutingDimension at a time, i.e. 393 /// all Resources in a group must apply attributes to the same single 394 /// dimension. 395 class ResourceGroup { 396 public: 397 /// Attributes for a dimension. 398 class Attributes { 399 public: 400 Attributes(); 401 Attributes(Domain start_domain, Domain end_domain); 402 start_domain()403 const Domain& start_domain() const { return start_domain_; } end_domain()404 const Domain& end_domain() const { return end_domain_; } 405 406 private: 407 /// The following domains constrain the dimension start/end cumul of the 408 /// the vehicle assigned to this resource: 409 /// start_domain_.Min() <= cumul[Start(v)] <= start_domain_.Max() 410 Domain start_domain_; 411 /// end_domain_.Min() <= cumul[End(v)] <= end_domain_.Max() 412 Domain end_domain_; 413 }; 414 415 /// A Resource sets attributes (costs/constraints) for a set of dimensions. 416 class Resource { 417 public: 418 const ResourceGroup::Attributes& GetDimensionAttributes( 419 const RoutingDimension* dimension) const; 420 421 private: Resource(const RoutingModel * model)422 explicit Resource(const RoutingModel* model) : model_(model) {} 423 424 void SetDimensionAttributes(ResourceGroup::Attributes attributes, 425 const RoutingDimension* dimension); 426 const ResourceGroup::Attributes& GetDefaultAttributes() const; 427 428 const RoutingModel* const model_; 429 absl::flat_hash_map<DimensionIndex, ResourceGroup::Attributes> 430 dimension_attributes_; 431 432 friend class ResourceGroup; 433 }; 434 ResourceGroup(const RoutingModel * model)435 explicit ResourceGroup(const RoutingModel* model) 436 : model_(model), vehicle_requires_resource_(model->vehicles(), false) {} 437 438 /// Adds a Resource with the given attributes for the corresponding 439 /// dimension. Returns the index of the added resource in resources_. 440 int AddResource(Attributes attributes, const RoutingDimension* dimension); 441 442 /// Notifies that the given vehicle index requires a resource from this 443 /// group if the vehicle is used (i.e. if its route is non-empty or 444 /// vehicle_used_when_empty_[vehicle] is true). 445 void NotifyVehicleRequiresAResource(int vehicle); 446 GetVehiclesRequiringAResource()447 const std::vector<int>& GetVehiclesRequiringAResource() const { 448 return vehicles_requiring_resource_; 449 } 450 VehicleRequiresAResource(int vehicle)451 bool VehicleRequiresAResource(int vehicle) const { 452 return vehicle_requires_resource_[vehicle]; 453 } 454 GetResources()455 const std::vector<Resource>& GetResources() const { return resources_; } GetResource(int resource_index)456 const Resource& GetResource(int resource_index) const { 457 DCHECK_LT(resource_index, resources_.size()); 458 return resources_[resource_index]; 459 } GetAffectedDimensionIndices()460 const absl::flat_hash_set<DimensionIndex>& GetAffectedDimensionIndices() 461 const { 462 return affected_dimension_indices_; 463 } Size()464 int Size() const { return resources_.size(); } 465 466 private: 467 const RoutingModel* const model_; 468 std::vector<Resource> resources_; 469 std::vector<bool> vehicle_requires_resource_; 470 std::vector<int> vehicles_requiring_resource_; 471 /// All indices of dimensions affected by this resource group. 472 absl::flat_hash_set<DimensionIndex> affected_dimension_indices_; 473 }; 474 475 /// Constant used to express a hard constraint instead of a soft penalty. 476 static const int64_t kNoPenalty; 477 478 /// Constant used to express the "no disjunction" index, returned when a node 479 /// does not appear in any disjunction. 480 static const DisjunctionIndex kNoDisjunction; 481 482 /// Constant used to express the "no dimension" index, returned when a 483 /// dimension name does not correspond to an actual dimension. 484 static const DimensionIndex kNoDimension; 485 486 /// Constructor taking an index manager. The version which does not take 487 /// RoutingModelParameters is equivalent to passing 488 /// DefaultRoutingModelParameters(). 489 explicit RoutingModel(const RoutingIndexManager& index_manager); 490 RoutingModel(const RoutingIndexManager& index_manager, 491 const RoutingModelParameters& parameters); 492 ~RoutingModel(); 493 494 /// Registers 'callback' and returns its index. 495 int RegisterUnaryTransitVector(std::vector<int64_t> values); 496 int RegisterUnaryTransitCallback(TransitCallback1 callback); 497 int RegisterPositiveUnaryTransitCallback(TransitCallback1 callback); 498 499 int RegisterTransitMatrix( 500 std::vector<std::vector<int64_t> /*needed_for_swig*/> values); 501 int RegisterTransitCallback(TransitCallback2 callback); 502 int RegisterPositiveTransitCallback(TransitCallback2 callback); 503 504 int RegisterStateDependentTransitCallback(VariableIndexEvaluator2 callback); TransitCallback(int callback_index)505 const TransitCallback2& TransitCallback(int callback_index) const { 506 CHECK_LT(callback_index, transit_evaluators_.size()); 507 return transit_evaluators_[callback_index]; 508 } UnaryTransitCallbackOrNull(int callback_index)509 const TransitCallback1& UnaryTransitCallbackOrNull(int callback_index) const { 510 CHECK_LT(callback_index, unary_transit_evaluators_.size()); 511 return unary_transit_evaluators_[callback_index]; 512 } StateDependentTransitCallback(int callback_index)513 const VariableIndexEvaluator2& StateDependentTransitCallback( 514 int callback_index) const { 515 CHECK_LT(callback_index, state_dependent_transit_evaluators_.size()); 516 return state_dependent_transit_evaluators_[callback_index]; 517 } 518 519 /// Model creation 520 521 /// Methods to add dimensions to routes; dimensions represent quantities 522 /// accumulated at nodes along the routes. They represent quantities such as 523 /// weights or volumes carried along the route, or distance or times. 524 /// Quantities at a node are represented by "cumul" variables and the increase 525 /// or decrease of quantities between nodes are represented by "transit" 526 /// variables. These variables are linked as follows: 527 /// if j == next(i), cumul(j) = cumul(i) + transit(i) + slack(i) 528 /// where slack is a positive slack variable (can represent waiting times for 529 /// a time dimension). 530 /// Setting the value of fix_start_cumul_to_zero to true will force the 531 /// "cumul" variable of the start node of all vehicles to be equal to 0. 532 533 /// Creates a dimension where the transit variable is constrained to be 534 /// equal to evaluator(i, next(i)); 'slack_max' is the upper bound of the 535 /// slack variable and 'capacity' is the upper bound of the cumul variables. 536 /// 'name' is the name used to reference the dimension; this name is used to 537 /// get cumul and transit variables from the routing model. 538 /// Returns false if a dimension with the same name has already been created 539 /// (and doesn't create the new dimension). 540 /// Takes ownership of the callback 'evaluator'. 541 bool AddDimension(int evaluator_index, int64_t slack_max, int64_t capacity, 542 bool fix_start_cumul_to_zero, const std::string& name); 543 bool AddDimensionWithVehicleTransits( 544 const std::vector<int>& evaluator_indices, int64_t slack_max, 545 int64_t capacity, bool fix_start_cumul_to_zero, const std::string& name); 546 bool AddDimensionWithVehicleCapacity(int evaluator_index, int64_t slack_max, 547 std::vector<int64_t> vehicle_capacities, 548 bool fix_start_cumul_to_zero, 549 const std::string& name); 550 bool AddDimensionWithVehicleTransitAndCapacity( 551 const std::vector<int>& evaluator_indices, int64_t slack_max, 552 std::vector<int64_t> vehicle_capacities, bool fix_start_cumul_to_zero, 553 const std::string& name); 554 /// Creates a dimension where the transit variable is constrained to be 555 /// equal to 'value'; 'capacity' is the upper bound of the cumul variables. 556 /// 'name' is the name used to reference the dimension; this name is used to 557 /// get cumul and transit variables from the routing model. 558 /// Returns a pair consisting of an index to the registered unary transit 559 /// callback and a bool denoting whether the dimension has been created. 560 /// It is false if a dimension with the same name has already been created 561 /// (and doesn't create the new dimension but still register a new callback). 562 std::pair<int, bool> AddConstantDimensionWithSlack( 563 int64_t value, int64_t capacity, int64_t slack_max, 564 bool fix_start_cumul_to_zero, const std::string& name); AddConstantDimension(int64_t value,int64_t capacity,bool fix_start_cumul_to_zero,const std::string & name)565 std::pair<int, bool> AddConstantDimension(int64_t value, int64_t capacity, 566 bool fix_start_cumul_to_zero, 567 const std::string& name) { 568 return AddConstantDimensionWithSlack(value, capacity, 0, 569 fix_start_cumul_to_zero, name); 570 } 571 /// Creates a dimension where the transit variable is constrained to be 572 /// equal to 'values[i]' for node i; 'capacity' is the upper bound of 573 /// the cumul variables. 'name' is the name used to reference the dimension; 574 /// this name is used to get cumul and transit variables from the routing 575 /// model. 576 /// Returns a pair consisting of an index to the registered unary transit 577 /// callback and a bool denoting whether the dimension has been created. 578 /// It is false if a dimension with the same name has already been created 579 /// (and doesn't create the new dimension but still register a new callback). 580 std::pair<int, bool> AddVectorDimension(std::vector<int64_t> values, 581 int64_t capacity, 582 bool fix_start_cumul_to_zero, 583 const std::string& name); 584 /// Creates a dimension where the transit variable is constrained to be 585 /// equal to 'values[i][next(i)]' for node i; 'capacity' is the upper bound of 586 /// the cumul variables. 'name' is the name used to reference the dimension; 587 /// this name is used to get cumul and transit variables from the routing 588 /// model. 589 /// Returns a pair consisting of an index to the registered transit callback 590 /// and a bool denoting whether the dimension has been created. 591 /// It is false if a dimension with the same name has already been created 592 /// (and doesn't create the new dimension but still register a new callback). 593 std::pair<int, bool> AddMatrixDimension( 594 std::vector<std::vector<int64_t> /*needed_for_swig*/> values, 595 int64_t capacity, bool fix_start_cumul_to_zero, const std::string& name); 596 /// Creates a dimension with transits depending on the cumuls of another 597 /// dimension. 'pure_transits' are the per-vehicle fixed transits as above. 598 /// 'dependent_transits' is a vector containing for each vehicle an index to a 599 /// registered state dependent transit callback. 'base_dimension' indicates 600 /// the dimension from which the cumul variable is taken. If 'base_dimension' 601 /// is nullptr, then the newly created dimension is self-based. AddDimensionDependentDimensionWithVehicleCapacity(const std::vector<int> & pure_transits,const std::vector<int> & dependent_transits,const RoutingDimension * base_dimension,int64_t slack_max,std::vector<int64_t> vehicle_capacities,bool fix_start_cumul_to_zero,const std::string & name)602 bool AddDimensionDependentDimensionWithVehicleCapacity( 603 const std::vector<int>& pure_transits, 604 const std::vector<int>& dependent_transits, 605 const RoutingDimension* base_dimension, int64_t slack_max, 606 std::vector<int64_t> vehicle_capacities, bool fix_start_cumul_to_zero, 607 const std::string& name) { 608 return AddDimensionDependentDimensionWithVehicleCapacityInternal( 609 pure_transits, dependent_transits, base_dimension, slack_max, 610 std::move(vehicle_capacities), fix_start_cumul_to_zero, name); 611 } 612 613 /// As above, but pure_transits are taken to be zero evaluators. 614 bool AddDimensionDependentDimensionWithVehicleCapacity( 615 const std::vector<int>& transits, const RoutingDimension* base_dimension, 616 int64_t slack_max, std::vector<int64_t> vehicle_capacities, 617 bool fix_start_cumul_to_zero, const std::string& name); 618 /// Homogeneous versions of the functions above. 619 bool AddDimensionDependentDimensionWithVehicleCapacity( 620 int transit, const RoutingDimension* base_dimension, int64_t slack_max, 621 int64_t vehicle_capacity, bool fix_start_cumul_to_zero, 622 const std::string& name); 623 bool AddDimensionDependentDimensionWithVehicleCapacity( 624 int pure_transit, int dependent_transit, 625 const RoutingDimension* base_dimension, int64_t slack_max, 626 int64_t vehicle_capacity, bool fix_start_cumul_to_zero, 627 const std::string& name); 628 629 /// Creates a cached StateDependentTransit from an std::function. 630 static RoutingModel::StateDependentTransit MakeStateDependentTransit( 631 const std::function<int64_t(int64_t)>& f, int64_t domain_start, 632 int64_t domain_end); 633 634 /// For every vehicle of the routing model: 635 /// - if total_slacks[vehicle] is not nullptr, constrains it to be the sum of 636 /// slacks on that vehicle, that is, 637 /// dimension->CumulVar(end) - dimension->CumulVar(start) - 638 /// sum_{node in path of vehicle} dimension->FixedTransitVar(node). 639 /// - if spans[vehicle] is not nullptr, constrains it to be 640 /// dimension->CumulVar(end) - dimension->CumulVar(start) 641 /// This does stronger propagation than a decomposition, and takes breaks into 642 /// account. 643 Constraint* MakePathSpansAndTotalSlacks(const RoutingDimension* dimension, 644 std::vector<IntVar*> spans, 645 std::vector<IntVar*> total_slacks); 646 647 /// Outputs the names of all dimensions added to the routing engine. 648 // TODO(user): rename. 649 std::vector<std::string> GetAllDimensionNames() const; 650 /// Returns all dimensions of the model. GetDimensions()651 const std::vector<RoutingDimension*>& GetDimensions() const { 652 return dimensions_.get(); 653 } 654 /// Returns dimensions with soft or vehicle span costs. 655 std::vector<RoutingDimension*> GetDimensionsWithSoftOrSpanCosts() const; 656 // clang-format off 657 /// Returns [global|local]_dimension_optimizers_, which are empty if the model 658 /// has not been closed. 659 const std::vector<std::unique_ptr<GlobalDimensionCumulOptimizer> >& GetGlobalDimensionCumulOptimizers()660 GetGlobalDimensionCumulOptimizers() const { 661 return global_dimension_optimizers_; 662 } 663 const std::vector<std::unique_ptr<GlobalDimensionCumulOptimizer> >& GetGlobalDimensionCumulMPOptimizers()664 GetGlobalDimensionCumulMPOptimizers() const { 665 return global_dimension_mp_optimizers_; 666 } 667 const std::vector<std::unique_ptr<LocalDimensionCumulOptimizer> >& GetLocalDimensionCumulOptimizers()668 GetLocalDimensionCumulOptimizers() const { 669 return local_dimension_optimizers_; 670 } 671 const std::vector<std::unique_ptr<LocalDimensionCumulOptimizer> >& GetLocalDimensionCumulMPOptimizers()672 GetLocalDimensionCumulMPOptimizers() const { 673 return local_dimension_mp_optimizers_; 674 } 675 // clang-format on 676 677 /// Returns the global/local dimension cumul optimizer for a given dimension, 678 /// or nullptr if there is none. 679 GlobalDimensionCumulOptimizer* GetMutableGlobalCumulOptimizer( 680 const RoutingDimension& dimension) const; 681 GlobalDimensionCumulOptimizer* GetMutableGlobalCumulMPOptimizer( 682 const RoutingDimension& dimension) const; 683 LocalDimensionCumulOptimizer* GetMutableLocalCumulOptimizer( 684 const RoutingDimension& dimension) const; 685 LocalDimensionCumulOptimizer* GetMutableLocalCumulMPOptimizer( 686 const RoutingDimension& dimension) const; 687 688 /// Returns true if a dimension exists for a given dimension name. 689 bool HasDimension(const std::string& dimension_name) const; 690 /// Returns a dimension from its name. Dies if the dimension does not exist. 691 const RoutingDimension& GetDimensionOrDie( 692 const std::string& dimension_name) const; 693 /// Returns a dimension from its name. Returns nullptr if the dimension does 694 /// not exist. 695 RoutingDimension* GetMutableDimension( 696 const std::string& dimension_name) const; 697 /// Set the given dimension as "primary constrained". As of August 2013, this 698 /// is only used by ArcIsMoreConstrainedThanArc(). 699 /// "dimension" must be the name of an existing dimension, or be empty, in 700 /// which case there will not be a primary dimension after this call. SetPrimaryConstrainedDimension(const std::string & dimension_name)701 void SetPrimaryConstrainedDimension(const std::string& dimension_name) { 702 DCHECK(dimension_name.empty() || HasDimension(dimension_name)); 703 primary_constrained_dimension_ = dimension_name; 704 } 705 /// Get the primary constrained dimension, or an empty string if it is unset. GetPrimaryConstrainedDimension()706 const std::string& GetPrimaryConstrainedDimension() const { 707 return primary_constrained_dimension_; 708 } 709 710 /// Adds a resource group to the routing model. Returns its index in 711 /// resource_groups_. 712 int AddResourceGroup(); 713 // clang-format off GetResourceGroups()714 const std::vector<std::unique_ptr<ResourceGroup> >& GetResourceGroups() 715 const { 716 return resource_groups_; 717 } 718 // clang-format on GetResourceGroup(int rg_index)719 ResourceGroup* GetResourceGroup(int rg_index) const { 720 DCHECK_LT(rg_index, resource_groups_.size()); 721 return resource_groups_[rg_index].get(); 722 } 723 724 /// Returns the indices of resource groups for this dimension. This method can 725 /// only be called after the model has been closed. 726 const std::vector<int>& GetDimensionResourceGroupIndices( 727 const RoutingDimension* dimension) const; 728 729 /// Returns the index of the resource group attached to the dimension. 730 /// DCHECKS that there's exactly one resource group for this dimension. GetDimensionResourceGroupIndex(const RoutingDimension * dimension)731 int GetDimensionResourceGroupIndex(const RoutingDimension* dimension) const { 732 DCHECK_EQ(GetDimensionResourceGroupIndices(dimension).size(), 1); 733 return GetDimensionResourceGroupIndices(dimension)[0]; 734 } 735 736 /// Adds a disjunction constraint on the indices: exactly 'max_cardinality' of 737 /// the indices are active. Start and end indices of any vehicle cannot be 738 /// part of a disjunction. 739 /// 740 /// If a penalty is given, at most 'max_cardinality' of the indices can be 741 /// active, and if less are active, 'penalty' is payed per inactive index. 742 /// This is equivalent to adding the constraint: 743 /// p + Sum(i)active[i] == max_cardinality 744 /// where p is an integer variable, and the following cost to the cost 745 /// function: 746 /// p * penalty. 747 /// 'penalty' must be positive to make the disjunction optional; a negative 748 /// penalty will force 'max_cardinality' indices of the disjunction to be 749 /// performed, and therefore p == 0. 750 /// Note: passing a vector with a single index will model an optional index 751 /// with a penalty cost if it is not visited. 752 DisjunctionIndex AddDisjunction(const std::vector<int64_t>& indices, 753 int64_t penalty = kNoPenalty, 754 int64_t max_cardinality = 1); 755 /// Returns the indices of the disjunctions to which an index belongs. GetDisjunctionIndices(int64_t index)756 const std::vector<DisjunctionIndex>& GetDisjunctionIndices( 757 int64_t index) const { 758 return index_to_disjunctions_[index]; 759 } 760 /// Calls f for each variable index of indices in the same disjunctions as the 761 /// node corresponding to the variable index 'index'; only disjunctions of 762 /// cardinality 'cardinality' are considered. 763 template <typename F> ForEachNodeInDisjunctionWithMaxCardinalityFromIndex(int64_t index,int64_t max_cardinality,F f)764 void ForEachNodeInDisjunctionWithMaxCardinalityFromIndex( 765 int64_t index, int64_t max_cardinality, F f) const { 766 for (const DisjunctionIndex disjunction : GetDisjunctionIndices(index)) { 767 if (disjunctions_[disjunction].value.max_cardinality == max_cardinality) { 768 for (const int64_t d_index : disjunctions_[disjunction].indices) { 769 f(d_index); 770 } 771 } 772 } 773 } 774 #if !defined(SWIGPYTHON) 775 /// Returns the variable indices of the nodes in the disjunction of index 776 /// 'index'. GetDisjunctionNodeIndices(DisjunctionIndex index)777 const std::vector<int64_t>& GetDisjunctionNodeIndices( 778 DisjunctionIndex index) const { 779 return disjunctions_[index].indices; 780 } 781 #endif // !defined(SWIGPYTHON) 782 /// Returns the penalty of the node disjunction of index 'index'. GetDisjunctionPenalty(DisjunctionIndex index)783 int64_t GetDisjunctionPenalty(DisjunctionIndex index) const { 784 return disjunctions_[index].value.penalty; 785 } 786 /// Returns the maximum number of possible active nodes of the node 787 /// disjunction of index 'index'. GetDisjunctionMaxCardinality(DisjunctionIndex index)788 int64_t GetDisjunctionMaxCardinality(DisjunctionIndex index) const { 789 return disjunctions_[index].value.max_cardinality; 790 } 791 /// Returns the number of node disjunctions in the model. GetNumberOfDisjunctions()792 int GetNumberOfDisjunctions() const { return disjunctions_.size(); } 793 /// Returns true if the model contains mandatory disjunctions (ones with 794 /// kNoPenalty as penalty). 795 bool HasMandatoryDisjunctions() const; 796 /// Returns true if the model contains at least one disjunction which is 797 /// constrained by its max_cardinality. 798 bool HasMaxCardinalityConstrainedDisjunctions() const; 799 /// Returns the list of all perfect binary disjunctions, as pairs of variable 800 /// indices: a disjunction is "perfect" when its variables do not appear in 801 /// any other disjunction. Each pair is sorted (lowest variable index first), 802 /// and the output vector is also sorted (lowest pairs first). 803 std::vector<std::pair<int64_t, int64_t>> GetPerfectBinaryDisjunctions() const; 804 /// SPECIAL: Makes the solver ignore all the disjunctions whose active 805 /// variables are all trivially zero (i.e. Max() == 0), by setting their 806 /// max_cardinality to 0. 807 /// This can be useful when using the BaseBinaryDisjunctionNeighborhood 808 /// operators, in the context of arc-based routing. 809 void IgnoreDisjunctionsAlreadyForcedToZero(); 810 811 /// Adds a soft constraint to force a set of variable indices to be on the 812 /// same vehicle. If all nodes are not on the same vehicle, each extra vehicle 813 /// used adds 'cost' to the cost function. 814 void AddSoftSameVehicleConstraint(const std::vector<int64_t>& indices, 815 int64_t cost); 816 817 /// Sets the vehicles which can visit a given node. If the node is in a 818 /// disjunction, this will not prevent it from being unperformed. 819 /// Specifying an empty vector of vehicles has no effect (all vehicles 820 /// will be allowed to visit the node). 821 void SetAllowedVehiclesForIndex(const std::vector<int>& vehicles, 822 int64_t index); 823 824 /// Returns true if a vehicle is allowed to visit a given node. IsVehicleAllowedForIndex(int vehicle,int64_t index)825 bool IsVehicleAllowedForIndex(int vehicle, int64_t index) { 826 return allowed_vehicles_[index].empty() || 827 allowed_vehicles_[index].find(vehicle) != 828 allowed_vehicles_[index].end(); 829 } 830 831 /// Notifies that index1 and index2 form a pair of nodes which should belong 832 /// to the same route. This methods helps the search find better solutions, 833 /// especially in the local search phase. 834 /// It should be called each time you have an equality constraint linking 835 /// the vehicle variables of two node (including for instance pickup and 836 /// delivery problems): 837 /// Solver* const solver = routing.solver(); 838 /// int64_t index1 = manager.NodeToIndex(node1); 839 /// int64_t index2 = manager.NodeToIndex(node2); 840 /// solver->AddConstraint(solver->MakeEquality( 841 /// routing.VehicleVar(index1), 842 /// routing.VehicleVar(index2))); 843 /// routing.AddPickupAndDelivery(index1, index2); 844 /// 845 // TODO(user): Remove this when model introspection detects linked nodes. 846 void AddPickupAndDelivery(int64_t pickup, int64_t delivery); 847 /// Same as AddPickupAndDelivery but notifying that the performed node from 848 /// the disjunction of index 'pickup_disjunction' is on the same route as the 849 /// performed node from the disjunction of index 'delivery_disjunction'. 850 void AddPickupAndDeliverySets(DisjunctionIndex pickup_disjunction, 851 DisjunctionIndex delivery_disjunction); 852 // clang-format off 853 /// Returns pairs for which the node is a pickup; the first element of each 854 /// pair is the index in the pickup and delivery pairs list in which the 855 /// pickup appears, the second element is its index in the pickups list. 856 const std::vector<std::pair<int, int> >& 857 GetPickupIndexPairs(int64_t node_index) const; 858 /// Same as above for deliveries. 859 const std::vector<std::pair<int, int> >& 860 GetDeliveryIndexPairs(int64_t node_index) const; 861 // clang-format on 862 863 /// Sets the Pickup and delivery policy of all vehicles. It is equivalent to 864 /// calling SetPickupAndDeliveryPolicyOfVehicle on all vehicles. 865 void SetPickupAndDeliveryPolicyOfAllVehicles(PickupAndDeliveryPolicy policy); 866 void SetPickupAndDeliveryPolicyOfVehicle(PickupAndDeliveryPolicy policy, 867 int vehicle); 868 PickupAndDeliveryPolicy GetPickupAndDeliveryPolicyOfVehicle( 869 int vehicle) const; 870 /// Returns the number of non-start/end nodes which do not appear in a 871 /// pickup/delivery pair. 872 873 int GetNumOfSingletonNodes() const; 874 875 #ifndef SWIG 876 /// Returns pickup and delivery pairs currently in the model. GetPickupAndDeliveryPairs()877 const IndexPairs& GetPickupAndDeliveryPairs() const { 878 return pickup_delivery_pairs_; 879 } 880 const std::vector<std::pair<DisjunctionIndex, DisjunctionIndex>>& GetPickupAndDeliveryDisjunctions()881 GetPickupAndDeliveryDisjunctions() const { 882 return pickup_delivery_disjunctions_; 883 } 884 /// Returns implicit pickup and delivery pairs currently in the model. 885 /// Pairs are implicit if they are not linked by a pickup and delivery 886 /// constraint but that for a given unary dimension, the first element of the 887 /// pair has a positive demand d, and the second element has a demand of -d. GetImplicitUniquePickupAndDeliveryPairs()888 const IndexPairs& GetImplicitUniquePickupAndDeliveryPairs() const { 889 DCHECK(closed_); 890 return implicit_pickup_delivery_pairs_without_alternatives_; 891 } 892 #endif // SWIG 893 /// Set the node visit types and incompatibilities/requirements between the 894 /// types (see below). 895 /// 896 /// NOTE: Before adding any incompatibilities and/or requirements on types: 897 /// 1) All corresponding node types must have been set. 898 /// 2) CloseVisitTypes() must be called so all containers are resized 899 /// accordingly. 900 /// 901 /// The following enum is used to describe how a node with a given type 'T' 902 /// impacts the number of types 'T' on the route when visited, and thus 903 /// determines how temporal incompatibilities and requirements take effect. 904 enum VisitTypePolicy { 905 /// When visited, the number of types 'T' on the vehicle increases by one. 906 TYPE_ADDED_TO_VEHICLE, 907 /// When visited, one instance of type 'T' previously added to the route 908 /// (TYPE_ADDED_TO_VEHICLE), if any, is removed from the vehicle. 909 /// If the type was not previously added to the route or all added instances 910 /// have already been removed, this visit has no effect on the types. 911 ADDED_TYPE_REMOVED_FROM_VEHICLE, 912 /// With the following policy, the visit enforces that type 'T' is 913 /// considered on the route from its start until this node is visited. 914 TYPE_ON_VEHICLE_UP_TO_VISIT, 915 /// The visit doesn't have an impact on the number of types 'T' on the 916 /// route, as it's (virtually) added and removed directly. 917 /// This policy can be used for visits which are part of an incompatibility 918 /// or requirement set without affecting the type count on the route. 919 TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED 920 }; 921 // TODO(user): Support multiple visit types per node? 922 void SetVisitType(int64_t index, int type, VisitTypePolicy type_policy); 923 int GetVisitType(int64_t index) const; 924 const std::vector<int>& GetSingleNodesOfType(int type) const; 925 const std::vector<int>& GetPairIndicesOfType(int type) const; 926 VisitTypePolicy GetVisitTypePolicy(int64_t index) const; 927 /// This function should be called once all node visit types have been set and 928 /// prior to adding any incompatibilities/requirements. 929 // TODO(user): Reconsider the logic and potentially remove the need to 930 /// "close" types. 931 void CloseVisitTypes(); GetNumberOfVisitTypes()932 int GetNumberOfVisitTypes() const { return num_visit_types_; } 933 #ifndef SWIG GetTopologicallySortedVisitTypes()934 const std::vector<std::vector<int>>& GetTopologicallySortedVisitTypes() 935 const { 936 DCHECK(closed_); 937 return topologically_sorted_visit_types_; 938 } 939 #endif // SWIG 940 /// Incompatibilities: 941 /// Two nodes with "hard" incompatible types cannot share the same route at 942 /// all, while with a "temporal" incompatibility they can't be on the same 943 /// route at the same time. 944 void AddHardTypeIncompatibility(int type1, int type2); 945 void AddTemporalTypeIncompatibility(int type1, int type2); 946 /// Returns visit types incompatible with a given type. 947 const absl::flat_hash_set<int>& GetHardTypeIncompatibilitiesOfType( 948 int type) const; 949 const absl::flat_hash_set<int>& GetTemporalTypeIncompatibilitiesOfType( 950 int type) const; 951 /// Returns true iff any hard (resp. temporal) type incompatibilities have 952 /// been added to the model. HasHardTypeIncompatibilities()953 bool HasHardTypeIncompatibilities() const { 954 return has_hard_type_incompatibilities_; 955 } HasTemporalTypeIncompatibilities()956 bool HasTemporalTypeIncompatibilities() const { 957 return has_temporal_type_incompatibilities_; 958 } 959 /// Requirements: 960 /// NOTE: As of 2019-04, cycles in the requirement graph are not supported, 961 /// and lead to the dependent nodes being skipped if possible (otherwise 962 /// the model is considered infeasible). 963 /// The following functions specify that "dependent_type" requires at least 964 /// one of the types in "required_type_alternatives". 965 /// 966 /// For same-vehicle requirements, a node of dependent type type_D requires at 967 /// least one node of type type_R among the required alternatives on the same 968 /// route. 969 void AddSameVehicleRequiredTypeAlternatives( 970 int dependent_type, absl::flat_hash_set<int> required_type_alternatives); 971 /// If type_D depends on type_R when adding type_D, any node_D of type_D and 972 /// VisitTypePolicy TYPE_ADDED_TO_VEHICLE or 973 /// TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED requires at least one type_R on its 974 /// vehicle at the time node_D is visited. 975 void AddRequiredTypeAlternativesWhenAddingType( 976 int dependent_type, absl::flat_hash_set<int> required_type_alternatives); 977 /// The following requirements apply when visiting dependent nodes that remove 978 /// their type from the route, i.e. type_R must be on the vehicle when type_D 979 /// of VisitTypePolicy ADDED_TYPE_REMOVED_FROM_VEHICLE, 980 /// TYPE_ON_VEHICLE_UP_TO_VISIT or TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED is 981 /// visited. 982 void AddRequiredTypeAlternativesWhenRemovingType( 983 int dependent_type, absl::flat_hash_set<int> required_type_alternatives); 984 // clang-format off 985 /// Returns the set of same-vehicle requirement alternatives for the given 986 /// type. 987 const std::vector<absl::flat_hash_set<int> >& 988 GetSameVehicleRequiredTypeAlternativesOfType(int type) const; 989 /// Returns the set of requirement alternatives when adding the given type. 990 const std::vector<absl::flat_hash_set<int> >& 991 GetRequiredTypeAlternativesWhenAddingType(int type) const; 992 /// Returns the set of requirement alternatives when removing the given type. 993 const std::vector<absl::flat_hash_set<int> >& 994 GetRequiredTypeAlternativesWhenRemovingType(int type) const; 995 // clang-format on 996 /// Returns true iff any same-route (resp. temporal) type requirements have 997 /// been added to the model. HasSameVehicleTypeRequirements()998 bool HasSameVehicleTypeRequirements() const { 999 return has_same_vehicle_type_requirements_; 1000 } HasTemporalTypeRequirements()1001 bool HasTemporalTypeRequirements() const { 1002 return has_temporal_type_requirements_; 1003 } 1004 1005 /// Returns true iff the model has any incompatibilities or requirements set 1006 /// on node types. HasTypeRegulations()1007 bool HasTypeRegulations() const { 1008 return HasTemporalTypeIncompatibilities() || 1009 HasHardTypeIncompatibilities() || HasSameVehicleTypeRequirements() || 1010 HasTemporalTypeRequirements(); 1011 } 1012 1013 /// Get the "unperformed" penalty of a node. This is only well defined if the 1014 /// node is only part of a single Disjunction, and that disjunction has a 1015 /// penalty. For forced active nodes returns max int64_t. In all other cases, 1016 /// this returns 0. 1017 int64_t UnperformedPenalty(int64_t var_index) const; 1018 /// Same as above except that it returns default_value instead of 0 when 1019 /// penalty is not well defined (default value is passed as first argument to 1020 /// simplify the usage of the method in a callback). 1021 int64_t UnperformedPenaltyOrValue(int64_t default_value, 1022 int64_t var_index) const; 1023 /// Returns the variable index of the first starting or ending node of all 1024 /// routes. If all routes start and end at the same node (single depot), this 1025 /// is the node returned. 1026 int64_t GetDepot() const; 1027 1028 /// Constrains the maximum number of active vehicles, aka the number of 1029 /// vehicles which do not have an empty route. For instance, this can be used 1030 /// to limit the number of routes in the case where there are fewer drivers 1031 /// than vehicles and that the fleet of vehicle is heterogeneous. SetMaximumNumberOfActiveVehicles(int max_active_vehicles)1032 void SetMaximumNumberOfActiveVehicles(int max_active_vehicles) { 1033 max_active_vehicles_ = max_active_vehicles; 1034 } 1035 /// Returns the maximum number of active vehicles. GetMaximumNumberOfActiveVehicles()1036 int GetMaximumNumberOfActiveVehicles() const { return max_active_vehicles_; } 1037 /// Sets the cost function of the model such that the cost of a segment of a 1038 /// route between node 'from' and 'to' is evaluator(from, to), whatever the 1039 /// route or vehicle performing the route. 1040 void SetArcCostEvaluatorOfAllVehicles(int evaluator_index); 1041 /// Sets the cost function for a given vehicle route. 1042 void SetArcCostEvaluatorOfVehicle(int evaluator_index, int vehicle); 1043 /// Sets the fixed cost of all vehicle routes. It is equivalent to calling 1044 /// SetFixedCostOfVehicle on all vehicle routes. 1045 void SetFixedCostOfAllVehicles(int64_t cost); 1046 /// Sets the fixed cost of one vehicle route. 1047 void SetFixedCostOfVehicle(int64_t cost, int vehicle); 1048 /// Returns the route fixed cost taken into account if the route of the 1049 /// vehicle is not empty, aka there's at least one node on the route other 1050 /// than the first and last nodes. 1051 int64_t GetFixedCostOfVehicle(int vehicle) const; 1052 1053 /// The following methods set the linear and quadratic cost factors of 1054 /// vehicles (must be positive values). The default value of these parameters 1055 /// is zero for all vehicles. 1056 /// 1057 /// When set, the cost_ of the model will contain terms aiming at reducing the 1058 /// number of vehicles used in the model, by adding the following to the 1059 /// objective for every vehicle v: 1060 /// INDICATOR(v used in the model) * 1061 /// [linear_cost_factor_of_vehicle_[v] 1062 /// - quadratic_cost_factor_of_vehicle_[v]*(square of length of route v)] 1063 /// i.e. for every used vehicle, we add the linear factor as fixed cost, and 1064 /// subtract the square of the route length multiplied by the quadratic 1065 /// factor. This second term aims at making the routes as dense as possible. 1066 /// 1067 /// Sets the linear and quadratic cost factor of all vehicles. 1068 void SetAmortizedCostFactorsOfAllVehicles(int64_t linear_cost_factor, 1069 int64_t quadratic_cost_factor); 1070 /// Sets the linear and quadratic cost factor of the given vehicle. 1071 void SetAmortizedCostFactorsOfVehicle(int64_t linear_cost_factor, 1072 int64_t quadratic_cost_factor, 1073 int vehicle); 1074 GetAmortizedLinearCostFactorOfVehicles()1075 const std::vector<int64_t>& GetAmortizedLinearCostFactorOfVehicles() const { 1076 return linear_cost_factor_of_vehicle_; 1077 } GetAmortizedQuadraticCostFactorOfVehicles()1078 const std::vector<int64_t>& GetAmortizedQuadraticCostFactorOfVehicles() 1079 const { 1080 return quadratic_cost_factor_of_vehicle_; 1081 } 1082 SetVehicleUsedWhenEmpty(bool is_used,int vehicle)1083 void SetVehicleUsedWhenEmpty(bool is_used, int vehicle) { 1084 DCHECK_LT(vehicle, vehicles_); 1085 vehicle_used_when_empty_[vehicle] = is_used; 1086 } 1087 IsVehicleUsedWhenEmpty(int vehicle)1088 bool IsVehicleUsedWhenEmpty(int vehicle) const { 1089 DCHECK_LT(vehicle, vehicles_); 1090 return vehicle_used_when_empty_[vehicle]; 1091 } 1092 1093 /// Gets/sets the evaluator used during the search. Only relevant when 1094 /// RoutingSearchParameters.first_solution_strategy = EVALUATOR_STRATEGY. 1095 #ifndef SWIG first_solution_evaluator()1096 const Solver::IndexEvaluator2& first_solution_evaluator() const { 1097 return first_solution_evaluator_; 1098 } 1099 #endif 1100 /// Takes ownership of evaluator. SetFirstSolutionEvaluator(Solver::IndexEvaluator2 evaluator)1101 void SetFirstSolutionEvaluator(Solver::IndexEvaluator2 evaluator) { 1102 first_solution_evaluator_ = std::move(evaluator); 1103 } 1104 /// Adds a local search operator to the set of operators used to solve the 1105 /// vehicle routing problem. 1106 void AddLocalSearchOperator(LocalSearchOperator* ls_operator); 1107 /// Adds a search monitor to the search used to solve the routing model. 1108 void AddSearchMonitor(SearchMonitor* const monitor); 1109 /// Adds a callback called each time a solution is found during the search. 1110 /// This is a shortcut to creating a monitor to call the callback on 1111 /// AtSolution() and adding it with AddSearchMonitor. 1112 void AddAtSolutionCallback(std::function<void()> callback); 1113 /// Adds a variable to minimize in the solution finalizer. The solution 1114 /// finalizer is called each time a solution is found during the search and 1115 /// allows to instantiate secondary variables (such as dimension cumul 1116 /// variables). 1117 void AddVariableMinimizedByFinalizer(IntVar* var); 1118 /// Adds a variable to maximize in the solution finalizer (see above for 1119 /// information on the solution finalizer). 1120 void AddVariableMaximizedByFinalizer(IntVar* var); 1121 /// Adds a variable to minimize in the solution finalizer, with a weighted 1122 /// priority: the higher the more priority it has. 1123 void AddWeightedVariableMinimizedByFinalizer(IntVar* var, int64_t cost); 1124 /// Add a variable to set the closest possible to the target value in the 1125 /// solution finalizer. 1126 void AddVariableTargetToFinalizer(IntVar* var, int64_t target); 1127 /// Closes the current routing model; after this method is called, no 1128 /// modification to the model can be done, but RoutesToAssignment becomes 1129 /// available. Note that CloseModel() is automatically called by Solve() and 1130 /// other methods that produce solution. 1131 /// This is equivalent to calling 1132 /// CloseModelWithParameters(DefaultRoutingSearchParameters()). 1133 void CloseModel(); 1134 /// Same as above taking search parameters (as of 10/2015 some the parameters 1135 /// have to be set when closing the model). 1136 void CloseModelWithParameters( 1137 const RoutingSearchParameters& search_parameters); 1138 /// Solves the current routing model; closes the current model. 1139 /// This is equivalent to calling 1140 /// SolveWithParameters(DefaultRoutingSearchParameters()) 1141 /// or 1142 /// SolveFromAssignmentWithParameters(assignment, 1143 /// DefaultRoutingSearchParameters()). 1144 const Assignment* Solve(const Assignment* assignment = nullptr); 1145 /// Solves the current routing model with the given parameters. If 'solutions' 1146 /// is specified, it will contain the k best solutions found during the search 1147 /// (from worst to best, including the one returned by this method), where k 1148 /// corresponds to the 'number_of_solutions_to_collect' in 1149 /// 'search_parameters'. Note that the Assignment returned by the method and 1150 /// the ones in solutions are owned by the underlying solver and should not be 1151 /// deleted. 1152 const Assignment* SolveWithParameters( 1153 const RoutingSearchParameters& search_parameters, 1154 std::vector<const Assignment*>* solutions = nullptr); 1155 /// Same as above, except that if assignment is not null, it will be used as 1156 /// the initial solution. 1157 const Assignment* SolveFromAssignmentWithParameters( 1158 const Assignment* assignment, 1159 const RoutingSearchParameters& search_parameters, 1160 std::vector<const Assignment*>* solutions = nullptr); 1161 /// Same as above but will try all assignments in order as first solutions 1162 /// until one succeeds. 1163 const Assignment* SolveFromAssignmentsWithParameters( 1164 const std::vector<const Assignment*>& assignments, 1165 const RoutingSearchParameters& search_parameters, 1166 std::vector<const Assignment*>* solutions = nullptr); 1167 /// Given a "source_model" and its "source_assignment", resets 1168 /// "target_assignment" with the IntVar variables (nexts_, and vehicle_vars_ 1169 /// if costs aren't homogeneous across vehicles) of "this" model, with the 1170 /// values set according to those in "other_assignment". 1171 /// The objective_element of target_assignment is set to this->cost_. 1172 void SetAssignmentFromOtherModelAssignment( 1173 Assignment* target_assignment, const RoutingModel* source_model, 1174 const Assignment* source_assignment); 1175 /// Computes a lower bound to the routing problem solving a linear assignment 1176 /// problem. The routing model must be closed before calling this method. 1177 /// Note that problems with node disjunction constraints (including optional 1178 /// nodes) and non-homogenous costs are not supported (the method returns 0 in 1179 /// these cases). 1180 // TODO(user): Add support for non-homogeneous costs and disjunctions. 1181 int64_t ComputeLowerBound(); 1182 /// Returns the current status of the routing model. status()1183 Status status() const { return status_; } 1184 /// Applies a lock chain to the next search. 'locks' represents an ordered 1185 /// vector of nodes representing a partial route which will be fixed during 1186 /// the next search; it will constrain next variables such that: 1187 /// next[locks[i]] == locks[i+1]. 1188 /// 1189 /// Returns the next variable at the end of the locked chain; this variable is 1190 /// not locked. An assignment containing the locks can be obtained by calling 1191 /// PreAssignment(). 1192 IntVar* ApplyLocks(const std::vector<int64_t>& locks); 1193 /// Applies lock chains to all vehicles to the next search, such that locks[p] 1194 /// is the lock chain for route p. Returns false if the locks do not contain 1195 /// valid routes; expects that the routes do not contain the depots, 1196 /// i.e. there are empty vectors in place of empty routes. 1197 /// If close_routes is set to true, adds the end nodes to the route of each 1198 /// vehicle and deactivates other nodes. 1199 /// An assignment containing the locks can be obtained by calling 1200 /// PreAssignment(). 1201 bool ApplyLocksToAllVehicles(const std::vector<std::vector<int64_t>>& locks, 1202 bool close_routes); 1203 /// Returns an assignment used to fix some of the variables of the problem. 1204 /// In practice, this assignment locks partial routes of the problem. This 1205 /// can be used in the context of locking the parts of the routes which have 1206 /// already been driven in online routing problems. PreAssignment()1207 const Assignment* const PreAssignment() const { return preassignment_; } MutablePreAssignment()1208 Assignment* MutablePreAssignment() { return preassignment_; } 1209 /// Writes the current solution to a file containing an AssignmentProto. 1210 /// Returns false if the file cannot be opened or if there is no current 1211 /// solution. 1212 bool WriteAssignment(const std::string& file_name) const; 1213 /// Reads an assignment from a file and returns the current solution. 1214 /// Returns nullptr if the file cannot be opened or if the assignment is not 1215 /// valid. 1216 Assignment* ReadAssignment(const std::string& file_name); 1217 /// Restores an assignment as a solution in the routing model and returns the 1218 /// new solution. Returns nullptr if the assignment is not valid. 1219 Assignment* RestoreAssignment(const Assignment& solution); 1220 /// Restores the routes as the current solution. Returns nullptr if the 1221 /// solution cannot be restored (routes do not contain a valid solution). Note 1222 /// that calling this method will run the solver to assign values to the 1223 /// dimension variables; this may take considerable amount of time, especially 1224 /// when using dimensions with slack. 1225 Assignment* ReadAssignmentFromRoutes( 1226 const std::vector<std::vector<int64_t>>& routes, 1227 bool ignore_inactive_indices); 1228 /// Fills an assignment from a specification of the routes of the 1229 /// vehicles. The routes are specified as lists of variable indices that 1230 /// appear on the routes of the vehicles. The indices of the outer vector in 1231 /// 'routes' correspond to vehicles IDs, the inner vector contains the 1232 /// variable indices on the routes for the given vehicle. The inner vectors 1233 /// must not contain the start and end indices, as these are determined by the 1234 /// routing model. Sets the value of NextVars in the assignment, adding the 1235 /// variables to the assignment if necessary. The method does not touch other 1236 /// variables in the assignment. The method can only be called after the model 1237 /// is closed. With ignore_inactive_indices set to false, this method will 1238 /// fail (return nullptr) in case some of the route contain indices that are 1239 /// deactivated in the model; when set to true, these indices will be 1240 /// skipped. Returns true if routes were successfully 1241 /// loaded. However, such assignment still might not be a valid 1242 /// solution to the routing problem due to more complex constraints; 1243 /// it is advisible to call solver()->CheckSolution() afterwards. 1244 bool RoutesToAssignment(const std::vector<std::vector<int64_t>>& routes, 1245 bool ignore_inactive_indices, bool close_routes, 1246 Assignment* const assignment) const; 1247 /// Converts the solution in the given assignment to routes for all vehicles. 1248 /// Expects that assignment contains a valid solution (i.e. routes for all 1249 /// vehicles end with an end index for that vehicle). 1250 void AssignmentToRoutes( 1251 const Assignment& assignment, 1252 std::vector<std::vector<int64_t>>* const routes) const; 1253 /// Converts the solution in the given assignment to routes for all vehicles. 1254 /// If the returned vector is route_indices, route_indices[i][j] is the index 1255 /// for jth location visited on route i. Note that contrary to 1256 /// AssignmentToRoutes, the vectors do include start and end locations. 1257 #ifndef SWIG 1258 std::vector<std::vector<int64_t>> GetRoutesFromAssignment( 1259 const Assignment& assignment); 1260 #endif 1261 /// Returns a compacted version of the given assignment, in which all vehicles 1262 /// with id lower or equal to some N have non-empty routes, and all vehicles 1263 /// with id greater than N have empty routes. Does not take ownership of the 1264 /// returned object. 1265 /// If found, the cost of the compact assignment is the same as in the 1266 /// original assignment and it preserves the values of 'active' variables. 1267 /// Returns nullptr if a compact assignment was not found. 1268 /// This method only works in homogenous mode, and it only swaps equivalent 1269 /// vehicles (vehicles with the same start and end nodes). When creating the 1270 /// compact assignment, the empty plan is replaced by the route assigned to 1271 /// the compatible vehicle with the highest id. Note that with more complex 1272 /// constraints on vehicle variables, this method might fail even if a compact 1273 /// solution exists. 1274 /// This method changes the vehicle and dimension variables as necessary. 1275 /// While compacting the solution, only basic checks on vehicle variables are 1276 /// performed; if one of these checks fails no attempts to repair it are made 1277 /// (instead, the method returns nullptr). 1278 Assignment* CompactAssignment(const Assignment& assignment) const; 1279 /// Same as CompactAssignment() but also checks the validity of the final 1280 /// compact solution; if it is not valid, no attempts to repair it are made 1281 /// (instead, the method returns nullptr). 1282 Assignment* CompactAndCheckAssignment(const Assignment& assignment) const; 1283 /// Adds an extra variable to the vehicle routing assignment. 1284 void AddToAssignment(IntVar* const var); 1285 void AddIntervalToAssignment(IntervalVar* const interval); 1286 /// For every dimension in the model with an optimizer in 1287 /// local/global_dimension_optimizers_, this method tries to pack the cumul 1288 /// values of the dimension, such that: 1289 /// - The cumul costs (span costs, soft lower and upper bound costs, etc) are 1290 /// minimized. 1291 /// - The cumuls of the ends of the routes are minimized for this given 1292 /// minimal cumul cost. 1293 /// - Given these minimal end cumuls, the route start cumuls are maximized. 1294 /// Returns the assignment resulting from allocating these packed cumuls with 1295 /// the solver, and nullptr if these cumuls could not be set by the solver. 1296 const Assignment* PackCumulsOfOptimizerDimensionsFromAssignment( 1297 const Assignment* original_assignment, absl::Duration duration_limit); 1298 #ifndef SWIG 1299 // TODO(user): Revisit if coordinates are added to the RoutingModel class. 1300 void SetSweepArranger(SweepArranger* sweep_arranger); 1301 /// Returns the sweep arranger to be used by routing heuristics. 1302 SweepArranger* sweep_arranger() const; 1303 #endif 1304 /// Adds a custom local search filter to the list of filters used to speed up 1305 /// local search by pruning unfeasible variable assignments. 1306 /// Calling this method after the routing model has been closed (CloseModel() 1307 /// or Solve() has been called) has no effect. 1308 /// The routing model does not take ownership of the filter. AddLocalSearchFilter(LocalSearchFilter * filter)1309 void AddLocalSearchFilter(LocalSearchFilter* filter) { 1310 CHECK(filter != nullptr); 1311 if (closed_) { 1312 LOG(WARNING) << "Model is closed, filter addition will be ignored."; 1313 } 1314 extra_filters_.push_back({filter, LocalSearchFilterManager::kRelax}); 1315 extra_filters_.push_back({filter, LocalSearchFilterManager::kAccept}); 1316 } 1317 1318 /// Model inspection. 1319 /// Returns the variable index of the starting node of a vehicle route. Start(int vehicle)1320 int64_t Start(int vehicle) const { return starts_[vehicle]; } 1321 /// Returns the variable index of the ending node of a vehicle route. End(int vehicle)1322 int64_t End(int vehicle) const { return ends_[vehicle]; } 1323 /// Returns true if 'index' represents the first node of a route. 1324 bool IsStart(int64_t index) const; 1325 /// Returns true if 'index' represents the last node of a route. IsEnd(int64_t index)1326 bool IsEnd(int64_t index) const { return index >= Size(); } 1327 /// Returns the vehicle of the given start/end index, and -1 if the given 1328 /// index is not a vehicle start/end. VehicleIndex(int64_t index)1329 int VehicleIndex(int64_t index) const { return index_to_vehicle_[index]; } 1330 /// Assignment inspection 1331 /// Returns the variable index of the node directly after the node 1332 /// corresponding to 'index' in 'assignment'. 1333 int64_t Next(const Assignment& assignment, int64_t index) const; 1334 /// Returns true if the route of 'vehicle' is non empty in 'assignment'. 1335 bool IsVehicleUsed(const Assignment& assignment, int vehicle) const; 1336 1337 #if !defined(SWIGPYTHON) 1338 /// Returns all next variables of the model, such that Nexts(i) is the next 1339 /// variable of the node corresponding to i. Nexts()1340 const std::vector<IntVar*>& Nexts() const { return nexts_; } 1341 /// Returns all vehicle variables of the model, such that VehicleVars(i) is 1342 /// the vehicle variable of the node corresponding to i. VehicleVars()1343 const std::vector<IntVar*>& VehicleVars() const { return vehicle_vars_; } 1344 /// Returns vehicle resource variables for a given resource group, such that 1345 /// ResourceVars(r_g)[v] is the resource variable for vehicle 'v' in resource 1346 /// group 'r_g'. ResourceVars(int resource_group)1347 const std::vector<IntVar*>& ResourceVars(int resource_group) const { 1348 return resource_vars_[resource_group]; 1349 } 1350 #endif /// !defined(SWIGPYTHON) 1351 /// Returns the next variable of the node corresponding to index. Note that 1352 /// NextVar(index) == index is equivalent to ActiveVar(index) == 0. NextVar(int64_t index)1353 IntVar* NextVar(int64_t index) const { return nexts_[index]; } 1354 /// Returns the active variable of the node corresponding to index. ActiveVar(int64_t index)1355 IntVar* ActiveVar(int64_t index) const { return active_[index]; } 1356 /// Returns the active variable of the vehicle. It will be equal to 1 iff the 1357 /// route of the vehicle is not empty, 0 otherwise. ActiveVehicleVar(int vehicle)1358 IntVar* ActiveVehicleVar(int vehicle) const { 1359 return vehicle_active_[vehicle]; 1360 } 1361 /// Returns the variable specifying whether or not the given vehicle route is 1362 /// considered for costs and constraints. It will be equal to 1 iff the route 1363 /// of the vehicle is not empty OR vehicle_used_when_empty_[vehicle] is true. VehicleRouteConsideredVar(int vehicle)1364 IntVar* VehicleRouteConsideredVar(int vehicle) const { 1365 return vehicle_route_considered_[vehicle]; 1366 } 1367 /// Returns the vehicle variable of the node corresponding to index. Note that 1368 /// VehicleVar(index) == -1 is equivalent to ActiveVar(index) == 0. VehicleVar(int64_t index)1369 IntVar* VehicleVar(int64_t index) const { return vehicle_vars_[index]; } 1370 /// Returns the resource variable for the given vehicle index in the given 1371 /// resource group. If a vehicle doesn't require a resource from the 1372 /// corresponding resource group, then ResourceVar(v, r_g) == -1. ResourceVar(int vehicle,int resource_group)1373 IntVar* ResourceVar(int vehicle, int resource_group) const { 1374 DCHECK_LT(resource_group, resource_vars_.size()); 1375 DCHECK_LT(vehicle, resource_vars_[resource_group].size()); 1376 return resource_vars_[resource_group][vehicle]; 1377 } 1378 /// Returns the global cost variable which is being minimized. CostVar()1379 IntVar* CostVar() const { return cost_; } 1380 1381 /// Returns the cost of the transit arc between two nodes for a given vehicle. 1382 /// Input are variable indices of node. This returns 0 if vehicle < 0. 1383 int64_t GetArcCostForVehicle(int64_t from_index, int64_t to_index, 1384 int64_t vehicle) const; 1385 /// Whether costs are homogeneous across all vehicles. CostsAreHomogeneousAcrossVehicles()1386 bool CostsAreHomogeneousAcrossVehicles() const { 1387 return costs_are_homogeneous_across_vehicles_; 1388 } 1389 /// Returns the cost of the segment between two nodes supposing all vehicle 1390 /// costs are the same (returns the cost for the first vehicle otherwise). GetHomogeneousCost(int64_t from_index,int64_t to_index)1391 int64_t GetHomogeneousCost(int64_t from_index, int64_t to_index) const { 1392 return GetArcCostForVehicle(from_index, to_index, /*vehicle=*/0); 1393 } 1394 /// Returns the cost of the arc in the context of the first solution strategy. 1395 /// This is typically a simplification of the actual cost; see the .cc. 1396 int64_t GetArcCostForFirstSolution(int64_t from_index, 1397 int64_t to_index) const; 1398 /// Returns the cost of the segment between two nodes for a given cost 1399 /// class. Input are variable indices of nodes and the cost class. 1400 /// Unlike GetArcCostForVehicle(), if cost_class is kNoCost, then the 1401 /// returned cost won't necessarily be zero: only some of the components 1402 /// of the cost that depend on the cost class will be omited. See the code 1403 /// for details. 1404 int64_t GetArcCostForClass(int64_t from_index, int64_t to_index, 1405 int64_t /*CostClassIndex*/ cost_class_index) const; 1406 /// Get the cost class index of the given vehicle. GetCostClassIndexOfVehicle(int64_t vehicle)1407 CostClassIndex GetCostClassIndexOfVehicle(int64_t vehicle) const { 1408 DCHECK(closed_); 1409 DCHECK_GE(vehicle, 0); 1410 DCHECK_LT(vehicle, cost_class_index_of_vehicle_.size()); 1411 DCHECK_GE(cost_class_index_of_vehicle_[vehicle], 0); 1412 return cost_class_index_of_vehicle_[vehicle]; 1413 } 1414 /// Returns true iff the model contains a vehicle with the given 1415 /// cost_class_index. HasVehicleWithCostClassIndex(CostClassIndex cost_class_index)1416 bool HasVehicleWithCostClassIndex(CostClassIndex cost_class_index) const { 1417 DCHECK(closed_); 1418 if (cost_class_index == kCostClassIndexOfZeroCost) { 1419 return has_vehicle_with_zero_cost_class_; 1420 } 1421 return cost_class_index < cost_classes_.size(); 1422 } 1423 /// Returns the number of different cost classes in the model. GetCostClassesCount()1424 int GetCostClassesCount() const { return cost_classes_.size(); } 1425 /// Ditto, minus the 'always zero', built-in cost class. GetNonZeroCostClassesCount()1426 int GetNonZeroCostClassesCount() const { 1427 return std::max(0, GetCostClassesCount() - 1); 1428 } GetVehicleClassIndexOfVehicle(int64_t vehicle)1429 VehicleClassIndex GetVehicleClassIndexOfVehicle(int64_t vehicle) const { 1430 DCHECK(closed_); 1431 return vehicle_class_index_of_vehicle_[vehicle]; 1432 } 1433 /// Returns a vehicle of the given vehicle class, and -1 if there are no 1434 /// vehicles for this class. GetVehicleOfClass(VehicleClassIndex vehicle_class)1435 int GetVehicleOfClass(VehicleClassIndex vehicle_class) const { 1436 DCHECK(closed_); 1437 const RoutingModel::VehicleTypeContainer& vehicle_type_container = 1438 GetVehicleTypeContainer(); 1439 if (vehicle_class.value() >= GetVehicleClassesCount() || 1440 vehicle_type_container.vehicles_per_vehicle_class[vehicle_class.value()] 1441 .empty()) { 1442 return -1; 1443 } 1444 return vehicle_type_container 1445 .vehicles_per_vehicle_class[vehicle_class.value()] 1446 .front(); 1447 } 1448 /// Returns the number of different vehicle classes in the model. GetVehicleClassesCount()1449 int GetVehicleClassesCount() const { return vehicle_classes_.size(); } 1450 /// Returns variable indices of nodes constrained to be on the same route. GetSameVehicleIndicesOfIndex(int node)1451 const std::vector<int>& GetSameVehicleIndicesOfIndex(int node) const { 1452 DCHECK(closed_); 1453 return same_vehicle_groups_[same_vehicle_group_[node]]; 1454 } 1455 GetVehicleTypeContainer()1456 const VehicleTypeContainer& GetVehicleTypeContainer() const { 1457 DCHECK(closed_); 1458 return vehicle_type_container_; 1459 } 1460 1461 /// Returns whether the arc from->to1 is more constrained than from->to2, 1462 /// taking into account, in order: 1463 /// - whether the destination node isn't an end node 1464 /// - whether the destination node is mandatory 1465 /// - whether the destination node is bound to the same vehicle as the source 1466 /// - the "primary constrained" dimension (see SetPrimaryConstrainedDimension) 1467 /// It then breaks ties using, in order: 1468 /// - the arc cost (taking unperformed penalties into account) 1469 /// - the size of the vehicle vars of "to1" and "to2" (lowest size wins) 1470 /// - the value: the lowest value of the indices to1 and to2 wins. 1471 /// See the .cc for details. 1472 /// The more constrained arc is typically preferable when building a 1473 /// first solution. This method is intended to be used as a callback for the 1474 /// BestValueByComparisonSelector value selector. 1475 /// Args: 1476 /// from: the variable index of the source node 1477 /// to1: the variable index of the first candidate destination node. 1478 /// to2: the variable index of the second candidate destination node. 1479 bool ArcIsMoreConstrainedThanArc(int64_t from, int64_t to1, int64_t to2); 1480 /// Print some debugging information about an assignment, including the 1481 /// feasible intervals of the CumulVar for dimension "dimension_to_print" 1482 /// at each step of the routes. 1483 /// If "dimension_to_print" is omitted, all dimensions will be printed. 1484 std::string DebugOutputAssignment( 1485 const Assignment& solution_assignment, 1486 const std::string& dimension_to_print) const; 1487 /// Returns a vector cumul_bounds, for which cumul_bounds[i][j] is a pair 1488 /// containing the minimum and maximum of the CumulVar of the jth node on 1489 /// route i. 1490 /// - cumul_bounds[i][j].first is the minimum. 1491 /// - cumul_bounds[i][j].second is the maximum. 1492 #ifndef SWIG 1493 std::vector<std::vector<std::pair<int64_t, int64_t>>> GetCumulBounds( 1494 const Assignment& solution_assignment, const RoutingDimension& dimension); 1495 #endif 1496 /// Returns the underlying constraint solver. Can be used to add extra 1497 /// constraints and/or modify search algorithms. solver()1498 Solver* solver() const { return solver_.get(); } 1499 1500 /// Returns true if the search limit has been crossed. CheckLimit()1501 bool CheckLimit() { 1502 DCHECK(limit_ != nullptr); 1503 return limit_->Check(); 1504 } 1505 1506 /// Returns the time left in the search limit. RemainingTime()1507 absl::Duration RemainingTime() const { 1508 DCHECK(limit_ != nullptr); 1509 return limit_->AbsoluteSolverDeadline() - solver_->Now(); 1510 } 1511 1512 /// Sizes and indices 1513 /// Returns the number of nodes in the model. nodes()1514 int nodes() const { return nodes_; } 1515 /// Returns the number of vehicle routes in the model. vehicles()1516 int vehicles() const { return vehicles_; } 1517 /// Returns the number of next variables in the model. Size()1518 int64_t Size() const { return nodes_ + vehicles_ - start_end_count_; } 1519 1520 /// Returns statistics on first solution search, number of decisions sent to 1521 /// filters, number of decisions rejected by filters. 1522 int64_t GetNumberOfDecisionsInFirstSolution( 1523 const RoutingSearchParameters& search_parameters) const; 1524 int64_t GetNumberOfRejectsInFirstSolution( 1525 const RoutingSearchParameters& search_parameters) const; 1526 /// Returns the automatic first solution strategy selected. 1527 operations_research::FirstSolutionStrategy::Value GetAutomaticFirstSolutionStrategy()1528 GetAutomaticFirstSolutionStrategy() const { 1529 return automatic_first_solution_strategy_; 1530 } 1531 1532 /// Returns true if a vehicle/node matching problem is detected. 1533 bool IsMatchingModel() const; 1534 1535 #ifndef SWIG 1536 /// Sets the callback returning the variable to use for the Tabu Search 1537 /// metaheuristic. 1538 using GetTabuVarsCallback = 1539 std::function<std::vector<operations_research::IntVar*>(RoutingModel*)>; 1540 1541 void SetTabuVarsCallback(GetTabuVarsCallback tabu_var_callback); 1542 #endif // SWIG 1543 1544 /// The next few members are in the public section only for testing purposes. 1545 // TODO(user): Find a way to test and restrict the access at the same time. 1546 /// 1547 /// MakeGuidedSlackFinalizer creates a DecisionBuilder for the slacks of a 1548 /// dimension using a callback to choose which values to start with. 1549 /// The finalizer works only when all next variables in the model have 1550 /// been fixed. It has the following two characteristics: 1551 /// 1. It follows the routes defined by the nexts variables when choosing a 1552 /// variable to make a decision on. 1553 /// 2. When it comes to choose a value for the slack of node i, the decision 1554 /// builder first calls the callback with argument i, and supposingly the 1555 /// returned value is x it creates decisions slack[i] = x, slack[i] = x + 1556 /// 1, slack[i] = x - 1, slack[i] = x + 2, etc. 1557 DecisionBuilder* MakeGuidedSlackFinalizer( 1558 const RoutingDimension* dimension, 1559 std::function<int64_t(int64_t)> initializer); 1560 #ifndef SWIG 1561 // TODO(user): MakeGreedyDescentLSOperator is too general for routing.h. 1562 /// Perhaps move it to constraint_solver.h. 1563 /// MakeGreedyDescentLSOperator creates a local search operator that tries to 1564 /// improve the initial assignment by moving a logarithmically decreasing step 1565 /// away in each possible dimension. 1566 static std::unique_ptr<LocalSearchOperator> MakeGreedyDescentLSOperator( 1567 std::vector<IntVar*> variables); 1568 // Read access to currently registered search monitors. GetSearchMonitors()1569 const std::vector<SearchMonitor*>& GetSearchMonitors() const { 1570 return monitors_; 1571 } 1572 #endif /// __SWIG__ 1573 /// MakeSelfDependentDimensionFinalizer is a finalizer for the slacks of a 1574 /// self-dependent dimension. It makes an extensive use of the caches of the 1575 /// state dependent transits. 1576 /// In detail, MakeSelfDependentDimensionFinalizer returns a composition of a 1577 /// local search decision builder with a greedy descent operator for the cumul 1578 /// of the start of each route and a guided slack finalizer. Provided there 1579 /// are no time windows and the maximum slacks are large enough, once the 1580 /// cumul of the start of route is fixed, the guided finalizer can find 1581 /// optimal values of the slacks for the rest of the route in time 1582 /// proportional to the length of the route. Therefore the composed finalizer 1583 /// generally works in time O(log(t)*n*m), where t is the latest possible 1584 /// departute time, n is the number of nodes in the network and m is the 1585 /// number of vehicles. 1586 DecisionBuilder* MakeSelfDependentDimensionFinalizer( 1587 const RoutingDimension* dimension); 1588 1589 private: 1590 /// Local search move operator usable in routing. 1591 enum RoutingLocalSearchOperator { 1592 RELOCATE = 0, 1593 RELOCATE_PAIR, 1594 LIGHT_RELOCATE_PAIR, 1595 RELOCATE_NEIGHBORS, 1596 EXCHANGE, 1597 EXCHANGE_PAIR, 1598 CROSS, 1599 CROSS_EXCHANGE, 1600 TWO_OPT, 1601 OR_OPT, 1602 GLOBAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS, 1603 LOCAL_CHEAPEST_INSERTION_CLOSE_NODES_LNS, 1604 GLOBAL_CHEAPEST_INSERTION_PATH_LNS, 1605 LOCAL_CHEAPEST_INSERTION_PATH_LNS, 1606 RELOCATE_PATH_GLOBAL_CHEAPEST_INSERTION_INSERT_UNPERFORMED, 1607 GLOBAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS, 1608 LOCAL_CHEAPEST_INSERTION_EXPENSIVE_CHAIN_LNS, 1609 RELOCATE_EXPENSIVE_CHAIN, 1610 LIN_KERNIGHAN, 1611 TSP_OPT, 1612 MAKE_ACTIVE, 1613 RELOCATE_AND_MAKE_ACTIVE, 1614 MAKE_ACTIVE_AND_RELOCATE, 1615 MAKE_INACTIVE, 1616 MAKE_CHAIN_INACTIVE, 1617 SWAP_ACTIVE, 1618 EXTENDED_SWAP_ACTIVE, 1619 NODE_PAIR_SWAP, 1620 PATH_LNS, 1621 FULL_PATH_LNS, 1622 TSP_LNS, 1623 INACTIVE_LNS, 1624 EXCHANGE_RELOCATE_PAIR, 1625 RELOCATE_SUBTRIP, 1626 EXCHANGE_SUBTRIP, 1627 LOCAL_SEARCH_OPERATOR_COUNTER 1628 }; 1629 1630 /// Structure storing a value for a set of variable indices. Is used to store 1631 /// data for index disjunctions (variable indices, max_cardinality and penalty 1632 /// when unperformed). 1633 template <typename T> 1634 struct ValuedNodes { 1635 std::vector<int64_t> indices; 1636 T value; 1637 }; 1638 struct DisjunctionValues { 1639 int64_t penalty; 1640 int64_t max_cardinality; 1641 }; 1642 typedef ValuedNodes<DisjunctionValues> Disjunction; 1643 1644 /// Storage of a cost cache element corresponding to a cost arc ending at 1645 /// node 'index' and on the cost class 'cost_class'. 1646 struct CostCacheElement { 1647 /// This is usually an int64_t, but using an int here decreases the RAM 1648 /// usage, and should be fine since in practice we never have more than 1649 /// 1<<31 vars. Note(user): on 2013-11, microbenchmarks on the arc costs 1650 /// callbacks also showed a 2% speed-up thanks to using int rather than 1651 /// int64_t. 1652 int index; 1653 CostClassIndex cost_class_index; 1654 int64_t cost; 1655 }; 1656 1657 /// Internal methods. 1658 void Initialize(); 1659 void AddNoCycleConstraintInternal(); 1660 bool AddDimensionWithCapacityInternal( 1661 const std::vector<int>& evaluator_indices, int64_t slack_max, 1662 std::vector<int64_t> vehicle_capacities, bool fix_start_cumul_to_zero, 1663 const std::string& name); 1664 bool AddDimensionDependentDimensionWithVehicleCapacityInternal( 1665 const std::vector<int>& pure_transits, 1666 const std::vector<int>& dependent_transits, 1667 const RoutingDimension* base_dimension, int64_t slack_max, 1668 std::vector<int64_t> vehicle_capacities, bool fix_start_cumul_to_zero, 1669 const std::string& name); 1670 bool InitializeDimensionInternal( 1671 const std::vector<int>& evaluator_indices, 1672 const std::vector<int>& state_dependent_evaluator_indices, 1673 int64_t slack_max, bool fix_start_cumul_to_zero, 1674 RoutingDimension* dimension); 1675 DimensionIndex GetDimensionIndex(const std::string& dimension_name) const; 1676 1677 /// Creates global and local cumul optimizers for the dimensions needing them, 1678 /// and stores them in the corresponding [local|global]_dimension_optimizers_ 1679 /// vectors. 1680 /// This function also computes and stores the "offsets" for these dimensions, 1681 /// used in the local/global optimizers to simplify LP computations. 1682 /// 1683 /// Note on the offsets computation: 1684 /// The global/local cumul offsets are used by the respective optimizers to 1685 /// have smaller numbers, and therefore better numerical behavior in the LP. 1686 /// These offsets are used as a minimum value for the cumuls over the route 1687 /// (or globally), i.e. a value we consider all cumuls to be greater or equal 1688 /// to. When transits are all positive, the cumuls of every node on a route is 1689 /// necessarily greater than the cumul of its start. Therefore, the local 1690 /// offset for a vehicle can be set to the minimum of its start node's cumul, 1691 /// and for the global optimizers, to the min start cumul over all vehicles. 1692 /// However, to be able to distinguish between infeasible nodes (i.e. nodes 1693 /// for which the cumul upper bound is less than the min cumul of the 1694 /// vehicle's start), we set the offset to "min_start_cumul" - 1. By doing so, 1695 /// all infeasible nodes described above will have bounds of [0, 0]. Example: 1696 /// Start cumul bounds: [11, 20] --> offset = 11 - 1 = 10. 1697 /// Two nodes with cumul bounds. Node1: [5, 10], Node2: [7, 20] 1698 /// After applying the offset to the above windows, they become: 1699 /// Vehicle: [1, 10]. Node1: [0, 0] (infeasible). Node2: [0, 10]. 1700 /// 1701 /// On the other hand, when transits on a route can be negative, no assumption 1702 /// can be made on the cumuls of nodes wrt the start cumuls, and the offset is 1703 /// therefore set to 0. 1704 void StoreDimensionCumulOptimizers(const RoutingSearchParameters& parameters); 1705 1706 void ComputeCostClasses(const RoutingSearchParameters& parameters); 1707 void ComputeVehicleClasses(); 1708 /// The following method initializes the vehicle_type_container_: 1709 /// - Computes the vehicle types of vehicles and stores it in 1710 /// type_index_of_vehicle. 1711 /// - The vehicle classes corresponding to each vehicle type index are stored 1712 /// and sorted by fixed cost in sorted_vehicle_classes_per_type. 1713 /// - The vehicles for each vehicle class are stored in 1714 /// vehicles_per_vehicle_class. 1715 void ComputeVehicleTypes(); 1716 /// This method scans the visit types and sets up the following members: 1717 /// - single_nodes_of_type_[type] contains indices of nodes of visit type 1718 /// "type" which are not part of any pickup/delivery pair. 1719 /// - pair_indices_of_type_[type] is the set of "pair_index" such that 1720 /// pickup_delivery_pairs_[pair_index] has at least one pickup or delivery 1721 /// with visit type "type". 1722 /// - topologically_sorted_visit_types_ contains the visit types in 1723 /// topological order based on required-->dependent arcs from the 1724 /// visit type requirements. 1725 void FinalizeVisitTypes(); 1726 // Called by FinalizeVisitTypes() to setup topologically_sorted_visit_types_. 1727 void TopologicallySortVisitTypes(); 1728 int64_t GetArcCostForClassInternal(int64_t from_index, int64_t to_index, 1729 CostClassIndex cost_class_index) const; 1730 void AppendHomogeneousArcCosts(const RoutingSearchParameters& parameters, 1731 int node_index, 1732 std::vector<IntVar*>* cost_elements); 1733 void AppendArcCosts(const RoutingSearchParameters& parameters, int node_index, 1734 std::vector<IntVar*>* cost_elements); 1735 Assignment* DoRestoreAssignment(); 1736 static const CostClassIndex kCostClassIndexOfZeroCost; SafeGetCostClassInt64OfVehicle(int64_t vehicle)1737 int64_t SafeGetCostClassInt64OfVehicle(int64_t vehicle) const { 1738 DCHECK_LT(0, vehicles_); 1739 return (vehicle >= 0 ? GetCostClassIndexOfVehicle(vehicle) 1740 : kCostClassIndexOfZeroCost) 1741 .value(); 1742 } 1743 int64_t GetDimensionTransitCostSum(int64_t i, int64_t j, 1744 const CostClass& cost_class) const; 1745 /// Returns nullptr if no penalty cost, otherwise returns penalty variable. 1746 IntVar* CreateDisjunction(DisjunctionIndex disjunction); 1747 /// Sets up pickup and delivery sets. 1748 void AddPickupAndDeliverySetsInternal(const std::vector<int64_t>& pickups, 1749 const std::vector<int64_t>& deliveries); 1750 /// Returns the cost variable related to the soft same vehicle constraint of 1751 /// index 'vehicle_index'. 1752 IntVar* CreateSameVehicleCost(int vehicle_index); 1753 /// Returns the first active variable index in 'indices' starting from index 1754 /// + 1. 1755 int FindNextActive(int index, const std::vector<int64_t>& indices) const; 1756 1757 /// Checks that all nodes on the route starting at start_index (using the 1758 /// solution stored in assignment) can be visited by the given vehicle. 1759 bool RouteCanBeUsedByVehicle(const Assignment& assignment, int start_index, 1760 int vehicle) const; 1761 /// Replaces the route of unused_vehicle with the route of active_vehicle in 1762 /// compact_assignment. Expects that unused_vehicle is a vehicle with an empty 1763 /// route and that the route of active_vehicle is non-empty. Also expects that 1764 /// 'assignment' contains the original assignment, from which 1765 /// compact_assignment was created. 1766 /// Returns true if the vehicles were successfully swapped; otherwise, returns 1767 /// false. 1768 bool ReplaceUnusedVehicle(int unused_vehicle, int active_vehicle, 1769 Assignment* compact_assignment) const; 1770 1771 void QuietCloseModel(); QuietCloseModelWithParameters(const RoutingSearchParameters & parameters)1772 void QuietCloseModelWithParameters( 1773 const RoutingSearchParameters& parameters) { 1774 if (!closed_) { 1775 CloseModelWithParameters(parameters); 1776 } 1777 } 1778 1779 /// Solve matching problem with min-cost flow and store result in assignment. 1780 bool SolveMatchingModel(Assignment* assignment, 1781 const RoutingSearchParameters& parameters); 1782 #ifndef SWIG 1783 /// Append an assignment to a vector of assignments if it is feasible. 1784 bool AppendAssignmentIfFeasible( 1785 const Assignment& assignment, 1786 std::vector<std::unique_ptr<Assignment>>* assignments); 1787 #endif 1788 /// Log a solution. 1789 void LogSolution(const RoutingSearchParameters& parameters, 1790 const std::string& description, int64_t solution_cost, 1791 int64_t start_time_ms); 1792 /// See CompactAssignment. Checks the final solution if 1793 /// check_compact_assignment is true. 1794 Assignment* CompactAssignmentInternal(const Assignment& assignment, 1795 bool check_compact_assignment) const; 1796 /// Checks that the current search parameters are valid for the current 1797 /// model's specific settings. This assumes that FindErrorInSearchParameters() 1798 /// from 1799 /// ./routing_flags.h caught no error. 1800 std::string FindErrorInSearchParametersForModel( 1801 const RoutingSearchParameters& search_parameters) const; 1802 /// Sets up search objects, such as decision builders and monitors. 1803 void SetupSearch(const RoutingSearchParameters& search_parameters); 1804 /// Set of auxiliary methods used to setup the search. 1805 // TODO(user): Document each auxiliary method. 1806 Assignment* GetOrCreateAssignment(); 1807 Assignment* GetOrCreateTmpAssignment(); 1808 RegularLimit* GetOrCreateLimit(); 1809 RegularLimit* GetOrCreateLocalSearchLimit(); 1810 RegularLimit* GetOrCreateLargeNeighborhoodSearchLimit(); 1811 RegularLimit* GetOrCreateFirstSolutionLargeNeighborhoodSearchLimit(); 1812 LocalSearchOperator* CreateInsertionOperator(); 1813 LocalSearchOperator* CreateMakeInactiveOperator(); 1814 template <class T> CreateCPOperator(const T & operator_factory)1815 LocalSearchOperator* CreateCPOperator(const T& operator_factory) { 1816 return operator_factory(solver_.get(), nexts_, 1817 CostsAreHomogeneousAcrossVehicles() 1818 ? std::vector<IntVar*>() 1819 : vehicle_vars_, 1820 vehicle_start_class_callback_); 1821 } 1822 template <class T> CreateCPOperator()1823 LocalSearchOperator* CreateCPOperator() { 1824 return CreateCPOperator(MakeLocalSearchOperator<T>); 1825 } 1826 template <class T, class Arg> CreateOperator(const Arg & arg)1827 LocalSearchOperator* CreateOperator(const Arg& arg) { 1828 return solver_->RevAlloc(new T(nexts_, 1829 CostsAreHomogeneousAcrossVehicles() 1830 ? std::vector<IntVar*>() 1831 : vehicle_vars_, 1832 vehicle_start_class_callback_, arg)); 1833 } 1834 template <class T> CreatePairOperator()1835 LocalSearchOperator* CreatePairOperator() { 1836 return CreateOperator<T>(pickup_delivery_pairs_); 1837 } 1838 void CreateNeighborhoodOperators(const RoutingSearchParameters& parameters); 1839 LocalSearchOperator* ConcatenateOperators( 1840 const RoutingSearchParameters& search_parameters, 1841 const std::vector<LocalSearchOperator*>& operators) const; 1842 LocalSearchOperator* GetNeighborhoodOperators( 1843 const RoutingSearchParameters& search_parameters) const; 1844 std::vector<LocalSearchFilterManager::FilterEvent> 1845 GetOrCreateLocalSearchFilters(const RoutingSearchParameters& parameters, 1846 bool filter_cost = true); 1847 LocalSearchFilterManager* GetOrCreateLocalSearchFilterManager( 1848 const RoutingSearchParameters& parameters); 1849 std::vector<LocalSearchFilterManager::FilterEvent> 1850 GetOrCreateFeasibilityFilters(const RoutingSearchParameters& parameters); 1851 LocalSearchFilterManager* GetOrCreateFeasibilityFilterManager( 1852 const RoutingSearchParameters& parameters); 1853 LocalSearchFilterManager* GetOrCreateStrongFeasibilityFilterManager( 1854 const RoutingSearchParameters& parameters); 1855 DecisionBuilder* CreateSolutionFinalizer(SearchLimit* lns_limit); 1856 DecisionBuilder* CreateFinalizerForMinimizedAndMaximizedVariables(); 1857 void CreateFirstSolutionDecisionBuilders( 1858 const RoutingSearchParameters& search_parameters); 1859 DecisionBuilder* GetFirstSolutionDecisionBuilder( 1860 const RoutingSearchParameters& search_parameters) const; 1861 IntVarFilteredDecisionBuilder* GetFilteredFirstSolutionDecisionBuilderOrNull( 1862 const RoutingSearchParameters& parameters) const; 1863 LocalSearchPhaseParameters* CreateLocalSearchParameters( 1864 const RoutingSearchParameters& search_parameters); 1865 DecisionBuilder* CreateLocalSearchDecisionBuilder( 1866 const RoutingSearchParameters& search_parameters); 1867 void SetupDecisionBuilders(const RoutingSearchParameters& search_parameters); 1868 void SetupMetaheuristics(const RoutingSearchParameters& search_parameters); 1869 void SetupAssignmentCollector( 1870 const RoutingSearchParameters& search_parameters); 1871 void SetupTrace(const RoutingSearchParameters& search_parameters); 1872 void SetupImprovementLimit(const RoutingSearchParameters& search_parameters); 1873 void SetupSearchMonitors(const RoutingSearchParameters& search_parameters); 1874 bool UsesLightPropagation( 1875 const RoutingSearchParameters& search_parameters) const; 1876 GetTabuVarsCallback tabu_var_callback_; 1877 1878 // Detects implicit pickup delivery pairs. These pairs are 1879 // non-pickup/delivery pairs for which there exists a unary dimension such 1880 // that the demand d of the implicit pickup is positive and the demand of the 1881 // implicit delivery is equal to -d. 1882 void DetectImplicitPickupAndDeliveries(); 1883 1884 int GetVehicleStartClass(int64_t start) const; 1885 InitSameVehicleGroups(int number_of_groups)1886 void InitSameVehicleGroups(int number_of_groups) { 1887 same_vehicle_group_.assign(Size(), 0); 1888 same_vehicle_groups_.assign(number_of_groups, {}); 1889 } SetSameVehicleGroup(int index,int group)1890 void SetSameVehicleGroup(int index, int group) { 1891 same_vehicle_group_[index] = group; 1892 same_vehicle_groups_[group].push_back(index); 1893 } 1894 1895 /// Model 1896 std::unique_ptr<Solver> solver_; 1897 int nodes_; 1898 int vehicles_; 1899 int max_active_vehicles_; 1900 Constraint* no_cycle_constraint_ = nullptr; 1901 /// Decision variables: indexed by int64_t var index. 1902 std::vector<IntVar*> nexts_; 1903 std::vector<IntVar*> vehicle_vars_; 1904 std::vector<IntVar*> active_; 1905 /// Resource variables, indexed first by resource group index and then by 1906 /// vehicle index. 1907 // clang-format off 1908 std::vector<std::vector<IntVar*> > resource_vars_; 1909 // clang-format on 1910 // The following vectors are indexed by vehicle index. 1911 std::vector<IntVar*> vehicle_active_; 1912 std::vector<IntVar*> vehicle_route_considered_; 1913 /// is_bound_to_end_[i] will be true iff the path starting at var #i is fully 1914 /// bound and reaches the end of a route, i.e. either: 1915 /// - IsEnd(i) is true 1916 /// - or nexts_[i] is bound and is_bound_to_end_[nexts_[i].Value()] is true. 1917 std::vector<IntVar*> is_bound_to_end_; 1918 mutable RevSwitch is_bound_to_end_ct_added_; 1919 /// Dimensions 1920 absl::flat_hash_map<std::string, DimensionIndex> dimension_name_to_index_; 1921 absl::StrongVector<DimensionIndex, RoutingDimension*> dimensions_; 1922 /// Resource Groups. 1923 /// If resource_groups_ is not empty, then for each group of resources, each 1924 /// (used) vehicle must be assigned to exactly 1 resource, and each resource 1925 /// can in turn be assigned to at most 1 vehicle. 1926 // clang-format off 1927 std::vector<std::unique_ptr<ResourceGroup> > resource_groups_; 1928 /// Stores the set of resource groups related to each dimension. 1929 absl::StrongVector<DimensionIndex, std::vector<int> > 1930 dimension_resource_group_indices_; 1931 1932 /// TODO(user): Define a new Dimension[Global|Local]OptimizerIndex type 1933 /// and use it to define ITIVectors and for the dimension to optimizer index 1934 /// mappings below. 1935 std::vector<std::unique_ptr<GlobalDimensionCumulOptimizer> > 1936 global_dimension_optimizers_; 1937 std::vector<std::unique_ptr<GlobalDimensionCumulOptimizer> > 1938 global_dimension_mp_optimizers_; 1939 absl::StrongVector<DimensionIndex, int> global_optimizer_index_; 1940 std::vector<std::unique_ptr<LocalDimensionCumulOptimizer> > 1941 local_dimension_optimizers_; 1942 std::vector<std::unique_ptr<LocalDimensionCumulOptimizer> > 1943 local_dimension_mp_optimizers_; 1944 // clang-format off 1945 absl::StrongVector<DimensionIndex, int> local_optimizer_index_; 1946 std::string primary_constrained_dimension_; 1947 /// Costs 1948 IntVar* cost_ = nullptr; 1949 std::vector<int> vehicle_to_transit_cost_; 1950 std::vector<int64_t> fixed_cost_of_vehicle_; 1951 std::vector<CostClassIndex> cost_class_index_of_vehicle_; 1952 bool has_vehicle_with_zero_cost_class_; 1953 std::vector<int64_t> linear_cost_factor_of_vehicle_; 1954 std::vector<int64_t> quadratic_cost_factor_of_vehicle_; 1955 bool vehicle_amortized_cost_factors_set_; 1956 /// vehicle_used_when_empty_[vehicle] determines if "vehicle" should be 1957 /// taken into account for costs (arc costs, span costs, etc.) and constraints 1958 /// (eg. resources) even when the route of the vehicle is empty (i.e. goes 1959 /// straight from its start to its end). 1960 /// 1961 /// NOTE1: A vehicle's fixed cost is added iff the vehicle serves nodes on its 1962 /// route, regardless of this variable's value. 1963 /// 1964 /// NOTE2: The default value for this boolean is 'false' for all vehicles, 1965 /// i.e. by default empty routes will not contribute to the cost nor be 1966 /// considered for constraints. 1967 std::vector<bool> vehicle_used_when_empty_; 1968 #ifndef SWIG 1969 absl::StrongVector<CostClassIndex, CostClass> cost_classes_; 1970 #endif // SWIG 1971 bool costs_are_homogeneous_across_vehicles_; 1972 bool cache_callbacks_; 1973 mutable std::vector<CostCacheElement> cost_cache_; /// Index by source index. 1974 std::vector<VehicleClassIndex> vehicle_class_index_of_vehicle_; 1975 #ifndef SWIG 1976 absl::StrongVector<VehicleClassIndex, VehicleClass> vehicle_classes_; 1977 #endif // SWIG 1978 VehicleTypeContainer vehicle_type_container_; 1979 std::function<int(int64_t)> vehicle_start_class_callback_; 1980 /// Disjunctions 1981 absl::StrongVector<DisjunctionIndex, Disjunction> disjunctions_; 1982 std::vector<std::vector<DisjunctionIndex> > index_to_disjunctions_; 1983 /// Same vehicle costs 1984 std::vector<ValuedNodes<int64_t> > same_vehicle_costs_; 1985 /// Allowed vehicles 1986 #ifndef SWIG 1987 std::vector<absl::flat_hash_set<int>> allowed_vehicles_; 1988 #endif // SWIG 1989 /// Pickup and delivery 1990 IndexPairs pickup_delivery_pairs_; 1991 IndexPairs implicit_pickup_delivery_pairs_without_alternatives_; 1992 std::vector<std::pair<DisjunctionIndex, DisjunctionIndex> > 1993 pickup_delivery_disjunctions_; 1994 // clang-format off 1995 // If node_index is a pickup, index_to_pickup_index_pairs_[node_index] is the 1996 // vector of pairs {pair_index, pickup_index} such that 1997 // (pickup_delivery_pairs_[pair_index].first)[pickup_index] == node_index 1998 std::vector<std::vector<std::pair<int, int> > > index_to_pickup_index_pairs_; 1999 // Same as above for deliveries. 2000 std::vector<std::vector<std::pair<int, int> > > 2001 index_to_delivery_index_pairs_; 2002 // clang-format on 2003 std::vector<PickupAndDeliveryPolicy> vehicle_pickup_delivery_policy_; 2004 // Same vehicle group to which a node belongs. 2005 std::vector<int> same_vehicle_group_; 2006 // Same vehicle node groups. 2007 std::vector<std::vector<int>> same_vehicle_groups_; 2008 // Node visit types 2009 // Variable index to visit type index. 2010 std::vector<int> index_to_visit_type_; 2011 // Variable index to VisitTypePolicy. 2012 std::vector<VisitTypePolicy> index_to_type_policy_; 2013 // clang-format off 2014 std::vector<std::vector<int> > single_nodes_of_type_; 2015 std::vector<std::vector<int> > pair_indices_of_type_; 2016 2017 std::vector<absl::flat_hash_set<int> > 2018 hard_incompatible_types_per_type_index_; 2019 bool has_hard_type_incompatibilities_; 2020 std::vector<absl::flat_hash_set<int> > 2021 temporal_incompatible_types_per_type_index_; 2022 bool has_temporal_type_incompatibilities_; 2023 2024 std::vector<std::vector<absl::flat_hash_set<int> > > 2025 same_vehicle_required_type_alternatives_per_type_index_; 2026 bool has_same_vehicle_type_requirements_; 2027 std::vector<std::vector<absl::flat_hash_set<int> > > 2028 required_type_alternatives_when_adding_type_index_; 2029 std::vector<std::vector<absl::flat_hash_set<int> > > 2030 required_type_alternatives_when_removing_type_index_; 2031 bool has_temporal_type_requirements_; 2032 absl::flat_hash_map</*type*/int, absl::flat_hash_set<VisitTypePolicy> > 2033 trivially_infeasible_visit_types_to_policies_; 2034 2035 // Visit types sorted topologically based on required-->dependent requirement 2036 // arcs between the types (if the requirement/dependency graph is acyclic). 2037 // Visit types of the same topological level are sorted in each sub-vector 2038 // by decreasing requirement "tightness", computed as the pair of the two 2039 // following criteria: 2040 // 2041 // 1) How highly *dependent* this type is, determined by 2042 // (total number of required alternative sets for that type) 2043 // / (average number of types in the required alternative sets) 2044 // 2) How highly *required* this type t is, computed as 2045 // SUM_{S required set containing t} ( 1 / |S| ), 2046 // i.e. the sum of reverse number of elements of all required sets 2047 // containing the type t. 2048 // 2049 // The higher these two numbers, the tighter the type is wrt requirements. 2050 std::vector<std::vector<int> > topologically_sorted_visit_types_; 2051 // clang-format on 2052 int num_visit_types_; 2053 // Two indices are equivalent if they correspond to the same node (as given 2054 // to the constructors taking a RoutingIndexManager). 2055 std::vector<int> index_to_equivalence_class_; 2056 std::vector<int> index_to_vehicle_; 2057 std::vector<int64_t> starts_; 2058 std::vector<int64_t> ends_; 2059 // TODO(user): b/62478706 Once the port is done, this shouldn't be needed 2060 // anymore. 2061 RoutingIndexManager manager_; 2062 int start_end_count_; 2063 // Model status 2064 bool closed_ = false; 2065 Status status_ = ROUTING_NOT_SOLVED; 2066 bool enable_deep_serialization_ = true; 2067 2068 // Search data 2069 std::vector<DecisionBuilder*> first_solution_decision_builders_; 2070 std::vector<IntVarFilteredDecisionBuilder*> 2071 first_solution_filtered_decision_builders_; 2072 Solver::IndexEvaluator2 first_solution_evaluator_; 2073 FirstSolutionStrategy::Value automatic_first_solution_strategy_ = 2074 FirstSolutionStrategy::UNSET; 2075 std::vector<LocalSearchOperator*> local_search_operators_; 2076 std::vector<SearchMonitor*> monitors_; 2077 SolutionCollector* collect_assignments_ = nullptr; 2078 SolutionCollector* collect_one_assignment_ = nullptr; 2079 SolutionCollector* packed_dimensions_assignment_collector_ = nullptr; 2080 DecisionBuilder* solve_db_ = nullptr; 2081 DecisionBuilder* improve_db_ = nullptr; 2082 DecisionBuilder* restore_assignment_ = nullptr; 2083 DecisionBuilder* restore_tmp_assignment_ = nullptr; 2084 Assignment* assignment_ = nullptr; 2085 Assignment* preassignment_ = nullptr; 2086 Assignment* tmp_assignment_ = nullptr; 2087 std::vector<IntVar*> extra_vars_; 2088 std::vector<IntervalVar*> extra_intervals_; 2089 std::vector<LocalSearchOperator*> extra_operators_; 2090 LocalSearchFilterManager* local_search_filter_manager_ = nullptr; 2091 LocalSearchFilterManager* feasibility_filter_manager_ = nullptr; 2092 LocalSearchFilterManager* strong_feasibility_filter_manager_ = nullptr; 2093 std::vector<LocalSearchFilterManager::FilterEvent> extra_filters_; 2094 #ifndef SWIG 2095 std::vector<std::pair<IntVar*, int64_t>> finalizer_variable_cost_pairs_; 2096 std::vector<std::pair<IntVar*, int64_t>> finalizer_variable_target_pairs_; 2097 absl::flat_hash_map<IntVar*, int> finalizer_variable_cost_index_; 2098 absl::flat_hash_set<IntVar*> finalizer_variable_target_set_; 2099 std::unique_ptr<SweepArranger> sweep_arranger_; 2100 #endif 2101 2102 RegularLimit* limit_ = nullptr; 2103 RegularLimit* ls_limit_ = nullptr; 2104 RegularLimit* lns_limit_ = nullptr; 2105 RegularLimit* first_solution_lns_limit_ = nullptr; 2106 2107 typedef std::pair<int64_t, int64_t> CacheKey; 2108 typedef absl::flat_hash_map<CacheKey, int64_t> TransitCallbackCache; 2109 typedef absl::flat_hash_map<CacheKey, StateDependentTransit> 2110 StateDependentTransitCallbackCache; 2111 2112 std::vector<TransitCallback1> unary_transit_evaluators_; 2113 std::vector<TransitCallback2> transit_evaluators_; 2114 // The following vector stores a boolean per transit_evaluator_, indicating 2115 // whether the transits are all positive. 2116 // is_transit_evaluator_positive_ will be set to true only when registering a 2117 // callback via RegisterPositiveTransitCallback(), and to false otherwise. 2118 // The actual positivity of the transit values will only be checked in debug 2119 // mode, when calling RegisterPositiveTransitCallback(). 2120 // Therefore, RegisterPositiveTransitCallback() should only be called when the 2121 // transits are known to be positive, as the positivity of a callback will 2122 // allow some improvements in the solver, but will entail in errors if the 2123 // transits are falsely assumed positive. 2124 std::vector<bool> is_transit_evaluator_positive_; 2125 std::vector<VariableIndexEvaluator2> state_dependent_transit_evaluators_; 2126 std::vector<std::unique_ptr<StateDependentTransitCallbackCache>> 2127 state_dependent_transit_evaluators_cache_; 2128 2129 friend class RoutingDimension; 2130 friend class RoutingModelInspector; 2131 friend class ResourceGroup::Resource; 2132 2133 DISALLOW_COPY_AND_ASSIGN(RoutingModel); 2134 }; 2135 2136 /// Routing model visitor. 2137 class RoutingModelVisitor : public BaseObject { 2138 public: 2139 /// Constraint types. 2140 static const char kLightElement[]; 2141 static const char kLightElement2[]; 2142 static const char kRemoveValues[]; 2143 }; 2144 2145 #if !defined(SWIG) 2146 /// This class acts like a CP propagator: it takes a set of tasks given by 2147 /// their start/duration/end features, and reduces the range of possible values. 2148 class DisjunctivePropagator { 2149 public: 2150 /// A structure to hold tasks described by their features. 2151 /// The first num_chain_tasks are considered linked by a chain of precedences, 2152 /// i.e. if i < j < num_chain_tasks, then end(i) <= start(j). 2153 /// This occurs frequently in routing, and can be leveraged by 2154 /// some variants of classic propagators. 2155 struct Tasks { 2156 int num_chain_tasks = 0; 2157 std::vector<int64_t> start_min; 2158 std::vector<int64_t> start_max; 2159 std::vector<int64_t> duration_min; 2160 std::vector<int64_t> duration_max; 2161 std::vector<int64_t> end_min; 2162 std::vector<int64_t> end_max; 2163 std::vector<bool> is_preemptible; 2164 std::vector<const SortedDisjointIntervalList*> forbidden_intervals; 2165 std::vector<std::pair<int64_t, int64_t>> distance_duration; 2166 int64_t span_min = 0; 2167 int64_t span_max = kint64max; 2168 ClearTasks2169 void Clear() { 2170 start_min.clear(); 2171 start_max.clear(); 2172 duration_min.clear(); 2173 duration_max.clear(); 2174 end_min.clear(); 2175 end_max.clear(); 2176 is_preemptible.clear(); 2177 forbidden_intervals.clear(); 2178 distance_duration.clear(); 2179 span_min = 0; 2180 span_max = kint64max; 2181 num_chain_tasks = 0; 2182 } 2183 }; 2184 2185 /// Computes new bounds for all tasks, returns false if infeasible. 2186 /// This does not compute a fixed point, so recalling it may filter more. 2187 bool Propagate(Tasks* tasks); 2188 2189 /// Propagates the deductions from the chain of precedences, if there is one. 2190 bool Precedences(Tasks* tasks); 2191 /// Transforms the problem with a time symmetry centered in 0. Returns true 2192 /// for convenience. 2193 bool MirrorTasks(Tasks* tasks); 2194 /// Does edge-finding deductions on all tasks. 2195 bool EdgeFinding(Tasks* tasks); 2196 /// Does detectable precedences deductions on tasks in the chain precedence, 2197 /// taking the time windows of nonchain tasks into account. 2198 bool DetectablePrecedencesWithChain(Tasks* tasks); 2199 /// Tasks might have holes in their domain, this enforces such holes. 2200 bool ForbiddenIntervals(Tasks* tasks); 2201 /// Propagates distance_duration constraints, if any. 2202 bool DistanceDuration(Tasks* tasks); 2203 /// Propagates a lower bound of the chain span, 2204 /// end[num_chain_tasks] - start[0], to span_min. 2205 bool ChainSpanMin(Tasks* tasks); 2206 /// Computes a lower bound of the span of the chain, taking into account only 2207 /// the first nonchain task. 2208 /// For more accurate results, this should be called after Precedences(), 2209 /// otherwise the lower bound might be lower than feasible. 2210 bool ChainSpanMinDynamic(Tasks* tasks); 2211 2212 private: 2213 /// The main algorithm uses Vilim's theta tree data structure. 2214 /// See Petr Vilim's PhD thesis "Global Constraints in Scheduling". 2215 sat::ThetaLambdaTree<int64_t> theta_lambda_tree_; 2216 /// Mappings between events and tasks. 2217 std::vector<int> tasks_by_start_min_; 2218 std::vector<int> tasks_by_end_max_; 2219 std::vector<int> event_of_task_; 2220 std::vector<int> nonchain_tasks_by_start_max_; 2221 /// Maps chain elements to the sum of chain task durations before them. 2222 std::vector<int64_t> total_duration_before_; 2223 }; 2224 2225 struct TravelBounds { 2226 std::vector<int64_t> min_travels; 2227 std::vector<int64_t> max_travels; 2228 std::vector<int64_t> pre_travels; 2229 std::vector<int64_t> post_travels; 2230 }; 2231 2232 void AppendTasksFromPath(const std::vector<int64_t>& path, 2233 const TravelBounds& travel_bounds, 2234 const RoutingDimension& dimension, 2235 DisjunctivePropagator::Tasks* tasks); 2236 void AppendTasksFromIntervals(const std::vector<IntervalVar*>& intervals, 2237 DisjunctivePropagator::Tasks* tasks); 2238 void FillPathEvaluation(const std::vector<int64_t>& path, 2239 const RoutingModel::TransitCallback2& evaluator, 2240 std::vector<int64_t>* values); 2241 void FillTravelBoundsOfVehicle(int vehicle, const std::vector<int64_t>& path, 2242 const RoutingDimension& dimension, 2243 TravelBounds* travel_bounds); 2244 #endif // !defined(SWIG) 2245 2246 /// GlobalVehicleBreaksConstraint ensures breaks constraints are enforced on 2247 /// all vehicles in the dimension passed to its constructor. 2248 /// It is intended to be used for dimensions representing time. 2249 /// A break constraint ensures break intervals fit on the route of a vehicle. 2250 /// For a given vehicle, it forces break intervals to be disjoint from visit 2251 /// intervals, where visit intervals start at CumulVar(node) and last for 2252 /// node_visit_transit[node]. Moreover, it ensures that there is enough time 2253 /// between two consecutive nodes of a route to do transit and vehicle breaks, 2254 /// i.e. if Next(nodeA) = nodeB, CumulVar(nodeA) = tA and CumulVar(nodeB) = tB, 2255 /// then SlackVar(nodeA) >= sum_{breaks \subseteq [tA, tB)} duration(break). 2256 class GlobalVehicleBreaksConstraint : public Constraint { 2257 public: 2258 explicit GlobalVehicleBreaksConstraint(const RoutingDimension* dimension); DebugString()2259 std::string DebugString() const override { 2260 return "GlobalVehicleBreaksConstraint"; 2261 } 2262 2263 void Post() override; 2264 void InitialPropagate() override; 2265 2266 private: 2267 void PropagateNode(int node); 2268 void PropagateVehicle(int vehicle); 2269 void PropagateMaxBreakDistance(int vehicle); 2270 2271 const RoutingModel* model_; 2272 const RoutingDimension* const dimension_; 2273 std::vector<Demon*> vehicle_demons_; 2274 std::vector<int64_t> path_; 2275 2276 /// Sets path_ to be the longest sequence such that 2277 /// _ path_[0] is the start of the vehicle 2278 /// _ Next(path_[i-1]) is Bound() and has value path_[i], 2279 /// followed by the end of the vehicle if the last node was not an end. 2280 void FillPartialPathOfVehicle(int vehicle); 2281 void FillPathTravels(const std::vector<int64_t>& path); 2282 2283 /// This translates pruning information to solver variables. 2284 /// If constructed with an IntervalVar*, it follows the usual semantics of 2285 /// IntervalVars. If constructed with an IntVar*, before_start and 2286 /// after_start, operations are translated to simulate an interval that starts 2287 /// at start - before_start and ends and start + after_start. If constructed 2288 /// with nothing, the TaskTranslator will do nothing. This class should have 2289 /// been an interface + subclasses, but that would force pointers in the 2290 /// user's task vector, which means dynamic allocation. With this union-like 2291 /// structure, a vector's reserved size will adjust to usage and eventually no 2292 /// more dynamic allocation will be made. 2293 class TaskTranslator { 2294 public: TaskTranslator(IntVar * start,int64_t before_start,int64_t after_start)2295 TaskTranslator(IntVar* start, int64_t before_start, int64_t after_start) 2296 : start_(start), 2297 before_start_(before_start), 2298 after_start_(after_start) {} TaskTranslator(IntervalVar * interval)2299 explicit TaskTranslator(IntervalVar* interval) : interval_(interval) {} TaskTranslator()2300 TaskTranslator() {} 2301 SetStartMin(int64_t value)2302 void SetStartMin(int64_t value) { 2303 if (start_ != nullptr) { 2304 start_->SetMin(CapAdd(before_start_, value)); 2305 } else if (interval_ != nullptr) { 2306 interval_->SetStartMin(value); 2307 } 2308 } SetStartMax(int64_t value)2309 void SetStartMax(int64_t value) { 2310 if (start_ != nullptr) { 2311 start_->SetMax(CapAdd(before_start_, value)); 2312 } else if (interval_ != nullptr) { 2313 interval_->SetStartMax(value); 2314 } 2315 } SetDurationMin(int64_t value)2316 void SetDurationMin(int64_t value) { 2317 if (interval_ != nullptr) { 2318 interval_->SetDurationMin(value); 2319 } 2320 } SetEndMin(int64_t value)2321 void SetEndMin(int64_t value) { 2322 if (start_ != nullptr) { 2323 start_->SetMin(CapSub(value, after_start_)); 2324 } else if (interval_ != nullptr) { 2325 interval_->SetEndMin(value); 2326 } 2327 } SetEndMax(int64_t value)2328 void SetEndMax(int64_t value) { 2329 if (start_ != nullptr) { 2330 start_->SetMax(CapSub(value, after_start_)); 2331 } else if (interval_ != nullptr) { 2332 interval_->SetEndMax(value); 2333 } 2334 } 2335 2336 private: 2337 IntVar* start_ = nullptr; 2338 int64_t before_start_; 2339 int64_t after_start_; 2340 IntervalVar* interval_ = nullptr; 2341 }; 2342 2343 /// Route and interval variables are normalized to the following values. 2344 std::vector<TaskTranslator> task_translators_; 2345 2346 /// This is used to restrict bounds of tasks. 2347 DisjunctivePropagator disjunctive_propagator_; 2348 DisjunctivePropagator::Tasks tasks_; 2349 2350 /// Used to help filling tasks_ at each propagation. 2351 TravelBounds travel_bounds_; 2352 }; 2353 2354 class TypeRegulationsChecker { 2355 public: 2356 explicit TypeRegulationsChecker(const RoutingModel& model); ~TypeRegulationsChecker()2357 virtual ~TypeRegulationsChecker() {} 2358 2359 bool CheckVehicle(int vehicle, 2360 const std::function<int64_t(int64_t)>& next_accessor); 2361 2362 protected: 2363 #ifndef SWIG 2364 using VisitTypePolicy = RoutingModel::VisitTypePolicy; 2365 #endif // SWIG 2366 2367 struct TypePolicyOccurrence { 2368 /// Number of TYPE_ADDED_TO_VEHICLE and 2369 /// TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED node type policies seen on the 2370 /// route. 2371 int num_type_added_to_vehicle = 0; 2372 /// Number of ADDED_TYPE_REMOVED_FROM_VEHICLE (effectively removing a type 2373 /// from the route) and TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED node type 2374 /// policies seen on the route. 2375 /// This number is always <= num_type_added_to_vehicle, as a type is only 2376 /// actually removed if it was on the route before. 2377 int num_type_removed_from_vehicle = 0; 2378 /// Position of the last node of policy TYPE_ON_VEHICLE_UP_TO_VISIT visited 2379 /// on the route. 2380 /// If positive, the type is considered on the vehicle from the start of the 2381 /// route until this position. 2382 int position_of_last_type_on_vehicle_up_to_visit = -1; 2383 }; 2384 2385 /// Returns true iff any occurrence of the given type was seen on the route, 2386 /// i.e. iff the added count for this type is positive, or if a node of this 2387 /// type and policy TYPE_ON_VEHICLE_UP_TO_VISIT is visited on the route (see 2388 /// TypePolicyOccurrence.last_type_on_vehicle_up_to_visit). 2389 bool TypeOccursOnRoute(int type) const; 2390 /// Returns true iff there's at least one instance of the given type on the 2391 /// route when scanning the route at the given position 'pos'. 2392 /// This is the case iff we have at least one added but non-removed instance 2393 /// of the type, or if 2394 /// occurrences_of_type_[type].last_type_on_vehicle_up_to_visit is greater 2395 /// than 'pos'. 2396 bool TypeCurrentlyOnRoute(int type, int pos) const; 2397 2398 void InitializeCheck(int vehicle, 2399 const std::function<int64_t(int64_t)>& next_accessor); OnInitializeCheck()2400 virtual void OnInitializeCheck() {} 2401 virtual bool HasRegulationsToCheck() const = 0; 2402 virtual bool CheckTypeRegulations(int type, VisitTypePolicy policy, 2403 int pos) = 0; FinalizeCheck()2404 virtual bool FinalizeCheck() const { return true; } 2405 2406 const RoutingModel& model_; 2407 2408 private: 2409 std::vector<TypePolicyOccurrence> occurrences_of_type_; 2410 std::vector<int64_t> current_route_visits_; 2411 }; 2412 2413 /// Checker for type incompatibilities. 2414 class TypeIncompatibilityChecker : public TypeRegulationsChecker { 2415 public: 2416 TypeIncompatibilityChecker(const RoutingModel& model, 2417 bool check_hard_incompatibilities); ~TypeIncompatibilityChecker()2418 ~TypeIncompatibilityChecker() override {} 2419 2420 private: 2421 bool HasRegulationsToCheck() const override; 2422 bool CheckTypeRegulations(int type, VisitTypePolicy policy, int pos) override; 2423 /// NOTE(user): As temporal incompatibilities are always verified with 2424 /// this checker, we only store 1 boolean indicating whether or not hard 2425 /// incompatibilities are also verified. 2426 bool check_hard_incompatibilities_; 2427 }; 2428 2429 /// Checker for type requirements. 2430 class TypeRequirementChecker : public TypeRegulationsChecker { 2431 public: TypeRequirementChecker(const RoutingModel & model)2432 explicit TypeRequirementChecker(const RoutingModel& model) 2433 : TypeRegulationsChecker(model) {} ~TypeRequirementChecker()2434 ~TypeRequirementChecker() override {} 2435 2436 private: 2437 bool HasRegulationsToCheck() const override; OnInitializeCheck()2438 void OnInitializeCheck() override { 2439 types_with_same_vehicle_requirements_on_route_.clear(); 2440 } 2441 // clang-format off 2442 /// Verifies that for each set in required_type_alternatives, at least one of 2443 /// the required types is on the route at position 'pos'. 2444 bool CheckRequiredTypesCurrentlyOnRoute( 2445 const std::vector<absl::flat_hash_set<int> >& required_type_alternatives, 2446 int pos); 2447 // clang-format on 2448 bool CheckTypeRegulations(int type, VisitTypePolicy policy, int pos) override; 2449 bool FinalizeCheck() const override; 2450 2451 absl::flat_hash_set<int> types_with_same_vehicle_requirements_on_route_; 2452 }; 2453 2454 /// The following constraint ensures that incompatibilities and requirements 2455 /// between types are respected. 2456 /// 2457 /// It verifies both "hard" and "temporal" incompatibilities. 2458 /// Two nodes with hard incompatible types cannot be served by the same vehicle 2459 /// at all, while with a temporal incompatibility they can't be on the same 2460 /// route at the same time. 2461 /// The VisitTypePolicy of a node determines how visiting it impacts the type 2462 /// count on the route. 2463 /// 2464 /// For example, for 2465 /// - three temporally incompatible types T1 T2 and T3 2466 /// - 2 pairs of nodes a1/r1 and a2/r2 of type T1 and T2 respectively, with 2467 /// - a1 and a2 of VisitTypePolicy TYPE_ADDED_TO_VEHICLE 2468 /// - r1 and r2 of policy ADDED_TYPE_REMOVED_FROM_VEHICLE 2469 /// - 3 nodes A, UV and AR of type T3, respectively with type policies 2470 /// TYPE_ADDED_TO_VEHICLE, TYPE_ON_VEHICLE_UP_TO_VISIT and 2471 /// TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED 2472 /// the configurations 2473 /// UV --> a1 --> r1 --> a2 --> r2, a1 --> r1 --> a2 --> r2 --> A and 2474 /// a1 --> r1 --> AR --> a2 --> r2 are acceptable, whereas the configurations 2475 /// a1 --> a2 --> r1 --> ..., or A --> a1 --> r1 --> ..., or 2476 /// a1 --> r1 --> UV --> ... are not feasible. 2477 /// 2478 /// It also verifies same-vehicle and temporal type requirements. 2479 /// A node of type T_d with a same-vehicle requirement for type T_r needs to be 2480 /// served by the same vehicle as a node of type T_r. 2481 /// Temporal requirements, on the other hand, can take effect either when the 2482 /// dependent type is being added to the route or when it's removed from it, 2483 /// which is determined by the dependent node's VisitTypePolicy. 2484 /// In the above example: 2485 /// - If T3 is required on the same vehicle as T1, A, AR or UV must be on the 2486 /// same vehicle as a1. 2487 /// - If T2 is required when adding T1, a2 must be visited *before* a1, and if 2488 /// r2 is also visited on the route, it must be *after* a1, i.e. T2 must be on 2489 /// the vehicle when a1 is visited: 2490 /// ... --> a2 --> ... --> a1 --> ... --> r2 --> ... 2491 /// - If T3 is required when removing T1, T3 needs to be on the vehicle when 2492 /// r1 is visited: 2493 /// ... --> A --> ... --> r1 --> ... OR ... --> r1 --> ... --> UV --> ... 2494 class TypeRegulationsConstraint : public Constraint { 2495 public: 2496 explicit TypeRegulationsConstraint(const RoutingModel& model); 2497 2498 void Post() override; 2499 void InitialPropagate() override; 2500 2501 private: 2502 void PropagateNodeRegulations(int node); 2503 void CheckRegulationsOnVehicle(int vehicle); 2504 2505 const RoutingModel& model_; 2506 TypeIncompatibilityChecker incompatibility_checker_; 2507 TypeRequirementChecker requirement_checker_; 2508 std::vector<Demon*> vehicle_demons_; 2509 }; 2510 #if !defined SWIG 2511 /// A structure meant to store soft bounds and associated violation constants. 2512 /// It is 'Simple' because it has one BoundCost per element, 2513 /// in contrast to 'Multiple'. Design notes: 2514 /// - it is meant to store model information to be shared through pointers, 2515 /// so it disallows copy and assign to avoid accidental duplication. 2516 /// - it keeps soft bounds as an array of structs to help cache, 2517 /// because code that uses such bounds typically use both bound and cost. 2518 /// - soft bounds are named pairs, prevents some mistakes. 2519 /// - using operator[] to access elements is not interesting, 2520 /// because the structure will be accessed through pointers, moreover having 2521 /// to type bound_cost reminds the user of the order if they do a copy 2522 /// assignment of the element. 2523 class SimpleBoundCosts { 2524 public: 2525 struct BoundCost { 2526 int64_t bound; 2527 int64_t cost; 2528 }; SimpleBoundCosts(int num_bounds,BoundCost default_bound_cost)2529 SimpleBoundCosts(int num_bounds, BoundCost default_bound_cost) 2530 : bound_costs_(num_bounds, default_bound_cost) {} bound_cost(int element)2531 BoundCost& bound_cost(int element) { return bound_costs_[element]; } bound_cost(int element)2532 BoundCost bound_cost(int element) const { return bound_costs_[element]; } Size()2533 int Size() { return bound_costs_.size(); } 2534 SimpleBoundCosts(const SimpleBoundCosts&) = delete; 2535 SimpleBoundCosts operator=(const SimpleBoundCosts&) = delete; 2536 2537 private: 2538 std::vector<BoundCost> bound_costs_; 2539 }; 2540 #endif // !defined SWIG 2541 2542 /// Dimensions represent quantities accumulated at nodes along the routes. They 2543 /// represent quantities such as weights or volumes carried along the route, or 2544 /// distance or times. 2545 /// 2546 /// Quantities at a node are represented by "cumul" variables and the increase 2547 /// or decrease of quantities between nodes are represented by "transit" 2548 /// variables. These variables are linked as follows: 2549 /// 2550 /// if j == next(i), 2551 /// cumuls(j) = cumuls(i) + transits(i) + slacks(i) + 2552 /// state_dependent_transits(i) 2553 /// 2554 /// where slack is a positive slack variable (can represent waiting times for 2555 /// a time dimension), and state_dependent_transits is a non-purely functional 2556 /// version of transits_. Favour transits over state_dependent_transits when 2557 /// possible, because purely functional callbacks allow more optimisations and 2558 /// make the model faster and easier to solve. 2559 // TODO(user): Break constraints need to know the service time of nodes 2560 /// for a given vehicle, it is passed as an external vector, it would be better 2561 /// to have this information here. 2562 class RoutingDimension { 2563 public: 2564 ~RoutingDimension(); 2565 /// Returns the model on which the dimension was created. model()2566 RoutingModel* model() const { return model_; } 2567 /// Returns the transition value for a given pair of nodes (as var index); 2568 /// this value is the one taken by the corresponding transit variable when 2569 /// the 'next' variable for 'from_index' is bound to 'to_index'. 2570 int64_t GetTransitValue(int64_t from_index, int64_t to_index, 2571 int64_t vehicle) const; 2572 /// Same as above but taking a vehicle class of the dimension instead of a 2573 /// vehicle (the class of a vehicle can be obtained with vehicle_to_class()). GetTransitValueFromClass(int64_t from_index,int64_t to_index,int64_t vehicle_class)2574 int64_t GetTransitValueFromClass(int64_t from_index, int64_t to_index, 2575 int64_t vehicle_class) const { 2576 return model_->TransitCallback(class_evaluators_[vehicle_class])(from_index, 2577 to_index); 2578 } 2579 /// Get the cumul, transit and slack variables for the given node (given as 2580 /// int64_t var index). CumulVar(int64_t index)2581 IntVar* CumulVar(int64_t index) const { return cumuls_[index]; } TransitVar(int64_t index)2582 IntVar* TransitVar(int64_t index) const { return transits_[index]; } FixedTransitVar(int64_t index)2583 IntVar* FixedTransitVar(int64_t index) const { 2584 return fixed_transits_[index]; 2585 } SlackVar(int64_t index)2586 IntVar* SlackVar(int64_t index) const { return slacks_[index]; } 2587 2588 #if !defined(SWIGPYTHON) 2589 /// Like CumulVar(), TransitVar(), SlackVar() but return the whole variable 2590 /// vectors instead (indexed by int64_t var index). cumuls()2591 const std::vector<IntVar*>& cumuls() const { return cumuls_; } fixed_transits()2592 const std::vector<IntVar*>& fixed_transits() const { return fixed_transits_; } transits()2593 const std::vector<IntVar*>& transits() const { return transits_; } slacks()2594 const std::vector<IntVar*>& slacks() const { return slacks_; } 2595 #if !defined(SWIGCSHARP) && !defined(SWIGJAVA) 2596 /// Returns forbidden intervals for each node. forbidden_intervals()2597 const std::vector<SortedDisjointIntervalList>& forbidden_intervals() const { 2598 return forbidden_intervals_; 2599 } 2600 /// Returns allowed intervals for a given node in a given interval. 2601 SortedDisjointIntervalList GetAllowedIntervalsInRange( 2602 int64_t index, int64_t min_value, int64_t max_value) const; 2603 /// Returns the smallest value outside the forbidden intervals of node 'index' 2604 /// that is greater than or equal to a given 'min_value'. GetFirstPossibleGreaterOrEqualValueForNode(int64_t index,int64_t min_value)2605 int64_t GetFirstPossibleGreaterOrEqualValueForNode(int64_t index, 2606 int64_t min_value) const { 2607 DCHECK_LT(index, forbidden_intervals_.size()); 2608 const SortedDisjointIntervalList& forbidden_intervals = 2609 forbidden_intervals_[index]; 2610 const auto first_forbidden_interval_it = 2611 forbidden_intervals.FirstIntervalGreaterOrEqual(min_value); 2612 if (first_forbidden_interval_it != forbidden_intervals.end() && 2613 min_value >= first_forbidden_interval_it->start) { 2614 /// min_value is in a forbidden interval. 2615 return CapAdd(first_forbidden_interval_it->end, 1); 2616 } 2617 /// min_value is not forbidden. 2618 return min_value; 2619 } 2620 /// Returns the largest value outside the forbidden intervals of node 'index' 2621 /// that is less than or equal to a given 'max_value'. 2622 /// NOTE: If this method is called with a max_value lower than the node's 2623 /// cumul min, it will return -1. GetLastPossibleLessOrEqualValueForNode(int64_t index,int64_t max_value)2624 int64_t GetLastPossibleLessOrEqualValueForNode(int64_t index, 2625 int64_t max_value) const { 2626 DCHECK_LT(index, forbidden_intervals_.size()); 2627 const SortedDisjointIntervalList& forbidden_intervals = 2628 forbidden_intervals_[index]; 2629 const auto last_forbidden_interval_it = 2630 forbidden_intervals.LastIntervalLessOrEqual(max_value); 2631 if (last_forbidden_interval_it != forbidden_intervals.end() && 2632 max_value <= last_forbidden_interval_it->end) { 2633 /// max_value is in a forbidden interval. 2634 return CapSub(last_forbidden_interval_it->start, 1); 2635 } 2636 /// max_value is not forbidden. 2637 return max_value; 2638 } 2639 /// Returns the capacities for all vehicles. vehicle_capacities()2640 const std::vector<int64_t>& vehicle_capacities() const { 2641 return vehicle_capacities_; 2642 } 2643 /// Returns the callback evaluating the transit value between two node indices 2644 /// for a given vehicle. transit_evaluator(int vehicle)2645 const RoutingModel::TransitCallback2& transit_evaluator(int vehicle) const { 2646 return model_->TransitCallback( 2647 class_evaluators_[vehicle_to_class_[vehicle]]); 2648 } 2649 2650 /// Returns the callback evaluating the transit value between two node indices 2651 /// for a given vehicle class. class_transit_evaluator(RoutingVehicleClassIndex vehicle_class)2652 const RoutingModel::TransitCallback2& class_transit_evaluator( 2653 RoutingVehicleClassIndex vehicle_class) const { 2654 const int vehicle = model_->GetVehicleOfClass(vehicle_class); 2655 DCHECK_NE(vehicle, -1); 2656 return transit_evaluator(vehicle); 2657 } 2658 2659 /// Returns the unary callback evaluating the transit value between two node 2660 /// indices for a given vehicle. If the corresponding callback is not unary, 2661 /// returns a null callback. GetUnaryTransitEvaluator(int vehicle)2662 const RoutingModel::TransitCallback1& GetUnaryTransitEvaluator( 2663 int vehicle) const { 2664 return model_->UnaryTransitCallbackOrNull( 2665 class_evaluators_[vehicle_to_class_[vehicle]]); 2666 } 2667 /// Returns true iff the transit evaluator of 'vehicle' is positive for all 2668 /// arcs. AreVehicleTransitsPositive(int vehicle)2669 bool AreVehicleTransitsPositive(int vehicle) const { 2670 return model()->is_transit_evaluator_positive_ 2671 [class_evaluators_[vehicle_to_class_[vehicle]]]; 2672 } vehicle_to_class(int vehicle)2673 int vehicle_to_class(int vehicle) const { return vehicle_to_class_[vehicle]; } 2674 #endif /// !defined(SWIGCSHARP) && !defined(SWIGJAVA) 2675 #endif /// !defined(SWIGPYTHON) 2676 /// Sets an upper bound on the dimension span on a given vehicle. This is the 2677 /// preferred way to limit the "length" of the route of a vehicle according to 2678 /// a dimension. 2679 void SetSpanUpperBoundForVehicle(int64_t upper_bound, int vehicle); 2680 /// Sets a cost proportional to the dimension span on a given vehicle, 2681 /// or on all vehicles at once. "coefficient" must be nonnegative. 2682 /// This is handy to model costs proportional to idle time when the dimension 2683 /// represents time. 2684 /// The cost for a vehicle is 2685 /// span_cost = coefficient * (dimension end value - dimension start value). 2686 void SetSpanCostCoefficientForVehicle(int64_t coefficient, int vehicle); 2687 void SetSpanCostCoefficientForAllVehicles(int64_t coefficient); 2688 /// Sets a cost proportional to the *global* dimension span, that is the 2689 /// difference between the largest value of route end cumul variables and 2690 /// the smallest value of route start cumul variables. 2691 /// In other words: 2692 /// global_span_cost = 2693 /// coefficient * (Max(dimension end value) - Min(dimension start value)). 2694 void SetGlobalSpanCostCoefficient(int64_t coefficient); 2695 2696 #ifndef SWIG 2697 /// Sets a piecewise linear cost on the cumul variable of a given variable 2698 /// index. If f is a piecewise linear function, the resulting cost at 'index' 2699 /// will be f(CumulVar(index)). As of 3/2017, only non-decreasing positive 2700 /// cost functions are supported. 2701 void SetCumulVarPiecewiseLinearCost(int64_t index, 2702 const PiecewiseLinearFunction& cost); 2703 /// Returns true if a piecewise linear cost has been set for a given variable 2704 /// index. 2705 bool HasCumulVarPiecewiseLinearCost(int64_t index) const; 2706 /// Returns the piecewise linear cost of a cumul variable for a given variable 2707 /// index. The returned pointer has the same validity as this class. 2708 const PiecewiseLinearFunction* GetCumulVarPiecewiseLinearCost( 2709 int64_t index) const; 2710 #endif 2711 2712 /// Sets a soft upper bound to the cumul variable of a given variable index. 2713 /// If the value of the cumul variable is greater than the bound, a cost 2714 /// proportional to the difference between this value and the bound is added 2715 /// to the cost function of the model: 2716 /// cumulVar <= upper_bound -> cost = 0 2717 /// cumulVar > upper_bound -> cost = coefficient * (cumulVar - upper_bound) 2718 /// This is also handy to model tardiness costs when the dimension represents 2719 /// time. 2720 void SetCumulVarSoftUpperBound(int64_t index, int64_t upper_bound, 2721 int64_t coefficient); 2722 /// Returns true if a soft upper bound has been set for a given variable 2723 /// index. 2724 bool HasCumulVarSoftUpperBound(int64_t index) const; 2725 /// Returns the soft upper bound of a cumul variable for a given variable 2726 /// index. The "hard" upper bound of the variable is returned if no soft upper 2727 /// bound has been set. 2728 int64_t GetCumulVarSoftUpperBound(int64_t index) const; 2729 /// Returns the cost coefficient of the soft upper bound of a cumul variable 2730 /// for a given variable index. If no soft upper bound has been set, 0 is 2731 /// returned. 2732 int64_t GetCumulVarSoftUpperBoundCoefficient(int64_t index) const; 2733 2734 /// Sets a soft lower bound to the cumul variable of a given variable index. 2735 /// If the value of the cumul variable is less than the bound, a cost 2736 /// proportional to the difference between this value and the bound is added 2737 /// to the cost function of the model: 2738 /// cumulVar > lower_bound -> cost = 0 2739 /// cumulVar <= lower_bound -> cost = coefficient * (lower_bound - 2740 /// cumulVar). 2741 /// This is also handy to model earliness costs when the dimension represents 2742 /// time. 2743 void SetCumulVarSoftLowerBound(int64_t index, int64_t lower_bound, 2744 int64_t coefficient); 2745 /// Returns true if a soft lower bound has been set for a given variable 2746 /// index. 2747 bool HasCumulVarSoftLowerBound(int64_t index) const; 2748 /// Returns the soft lower bound of a cumul variable for a given variable 2749 /// index. The "hard" lower bound of the variable is returned if no soft lower 2750 /// bound has been set. 2751 int64_t GetCumulVarSoftLowerBound(int64_t index) const; 2752 /// Returns the cost coefficient of the soft lower bound of a cumul variable 2753 /// for a given variable index. If no soft lower bound has been set, 0 is 2754 /// returned. 2755 int64_t GetCumulVarSoftLowerBoundCoefficient(int64_t index) const; 2756 /// Sets the breaks for a given vehicle. Breaks are represented by 2757 /// IntervalVars. They may interrupt transits between nodes and increase 2758 /// the value of corresponding slack variables. 2759 /// A break may take place before the start of a vehicle, after the end of 2760 /// a vehicle, or during a travel i -> j. 2761 /// 2762 /// In that case, the interval [break.Start(), break.End()) must be a subset 2763 /// of [CumulVar(i) + pre_travel(i, j), CumulVar(j) - post_travel(i, j)). In 2764 /// other words, a break may not overlap any node n's visit, given by 2765 /// [CumulVar(n) - post_travel(_, n), CumulVar(n) + pre_travel(n, _)). 2766 /// This formula considers post_travel(_, start) and pre_travel(end, _) to be 2767 /// 0; pre_travel will never be called on any (_, start) and post_travel will 2768 /// never we called on any (end, _). If pre_travel_evaluator or 2769 /// post_travel_evaluator is -1, it will be taken as a function that always 2770 /// returns 0. 2771 // TODO(user): Remove if !defined when routing.i is repaired. 2772 #if !defined(SWIGPYTHON) 2773 void SetBreakIntervalsOfVehicle(std::vector<IntervalVar*> breaks, int vehicle, 2774 int pre_travel_evaluator, 2775 int post_travel_evaluator); 2776 #endif // !defined(SWIGPYTHON) 2777 2778 /// Deprecated, sets pre_travel(i, j) = node_visit_transit[i]. 2779 void SetBreakIntervalsOfVehicle(std::vector<IntervalVar*> breaks, int vehicle, 2780 std::vector<int64_t> node_visit_transits); 2781 2782 /// With breaks supposed to be consecutive, this forces the distance between 2783 /// breaks of size at least minimum_break_duration to be at most distance. 2784 /// This supposes that the time until route start and after route end are 2785 /// infinite breaks. 2786 void SetBreakDistanceDurationOfVehicle(int64_t distance, int64_t duration, 2787 int vehicle); 2788 /// Sets up vehicle_break_intervals_, vehicle_break_distance_duration_, 2789 /// pre_travel_evaluators and post_travel_evaluators. 2790 void InitializeBreaks(); 2791 /// Returns true if any break interval or break distance was defined. 2792 bool HasBreakConstraints() const; 2793 #if !defined(SWIGPYTHON) 2794 /// Deprecated, sets pre_travel(i, j) = node_visit_transit[i] 2795 /// and post_travel(i, j) = delays(i, j). 2796 void SetBreakIntervalsOfVehicle( 2797 std::vector<IntervalVar*> breaks, int vehicle, 2798 std::vector<int64_t> node_visit_transits, 2799 std::function<int64_t(int64_t, int64_t)> delays); 2800 2801 /// Returns the break intervals set by SetBreakIntervalsOfVehicle(). 2802 const std::vector<IntervalVar*>& GetBreakIntervalsOfVehicle( 2803 int vehicle) const; 2804 /// Returns the pairs (distance, duration) specified by break distance 2805 /// constraints. 2806 // clang-format off 2807 const std::vector<std::pair<int64_t, int64_t> >& 2808 GetBreakDistanceDurationOfVehicle(int vehicle) const; 2809 // clang-format on 2810 #endif /// !defined(SWIGPYTHON) 2811 int GetPreTravelEvaluatorOfVehicle(int vehicle) const; 2812 int GetPostTravelEvaluatorOfVehicle(int vehicle) const; 2813 2814 /// Returns the parent in the dependency tree if any or nullptr otherwise. base_dimension()2815 const RoutingDimension* base_dimension() const { return base_dimension_; } 2816 /// It makes sense to use the function only for self-dependent dimension. 2817 /// For such dimensions the value of the slack of a node determines the 2818 /// transition cost of the next transit. Provided that 2819 /// 1. cumul[node] is fixed, 2820 /// 2. next[node] and next[next[node]] (if exists) are fixed, 2821 /// the value of slack[node] for which cumul[next[node]] + transit[next[node]] 2822 /// is minimized can be found in O(1) using this function. 2823 int64_t ShortestTransitionSlack(int64_t node) const; 2824 2825 /// Returns the name of the dimension. name()2826 const std::string& name() const { return name_; } 2827 2828 /// Accessors. 2829 #ifndef SWIG GetPathPrecedenceGraph()2830 const ReverseArcListGraph<int, int>& GetPathPrecedenceGraph() const { 2831 return path_precedence_graph_; 2832 } 2833 #endif // SWIG 2834 2835 /// Limits, in terms of maximum difference between the cumul variables, 2836 /// between the pickup and delivery alternatives belonging to a single 2837 /// pickup/delivery pair in the RoutingModel. The indices passed to the 2838 /// function respectively correspond to the position of the pickup in the 2839 /// vector of pickup alternatives, and delivery position in the delivery 2840 /// alternatives for this pickup/delivery pair. These limits should only be 2841 /// set when each node index appears in at most one pickup/delivery pair, i.e. 2842 /// each pickup (delivery) index is in a single pickup/delivery pair.first 2843 /// (pair.second). 2844 typedef std::function<int64_t(int, int)> PickupToDeliveryLimitFunction; 2845 2846 void SetPickupToDeliveryLimitFunctionForPair( 2847 PickupToDeliveryLimitFunction limit_function, int pair_index); 2848 2849 bool HasPickupToDeliveryLimits() const; 2850 #ifndef SWIG 2851 int64_t GetPickupToDeliveryLimitForPair(int pair_index, int pickup, 2852 int delivery) const; 2853 2854 struct NodePrecedence { 2855 int64_t first_node; 2856 int64_t second_node; 2857 int64_t offset; 2858 }; 2859 AddNodePrecedence(NodePrecedence precedence)2860 void AddNodePrecedence(NodePrecedence precedence) { 2861 node_precedences_.push_back(precedence); 2862 } GetNodePrecedences()2863 const std::vector<NodePrecedence>& GetNodePrecedences() const { 2864 return node_precedences_; 2865 } 2866 #endif // SWIG 2867 AddNodePrecedence(int64_t first_node,int64_t second_node,int64_t offset)2868 void AddNodePrecedence(int64_t first_node, int64_t second_node, 2869 int64_t offset) { 2870 AddNodePrecedence({first_node, second_node, offset}); 2871 } 2872 GetSpanUpperBoundForVehicle(int vehicle)2873 int64_t GetSpanUpperBoundForVehicle(int vehicle) const { 2874 return vehicle_span_upper_bounds_[vehicle]; 2875 } 2876 #ifndef SWIG vehicle_span_upper_bounds()2877 const std::vector<int64_t>& vehicle_span_upper_bounds() const { 2878 return vehicle_span_upper_bounds_; 2879 } 2880 #endif // SWIG GetSpanCostCoefficientForVehicle(int vehicle)2881 int64_t GetSpanCostCoefficientForVehicle(int vehicle) const { 2882 return vehicle_span_cost_coefficients_[vehicle]; 2883 } 2884 #ifndef SWIG GetSpanCostCoefficientForVehicleClass(RoutingVehicleClassIndex vehicle_class)2885 int64_t GetSpanCostCoefficientForVehicleClass( 2886 RoutingVehicleClassIndex vehicle_class) const { 2887 const int vehicle = model_->GetVehicleOfClass(vehicle_class); 2888 DCHECK_NE(vehicle, -1); 2889 return GetSpanCostCoefficientForVehicle(vehicle); 2890 } 2891 #endif // SWIG 2892 #ifndef SWIG vehicle_span_cost_coefficients()2893 const std::vector<int64_t>& vehicle_span_cost_coefficients() const { 2894 return vehicle_span_cost_coefficients_; 2895 } 2896 #endif // SWIG global_span_cost_coefficient()2897 int64_t global_span_cost_coefficient() const { 2898 return global_span_cost_coefficient_; 2899 } 2900 GetGlobalOptimizerOffset()2901 int64_t GetGlobalOptimizerOffset() const { 2902 DCHECK_GE(global_optimizer_offset_, 0); 2903 return global_optimizer_offset_; 2904 } GetLocalOptimizerOffsetForVehicle(int vehicle)2905 int64_t GetLocalOptimizerOffsetForVehicle(int vehicle) const { 2906 if (vehicle >= local_optimizer_offset_for_vehicle_.size()) { 2907 return 0; 2908 } 2909 DCHECK_GE(local_optimizer_offset_for_vehicle_[vehicle], 0); 2910 return local_optimizer_offset_for_vehicle_[vehicle]; 2911 } 2912 #if !defined SWIG 2913 /// If the span of vehicle on this dimension is larger than bound, 2914 /// the cost will be increased by cost * (span - bound). SetSoftSpanUpperBoundForVehicle(SimpleBoundCosts::BoundCost bound_cost,int vehicle)2915 void SetSoftSpanUpperBoundForVehicle(SimpleBoundCosts::BoundCost bound_cost, 2916 int vehicle) { 2917 if (!HasSoftSpanUpperBounds()) { 2918 vehicle_soft_span_upper_bound_ = absl::make_unique<SimpleBoundCosts>( 2919 model_->vehicles(), SimpleBoundCosts::BoundCost{kint64max, 0}); 2920 } 2921 vehicle_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost; 2922 } HasSoftSpanUpperBounds()2923 bool HasSoftSpanUpperBounds() const { 2924 return vehicle_soft_span_upper_bound_ != nullptr; 2925 } GetSoftSpanUpperBoundForVehicle(int vehicle)2926 SimpleBoundCosts::BoundCost GetSoftSpanUpperBoundForVehicle( 2927 int vehicle) const { 2928 DCHECK(HasSoftSpanUpperBounds()); 2929 return vehicle_soft_span_upper_bound_->bound_cost(vehicle); 2930 } 2931 /// If the span of vehicle on this dimension is larger than bound, 2932 /// the cost will be increased by cost * (span - bound)^2. SetQuadraticCostSoftSpanUpperBoundForVehicle(SimpleBoundCosts::BoundCost bound_cost,int vehicle)2933 void SetQuadraticCostSoftSpanUpperBoundForVehicle( 2934 SimpleBoundCosts::BoundCost bound_cost, int vehicle) { 2935 if (!HasQuadraticCostSoftSpanUpperBounds()) { 2936 vehicle_quadratic_cost_soft_span_upper_bound_ = 2937 absl::make_unique<SimpleBoundCosts>( 2938 model_->vehicles(), SimpleBoundCosts::BoundCost{kint64max, 0}); 2939 } 2940 vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle) = 2941 bound_cost; 2942 } HasQuadraticCostSoftSpanUpperBounds()2943 bool HasQuadraticCostSoftSpanUpperBounds() const { 2944 return vehicle_quadratic_cost_soft_span_upper_bound_ != nullptr; 2945 } GetQuadraticCostSoftSpanUpperBoundForVehicle(int vehicle)2946 SimpleBoundCosts::BoundCost GetQuadraticCostSoftSpanUpperBoundForVehicle( 2947 int vehicle) const { 2948 DCHECK(HasQuadraticCostSoftSpanUpperBounds()); 2949 return vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle); 2950 } 2951 #endif /// !defined SWIG 2952 2953 private: 2954 struct SoftBound { 2955 IntVar* var; 2956 int64_t bound; 2957 int64_t coefficient; 2958 }; 2959 2960 struct PiecewiseLinearCost { PiecewiseLinearCostPiecewiseLinearCost2961 PiecewiseLinearCost() : var(nullptr), cost(nullptr) {} 2962 IntVar* var; 2963 std::unique_ptr<PiecewiseLinearFunction> cost; 2964 }; 2965 2966 class SelfBased {}; 2967 RoutingDimension(RoutingModel* model, std::vector<int64_t> vehicle_capacities, 2968 const std::string& name, 2969 const RoutingDimension* base_dimension); 2970 RoutingDimension(RoutingModel* model, std::vector<int64_t> vehicle_capacities, 2971 const std::string& name, SelfBased); 2972 void Initialize(const std::vector<int>& transit_evaluators, 2973 const std::vector<int>& state_dependent_transit_evaluators, 2974 int64_t slack_max); 2975 void InitializeCumuls(); 2976 void InitializeTransits( 2977 const std::vector<int>& transit_evaluators, 2978 const std::vector<int>& state_dependent_transit_evaluators, 2979 int64_t slack_max); 2980 void InitializeTransitVariables(int64_t slack_max); 2981 /// Sets up the cost variables related to cumul soft upper bounds. 2982 void SetupCumulVarSoftUpperBoundCosts( 2983 std::vector<IntVar*>* cost_elements) const; 2984 /// Sets up the cost variables related to cumul soft lower bounds. 2985 void SetupCumulVarSoftLowerBoundCosts( 2986 std::vector<IntVar*>* cost_elements) const; 2987 void SetupCumulVarPiecewiseLinearCosts( 2988 std::vector<IntVar*>* cost_elements) const; 2989 /// Sets up the cost variables related to the global span and per-vehicle span 2990 /// costs (only for the "slack" part of the latter). 2991 void SetupGlobalSpanCost(std::vector<IntVar*>* cost_elements) const; 2992 void SetupSlackAndDependentTransitCosts() const; 2993 /// Finalize the model of the dimension. 2994 void CloseModel(bool use_light_propagation); 2995 SetOffsetForGlobalOptimizer(int64_t offset)2996 void SetOffsetForGlobalOptimizer(int64_t offset) { 2997 global_optimizer_offset_ = std::max(Zero(), offset); 2998 } 2999 /// Moves elements of "offsets" into vehicle_offsets_for_local_optimizer_. SetVehicleOffsetsForLocalOptimizer(std::vector<int64_t> offsets)3000 void SetVehicleOffsetsForLocalOptimizer(std::vector<int64_t> offsets) { 3001 /// Make sure all offsets are positive. 3002 std::transform(offsets.begin(), offsets.end(), offsets.begin(), 3003 [](int64_t offset) { return std::max(Zero(), offset); }); 3004 local_optimizer_offset_for_vehicle_ = std::move(offsets); 3005 } 3006 3007 std::vector<IntVar*> cumuls_; 3008 std::vector<SortedDisjointIntervalList> forbidden_intervals_; 3009 std::vector<IntVar*> capacity_vars_; 3010 const std::vector<int64_t> vehicle_capacities_; 3011 std::vector<IntVar*> transits_; 3012 std::vector<IntVar*> fixed_transits_; 3013 /// Values in class_evaluators_ correspond to the evaluators in 3014 /// RoutingModel::transit_evaluators_ for each vehicle class. 3015 std::vector<int> class_evaluators_; 3016 std::vector<int64_t> vehicle_to_class_; 3017 #ifndef SWIG 3018 ReverseArcListGraph<int, int> path_precedence_graph_; 3019 #endif 3020 // For every {first_node, second_node, offset} element in node_precedences_, 3021 // if both first_node and second_node are performed, then 3022 // cumuls_[second_node] must be greater than (or equal to) 3023 // cumuls_[first_node] + offset. 3024 std::vector<NodePrecedence> node_precedences_; 3025 3026 // The transits of a dimension may depend on its cumuls or the cumuls of 3027 // another dimension. There can be no cycles, except for self loops, a 3028 // typical example for this is a time dimension. 3029 const RoutingDimension* const base_dimension_; 3030 3031 // Values in state_dependent_class_evaluators_ correspond to the evaluators 3032 // in RoutingModel::state_dependent_transit_evaluators_ for each vehicle 3033 // class. 3034 std::vector<int> state_dependent_class_evaluators_; 3035 std::vector<int64_t> state_dependent_vehicle_to_class_; 3036 3037 // For each pickup/delivery pair_index for which limits have been set, 3038 // pickup_to_delivery_limits_per_pair_index_[pair_index] contains the 3039 // PickupToDeliveryLimitFunction for the pickup and deliveries in this pair. 3040 std::vector<PickupToDeliveryLimitFunction> 3041 pickup_to_delivery_limits_per_pair_index_; 3042 3043 // Used if some vehicle has breaks in this dimension, typically time. 3044 bool break_constraints_are_initialized_ = false; 3045 // clang-format off 3046 std::vector<std::vector<IntervalVar*> > vehicle_break_intervals_; 3047 std::vector<std::vector<std::pair<int64_t, int64_t> > > 3048 vehicle_break_distance_duration_; 3049 // clang-format on 3050 // For each vehicle, stores the part of travel that is made directly 3051 // after (before) the departure (arrival) node of the travel. 3052 // These parts of the travel are non-interruptible, in particular by a break. 3053 std::vector<int> vehicle_pre_travel_evaluators_; 3054 std::vector<int> vehicle_post_travel_evaluators_; 3055 3056 std::vector<IntVar*> slacks_; 3057 std::vector<IntVar*> dependent_transits_; 3058 std::vector<int64_t> vehicle_span_upper_bounds_; 3059 int64_t global_span_cost_coefficient_; 3060 std::vector<int64_t> vehicle_span_cost_coefficients_; 3061 std::vector<SoftBound> cumul_var_soft_upper_bound_; 3062 std::vector<SoftBound> cumul_var_soft_lower_bound_; 3063 std::vector<PiecewiseLinearCost> cumul_var_piecewise_linear_cost_; 3064 RoutingModel* const model_; 3065 const std::string name_; 3066 int64_t global_optimizer_offset_; 3067 std::vector<int64_t> local_optimizer_offset_for_vehicle_; 3068 /// nullptr if not defined. 3069 std::unique_ptr<SimpleBoundCosts> vehicle_soft_span_upper_bound_; 3070 std::unique_ptr<SimpleBoundCosts> 3071 vehicle_quadratic_cost_soft_span_upper_bound_; 3072 friend class RoutingModel; 3073 friend class RoutingModelInspector; 3074 friend void AppendDimensionCumulFilters( 3075 const std::vector<RoutingDimension*>& dimensions, 3076 const RoutingSearchParameters& parameters, bool filter_objective_cost, 3077 std::vector<LocalSearchFilterManager::FilterEvent>* filters); 3078 3079 DISALLOW_COPY_AND_ASSIGN(RoutingDimension); 3080 }; 3081 3082 /// A decision builder which tries to assign values to variables as close as 3083 /// possible to target values first. 3084 DecisionBuilder* MakeSetValuesFromTargets(Solver* solver, 3085 std::vector<IntVar*> variables, 3086 std::vector<int64_t> targets); 3087 3088 /// Attempts to solve the model using the cp-sat solver. As of 5/2019, will 3089 /// solve the TSP corresponding to the model if it has a single vehicle. 3090 /// Therefore the resulting solution might not actually be feasible. Will return 3091 /// false if a solution could not be found. 3092 bool SolveModelWithSat(const RoutingModel& model, 3093 const RoutingSearchParameters& search_parameters, 3094 const Assignment* initial_solution, 3095 Assignment* solution); 3096 3097 #if !defined(SWIG) 3098 IntVarLocalSearchFilter* MakeVehicleBreaksFilter( 3099 const RoutingModel& routing_model, const RoutingDimension& dimension); 3100 3101 // A decision builder that monitors solutions, and tries to fix dimension 3102 // variables whose route did not change in the candidate solution. 3103 // Dimension variables are Cumul, Slack and break variables of all dimensions. 3104 // The user must make sure that those variables will be always be fixed at 3105 // solution, typically by composing another DecisionBuilder after this one. 3106 // If this DecisionBuilder returns a non-nullptr value at some node of the 3107 // search tree, it will always return nullptr in the subtree of that node. 3108 // Moreover, the decision will be a simultaneous assignment of the dimension 3109 // variables of unchanged routes on the left branch, and an empty decision on 3110 // the right branch. 3111 DecisionBuilder* MakeRestoreDimensionValuesForUnchangedRoutes( 3112 RoutingModel* model); 3113 #endif 3114 3115 } // namespace operations_research 3116 #endif // OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_H_ 3117