21#include "absl/strings/str_cat.h"
22#include "absl/strings/str_format.h"
23#include "absl/time/time.h"
24#include "google/protobuf/descriptor.h"
25#include "google/protobuf/duration.pb.h"
26#include "google/protobuf/message.h"
31#include "ortools/constraint_solver/routing_enums.pb.h"
32#include "ortools/constraint_solver/routing_ils.pb.h"
33#include "ortools/constraint_solver/routing_parameters.pb.h"
34#include "ortools/constraint_solver/solver_parameters.pb.h"
35#include "ortools/sat/sat_parameters.pb.h"
36#include "ortools/util/optional_boolean.pb.h"
43 ConstraintSolverParameters*
const solver_parameters =
46 solver_parameters->set_compress_trail(
47 ConstraintSolverParameters::COMPRESS_WITH_ZLIB);
48 solver_parameters->set_skip_locally_optimal_paths(
true);
49 parameters.set_reduce_vehicle_cost_model(
true);
54IteratedLocalSearchParameters CreateDefaultIteratedLocalSearchParameters() {
55 IteratedLocalSearchParameters ils;
56 ils.set_perturbation_strategy(PerturbationStrategy::RUIN_AND_RECREATE);
57 RuinRecreateParameters* rr = ils.mutable_ruin_recreate_parameters();
58 rr->set_ruin_strategy(RuinStrategy::SPATIALLY_CLOSE_ROUTES_REMOVAL);
59 rr->set_recreate_strategy(FirstSolutionStrategy::LOCAL_CHEAPEST_INSERTION);
60 rr->set_num_ruined_routes(2);
61 ils.set_improve_perturbed_solution(
true);
62 ils.set_acceptance_strategy(AcceptanceStrategy::GREEDY_DESCENT);
66RoutingSearchParameters CreateDefaultRoutingSearchParameters() {
67 RoutingSearchParameters p;
68 p.set_first_solution_strategy(FirstSolutionStrategy::AUTOMATIC);
69 p.set_use_unfiltered_first_solution_strategy(
false);
70 p.set_savings_neighbors_ratio(1);
71 p.set_savings_max_memory_usage_bytes(6e9);
72 p.set_savings_add_reverse_arcs(
false);
73 p.set_savings_arc_coefficient(1);
74 p.set_savings_parallel_routes(
false);
75 p.set_cheapest_insertion_farthest_seeds_ratio(0);
76 p.set_cheapest_insertion_first_solution_neighbors_ratio(1);
77 p.set_cheapest_insertion_first_solution_min_neighbors(1);
78 p.set_cheapest_insertion_ls_operator_neighbors_ratio(1);
79 p.set_cheapest_insertion_ls_operator_min_neighbors(1);
80 p.set_cheapest_insertion_first_solution_use_neighbors_ratio_for_initialization(
82 p.set_cheapest_insertion_add_unperformed_entries(
false);
83 p.set_local_cheapest_insertion_pickup_delivery_strategy(
84 RoutingSearchParameters::BEST_PICKUP_THEN_BEST_DELIVERY);
85 p.set_local_cheapest_cost_insertion_pickup_delivery_strategy(
86 RoutingSearchParameters::BEST_PICKUP_DELIVERY_PAIR);
87 RoutingSearchParameters::LocalSearchNeighborhoodOperators* o =
88 p.mutable_local_search_operators();
89 o->set_use_relocate(BOOL_TRUE);
90 o->set_use_relocate_pair(BOOL_TRUE);
91 o->set_use_light_relocate_pair(BOOL_TRUE);
92 o->set_use_relocate_subtrip(BOOL_TRUE);
93 o->set_use_relocate_neighbors(BOOL_FALSE);
94 o->set_use_exchange(BOOL_TRUE);
95 o->set_use_exchange_pair(BOOL_TRUE);
96 o->set_use_exchange_subtrip(BOOL_TRUE);
97 o->set_use_cross(BOOL_TRUE);
98 o->set_use_cross_exchange(BOOL_FALSE);
99 o->set_use_relocate_expensive_chain(BOOL_TRUE);
100 o->set_use_two_opt(BOOL_TRUE);
101 o->set_use_or_opt(BOOL_TRUE);
102 o->set_use_lin_kernighan(BOOL_TRUE);
103 o->set_use_tsp_opt(BOOL_FALSE);
104 o->set_use_make_active(BOOL_TRUE);
105 o->set_use_relocate_and_make_active(BOOL_FALSE);
106 o->set_use_make_inactive(BOOL_TRUE);
107 o->set_use_make_chain_inactive(BOOL_TRUE);
108 o->set_use_swap_active(BOOL_TRUE);
109 o->set_use_extended_swap_active(BOOL_FALSE);
110 o->set_use_shortest_path_swap_active(BOOL_TRUE);
111 o->set_use_node_pair_swap_active(BOOL_FALSE);
112 o->set_use_path_lns(BOOL_FALSE);
113 o->set_use_full_path_lns(BOOL_FALSE);
114 o->set_use_tsp_lns(BOOL_FALSE);
115 o->set_use_inactive_lns(BOOL_FALSE);
116 o->set_use_global_cheapest_insertion_path_lns(BOOL_TRUE);
117 o->set_use_local_cheapest_insertion_path_lns(BOOL_TRUE);
118 o->set_use_relocate_path_global_cheapest_insertion_insert_unperformed(
120 o->set_use_global_cheapest_insertion_expensive_chain_lns(BOOL_FALSE);
121 o->set_use_local_cheapest_insertion_expensive_chain_lns(BOOL_FALSE);
122 o->set_use_global_cheapest_insertion_close_nodes_lns(BOOL_FALSE);
123 o->set_use_local_cheapest_insertion_close_nodes_lns(BOOL_FALSE);
124 p.set_ls_operator_neighbors_ratio(1);
125 p.set_ls_operator_min_neighbors(1);
126 p.set_use_multi_armed_bandit_concatenate_operators(
false);
127 p.set_multi_armed_bandit_compound_operator_memory_coefficient(0.04);
128 p.set_multi_armed_bandit_compound_operator_exploration_coefficient(1e12);
129 p.set_relocate_expensive_chain_num_arcs_to_consider(4);
130 p.set_heuristic_expensive_chain_lns_num_arcs_to_consider(4);
131 p.set_heuristic_close_nodes_lns_num_nodes(5);
132 p.set_local_search_metaheuristic(LocalSearchMetaheuristic::AUTOMATIC);
133 p.set_guided_local_search_lambda_coefficient(0.1);
134 p.set_guided_local_search_reset_penalties_on_new_best_solution(
false);
135 p.set_use_depth_first_search(
false);
136 p.set_use_cp(BOOL_TRUE);
137 p.set_use_cp_sat(BOOL_FALSE);
138 p.set_use_generalized_cp_sat(BOOL_FALSE);
139 p.mutable_sat_parameters()->set_linearization_level(2);
140 p.mutable_sat_parameters()->set_num_search_workers(1);
141 p.set_report_intermediate_cp_sat_solutions(
false);
142 p.set_fallback_to_cp_sat_size_threshold(20);
143 p.set_continuous_scheduling_solver(RoutingSearchParameters::SCHEDULING_GLOP);
144 p.set_mixed_integer_scheduling_solver(
145 RoutingSearchParameters::SCHEDULING_CP_SAT);
146 p.set_disable_scheduling_beware_this_may_degrade_performance(
false);
147 p.set_optimization_step(0.0);
148 p.set_number_of_solutions_to_collect(1);
151 p.mutable_lns_time_limit()->set_nanos(100000000);
152 p.set_secondary_ls_time_limit_ratio(0);
153 p.set_use_full_propagation(
false);
154 p.set_log_search(
false);
155 p.set_log_cost_scaling_factor(1.0);
156 p.set_log_cost_offset(0.0);
157 p.set_use_iterated_local_search(
false);
158 *p.mutable_iterated_local_search_parameters() =
159 CreateDefaultIteratedLocalSearchParameters();
162 LOG_IF(DFATAL, !error.empty())
163 <<
"The default search parameters aren't valid: " << error;
167RoutingSearchParameters CreateDefaultSecondaryRoutingSearchParameters() {
168 RoutingSearchParameters p = CreateDefaultRoutingSearchParameters();
169 p.set_local_search_metaheuristic(LocalSearchMetaheuristic::GREEDY_DESCENT);
170 p.set_use_iterated_local_search(
false);
171 *p.mutable_iterated_local_search_parameters() =
172 CreateDefaultIteratedLocalSearchParameters();
173 RoutingSearchParameters::LocalSearchNeighborhoodOperators* o =
174 p.mutable_local_search_operators();
175 o->set_use_relocate(BOOL_TRUE);
176 o->set_use_relocate_pair(BOOL_FALSE);
177 o->set_use_light_relocate_pair(BOOL_TRUE);
178 o->set_use_relocate_subtrip(BOOL_TRUE);
179 o->set_use_relocate_neighbors(BOOL_FALSE);
180 o->set_use_exchange(BOOL_TRUE);
181 o->set_use_exchange_pair(BOOL_TRUE);
182 o->set_use_exchange_subtrip(BOOL_TRUE);
183 o->set_use_cross(BOOL_TRUE);
184 o->set_use_cross_exchange(BOOL_FALSE);
185 o->set_use_relocate_expensive_chain(BOOL_FALSE);
186 o->set_use_two_opt(BOOL_TRUE);
187 o->set_use_or_opt(BOOL_TRUE);
188 o->set_use_lin_kernighan(BOOL_TRUE);
189 o->set_use_tsp_opt(BOOL_FALSE);
190 o->set_use_make_active(BOOL_FALSE);
191 o->set_use_relocate_and_make_active(BOOL_FALSE);
192 o->set_use_make_inactive(BOOL_FALSE);
193 o->set_use_make_chain_inactive(BOOL_FALSE);
194 o->set_use_swap_active(BOOL_FALSE);
195 o->set_use_extended_swap_active(BOOL_FALSE);
196 o->set_use_shortest_path_swap_active(BOOL_FALSE);
197 o->set_use_node_pair_swap_active(BOOL_FALSE);
198 o->set_use_path_lns(BOOL_FALSE);
199 o->set_use_full_path_lns(BOOL_FALSE);
200 o->set_use_tsp_lns(BOOL_FALSE);
201 o->set_use_inactive_lns(BOOL_FALSE);
202 o->set_use_global_cheapest_insertion_path_lns(BOOL_FALSE);
203 o->set_use_local_cheapest_insertion_path_lns(BOOL_FALSE);
204 o->set_use_relocate_path_global_cheapest_insertion_insert_unperformed(
207 LOG_IF(DFATAL, !error.empty())
208 <<
"The default secondary search parameters aren't valid: " << error;
215 static const auto* default_parameters =
216 new RoutingSearchParameters(CreateDefaultRoutingSearchParameters());
217 return *default_parameters;
221 static const auto* default_parameters =
new RoutingSearchParameters(
222 CreateDefaultSecondaryRoutingSearchParameters());
223 return *default_parameters;
227bool IsValidNonNegativeDuration(
const google::protobuf::Duration& d) {
229 return status_or_duration.ok() &&
230 status_or_duration.value() >= absl::ZeroDuration();
235 const RoutingSearchParameters& search_parameters) {
236 const std::vector<std::string> errors =
238 return (errors.empty()) ?
"" : errors[0];
242 const RoutingSearchParameters& search_parameters) {
244 std::vector<std::string> errors;
249#if !defined(__ANDROID__) && !defined(__wasm__)
251 using Reflection = google::protobuf::Reflection;
252 using Descriptor = google::protobuf::Descriptor;
253 using FieldDescriptor = google::protobuf::FieldDescriptor;
254 const RoutingSearchParameters::LocalSearchNeighborhoodOperators& operators =
255 search_parameters.local_search_operators();
256 const Reflection* ls_reflection = operators.GetReflection();
257 const Descriptor* ls_descriptor = operators.GetDescriptor();
258 for (
int field_index = 0;
259 field_index < ls_descriptor->field_count(); ++field_index) {
260 const FieldDescriptor* field = ls_descriptor->field(field_index);
261 if (field->type() != FieldDescriptor::TYPE_ENUM ||
262 field->enum_type() != OptionalBoolean_descriptor()) {
264 <<
"In RoutingSearchParameters::LocalSearchNeighborhoodOperators,"
265 <<
" field '" << field->name() <<
"' is not an OptionalBoolean.";
267 const int value = ls_reflection->GetEnum(operators, field)->number();
268 if (!OptionalBoolean_IsValid(
value) ||
value == 0) {
269 errors.emplace_back(absl::StrFormat(
270 "local_search_neighborhood_operator.%s should be set to "
271 "BOOL_TRUE or BOOL_FALSE instead of %s (value: %d)",
273 OptionalBoolean_Name(
static_cast<OptionalBoolean
>(
value)),
280 if (
const double ratio = search_parameters.savings_neighbors_ratio();
282 errors.emplace_back(StrCat(
"Invalid savings_neighbors_ratio: ",
ratio));
284 if (
const double max_memory =
285 search_parameters.savings_max_memory_usage_bytes();
286 std::isnan(max_memory) || max_memory <= 0 || max_memory > 1e10) {
288 StrCat(
"Invalid savings_max_memory_usage_bytes: ", max_memory));
290 if (
const double coefficient = search_parameters.savings_arc_coefficient();
293 StrCat(
"Invalid savings_arc_coefficient: ",
coefficient));
295 if (
const double ratio =
296 search_parameters.cheapest_insertion_farthest_seeds_ratio();
299 StrCat(
"Invalid cheapest_insertion_farthest_seeds_ratio: ",
ratio));
301 if (
const double ratio =
302 search_parameters.cheapest_insertion_first_solution_neighbors_ratio();
304 errors.emplace_back(StrCat(
305 "Invalid cheapest_insertion_first_solution_neighbors_ratio: ",
ratio));
307 if (
const int32_t min_neighbors =
308 search_parameters.cheapest_insertion_first_solution_min_neighbors();
311 StrCat(
"Invalid cheapest_insertion_first_solution_min_neighbors: ",
312 min_neighbors,
". Must be greater or equal to 1."));
314 if (
const double ratio =
315 search_parameters.cheapest_insertion_ls_operator_neighbors_ratio();
317 errors.emplace_back(StrCat(
318 "Invalid cheapest_insertion_ls_operator_neighbors_ratio: ",
ratio));
320 if (
const int32_t min_neighbors =
321 search_parameters.cheapest_insertion_ls_operator_min_neighbors();
323 errors.emplace_back(StrCat(
324 "Invalid cheapest_insertion_ls_operator_min_neighbors: ", min_neighbors,
325 ". Must be greater or equal to 1."));
327 if (
const double ratio = search_parameters.ls_operator_neighbors_ratio();
329 errors.emplace_back(StrCat(
"Invalid ls_operator_neighbors_ratio: ",
ratio));
331 if (
const int32_t min_neighbors =
332 search_parameters.ls_operator_min_neighbors();
335 StrCat(
"Invalid ls_operator_min_neighbors: ", min_neighbors,
336 ". Must be greater or equal to 1."));
338 if (
const int32_t num_arcs =
339 search_parameters.relocate_expensive_chain_num_arcs_to_consider();
340 num_arcs < 2 || num_arcs > 1e6) {
341 errors.emplace_back(StrCat(
342 "Invalid relocate_expensive_chain_num_arcs_to_consider: ", num_arcs,
343 ". Must be between 2 and 10^6 (included)."));
345 if (
const int32_t num_arcs =
347 .heuristic_expensive_chain_lns_num_arcs_to_consider();
348 num_arcs < 2 || num_arcs > 1e6) {
350 StrCat(
"Invalid heuristic_expensive_chain_lns_num_arcs_to_consider: ",
351 num_arcs,
". Must be between 2 and 10^6 (included)."));
353 if (
const int32_t num_nodes =
354 search_parameters.heuristic_close_nodes_lns_num_nodes();
355 num_nodes < 0 || num_nodes > 1e4) {
357 StrCat(
"Invalid heuristic_close_nodes_lns_num_nodes: ", num_nodes,
358 ". Must be between 0 and 10000 (included)."));
360 if (
const double gls_coefficient =
361 search_parameters.guided_local_search_lambda_coefficient();
362 std::isnan(gls_coefficient) || gls_coefficient < 0 ||
363 std::isinf(gls_coefficient)) {
364 errors.emplace_back(StrCat(
365 "Invalid guided_local_search_lambda_coefficient: ", gls_coefficient));
367 if (
const double step = search_parameters.optimization_step();
368 std::isnan(step) || step < 0.0) {
369 errors.emplace_back(StrCat(
"Invalid optimization_step: ", step));
371 if (
const int32_t num = search_parameters.number_of_solutions_to_collect();
374 StrCat(
"Invalid number_of_solutions_to_collect: ", num));
376 if (
const int64_t lim = search_parameters.solution_limit(); lim < 1)
377 errors.emplace_back(StrCat(
"Invalid solution_limit: ", lim));
378 if (!IsValidNonNegativeDuration(search_parameters.time_limit())) {
379 errors.emplace_back(
"Invalid time_limit: " +
380 search_parameters.time_limit().ShortDebugString());
382 if (!IsValidNonNegativeDuration(search_parameters.lns_time_limit())) {
383 errors.emplace_back(
"Invalid lns_time_limit: " +
384 search_parameters.lns_time_limit().ShortDebugString());
386 if (
const double ratio = search_parameters.secondary_ls_time_limit_ratio();
389 StrCat(
"Invalid secondary_ls_time_limit_ratio: ",
ratio));
391 if (!FirstSolutionStrategy::Value_IsValid(
392 search_parameters.first_solution_strategy())) {
393 errors.emplace_back(StrCat(
"Invalid first_solution_strategy: ",
394 search_parameters.first_solution_strategy()));
396 if (!LocalSearchMetaheuristic::Value_IsValid(
397 search_parameters.local_search_metaheuristic())) {
398 errors.emplace_back(StrCat(
"Invalid metaheuristic: ",
399 search_parameters.local_search_metaheuristic()));
402 const double scaling_factor = search_parameters.log_cost_scaling_factor();
403 if (scaling_factor == 0 || std::isnan(scaling_factor) ||
404 std::isinf(scaling_factor)) {
406 StrCat(
"Invalid value for log_cost_scaling_factor: ", scaling_factor));
408 const double offset = search_parameters.log_cost_offset();
409 if (std::isnan(offset) || std::isinf(offset)) {
410 errors.emplace_back(StrCat(
"Invalid value for log_cost_offset: ", offset));
412 const RoutingSearchParameters::SchedulingSolver continuous_scheduling_solver =
413 search_parameters.continuous_scheduling_solver();
414 if (continuous_scheduling_solver ==
415 RoutingSearchParameters::SCHEDULING_UNSET ||
416 continuous_scheduling_solver ==
417 RoutingSearchParameters::SCHEDULING_CP_SAT) {
419 StrCat(
"Invalid value for continuous_scheduling_solver: ",
420 RoutingSearchParameters::SchedulingSolver_Name(
421 continuous_scheduling_solver)));
424 if (
const RoutingSearchParameters::SchedulingSolver
425 mixed_integer_scheduling_solver =
426 search_parameters.mixed_integer_scheduling_solver();
427 mixed_integer_scheduling_solver ==
428 RoutingSearchParameters::SCHEDULING_UNSET) {
430 StrCat(
"Invalid value for mixed_integer_scheduling_solver: ",
431 RoutingSearchParameters::SchedulingSolver_Name(
432 mixed_integer_scheduling_solver)));
435 if (search_parameters.has_improvement_limit_parameters()) {
436 const double improvement_rate_coefficient =
437 search_parameters.improvement_limit_parameters()
438 .improvement_rate_coefficient();
439 if (std::isnan(improvement_rate_coefficient) ||
440 improvement_rate_coefficient <= 0) {
442 StrCat(
"Invalid value for "
443 "improvement_limit_parameters.improvement_rate_coefficient: ",
444 improvement_rate_coefficient));
447 const int32_t improvement_rate_solutions_distance =
448 search_parameters.improvement_limit_parameters()
449 .improvement_rate_solutions_distance();
450 if (improvement_rate_solutions_distance <= 0) {
451 errors.emplace_back(StrCat(
453 "improvement_limit_parameters.improvement_rate_solutions_distance: ",
454 improvement_rate_solutions_distance));
458 if (
const double memory_coefficient =
460 .multi_armed_bandit_compound_operator_memory_coefficient();
461 std::isnan(memory_coefficient) || memory_coefficient < 0 ||
462 memory_coefficient > 1) {
464 StrCat(
"Invalid value for "
465 "multi_armed_bandit_compound_operator_memory_coefficient: ",
466 memory_coefficient));
468 if (
const double exploration_coefficient =
470 .multi_armed_bandit_compound_operator_exploration_coefficient();
471 std::isnan(exploration_coefficient) || exploration_coefficient < 0) {
473 StrCat(
"Invalid value for "
474 "multi_armed_bandit_compound_operator_exploration_coefficient: ",
475 exploration_coefficient));
478 if (
const sat::SatParameters& sat_parameters =
479 search_parameters.sat_parameters();
480 sat_parameters.enumerate_all_solutions() &&
481 (sat_parameters.num_search_workers() > 1 ||
482 sat_parameters.interleave_search())) {
484 "sat_parameters.enumerate_all_solutions cannot be true in parallel"
static ConstraintSolverParameters DefaultSolverParameters()
--— ConstraintSolverParameters --—
In SWIG mode, we don't want anything besides these top-level includes.
RoutingModelParameters DefaultRoutingModelParameters()
RoutingSearchParameters DefaultSecondaryRoutingSearchParameters()
std::vector< std::string > FindErrorsInRoutingSearchParameters(const RoutingSearchParameters &search_parameters)
RoutingSearchParameters DefaultRoutingSearchParameters()
static
std::string FindErrorInRoutingSearchParameters(const RoutingSearchParameters &search_parameters)
inline ::absl::StatusOr< absl::Duration > DecodeGoogleApiProto(const google::protobuf::Duration &proto)
static const int64_t kint64max