24#include "absl/cleanup/cleanup.h"
25#include "absl/container/btree_map.h"
26#include "absl/container/btree_set.h"
27#include "absl/container/flat_hash_set.h"
28#include "absl/log/check.h"
29#include "absl/strings/str_cat.h"
30#include "absl/strings/str_format.h"
31#include "absl/strings/string_view.h"
32#include "absl/types/span.h"
36#include "ortools/sat/boolean_problem.pb.h"
46#include "ortools/sat/sat_parameters.pb.h"
58 std::vector<Literal>* core) {
60 absl::btree_set<LiteralIndex> moved_last;
61 std::vector<Literal> candidate(core->begin(), core->end());
73 if (target_level == -1)
break;
92 moved_last.insert(candidate.back().Index());
97 if (candidate.size() < core->size()) {
98 VLOG(1) <<
"minimization with propag " << core->size() <<
" -> "
102 absl::flat_hash_set<LiteralIndex> set;
103 for (
const Literal l : candidate) set.insert(l.Index());
105 for (
const Literal l : *core) {
106 if (set.contains(l.Index())) {
107 (*core)[new_size++] = l;
110 core->resize(new_size);
115 std::vector<Literal>* core) {
119 if (core->size() > 100 || core->size() == 1)
return;
124 const int old_size = core->size();
125 std::vector<Literal> assumptions;
126 absl::flat_hash_set<LiteralIndex> removed_once;
136 for (
int i = core->size(); --
i >= 0;) {
138 const auto [_, inserted] = removed_once.insert(l.
Index());
144 if (to_remove == -1)
break;
147 for (
int i = 0;
i < core->size(); ++
i) {
148 if (
i == to_remove)
continue;
149 assumptions.push_back((*core)[
i]);
159 if (core->size() < old_size) {
160 VLOG(1) <<
"minimization with search " << old_size <<
" -> "
179 {assumption}, 1'000);
197 std::vector<Literal>* core) {
199 for (
const Literal lit : *core) {
206 (*core)[new_size++] = lit;
208 core->resize(new_size);
212 IntegerVariable objective_var,
213 const std::function<
void()>& feasible_solution_observer,
Model* model) {
217 const SatParameters& parameters = *(model->
GetOrCreate<SatParameters>());
226 const IntegerValue objective = integer_trail->LowerBound(objective_var);
229 if (feasible_solution_observer !=
nullptr) {
230 feasible_solution_observer();
232 if (parameters.stop_after_first_solution()) {
238 if (!integer_trail->Enqueue(
247 IntegerVariable objective_var,
248 const std::function<
void()>& feasible_solution_observer,
Model* model) {
249 const SatParameters old_params = *model->
GetOrCreate<SatParameters>();
256 SatParameters new_params = old_params;
257 new_params.set_max_number_of_conflicts(
258 old_params.binary_search_num_conflicts());
265 IntegerValue unknown_min = integer_trail->UpperBound(objective_var);
266 IntegerValue unknown_max = integer_trail->LowerBound(objective_var);
268 sat_solver->Backtrack(0);
269 const IntegerValue lb = integer_trail->LowerBound(objective_var);
270 const IntegerValue ub = integer_trail->UpperBound(objective_var);
271 unknown_min = std::min(unknown_min, ub);
272 unknown_max = std::max(unknown_max, lb);
276 if (lb < unknown_min) {
277 target = lb + (unknown_min - lb) / 2;
278 }
else if (unknown_max < ub) {
279 target = ub - (ub - unknown_max) / 2;
281 VLOG(1) <<
"Binary-search, done.";
284 VLOG(1) <<
"Binary-search, objective: [" << lb <<
"," << ub <<
"]"
285 <<
" tried: [" << unknown_min <<
"," << unknown_max <<
"]"
286 <<
" target: obj<=" << target;
289 const Literal assumption = integer_encoder->GetOrCreateAssociatedLiteral(
303 sat_solver->Backtrack(0);
304 if (!integer_trail->Enqueue(
313 const IntegerValue objective = integer_trail->LowerBound(objective_var);
314 if (feasible_solution_observer !=
nullptr) {
315 feasible_solution_observer();
320 sat_solver->Backtrack(0);
321 if (!integer_trail->Enqueue(
329 unknown_min = std::min(target, unknown_min);
330 unknown_max = std::max(target, unknown_max);
336 sat_solver->Backtrack(0);
364 std::vector<IntegerValue> assumption_weights,
365 IntegerValue stratified_threshold,
Model* model,
366 std::vector<std::vector<Literal>>* cores) {
368 SatSolver* sat_solver = model->GetOrCreate<SatSolver>();
376 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
377 if (sat_solver->parameters().core_minimization_level() > 0) {
380 if (core.size() == 1) {
381 if (!sat_solver->AddUnitClause(core[0].Negated())) {
385 if (core.empty())
return sat_solver->UnsatStatus();
386 cores->push_back(core);
387 if (!sat_solver->parameters().find_multiple_cores())
break;
391 std::vector<int> indices;
393 absl::btree_set<Literal> temp(core.begin(), core.end());
394 for (
int i = 0;
i < assumptions.size(); ++
i) {
395 if (temp.contains(assumptions[
i])) {
396 indices.push_back(
i);
406 IntegerValue min_weight = assumption_weights[indices.front()];
407 for (
const int i : indices) {
408 min_weight = std::min(min_weight, assumption_weights[
i]);
410 for (
const int i : indices) {
411 assumption_weights[
i] -= min_weight;
417 for (
int i = 0;
i < assumptions.size(); ++
i) {
418 if (assumption_weights[
i] < stratified_threshold)
continue;
419 assumptions[new_size] = assumptions[
i];
420 assumption_weights[new_size] = assumption_weights[
i];
423 assumptions.resize(new_size);
424 assumption_weights.resize(new_size);
425 }
while (!assumptions.empty());
432 IntegerVariable objective_var, absl::Span<const IntegerVariable> variables,
433 absl::Span<const IntegerValue> coefficients,
434 std::function<
void()> feasible_solution_observer,
Model* model)
435 : parameters_(model->GetOrCreate<SatParameters>()),
436 sat_solver_(model->GetOrCreate<
SatSolver>()),
438 time_limit_(model->GetOrCreate<
TimeLimit>()),
443 objective_var_(objective_var),
444 feasible_solution_observer_(
std::move(feasible_solution_observer)) {
445 CHECK_EQ(variables.size(), coefficients.size());
446 for (
int i = 0;
i < variables.size(); ++
i) {
447 if (coefficients[
i] > 0) {
448 terms_.push_back({variables[
i], coefficients[
i]});
449 }
else if (coefficients[
i] < 0) {
450 terms_.push_back({
NegationOf(variables[
i]), -coefficients[
i]});
454 terms_.back().depth = 0;
460 stratification_threshold_ = parameters_->max_sat_stratification() ==
461 SatParameters::STRATIFICATION_NONE
466bool CoreBasedOptimizer::ProcessSolution() {
469 IntegerValue objective(0);
470 for (ObjectiveTerm& term : terms_) {
471 const IntegerValue value = integer_trail_->
LowerBound(term.var);
472 objective += term.weight * value;
476 term.cover_ub = std::min(term.cover_ub, value);
486 if (feasible_solution_observer_ !=
nullptr) {
487 feasible_solution_observer_();
489 if (parameters_->stop_after_first_solution()) {
495 sat_solver_->Backtrack(0);
496 sat_solver_->SetAssumptionLevel(0);
497 return integer_trail_->Enqueue(
501bool CoreBasedOptimizer::PropagateObjectiveBounds() {
503 bool some_bound_were_tightened =
true;
504 while (some_bound_were_tightened) {
505 some_bound_were_tightened =
false;
506 if (!sat_solver_->ResetToLevelZero())
return false;
507 if (time_limit_->LimitReached())
return true;
510 IntegerValue implied_objective_lb(0);
511 for (ObjectiveTerm& term : terms_) {
512 const IntegerValue var_lb = integer_trail_->LowerBound(term.var);
513 term.old_var_lb = var_lb;
514 implied_objective_lb += term.weight * var_lb.value();
518 if (implied_objective_lb > integer_trail_->LowerBound(objective_var_)) {
520 objective_var_, implied_objective_lb),
525 some_bound_were_tightened =
true;
534 const IntegerValue gap =
535 integer_trail_->UpperBound(objective_var_) - implied_objective_lb;
537 for (
const ObjectiveTerm& term : terms_) {
538 if (term.weight == 0)
continue;
539 const IntegerValue var_lb = integer_trail_->LowerBound(term.var);
540 const IntegerValue var_ub = integer_trail_->UpperBound(term.var);
541 if (var_lb == var_ub)
continue;
548 if (gap / term.weight < var_ub - var_lb) {
549 some_bound_were_tightened =
true;
550 const IntegerValue new_ub = var_lb + gap / term.weight;
551 DCHECK_LT(new_ub, var_ub);
552 if (!integer_trail_->Enqueue(
571void CoreBasedOptimizer::ComputeNextStratificationThreshold() {
572 std::vector<IntegerValue> weights;
573 for (ObjectiveTerm& term : terms_) {
574 if (term.weight >= stratification_threshold_)
continue;
575 if (term.weight == 0)
continue;
577 const IntegerValue var_lb = integer_trail_->LevelZeroLowerBound(term.var);
578 const IntegerValue var_ub = integer_trail_->LevelZeroUpperBound(term.var);
579 if (var_lb == var_ub)
continue;
581 weights.push_back(term.weight);
583 if (weights.empty()) {
584 stratification_threshold_ = IntegerValue(0);
589 stratification_threshold_ =
590 weights[
static_cast<int>(std::floor(0.9 * weights.size()))];
593bool CoreBasedOptimizer::CoverOptimization() {
594 if (!sat_solver_->ResetToLevelZero())
return false;
598 constexpr double max_dtime_per_core = 0.5;
599 const double old_time_limit = parameters_->max_deterministic_time();
600 parameters_->set_max_deterministic_time(max_dtime_per_core);
601 auto cleanup = ::absl::MakeCleanup([old_time_limit,
this]() {
602 parameters_->set_max_deterministic_time(old_time_limit);
605 for (
const ObjectiveTerm& term : terms_) {
609 if (term.depth == 0)
continue;
615 const IntegerVariable var = term.var;
617 std::min(term.cover_ub, integer_trail_->UpperBound(var));
622 if (best <= integer_trail_->
LowerBound(var))
continue;
626 const double deterministic_limit =
627 time_limit_->GetElapsedDeterministicTime() + max_dtime_per_core;
631 while (best > integer_trail_->LowerBound(var)) {
632 const Literal assumption = integer_encoder_->GetOrCreateAssociatedLiteral(
637 best = integer_trail_->LowerBound(var);
638 VLOG(1) <<
"cover_opt var:" << var <<
" domain:["
639 << integer_trail_->LevelZeroLowerBound(var) <<
"," << best <<
"]";
640 if (!ProcessSolution())
return false;
641 if (!sat_solver_->ResetToLevelZero())
return false;
643 time_limit_->GetElapsedDeterministicTime() > deterministic_limit) {
649 if (!sat_solver_->ResetToLevelZero())
return false;
661 return PropagateObjectiveBounds();
665 absl::Span<const Literal> literals, absl::Span<const IntegerVariable> vars,
666 absl::Span<const Coefficient> coefficients, Coefficient offset) {
680 for (
int i = 0;
i < literals.size(); ++
i) {
681 CHECK_GT(coefficients[
i], 0);
687 CHECK_EQ(vars.size(), coefficients.size());
688 for (
int i = 0;
i < vars.size(); ++
i) {
689 CHECK_GT(coefficients[
i], 0);
690 const IntegerVariable var = vars[
i];
691 const IntegerValue var_lb = integer_trail_->LowerBound(var);
692 const IntegerValue var_ub = integer_trail_->UpperBound(var);
693 if (var_ub - var_lb == 1) {
694 const Literal lit = integer_encoder_->GetOrCreateAssociatedLiteral(
702 const int ub =
static_cast<int>(var_ub.value() - var_lb.value());
705 [var, var_lb,
this](
int x) {
706 return integer_encoder_->GetOrCreateAssociatedLiteral(
708 var_lb + IntegerValue(x + 1)));
717 Coefficient lower_bound(0);
720 Coefficient stratified_lower_bound(0);
721 if (parameters_->max_sat_stratification() !=
722 SatParameters::STRATIFICATION_NONE) {
724 stratified_lower_bound = std::max(stratified_lower_bound, n->weight());
730 std::string previous_core_info =
"";
731 for (
int iter = 0;;) {
738 const Coefficient upper_bound(
739 integer_trail_->UpperBound(objective_var_).value() - offset.value());
742 const IntegerValue new_obj_lb(lower_bound.value() + offset.value());
743 if (new_obj_lb > integer_trail_->LowerBound(objective_var_)) {
744 if (!integer_trail_->Enqueue(
753 const int num_bools = sat_solver_->NumVariables();
754 const int num_fixed = sat_solver_->NumFixedVariables();
756 absl::StrFormat(
"bool_%s (num_cores=%d [%s] a=%u d=%d "
757 "fixed=%d/%d clauses=%s)",
758 model_->Name(), iter, previous_core_info,
759 encoder.
nodes().size(), max_depth, num_fixed,
761 new_obj_lb, integer_trail_->LevelZeroUpperBound(objective_var_));
764 if (parameters_->cover_optimization() && encoder.
nodes().size() > 1) {
768 previous_core_info =
"cover";
776 const Coefficient gap = upper_bound - lower_bound;
777 if (stratified_lower_bound > (gap + 2) / 2) {
778 stratified_lower_bound = (gap + 2) / 2;
780 std::vector<Literal> assumptions;
784 if (!assumptions.empty())
break;
786 stratified_lower_bound =
788 if (stratified_lower_bound > 0)
continue;
794 VLOG(2) <<
"[Core] #nodes " << encoder.
nodes().size()
795 <<
" #assumptions:" << assumptions.size()
796 <<
" stratification:" << stratified_lower_bound <<
" gap:" << gap;
815 stratified_lower_bound =
817 if (stratified_lower_bound > 0)
continue;
823 std::vector<Literal> core = sat_solver_->GetLastIncompatibleDecisions();
824 if (parameters_->core_minimization_level() > 0) {
827 if (parameters_->core_minimization_level() > 1) {
838 absl::StrFormat(
"size:%u mw:%d", core.size(), min_weight.value());
842 if (!encoder.
ProcessCore(core, min_weight, gap, &previous_core_info)) {
845 max_depth = std::max(max_depth, encoder.
nodes().back()->depth());
852 std::vector<Coefficient>* coefficients,
853 Coefficient* offset) {
855 std::vector<std::pair<LiteralIndex, Coefficient>> pairs;
856 const int size = literals->size();
857 for (
int i = 0;
i < size; ++
i) {
858 pairs.push_back({(*literals)[
i].Index(), (*coefficients)[
i]});
860 std::sort(pairs.begin(), pairs.end());
864 for (
const auto& [index, coeff] : pairs) {
866 if (pairs[new_size - 1].first == index) {
867 pairs[new_size - 1].second += coeff;
869 }
else if (pairs[new_size - 1].first ==
Literal(index).NegatedIndex()) {
871 pairs[new_size - 1].second -= coeff;
876 pairs[new_size++] = {index, coeff};
878 pairs.resize(new_size);
882 coefficients->clear();
883 for (
const auto& [index, coeff] : pairs) {
885 literals->push_back(
Literal(index));
886 coefficients->push_back(coeff);
887 }
else if (coeff < 0) {
890 literals->push_back(
Literal(index).Negated());
891 coefficients->push_back(-coeff);
896void CoreBasedOptimizer::PresolveObjectiveWithAtMostOne(
897 std::vector<Literal>* literals, std::vector<Coefficient>* coefficients,
898 Coefficient* offset) {
916 std::vector<Literal> candidates;
917 const int num_terms = literals->size();
918 for (
int i = 0;
i < num_terms; ++
i) {
919 const Literal lit = (*literals)[
i];
920 const Coefficient coeff = (*coefficients)[
i];
925 weights[lit] = coeff;
927 candidates.push_back(lit.Negated());
928 is_candidate[lit.NegatedIndex()] =
true;
931 int num_at_most_ones = 0;
932 Coefficient overall_lb_increase(0);
934 std::vector<Literal> at_most_one;
935 std::vector<std::pair<Literal, Coefficient>> new_obj_terms;
937 for (
const Literal root : candidates) {
938 if (weights[root.NegatedIndex()] == 0)
continue;
939 if (implications_->
WorkDone() > 1e8)
continue;
942 CHECK_EQ(weights[root], 0);
948 {root}, is_candidate, preferences);
949 if (at_most_one.size() <= 1)
continue;
955 Coefficient max_coeff(0);
956 Coefficient lb_increase(0);
957 for (
const Literal lit : at_most_one) {
958 const Coefficient coeff = weights[lit.NegatedIndex()];
959 lb_increase += coeff;
960 max_coeff = std::max(max_coeff, coeff);
962 lb_increase -= max_coeff;
964 *offset += lb_increase;
965 overall_lb_increase += lb_increase;
967 for (
const Literal lit : at_most_one) {
968 is_candidate[lit] =
false;
969 const Coefficient new_weight = max_coeff - weights[lit.NegatedIndex()];
970 CHECK_EQ(weights[lit], 0);
971 weights[lit] = new_weight;
972 weights[lit.NegatedIndex()] = 0;
973 if (new_weight > 0) {
977 is_candidate[lit.NegatedIndex()] =
true;
982 const Literal new_lit(sat_solver_->NewBooleanVariable(),
true);
983 new_obj_terms.push_back({new_lit, max_coeff});
986 at_most_one.push_back(new_lit);
987 sat_solver_->AddProblemClause(at_most_one);
988 is_candidate.resize(implications_->literal_size(),
false);
989 preferences.
resize(implications_->literal_size(), 1.0);
992 if (overall_lb_increase > 0) {
994 model_->GetOrCreate<SharedResponseManager>()->UpdateInnerObjectiveBounds(
995 absl::StrFormat(
"am1_presolve (num_literals=%d num_am1=%d "
996 "increase=%lld work_done=%lld)",
997 (
int)candidates.size(), num_at_most_ones,
998 overall_lb_increase.value(), implications_->WorkDone()),
999 IntegerValue(offset->value()),
1000 integer_trail_->LevelZeroUpperBound(objective_var_));
1005 coefficients->clear();
1006 for (
const Literal root : candidates) {
1007 if (weights[root] > 0) {
1008 CHECK_EQ(weights[root.NegatedIndex()], 0);
1009 literals->push_back(root);
1010 coefficients->push_back(weights[root]);
1012 if (weights[root.NegatedIndex()] > 0) {
1013 CHECK_EQ(weights[root], 0);
1014 literals->push_back(root.Negated());
1015 coefficients->push_back(weights[root.NegatedIndex()]);
1018 for (
const auto& [lit, coeff] : new_obj_terms) {
1019 literals->push_back(lit);
1020 coefficients->push_back(coeff);
1029 if (!parameters_->interleave_search()) {
1030 Coefficient offset(0);
1031 std::vector<Literal> literals;
1032 std::vector<IntegerVariable> vars;
1033 std::vector<Coefficient> coefficients;
1034 bool all_booleans =
true;
1035 IntegerValue range(0);
1036 for (
const ObjectiveTerm& term : terms_) {
1037 const IntegerVariable var = term.var;
1038 const IntegerValue coeff = term.weight;
1039 const IntegerValue lb = integer_trail_->LowerBound(var);
1040 const IntegerValue ub = integer_trail_->UpperBound(var);
1041 offset += Coefficient((lb * coeff).value());
1042 if (lb == ub)
continue;
1044 vars.push_back(var);
1045 coefficients.push_back(Coefficient(coeff.value()));
1047 literals.push_back(integer_encoder_->GetOrCreateAssociatedLiteral(
1050 all_booleans =
false;
1069 PresolveObjectiveWithAtMostOne(&literals, &coefficients, &offset);
1081 absl::btree_map<LiteralIndex, int> literal_to_term_index;
1095 if (parameters_->cover_optimization()) {
1101 std::vector<int> term_indices;
1102 std::vector<IntegerLiteral> integer_assumptions;
1103 std::vector<IntegerValue> assumption_weights;
1104 IntegerValue objective_offset(0);
1105 bool some_assumptions_were_skipped =
false;
1106 for (
int i = 0;
i < terms_.size(); ++
i) {
1107 const ObjectiveTerm term = terms_[
i];
1110 if (term.weight == 0)
continue;
1116 const IntegerValue var_lb = integer_trail_->LowerBound(term.var);
1117 const IntegerValue var_ub = integer_trail_->UpperBound(term.var);
1118 if (var_lb == var_ub) {
1119 objective_offset += term.weight * var_lb.value();
1124 if (term.weight >= stratification_threshold_) {
1125 integer_assumptions.push_back(
1127 assumption_weights.push_back(term.weight);
1128 term_indices.push_back(
i);
1130 some_assumptions_were_skipped =
true;
1135 if (term_indices.empty() && some_assumptions_were_skipped) {
1136 ComputeNextStratificationThreshold();
1141 if (term_indices.size() <= 2 && !some_assumptions_were_skipped) {
1142 VLOG(1) <<
"Switching to linear scan...";
1143 if (!already_switched_to_linear_scan_) {
1144 already_switched_to_linear_scan_ =
true;
1145 std::vector<IntegerVariable> constraint_vars;
1146 std::vector<int64_t> constraint_coeffs;
1147 for (
const int index : term_indices) {
1148 constraint_vars.push_back(terms_[index].var);
1149 constraint_coeffs.push_back(terms_[index].weight.value());
1151 constraint_vars.push_back(objective_var_);
1152 constraint_coeffs.push_back(-1);
1154 -objective_offset.value()));
1158 objective_var_, feasible_solution_observer_, model_);
1162 if (VLOG_IS_ON(1)) {
1164 for (
const ObjectiveTerm& term : terms_) {
1165 max_depth = std::max(max_depth, term.depth);
1167 const int64_t lb = integer_trail_->LowerBound(objective_var_).value();
1168 const int64_t ub = integer_trail_->UpperBound(objective_var_).value();
1172 :
static_cast<int>(std::ceil(
1173 100.0 * (ub - lb) / std::max(std::abs(ub), std::abs(lb))));
1174 VLOG(1) << absl::StrCat(
"unscaled_next_obj_range:[", lb,
",", ub,
1177 gap,
"%",
" assumptions:", term_indices.size(),
1178 " strat:", stratification_threshold_.value(),
1179 " depth:", max_depth,
1180 " bool: ", sat_solver_->NumVariables());
1184 std::vector<Literal> assumptions;
1185 literal_to_term_index.clear();
1186 for (
int i = 0;
i < integer_assumptions.size(); ++
i) {
1187 assumptions.push_back(integer_encoder_->GetOrCreateAssociatedLiteral(
1188 integer_assumptions[
i]));
1196 literal_to_term_index[assumptions.back()] = term_indices[
i];
1204 std::vector<std::vector<Literal>> cores;
1206 FindCores(assumptions, assumption_weights, stratification_threshold_,
1212 if (cores.empty()) {
1213 ComputeNextStratificationThreshold();
1222 for (
const std::vector<Literal>& core : cores) {
1225 if (core.size() == 1) {
1226 if (!sat_solver_->AddUnitClause(core[0].Negated())) {
1235 bool ignore_this_core =
false;
1237 IntegerValue max_weight(0);
1238 IntegerValue new_var_lb(1);
1239 IntegerValue new_var_ub(0);
1241 for (
const Literal lit : core) {
1242 const int index = literal_to_term_index.at(lit.Index());
1246 if (terms_[index].old_var_lb <
1247 integer_trail_->LowerBound(terms_[index].var)) {
1248 ignore_this_core =
true;
1252 const IntegerValue weight = terms_[index].weight;
1253 min_weight = std::min(min_weight, weight);
1254 max_weight = std::max(max_weight, weight);
1255 new_depth = std::max(new_depth, terms_[index].depth + 1);
1256 new_var_lb += integer_trail_->LowerBound(terms_[index].var);
1257 new_var_ub += integer_trail_->UpperBound(terms_[index].var);
1259 if (ignore_this_core)
continue;
1261 VLOG(1) << absl::StrFormat(
1262 "core:%u weight:[%d,%d] domain:[%d,%d] depth:%d", core.size(),
1263 min_weight.value(), max_weight.value(), new_var_lb.value(),
1264 new_var_ub.value(), new_depth);
1268 const IntegerVariable new_var =
1269 integer_trail_->AddIntegerVariable(new_var_lb, new_var_ub);
1270 terms_.push_back({new_var, min_weight, new_depth});
1271 terms_.back().cover_ub = new_var_ub;
1275 std::vector<IntegerVariable> constraint_vars;
1276 std::vector<int64_t> constraint_coeffs;
1277 for (
const Literal lit : core) {
1278 const int index = literal_to_term_index.at(lit.Index());
1279 terms_[index].weight -= min_weight;
1280 constraint_vars.push_back(terms_[index].var);
1281 constraint_coeffs.push_back(1);
1283 constraint_vars.push_back(new_var);
1284 constraint_coeffs.push_back(-1);
bool Contains(int64_t value) const
void EnableLogging(bool enable)
bool LoggingIsEnabled() const
Returns true iff logging is enabled.
std::vector< Literal > ExpandAtMostOneWithWeight(absl::Span< const Literal > at_most_one, const util_intops::StrongVector< LiteralIndex, bool > &can_be_included, const util_intops::StrongVector< LiteralIndex, double > &expanded_lp_values)
Same as ExpandAtMostOne() but try to maximize the weight in the clique.
int64_t literal_size() const
SatSolver::Status OptimizeWithSatEncoding(absl::Span< const Literal > literals, absl::Span< const IntegerVariable > vars, absl::Span< const Coefficient > coefficients, Coefficient offset)
SatSolver::Status Optimize()
CoreBasedOptimizer(IntegerVariable objective_var, absl::Span< const IntegerVariable > variables, absl::Span< const IntegerValue > coefficients, std::function< void()> feasible_solution_observer, Model *model)
static EncodingNode GenericNode(int lb, int ub, std::function< Literal(int x)> create_lit, Coefficient weight)
static EncodingNode LiteralNode(Literal l, Coefficient weight)
An helper class to share the code used by the different kind of search.
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
const Domain & InitialVariableDomain(IntegerVariable var) const
LiteralIndex Index() const
std::vector< EncodingNode * > * mutable_nodes()
void AddBaseNode(EncodingNode node)
const std::vector< EncodingNode * > & nodes() const
bool ProcessCore(absl::Span< const Literal > core, Coefficient min_weight, Coefficient gap, std::string *info)
Status EnqueueDecisionAndBacktrackOnConflict(Literal true_literal, int *first_propagation_index=nullptr)
SolverLogger * mutable_logger()
Hack to allow to temporarily disable logging if it is enabled.
void NotifyThatModelIsUnsat()
std::vector< Literal > GetLastIncompatibleDecisions()
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
bool ModelIsUnsat() const
void Backtrack(int target_level)
ABSL_MUST_USE_RESULT bool Propagate()
void SetAssumptionLevel(int assumption_level)
ABSL_MUST_USE_RESULT bool AddUnitClause(Literal true_literal)
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions, int64_t max_number_of_conflicts=-1)
const VariablesAssignment & Assignment() const
int CurrentDecisionLevel() const
ABSL_MUST_USE_RESULT bool ResetToLevelZero()
ABSL_MUST_USE_RESULT bool FinishPropagation()
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
void resize(size_type new_size)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::vector< Literal > ExtractAssumptions(Coefficient stratified_lower_bound, const std::vector< EncodingNode * > &nodes, SatSolver *solver)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Returns the vector of the negated variables.
void ReduceNodes(Coefficient upper_bound, Coefficient *lower_bound, std::vector< EncodingNode * > *nodes, SatSolver *solver)
void MinimizeCoreWithPropagation(TimeLimit *limit, SatSolver *solver, std::vector< Literal > *core)
void FilterAssignedLiteral(const VariablesAssignment &assignment, std::vector< Literal > *core)
A core cannot be all true.
Coefficient ComputeCoreMinWeight(const std::vector< EncodingNode * > &nodes, absl::Span< const Literal > core)
void MinimizeCoreWithSearch(TimeLimit *limit, SatSolver *solver, std::vector< Literal > *core)
void PresolveBooleanLinearExpression(std::vector< Literal > *literals, std::vector< Coefficient > *coefficients, Coefficient *offset)
std::string FormatCounter(int64_t num)
Prints a positive number with separators for easier reading (ex: 1'348'065).
bool ProbeLiteral(Literal assumption, SatSolver *solver)
SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
int MoveOneUnprocessedLiteralLast(const absl::btree_set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
SatSolver::Status ResetAndSolveIntegerProblem(const std::vector< Literal > &assumptions, Model *model)
void RestrictObjectiveDomainWithBinarySearch(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
Coefficient MaxNodeWeightSmallerThan(const std::vector< EncodingNode * > &nodes, Coefficient upper_bound)
std::function< void(Model *)> WeightedSumLowerOrEqual(absl::Span< const IntegerVariable > vars, const VectorInt &coefficients, int64_t upper_bound)
Weighted sum <= constant.
In SWIG mode, we don't want anything besides these top-level includes.
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)