19 #include "absl/container/flat_hash_map.h"
20 #include "absl/strings/str_format.h"
70 int64_t
value)
const {
86 int64_t
value)
const {
108 const std::vector<DecisionStrategyProto>& strategies,
Model*
model) {
115 return [&view, &
parameters, random, strategies]() {
116 for (
const DecisionStrategyProto& strategy : strategies) {
124 std::vector<VarValue> active_refs;
127 for (
int i = 0; i < strategy.variables().size(); ++i) {
128 const int ref = strategy.variables(i);
130 if (view.IsFixed(
var) || view.IsCurrentlyFree(
var))
continue;
134 while (t_index < strategy.transformations().size() &&
135 strategy.transformations(t_index).index() < i) {
138 if (t_index < strategy.transformations_size() &&
139 strategy.transformations(t_index).index() == i) {
140 coeff = strategy.transformations(t_index).positive_coeff();
141 offset = strategy.transformations(t_index).offset();
149 int64_t lb = view.Min(
var);
150 int64_t ub = view.Max(
var);
155 switch (strategy.variable_selection_strategy()) {
156 case DecisionStrategyProto::CHOOSE_FIRST:
158 case DecisionStrategyProto::CHOOSE_LOWEST_MIN:
159 value = coeff * lb + offset;
161 case DecisionStrategyProto::CHOOSE_HIGHEST_MAX:
162 value = -(coeff * ub + offset);
164 case DecisionStrategyProto::CHOOSE_MIN_DOMAIN_SIZE:
165 value = coeff * (ub - lb + 1);
167 case DecisionStrategyProto::CHOOSE_MAX_DOMAIN_SIZE:
168 value = -coeff * (ub - lb + 1);
171 LOG(
FATAL) <<
"Unknown VariableSelectionStrategy "
172 << strategy.variable_selection_strategy();
174 if (
value < candidate_value) {
176 candidate_value =
value;
178 if (strategy.variable_selection_strategy() ==
179 DecisionStrategyProto::CHOOSE_FIRST &&
184 candidate_value +
parameters.search_randomization_tolerance()) {
185 active_refs.push_back({ref,
value});
190 if (candidate_value ==
kint64max)
continue;
192 CHECK(!active_refs.empty());
193 const IntegerValue threshold(
194 candidate_value +
parameters.search_randomization_tolerance());
195 auto is_above_tolerance = [threshold](
const VarValue& entry) {
196 return entry.value > threshold;
199 active_refs.erase(std::remove_if(active_refs.begin(), active_refs.end(),
202 const int winner = absl::Uniform<int>(*random, 0, active_refs.size());
203 candidate = active_refs[winner].ref;
206 DecisionStrategyProto::DomainReductionStrategy selection =
207 strategy.domain_reduction_strategy();
210 case DecisionStrategyProto::SELECT_MIN_VALUE:
211 selection = DecisionStrategyProto::SELECT_MAX_VALUE;
213 case DecisionStrategyProto::SELECT_MAX_VALUE:
214 selection = DecisionStrategyProto::SELECT_MIN_VALUE;
216 case DecisionStrategyProto::SELECT_LOWER_HALF:
217 selection = DecisionStrategyProto::SELECT_UPPER_HALF;
219 case DecisionStrategyProto::SELECT_UPPER_HALF:
220 selection = DecisionStrategyProto::SELECT_LOWER_HALF;
228 const int64_t lb = view.Min(
var);
229 const int64_t ub = view.Max(
var);
231 case DecisionStrategyProto::SELECT_MIN_VALUE:
232 return view.LowerOrEqual(
var, lb);
233 case DecisionStrategyProto::SELECT_MAX_VALUE:
234 return view.GreaterOrEqual(
var, ub);
235 case DecisionStrategyProto::SELECT_LOWER_HALF:
236 return view.LowerOrEqual(
var, lb + (ub - lb) / 2);
237 case DecisionStrategyProto::SELECT_UPPER_HALF:
238 return view.GreaterOrEqual(
var, ub - (ub - lb) / 2);
239 case DecisionStrategyProto::SELECT_MEDIAN_VALUE:
241 return view.LowerOrEqual(
var, lb);
243 LOG(
FATAL) <<
"Unknown DomainReductionStrategy "
244 << strategy.domain_reduction_strategy();
252 const CpModelProto& cp_model_proto,
253 const std::vector<IntegerVariable>& variable_mapping,
254 IntegerVariable objective_var,
Model*
model) {
257 const bool instantiate_all_variables =
258 model->GetOrCreate<SatParameters>()->instantiate_all_variables();
260 if (instantiate_all_variables) {
261 std::vector<IntegerVariable> decisions;
262 for (
const IntegerVariable
var : variable_mapping) {
267 decisions.push_back(objective_var);
269 decisions.push_back(
var);
272 default_search_strategy =
276 std::vector<DecisionStrategyProto> strategies;
277 for (
const DecisionStrategyProto&
proto : cp_model_proto.search_strategy()) {
278 strategies.push_back(
proto);
280 if (instantiate_all_variables) {
282 default_search_strategy});
289 const CpModelProto& cp_model_proto,
290 const std::vector<IntegerVariable>& variable_mapping,
293 std::vector<int> ref_to_display;
294 for (
int i = 0; i < cp_model_proto.variables_size(); ++i) {
296 if (cp_model_proto.variables(i).name().empty())
continue;
297 ref_to_display.push_back(i);
299 std::sort(ref_to_display.begin(), ref_to_display.end(), [&](
int i,
int j) {
300 return cp_model_proto.variables(i).name() <
301 cp_model_proto.variables(j).name();
304 std::vector<std::pair<int64_t, int64_t>> old_domains(variable_mapping.size());
305 return [instrumented_strategy,
model, variable_mapping, cp_model_proto,
306 old_domains, ref_to_display]()
mutable {
308 if (!decision.
HasValue())
return decision;
312 LOG(
INFO) <<
"Boolean decision " << l;
315 LOG(
INFO) <<
" - associated with " << i_lit;
320 const int level =
model->Get<
Trail>()->CurrentDecisionLevel();
321 std::string to_display =
322 absl::StrCat(
"Diff since last call, level=", level,
"\n");
324 for (
const int ref : ref_to_display) {
325 const IntegerVariable
var = variable_mapping[ref];
326 const std::pair<int64_t, int64_t> new_domain(
329 if (new_domain != old_domains[ref]) {
330 absl::StrAppend(&to_display, cp_model_proto.variables(ref).name(),
" [",
331 old_domains[ref].first,
",", old_domains[ref].second,
332 "] -> [", new_domain.first,
",", new_domain.second,
334 old_domains[ref] = new_domain;
350 const SatParameters& base_params,
const CpModelProto& cp_model,
351 const int num_workers) {
354 std::map<std::string, SatParameters> strategies;
358 SatParameters new_params = base_params;
359 new_params.set_linearization_level(0);
360 strategies[
"no_lp"] = new_params;
361 new_params.set_linearization_level(1);
362 strategies[
"default_lp"] = new_params;
363 new_params.set_linearization_level(2);
364 new_params.set_add_lp_constraints_lazily(
false);
365 strategies[
"max_lp"] = new_params;
375 SatParameters new_params = base_params;
376 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
377 new_params.set_optimize_with_core(
true);
378 new_params.set_linearization_level(0);
379 strategies[
"core"] = new_params;
384 SatParameters new_params = base_params;
385 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
386 new_params.set_optimize_with_core(
true);
387 new_params.set_linearization_level(1);
388 strategies[
"core_default_lp"] = new_params;
392 SatParameters new_params = base_params;
393 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
394 new_params.set_optimize_with_core(
true);
395 new_params.set_linearization_level(2);
396 strategies[
"core_max_lp"] = new_params;
400 SatParameters new_params = base_params;
401 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
402 new_params.set_use_probing_search(
true);
403 strategies[
"probing"] = new_params;
408 SatParameters new_params = base_params;
409 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
410 strategies[
"auto"] = new_params;
412 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
413 strategies[
"fixed"] = new_params;
415 new_params.set_search_branching(
416 SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH);
417 strategies[
"quick_restart"] = new_params;
419 new_params.set_search_branching(
420 SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH);
421 new_params.set_linearization_level(0);
422 strategies[
"quick_restart_no_lp"] = new_params;
425 new_params.set_linearization_level(2);
426 new_params.set_search_branching(SatParameters::LP_SEARCH);
427 strategies[
"reduced_costs"] = new_params;
430 new_params.set_linearization_level(2);
431 new_params.set_search_branching(SatParameters::PSEUDO_COST_SEARCH);
432 new_params.set_exploit_best_solution(
true);
433 strategies[
"pseudo_costs"] = new_params;
438 SatParameters new_params = base_params;
439 new_params.set_boolean_encoding_level(0);
440 strategies[
"less_encoding"] = new_params;
447 std::vector<std::string> names;
448 if (base_params.reduce_memory_usage_in_interleave_mode() &&
449 base_params.interleave_search()) {
451 if (cp_model.has_objective()) {
452 names.push_back(
"default_lp");
453 names.push_back(!cp_model.search_strategy().empty() ?
"fixed"
455 names.push_back(cp_model.objective().vars_size() > 1 ?
"core" :
"no_lp");
456 names.push_back(
"max_lp");
458 names.push_back(
"default_lp");
459 names.push_back(cp_model.search_strategy_size() > 0 ?
"fixed" :
"no_lp");
460 names.push_back(
"less_encoding");
461 names.push_back(
"max_lp");
462 names.push_back(
"quick_restart");
464 }
else if (cp_model.has_objective()) {
465 names.push_back(
"default_lp");
466 names.push_back(!cp_model.search_strategy().empty() ?
"fixed"
468 names.push_back(
"pseudo_costs");
469 names.push_back(
"no_lp");
470 names.push_back(
"max_lp");
471 if (cp_model.objective().vars_size() > 1) names.push_back(
"core");
475 if (num_workers > 8 || base_params.interleave_search()) {
476 names.push_back(
"quick_restart");
478 if (num_workers > 10) {
479 names.push_back(
"quick_restart_no_lp");
482 names.push_back(
"default_lp");
483 if (cp_model.search_strategy_size() > 0) names.push_back(
"fixed");
484 names.push_back(
"less_encoding");
485 names.push_back(
"no_lp");
486 names.push_back(
"max_lp");
487 names.push_back(
"quick_restart");
488 if (num_workers > 10) {
489 names.push_back(
"quick_restart_no_lp");
492 if (num_workers > 12) {
493 names.push_back(
"probing");
498 std::vector<SatParameters> result;
499 for (
const std::string&
name : names) {
500 SatParameters new_params = strategies.at(
name);
501 new_params.set_name(
name);
502 new_params.set_random_seed(result.size() + 1);
503 result.push_back(new_params);
508 if (!cp_model.has_objective()) {
509 int target = num_workers;
513 if (!base_params.interleave_search() &&
514 (base_params.use_rins_lns() || base_params.use_relaxation_lns() ||
515 base_params.use_feasibility_pump())) {
516 target =
std::max(1, num_workers - 1);
520 while (result.size() < target) {
522 SatParameters new_params = base_params;
523 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
524 new_params.set_randomize_search(
true);
525 new_params.set_search_randomization_tolerance(
index);
526 new_params.set_random_seed(result.size() + 1);
527 new_params.set_name(absl::StrCat(
"random_",
index));
528 result.push_back(new_params);
537 if (!base_params.interleave_search() && result.size() > num_workers) {
538 result.resize(num_workers);
#define DCHECK(condition)
An Assignment is a variable -> domains mapping, used to report solutions to the user.
bool IsBoolean(int ref) const
bool IsInteger(int ref) const
IntegerVariable Integer(int ref) const
sat::Literal Literal(int ref) const
int NumProtoVariables() const
bool IsFixed(int var) const
BooleanOrIntegerLiteral GreaterOrEqual(int var, int64_t value) const
bool IsCurrentlyFree(int var) const
CpModelView(Model *model)
int64_t Max(int var) const
BooleanOrIntegerLiteral LowerOrEqual(int var, int64_t value) const
int64_t Min(int var) const
const InlinedIntegerLiteralVector & GetAllIntegerLiterals(Literal lit) const
bool IsCurrentlyIgnored(IntegerVariable i) const
bool IsFixed(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
LiteralIndex NegatedIndex() const
LiteralIndex Index() const
BooleanVariable Variable() const
Class that owns everything related to a particular optimization model.
bool VariableIsAssigned(BooleanVariable var) const
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
static const int64_t kint64max
const std::function< BooleanOrIntegerLiteral()> ConstructSearchStrategyInternal(const std::vector< DecisionStrategyProto > &strategies, Model *model)
std::function< BooleanOrIntegerLiteral()> FirstUnassignedVarAtItsMinHeuristic(const std::vector< IntegerVariable > &vars, Model *model)
bool RefIsPositive(int ref)
const LiteralIndex kNoLiteralIndex(-1)
const IntegerVariable kNoIntegerVariable(-1)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
std::function< BooleanOrIntegerLiteral()> SequentialSearch(std::vector< std::function< BooleanOrIntegerLiteral()>> heuristics)
std::vector< SatParameters > GetDiverseSetOfParameters(const SatParameters &base_params, const CpModelProto &cp_model, const int num_workers)
std::function< BooleanOrIntegerLiteral()> ConstructSearchStrategy(const CpModelProto &cp_model_proto, const std::vector< IntegerVariable > &variable_mapping, IntegerVariable objective_var, Model *model)
std::function< BooleanOrIntegerLiteral()> InstrumentSearchStrategy(const CpModelProto &cp_model_proto, const std::vector< IntegerVariable > &variable_mapping, const std::function< BooleanOrIntegerLiteral()> &instrumented_strategy, Model *model)
Collection of objects used to extend the Constraint Solver library.
LiteralIndex boolean_literal_index
IntegerLiteral integer_literal
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)