46 const auto& variables =
49 if (variables.contains(
var)) {
63 const IntegerValue chosen_value =
64 var_lb +
std::max(IntegerValue(1), (var_ub - var_lb) / IntegerValue(2));
72 const IntegerValue ub = integer_trail->UpperBound(
var);
74 const absl::flat_hash_set<IntegerVariable>& variables =
82 const bool branch_down_feasible =
value >= lb &&
value < ub;
83 const bool branch_up_feasible =
value > lb &&
value <= ub;
84 if (variables.contains(
var) && branch_down_feasible) {
86 }
else if (variables.contains(
NegationOf(
var)) && branch_up_feasible) {
88 }
else if (branch_down_feasible) {
90 }
else if (branch_up_feasible) {
100 DCHECK(!integer_trail->IsCurrentlyIgnored(
var));
113 const IntegerValue
value = IntegerValue(
130 const int proto_var =
138 VLOG(2) <<
"Using solution value for branching.";
149 const std::vector<IntegerVariable>& vars,
Model*
model) {
151 return [ vars, integer_trail]() {
152 for (
const IntegerVariable
var : vars) {
154 if (integer_trail->IsCurrentlyIgnored(
var))
continue;
162 std::function<BooleanOrIntegerLiteral()>
164 const std::vector<IntegerVariable>& vars,
Model*
model) {
166 return [ vars, integer_trail]() {
168 IntegerValue candidate_lb;
169 for (
const IntegerVariable
var : vars) {
170 if (integer_trail->IsCurrentlyIgnored(
var))
continue;
171 const IntegerValue lb = integer_trail->LowerBound(
var);
185 return [heuristics]() {
186 for (
const auto& h : heuristics) {
188 if (decision.
HasValue())
return decision;
196 value_selection_heuristics,
204 if (!current_decision.
HasValue())
return current_decision;
208 for (
const auto& value_heuristic : value_selection_heuristics) {
213 return current_decision;
220 if (integer_trail->IsCurrentlyIgnored(l.var))
continue;
223 for (
const auto& value_heuristic : value_selection_heuristics) {
229 VLOG(2) <<
"Value selection: using default decision.";
230 return current_decision;
235 auto* lp_constraints =
237 int num_lp_variables = 0;
239 num_lp_variables += lp->NumVariables();
241 const int num_integer_variables =
243 return (num_integer_variables <= 2 * num_lp_variables);
250 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
252 value_selection_heuristics;
261 VLOG(1) <<
"Using LP value selection heuristic.";
262 value_selection_heuristics.push_back([
model](IntegerVariable
var) {
270 if (response_manager !=
nullptr) {
271 VLOG(1) <<
"Using best solution value selection heuristic.";
272 value_selection_heuristics.push_back(
273 [
model, response_manager](IntegerVariable
var) {
275 var, response_manager->SolutionsRepository(),
model);
281 if (
parameters.exploit_relaxation_solution()) {
285 value_selection_heuristics.push_back(
287 VLOG(1) <<
"Using relaxation solution value selection heuristic.";
296 VLOG(1) <<
"Using objective value selection heuristic.";
297 value_selection_heuristics.push_back([
model](IntegerVariable
var) {
303 var_selection_heuristic,
model);
310 return [sat_solver, trail, decision_policy] {
311 const bool all_assigned = trail->Index() == sat_solver->NumVariables();
313 const Literal result = decision_policy->NextBranch();
314 CHECK(!sat_solver->Assignment().LiteralIsAssigned(result));
321 const bool has_objective =
323 if (!has_objective) {
329 return [pseudo_costs, integer_trail]() {
330 const IntegerVariable chosen_var = pseudo_costs->GetBestDecisionVar();
350 std::discrete_distribution<int> var_dist{3 , 1 };
354 value_selection_heuristics;
355 std::vector<int> value_selection_weight;
358 value_selection_heuristics.push_back([
model](IntegerVariable
var) {
361 value_selection_weight.push_back(8);
365 if (response_manager !=
nullptr) {
366 value_selection_heuristics.push_back(
367 [
model, response_manager](IntegerVariable
var) {
369 var, response_manager->SolutionsRepository(),
model);
371 value_selection_weight.push_back(5);
377 value_selection_heuristics.push_back(
382 value_selection_weight.push_back(3);
387 value_selection_heuristics.push_back([integer_trail](IntegerVariable
var) {
390 value_selection_weight.push_back(1);
393 value_selection_heuristics.push_back([integer_trail](IntegerVariable
var) {
396 value_selection_weight.push_back(1);
399 value_selection_weight.push_back(10);
403 std::discrete_distribution<int> val_dist(value_selection_weight.begin(),
404 value_selection_weight.end());
406 int policy_index = 0;
407 int val_policy_index = 0;
409 return [=]()
mutable {
413 decision_policy->ResetDecisionHeuristic();
416 policy_index = var_dist(*(random));
419 val_policy_index = val_dist(*(random));
424 if (!current_decision.
HasValue())
return current_decision;
427 if (val_policy_index >= value_selection_heuristics.size()) {
428 return current_decision;
433 value_selection_heuristics[val_policy_index](
436 return current_decision;
442 if (integer_trail->IsCurrentlyIgnored(l.var))
continue;
446 value_selection_heuristics[val_policy_index](l.var);
451 return current_decision;
457 const std::vector<BooleanOrIntegerVariable>& vars,
458 const std::vector<IntegerValue>& values,
Model*
model) {
462 for (
int i = 0; i < vars.size(); ++i) {
463 const IntegerValue
value = values[i];
469 const IntegerVariable integer_var = vars[i].int_var;
470 if (integer_trail->IsCurrentlyIgnored(integer_var))
continue;
471 if (integer_trail->IsFixed(integer_var))
continue;
487 bool reset_at_next_call =
true;
488 int next_num_failures = 0;
489 return [=]()
mutable {
490 if (reset_at_next_call) {
492 reset_at_next_call =
false;
493 }
else if (solver->
num_failures() >= next_num_failures) {
494 reset_at_next_call =
true;
496 return reset_at_next_call;
507 std::function<BooleanOrIntegerLiteral()> WrapIntegerLiteralHeuristic(
508 std::function<IntegerLiteral()> f) {
509 return [f]() {
return BooleanOrIntegerLiteral(f()); };
521 const SatParameters&
parameters = *(
model->GetOrCreate<SatParameters>());
523 case SatParameters::AUTOMATIC_SEARCH: {
537 case SatParameters::FIXED_SEARCH: {
550 auto no_restart = []() {
return false; };
554 case SatParameters::HINT_SEARCH: {
559 auto no_restart = []() {
return false; };
563 case SatParameters::PORTFOLIO_SEARCH: {
569 for (
const auto&
ct :
571 base_heuristics.push_back(WrapIntegerLiteralHeuristic(
572 ct->HeuristicLpReducedCostBinary(
model)));
573 base_heuristics.push_back(WrapIntegerLiteralHeuristic(
574 ct->HeuristicLpMostInfeasibleBinary(
model)));
586 case SatParameters::LP_SEARCH: {
588 for (
const auto&
ct :
590 lp_heuristics.push_back(WrapIntegerLiteralHeuristic(
591 ct->HeuristicLpReducedCostAverageBranching()));
593 if (lp_heuristics.empty()) {
606 case SatParameters::PSEUDO_COST_SEARCH: {
615 case SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH: {
628 incomplete_heuristics,
631 complete_heuristics.reserve(incomplete_heuristics.size());
632 for (
const auto& incomplete : incomplete_heuristics) {
633 complete_heuristics.push_back(
636 return complete_heuristics;
652 if (objective !=
nullptr) objective_var = objective->
objective_var;
677 const SatParameters& sat_parameters = *(
model->GetOrCreate<SatParameters>());
681 const int64 conflict_limit = sat_parameters.max_number_of_conflicts();
682 int64 num_decisions_since_last_lp_record_ = 0;
683 int64 num_decisions_without_probing = 0;
685 (sat_solver->
num_failures() - old_num_conflicts < conflict_limit)) {
695 if (integer_trail->HasPendingRootLevelDeduction()) {
702 if (!implied_bounds->EnqueueNewDeductions()) {
706 auto* level_zero_callbacks =
708 for (
const auto& cb : level_zero_callbacks->callbacks) {
714 if (sat_parameters.use_sat_inprocessing() &&
723 if (integer_trail->InPropagationLoop()) {
724 const IntegerVariable
var =
725 integer_trail->NextVariableToBranchOnInPropagationLoop();
735 integer_trail->CurrentBranchHadAnIncompletePropagation()) {
736 const IntegerVariable
var = integer_trail->FirstUnassignedVariable();
741 if (!new_decision.
HasValue())
break;
761 VLOG(1) <<
"Trying to take a decision that is already assigned!"
762 <<
" Fix this. Continuing for now...";
768 sat_parameters.probing_period_at_root() > 0 &&
769 ++num_decisions_without_probing >=
770 sat_parameters.probing_period_at_root()) {
771 num_decisions_without_probing = 0;
801 if (
model->GetOrCreate<SatParameters>()->use_optimization_hints()) {
803 const auto& trail = *
model->GetOrCreate<
Trail>();
804 for (
int i = 0; i < trail.Index(); ++i) {
805 sat_decision->SetAssignmentPreference(trail[i], 0.0);
812 const std::vector<PseudoCosts::VariableBoundChange> bound_changes =
817 old_obj_lb = integer_trail->LowerBound(objective_var);
818 old_obj_ub = integer_trail->UpperBound(objective_var);
829 implied_bounds->ProcessIntegerTrail(
Literal(decision));
835 const IntegerValue new_obj_lb = integer_trail->LowerBound(objective_var);
836 const IntegerValue new_obj_ub = integer_trail->UpperBound(objective_var);
837 const IntegerValue objective_bound_change =
838 (new_obj_lb - old_obj_lb) + (old_obj_ub - new_obj_ub);
839 pseudo_costs->
UpdateCost(bound_changes, objective_bound_change);
856 num_decisions_since_last_lp_record_++;
857 if (num_decisions_since_last_lp_record_ >= 100) {
862 num_decisions_since_last_lp_record_ = 0;
866 return SatSolver::Status::LIMIT_REACHED;
870 const std::vector<Literal>& assumptions,
Model*
model) {
876 for (
const auto& cb : level_zero_callbacks->callbacks) {
888 const IntegerVariable num_vars =
890 std::vector<IntegerVariable> all_variables;
891 for (IntegerVariable
var(0);
var < num_vars; ++
var) {
892 all_variables.push_back(
var);