18 #include "absl/container/flat_hash_map.h"
19 #include "absl/strings/str_format.h"
43 const absl::flat_hash_map<
int, std::pair<int64, int64>>&
44 var_to_coeff_offset_pair,
45 const std::vector<Strategy>& strategies,
Model*
model) {
51 return [integer_encoder, integer_trail, strategies, var_to_coeff_offset_pair,
53 const SatParameters*
const parameters =
model->GetOrCreate<SatParameters>();
55 for (
const Strategy& strategy : strategies) {
58 IntegerValue candidate_lb;
59 IntegerValue candidate_ub;
65 std::vector<VarValue> active_vars;
67 for (
const IntegerVariable
var : strategy.variables) {
71 if (lb == ub)
continue;
72 IntegerValue
value(0);
73 IntegerValue coeff(1);
74 IntegerValue offset(0);
76 const auto coeff_offset =
78 coeff = coeff_offset.first;
79 offset = coeff_offset.second;
85 switch (strategy.var_strategy) {
86 case DecisionStrategyProto::CHOOSE_FIRST:
88 case DecisionStrategyProto::CHOOSE_LOWEST_MIN:
89 value = coeff * lb + offset;
91 case DecisionStrategyProto::CHOOSE_HIGHEST_MAX:
92 value = -(coeff * ub + offset);
94 case DecisionStrategyProto::CHOOSE_MIN_DOMAIN_SIZE:
96 value = coeff * (ub - lb + 1);
98 case DecisionStrategyProto::CHOOSE_MAX_DOMAIN_SIZE:
100 value = -coeff * (ub - lb + 1);
103 LOG(FATAL) <<
"Unknown VariableSelectionStrategy "
104 << strategy.var_strategy;
106 if (
value < candidate_value) {
110 candidate_value =
value;
112 if (strategy.var_strategy == DecisionStrategyProto::CHOOSE_FIRST &&
116 if (active_vars.empty() ||
117 value <= candidate_value +
118 parameters->search_randomization_tolerance()) {
119 active_vars.push_back({
var,
value});
125 CHECK(!active_vars.empty());
126 const IntegerValue threshold(
127 candidate_value +
parameters->search_randomization_tolerance());
128 auto is_above_tolerance = [threshold](
const VarValue& entry) {
129 return entry.value > threshold;
132 active_vars.erase(std::remove_if(active_vars.begin(), active_vars.end(),
136 std::uniform_int_distribution<int>(0, active_vars.size() - 1)(
138 candidate = active_vars[winner].var;
139 candidate_lb = integer_trail->
LowerBound(candidate);
140 candidate_ub = integer_trail->
UpperBound(candidate);
144 switch (strategy.domain_strategy) {
145 case DecisionStrategyProto::SELECT_MIN_VALUE:
148 case DecisionStrategyProto::SELECT_MAX_VALUE:
151 case DecisionStrategyProto::SELECT_LOWER_HALF:
153 candidate, candidate_lb + (candidate_ub - candidate_lb) / 2);
155 case DecisionStrategyProto::SELECT_UPPER_HALF:
157 candidate, candidate_ub - (candidate_ub - candidate_lb) / 2);
159 case DecisionStrategyProto::SELECT_MEDIAN_VALUE:
164 LOG(FATAL) <<
"Unknown DomainReductionStrategy "
165 << strategy.domain_strategy;
167 return integer_encoder->GetOrCreateAssociatedLiteral(
literal).
Index();
174 const CpModelProto& cp_model_proto,
175 const std::vector<IntegerVariable>& variable_mapping,
176 IntegerVariable objective_var,
Model*
model) {
178 std::function<LiteralIndex()> default_search_strategy =
nullptr;
179 const bool instantiate_all_variables =
180 model->GetOrCreate<SatParameters>()->instantiate_all_variables();
182 if (instantiate_all_variables) {
183 std::vector<IntegerVariable> decisions;
184 for (
const IntegerVariable
var : variable_mapping) {
189 decisions.push_back(objective_var);
191 decisions.push_back(
var);
194 default_search_strategy =
198 std::vector<Strategy> strategies;
199 absl::flat_hash_map<int, std::pair<int64, int64>> var_to_coeff_offset_pair;
200 for (
const DecisionStrategyProto&
proto : cp_model_proto.search_strategy()) {
202 Strategy& strategy = strategies.back();
203 for (
const int ref :
proto.variables()) {
210 for (
const auto& transform :
proto.transformations()) {
211 const int ref = transform.var();
212 const IntegerVariable
var =
216 var_to_coeff_offset_pair[
var.value()] = {transform.positive_coeff(),
221 if (instantiate_all_variables) {
223 var_to_coeff_offset_pair, strategies,
model),
224 default_search_strategy});
232 const CpModelProto& cp_model_proto,
233 const std::vector<IntegerVariable>& variable_mapping,
234 const std::function<LiteralIndex()>& instrumented_strategy,
Model*
model) {
235 std::vector<int> ref_to_display;
236 for (
int i = 0; i < cp_model_proto.variables_size(); ++i) {
238 if (cp_model_proto.variables(i).name().empty())
continue;
239 ref_to_display.push_back(i);
241 std::sort(ref_to_display.begin(), ref_to_display.end(), [&](
int i,
int j) {
242 return cp_model_proto.variables(i).name() <
243 cp_model_proto.variables(j).name();
246 std::vector<std::pair<int64, int64>> old_domains(variable_mapping.size());
247 return [instrumented_strategy,
model, variable_mapping, cp_model_proto,
248 old_domains, ref_to_display]()
mutable {
249 const LiteralIndex decision = instrumented_strategy();
255 LOG(INFO) <<
"decision " << i_lit;
257 const int level =
model->Get<
Trail>()->CurrentDecisionLevel();
258 std::string to_display =
259 absl::StrCat(
"Diff since last call, level=", level,
"\n");
261 for (
const int ref : ref_to_display) {
262 const IntegerVariable
var = variable_mapping[ref];
263 const std::pair<int64, int64> new_domain(
266 if (new_domain != old_domains[ref]) {
267 absl::StrAppend(&to_display, cp_model_proto.variables(ref).name(),
" [",
268 old_domains[ref].first,
",", old_domains[ref].second,
269 "] -> [", new_domain.first,
",", new_domain.second,
271 old_domains[ref] = new_domain;
274 LOG(INFO) << to_display;
280 const CpModelProto& cp_model,
290 SatParameters new_params = params;
291 new_params.set_random_seed(params.random_seed() + worker_id);
292 new_params.set_use_lns_only(
false);
293 int index = worker_id;
295 if (params.reduce_memory_usage_in_interleave_mode() &&
296 params.interleave_search()) {
299 if (cp_model.has_objective()) {
302 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
308 if (cp_model.search_strategy_size() > 0) {
310 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
316 new_params.set_search_branching(SatParameters::PSEUDO_COST_SEARCH);
317 new_params.set_exploit_best_solution(
true);
318 *
name =
"pseudo_cost";
324 if (cp_model.objective().vars_size() > 1) {
326 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
327 new_params.set_optimize_with_core(
true);
328 new_params.set_linearization_level(0);
334 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
335 new_params.set_linearization_level(0);
343 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
344 new_params.set_linearization_level(2);
345 new_params.set_use_branching_in_lp(
true);
351 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
352 new_params.set_use_lns_only(
true);
358 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
363 if (cp_model.search_strategy_size() > 0) {
365 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
372 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
373 new_params.set_linearization_level(0);
381 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
382 new_params.set_boolean_encoding_level(0);
383 *
name =
"less encoding";
389 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
390 new_params.set_linearization_level(2);
396 new_params.set_search_branching(
397 SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH);
401 }
else if (cp_model.has_objective()) {
403 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
404 new_params.set_linearization_level(1);
409 if (cp_model.search_strategy_size() > 0) {
411 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
418 new_params.set_search_branching(SatParameters::LP_SEARCH);
425 new_params.set_search_branching(SatParameters::PSEUDO_COST_SEARCH);
426 new_params.set_exploit_best_solution(
true);
427 *
name =
"pseudo_cost";
433 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
434 new_params.set_linearization_level(0);
441 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
442 new_params.set_linearization_level(2);
443 new_params.set_use_branching_in_lp(
true);
449 if (params.num_search_workers() > 8 && --
index == 0) {
450 new_params.set_search_branching(
451 SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH);
452 *
name =
"quick_restart";
456 if (cp_model.objective().vars_size() > 1) {
458 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
459 new_params.set_optimize_with_core(
true);
460 new_params.set_linearization_level(0);
467 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
468 new_params.set_use_lns_only(
true);
469 *
name = absl::StrFormat(
"lns_%i",
index);
474 int index = worker_id;
477 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
482 if (cp_model.search_strategy_size() > 0) {
484 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
491 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
492 new_params.set_boolean_encoding_level(0);
493 *
name =
"less encoding";
499 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
500 new_params.set_linearization_level(0);
507 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
508 new_params.set_linearization_level(2);
514 new_params.set_search_branching(
515 SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH);
521 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
522 new_params.set_randomize_search(
true);
523 new_params.set_search_randomization_tolerance(
index);
524 *
name = absl::StrFormat(
"random_%i",
index);