Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
parameters_validation.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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
15
16#include <stdint.h>
17
18#include <algorithm>
19#include <cmath>
20#include <limits>
21#include <string>
22
23#include "absl/strings/str_cat.h"
25#include "ortools/sat/sat_parameters.pb.h"
26
27namespace operations_research {
28namespace sat {
29
30#define TEST_IN_RANGE(name, min, max) \
31 if (params.name() < min || params.name() > max) { \
32 return absl::StrCat("parameter '", #name, "' should be in [", min, ",", \
33 max, "]. Current value is ", params.name()); \
34 }
35
36#define TEST_NON_NEGATIVE(name) \
37 if (params.name() < 0) { \
38 return absl::StrCat("Parameters ", #name, " must be non-negative"); \
39 }
40
41#define TEST_POSITIVE(name) \
42 if (params.name() <= 0) { \
43 return absl::StrCat("Parameters ", #name, " must be positive"); \
44 }
45
46#define TEST_NOT_NAN(name) \
47 if (std::isnan(params.name())) { \
48 return absl::StrCat("parameter '", #name, "' is NaN"); \
49 }
50
51#define TEST_IS_FINITE(name) \
52 if (!std::isfinite(params.name())) { \
53 return absl::StrCat("parameter '", #name, "' is NaN or not finite"); \
54 }
55
56std::string ValidateParameters(const SatParameters& params) {
57 // Test that all floating point parameters are not NaN or +/- infinity.
58 TEST_IS_FINITE(random_polarity_ratio);
59 TEST_IS_FINITE(random_branches_ratio);
60 TEST_IS_FINITE(initial_variables_activity);
61 TEST_IS_FINITE(clause_cleanup_ratio);
62 TEST_IS_FINITE(pb_cleanup_ratio);
63 TEST_IS_FINITE(variable_activity_decay);
64 TEST_IS_FINITE(max_variable_activity_value);
65 TEST_IS_FINITE(glucose_max_decay);
66 TEST_IS_FINITE(glucose_decay_increment);
67 TEST_IS_FINITE(clause_activity_decay);
68 TEST_IS_FINITE(max_clause_activity_value);
69 TEST_IS_FINITE(restart_dl_average_ratio);
70 TEST_IS_FINITE(restart_lbd_average_ratio);
71 TEST_IS_FINITE(blocking_restart_multiplier);
72 TEST_IS_FINITE(strategy_change_increase_ratio);
73 TEST_IS_FINITE(absolute_gap_limit);
74 TEST_IS_FINITE(relative_gap_limit);
75 TEST_IS_FINITE(probing_deterministic_time_limit);
76 TEST_IS_FINITE(presolve_probing_deterministic_time_limit);
77 TEST_IS_FINITE(propagation_loop_detection_factor);
78 TEST_IS_FINITE(merge_no_overlap_work_limit);
79 TEST_IS_FINITE(merge_at_most_one_work_limit);
80 TEST_IS_FINITE(min_orthogonality_for_lp_constraints);
81 TEST_IS_FINITE(mip_var_scaling);
82 TEST_IS_FINITE(cut_max_active_count_value);
83 TEST_IS_FINITE(cut_active_count_decay);
84 TEST_IS_FINITE(shaving_search_deterministic_time);
85 TEST_IS_FINITE(inprocessing_dtime_ratio);
86 TEST_IS_FINITE(inprocessing_probing_dtime);
87 TEST_IS_FINITE(inprocessing_minimization_dtime);
88 TEST_IS_FINITE(mip_max_bound);
89 TEST_IS_FINITE(mip_wanted_precision);
90 TEST_IS_FINITE(mip_check_precision);
91 TEST_IS_FINITE(mip_max_valid_magnitude);
92 TEST_IS_FINITE(mip_drop_tolerance);
93 TEST_IS_FINITE(shared_tree_worker_objective_split_probability);
94 TEST_IS_FINITE(shared_tree_open_leaves_per_worker);
95 TEST_IS_FINITE(feasibility_jump_batch_dtime);
96
97 TEST_POSITIVE(at_most_one_max_expansion_size);
98
99 TEST_NOT_NAN(max_time_in_seconds);
100 TEST_NOT_NAN(max_deterministic_time);
101
102 // Parallelism.
103 const int kMaxReasonableParallelism = 10'000;
104 TEST_IN_RANGE(num_workers, 0, kMaxReasonableParallelism);
105 TEST_IN_RANGE(num_search_workers, 0, kMaxReasonableParallelism);
106 TEST_IN_RANGE(shared_tree_num_workers, 0, kMaxReasonableParallelism);
107 TEST_IN_RANGE(interleave_batch_size, 0, kMaxReasonableParallelism);
108 TEST_IN_RANGE(shared_tree_open_leaves_per_worker, 1,
109 kMaxReasonableParallelism);
110
111 // TODO(user): Consider using annotations directly in the proto for these
112 // validation. It is however not open sourced.
113 TEST_IN_RANGE(mip_max_activity_exponent, 1, 62);
114 TEST_IN_RANGE(mip_max_bound, 0, 1e17);
115 TEST_IN_RANGE(solution_pool_size, 1, std::numeric_limits<int32_t>::max());
116 TEST_IN_RANGE(shared_tree_worker_objective_split_probability, 0.0, 1.0);
117
118 // Feasibility jump.
119 TEST_NOT_NAN(feasibility_jump_decay);
120 TEST_NOT_NAN(feasibility_jump_var_randomization_probability);
121 TEST_NOT_NAN(feasibility_jump_var_perburbation_range_ratio);
122 TEST_IN_RANGE(feasibility_jump_decay, 0.0, 1.0);
123 TEST_IN_RANGE(feasibility_jump_var_randomization_probability, 0.0, 1.0);
124 TEST_IN_RANGE(feasibility_jump_var_perburbation_range_ratio, 0.0, 1.0);
125
126 // Violation ls.
127 TEST_NOT_NAN(violation_ls_compound_move_probability);
128 TEST_IN_RANGE(num_violation_ls, 0, kMaxReasonableParallelism);
129 TEST_IN_RANGE(violation_ls_perturbation_period, 1, 1'000'000'000);
130 TEST_IN_RANGE(violation_ls_compound_move_probability, 0.0, 1.0);
131
132 TEST_POSITIVE(glucose_decay_increment_period);
133 TEST_POSITIVE(shared_tree_max_nodes_per_worker);
134 TEST_POSITIVE(shared_tree_open_leaves_per_worker);
135 TEST_POSITIVE(mip_var_scaling);
136
137 // Test LP tolerances.
138 TEST_IS_FINITE(lp_primal_tolerance);
139 TEST_IS_FINITE(lp_dual_tolerance);
140 TEST_NON_NEGATIVE(lp_primal_tolerance);
141 TEST_NON_NEGATIVE(lp_dual_tolerance);
142
143 TEST_NON_NEGATIVE(mip_wanted_precision);
144 TEST_NON_NEGATIVE(max_time_in_seconds);
145 TEST_NON_NEGATIVE(max_deterministic_time);
146 TEST_NON_NEGATIVE(new_constraints_batch_size);
147 TEST_NON_NEGATIVE(probing_deterministic_time_limit);
148 TEST_NON_NEGATIVE(presolve_probing_deterministic_time_limit);
149 TEST_NON_NEGATIVE(linearization_level);
150
151 if (params.enumerate_all_solutions() &&
152 (params.num_search_workers() > 1 || params.num_workers() > 1)) {
153 return "Enumerating all solutions does not work in parallel";
154 }
155
156 if (params.enumerate_all_solutions() &&
157 (!params.subsolvers().empty() || !params.extra_subsolvers().empty() ||
158 !params.ignore_subsolvers().empty())) {
159 return "Enumerating all solutions does not work with custom subsolvers";
160 }
161
162 if (params.num_search_workers() >= 1 && params.num_workers() >= 1) {
163 return "Do not specify both num_search_workers and num_workers";
164 }
165
166 if (params.use_shared_tree_search()) {
167 return "use_shared_tree_search must only be set on workers' parameters";
168 }
169
170 if (params.enumerate_all_solutions() && params.interleave_search()) {
171 return "Enumerating all solutions does not work with interleaved search";
172 }
173
174 for (const SatParameters& new_subsolver : params.subsolver_params()) {
175 if (new_subsolver.name().empty()) {
176 return "New subsolver parameter defined without a name";
177 }
178 }
179
180 const auto strategies = GetNamedParameters(params);
181 for (const std::string& subsolver : params.subsolvers()) {
182 if (subsolver == "core_or_no_lp") continue; // Used by fz free search.
183 if (!strategies.contains(subsolver)) {
184 return absl::StrCat("subsolver \'", subsolver, "\' is not valid");
185 }
186 }
187
188 for (const std::string& subsolver : params.extra_subsolvers()) {
189 if (!strategies.contains(subsolver)) {
190 return absl::StrCat("subsolver \'", subsolver, "\' is not valid");
191 }
192 }
193
194 return "";
195}
196
197#undef TEST_IN_RANGE
198#undef TEST_POSITIVE
199#undef TEST_NON_NEGATIVE
200#undef TEST_NOT_NAN
201#undef TEST_IS_FINITE
202
203} // namespace sat
204} // namespace operations_research
#define TEST_NON_NEGATIVE(name)
#define TEST_NOT_NAN(name)
std::string ValidateParameters(const SatParameters &params)
absl::flat_hash_map< std::string, SatParameters > GetNamedParameters(SatParameters base_params)
In SWIG mode, we don't want anything besides these top-level includes.
#define TEST_IN_RANGE(name, min, max)
#define TEST_POSITIVE(name)
#define TEST_IS_FINITE(name)