28 #include "absl/random/random.h" 29 #include "absl/strings/str_cat.h" 30 #include "absl/strings/str_format.h" 38 #if !defined(__PORTABLE_PLATFORM__) && defined(USE_SCIP) 41 #endif // __PORTABLE_PLATFORM__ 62 void Log(
const std::string&
message) {
76 std::string CnfObjectiveLine(
const LinearBooleanProblem& problem,
78 const double scaled_objective =
80 return absl::StrFormat(
"o %d", static_cast<int64_t>(scaled_objective));
83 struct LiteralWithCoreIndex {
92 template <
typename Vector>
93 void DeleteVectorIndices(
const std::vector<int>& indices, Vector* v) {
95 int indices_index = 0;
96 for (
int i = 0; i < v->size(); ++i) {
97 if (indices_index < indices.size() && i == indices[indices_index]) {
100 (*v)[new_size] = (*v)[i];
136 class FuMalikSymmetryBreaker {
138 FuMalikSymmetryBreaker() {}
141 void StartResolvingNewCore(
int new_core_index) {
142 literal_by_core_.resize(new_core_index);
143 for (
int i = 0; i < new_core_index; ++i) {
144 literal_by_core_[i].clear();
158 std::vector<Literal> ProcessLiteral(
int assumption_index, Literal
b) {
159 if (assumption_index >= info_by_assumption_index_.size()) {
160 info_by_assumption_index_.resize(assumption_index + 1);
167 std::vector<Literal> result;
168 for (LiteralWithCoreIndex data :
169 info_by_assumption_index_[assumption_index]) {
176 result.insert(result.end(), literal_by_core_[data.core_index].begin(),
177 literal_by_core_[data.core_index].end());
181 for (LiteralWithCoreIndex data :
182 info_by_assumption_index_[assumption_index]) {
183 literal_by_core_[data.core_index].push_back(data.literal);
185 info_by_assumption_index_[assumption_index].push_back(
186 LiteralWithCoreIndex(
b, literal_by_core_.size()));
191 void DeleteIndices(
const std::vector<int>& indices) {
192 DeleteVectorIndices(indices, &info_by_assumption_index_);
197 void ClearInfo(
int assumption_index) {
198 CHECK_LE(assumption_index, info_by_assumption_index_.size());
199 info_by_assumption_index_[assumption_index].clear();
203 void AddInfo(
int assumption_index, Literal
b) {
204 CHECK_GE(assumption_index, info_by_assumption_index_.size());
205 info_by_assumption_index_.resize(assumption_index + 1);
206 info_by_assumption_index_[assumption_index].push_back(
207 LiteralWithCoreIndex(
b, literal_by_core_.size()));
211 std::vector<std::vector<LiteralWithCoreIndex>> info_by_assumption_index_;
212 std::vector<std::vector<Literal>> literal_by_core_;
220 std::vector<Literal>* core) {
222 std::set<LiteralIndex> moved_last;
223 std::vector<Literal> candidate(core->begin(), core->end());
235 if (target_level == -1)
break;
253 if (candidate.empty() || solver->
IsModelUnsat())
return;
254 moved_last.insert(candidate.back().Index());
259 if (candidate.size() < core->size()) {
260 VLOG(1) <<
"minimization " << core->size() <<
" -> " << candidate.size();
261 core->assign(candidate.begin(), candidate.end());
273 std::vector<bool>* solution) {
275 FuMalikSymmetryBreaker symmetry;
296 std::vector<std::vector<Literal>> blocking_clauses;
297 std::vector<Literal> assumptions;
305 <<
"The basic Fu & Malik algorithm needs constant objective coeffs.";
311 blocking_clauses.push_back(std::vector<Literal>(1, min_literal));
314 assumptions.push_back(min_literal);
318 logger.Log(absl::StrFormat(
"c #weights:%u #vars:%d #constraints:%d",
327 for (
int iter = 0;; ++iter) {
333 logger.Log(CnfObjectiveLine(problem, objective));
349 logger.Log(absl::StrFormat(
"c iter:%d core:%u", iter, core.size()));
352 if (core.size() == 1) {
356 std::find(assumptions.begin(), assumptions.end(), core[0]) -
369 std::vector<int> to_delete(1,
index);
370 DeleteVectorIndices(to_delete, &assumptions);
371 DeleteVectorIndices(to_delete, &blocking_clauses);
372 symmetry.DeleteIndices(to_delete);
374 symmetry.StartResolvingNewCore(iter);
378 if (core.size() == 2) {
388 std::vector<LiteralWithCoeff> at_most_one_constraint;
389 std::vector<Literal> at_least_one_constraint;
397 for (
int i = 0; i < core.size(); ++i) {
402 std::find(assumptions.begin() +
index, assumptions.end(), core[i]) -
407 const Literal a(BooleanVariable(old_num_variables + i),
true);
408 Literal b(BooleanVariable(old_num_variables + core.size() + i),
true);
409 if (core.size() == 2) {
410 b =
Literal(BooleanVariable(old_num_variables + 2),
true);
411 if (i == 1)
b =
b.Negated();
431 blocking_clauses[
index].push_back(
b);
435 blocking_clauses[
index].push_back(
a);
437 blocking_clauses[
index].pop_back();
441 at_least_one_constraint.push_back(
b);
444 assumptions[
index] =
a.Negated();
450 &at_most_one_constraint);
460 LOG(
INFO) <<
"Infeasible while adding a clause.";
470 std::vector<bool>* solution) {
472 FuMalikSymmetryBreaker symmetry;
480 std::vector<Literal> assumptions;
481 std::vector<Coefficient> costs;
482 std::vector<Literal> reference;
495 costs.push_back(coeff);
497 assumptions.push_back(
literal);
498 costs.push_back(-coeff);
502 reference = assumptions;
506 *std::max_element(costs.begin(), costs.end());
509 logger.Log(absl::StrFormat(
"c #weights:%u #vars:%d #constraints:%d",
513 for (
int iter = 0;; ++iter) {
521 std::vector<int> to_delete;
522 int num_above_threshold = 0;
523 for (
int i = 0; i < assumptions.size(); ++i) {
524 if (costs[i] > hardening_threshold) {
528 to_delete.push_back(i);
529 ++num_above_threshold;
533 to_delete.push_back(i);
537 if (!to_delete.empty()) {
538 logger.Log(absl::StrFormat(
"c fixed %u assumptions, %d with cost > %d",
539 to_delete.size(), num_above_threshold,
540 hardening_threshold.value()));
541 DeleteVectorIndices(to_delete, &assumptions);
542 DeleteVectorIndices(to_delete, &costs);
543 DeleteVectorIndices(to_delete, &reference);
544 symmetry.DeleteIndices(to_delete);
549 std::vector<Literal> assumptions_subset;
550 for (
int i = 0; i < assumptions.size(); ++i) {
551 if (costs[i] >= stratified_lower_bound) {
552 assumptions_subset.push_back(assumptions[i]);
564 const Coefficient old_lower_bound = stratified_lower_bound;
566 if (
cost < old_lower_bound) {
567 if (stratified_lower_bound == old_lower_bound ||
568 cost > stratified_lower_bound) {
569 stratified_lower_bound =
cost;
580 logger.Log(CnfObjectiveLine(problem, objective));
584 if (stratified_lower_bound < old_lower_bound)
continue;
604 for (
int i = 0; i < core.size(); ++i) {
606 std::find(assumptions.begin() +
index, assumptions.end(), core[i]) -
615 logger.Log(absl::StrFormat(
616 "c iter:%d core:%u lb:%d min_cost:%d strat:%d", iter, core.size(),
617 lower_bound.value(), min_cost.value(), stratified_lower_bound.value()));
623 if (min_cost > stratified_lower_bound) {
624 stratified_lower_bound = min_cost;
628 if (core.size() == 1) {
632 std::find(assumptions.begin(), assumptions.end(), core[0]) -
642 std::vector<int> to_delete(1,
index);
643 DeleteVectorIndices(to_delete, &assumptions);
644 DeleteVectorIndices(to_delete, &costs);
645 DeleteVectorIndices(to_delete, &reference);
646 symmetry.DeleteIndices(to_delete);
648 symmetry.StartResolvingNewCore(iter);
652 if (core.size() == 2) {
662 std::vector<LiteralWithCoeff> at_most_one_constraint;
663 std::vector<Literal> at_least_one_constraint;
671 for (
int i = 0; i < core.size(); ++i) {
676 std::find(assumptions.begin() +
index, assumptions.end(), core[i]) -
681 const Literal a(BooleanVariable(old_num_variables + i),
true);
682 Literal b(BooleanVariable(old_num_variables + core.size() + i),
true);
683 if (core.size() == 2) {
684 b =
Literal(BooleanVariable(old_num_variables + 2),
true);
685 if (i == 1)
b =
b.Negated();
707 if (costs[
index] == min_cost) {
709 assumptions[
index] =
a.Negated();
719 symmetry.AddInfo(assumptions.size(),
b);
720 symmetry.ClearInfo(
index);
723 costs[
index] -= min_cost;
731 assumptions.push_back(
a.Negated());
732 costs.push_back(min_cost);
733 reference.push_back(reference[
index]);
745 at_least_one_constraint.push_back(reference[
index].Negated());
751 &at_most_one_constraint);
757 LOG(
INFO) <<
"Unsat while adding a clause.";
767 std::vector<bool>* solution) {
777 int max_number_of_conflicts = 5;
783 for (
int i = 0; i < num_times; ++i) {
793 const bool use_obj = absl::Bernoulli(random, 1.0 / 4);
812 std::vector<bool> candidate;
816 if (objective < best) {
817 *solution = candidate;
819 logger.Log(CnfObjectiveLine(problem, objective));
824 objective - 1, solver)) {
828 min_seen =
std::min(min_seen, objective);
829 max_seen =
std::max(max_seen, objective);
831 logger.Log(absl::StrCat(
832 "c ", objective.value(),
" [", min_seen.value(),
", ", max_seen.value(),
833 "] objective_preference: ", use_obj ?
"true" :
"false",
" ",
847 std::vector<bool>* solution) {
854 if (!solution->empty()) {
863 objective - 1, solver)) {
886 logger.Log(CnfObjectiveLine(problem, objective));
892 std::vector<bool>* solution) {
894 std::deque<EncodingNode> repository;
898 std::vector<EncodingNode*>
nodes =
909 if (!solution->empty()) {
916 logger.Log(absl::StrFormat(
"c #weights:%u #vars:%d #constraints:%d",
924 logger.Log(absl::StrFormat(
"c encoding depth:%d", root->
depth()));
930 const int index = offset.value() + objective.value();
954 logger.Log(CnfObjectiveLine(problem, objective));
960 std::vector<bool>* solution) {
966 std::deque<EncodingNode> repository;
967 std::vector<EncodingNode*>
nodes =
974 if (!solution->empty()) {
980 logger.Log(absl::StrFormat(
"c #weights:%u #vars:%d #constraints:%d",
990 stratified_lower_bound =
std::max(stratified_lower_bound, n->weight());
996 std::string previous_core_info =
"";
997 for (
int iter = 0;; ++iter) {
1003 const std::string gap_string =
1008 absl::StrFormat(
"c iter:%d [%s] lb:%d%s assumptions:%u depth:%d", iter,
1012 gap_string,
nodes.size(), max_depth));
1019 std::vector<bool> temp_solution;
1024 *solution = temp_solution;
1025 logger.Log(CnfObjectiveLine(problem, obj));
1031 stratified_lower_bound =
1033 if (stratified_lower_bound > 0)
continue;
1045 previous_core_info =
1046 absl::StrFormat(
"core:%u mw:%d", core.size(), min_weight.value());
1049 if (stratified_lower_bound < min_weight &&
1052 stratified_lower_bound = min_weight;
1061 IntegerVariable objective_var,
1062 const std::function<
void()>& feasible_solution_observer,
Model*
model) {
1073 const IntegerValue objective = integer_trail->LowerBound(objective_var);
1076 if (feasible_solution_observer !=
nullptr) {
1077 feasible_solution_observer();
1085 if (!integer_trail->Enqueue(
1094 IntegerVariable objective_var,
1095 const std::function<
void()>& feasible_solution_observer,
Model*
model) {
1112 IntegerValue unknown_min = integer_trail->UpperBound(objective_var);
1113 IntegerValue unknown_max = integer_trail->LowerBound(objective_var);
1115 sat_solver->Backtrack(0);
1116 const IntegerValue lb = integer_trail->LowerBound(objective_var);
1117 const IntegerValue ub = integer_trail->UpperBound(objective_var);
1118 unknown_min =
std::min(unknown_min, ub);
1119 unknown_max =
std::max(unknown_max, lb);
1122 IntegerValue target;
1123 if (lb < unknown_min) {
1124 target = lb + (unknown_min - lb) / 2;
1125 }
else if (unknown_max < ub) {
1126 target = ub - (ub - unknown_max) / 2;
1128 VLOG(1) <<
"Binary-search, done.";
1131 VLOG(1) <<
"Binary-search, objective: [" << lb <<
"," << ub <<
"]" 1132 <<
" tried: [" << unknown_min <<
"," << unknown_max <<
"]" 1133 <<
" target: obj<=" << target;
1136 const Literal assumption = integer_encoder->GetOrCreateAssociatedLiteral(
1150 sat_solver->Backtrack(0);
1151 if (!integer_trail->Enqueue(
1160 const IntegerValue objective = integer_trail->LowerBound(objective_var);
1161 if (feasible_solution_observer !=
nullptr) {
1162 feasible_solution_observer();
1167 sat_solver->Backtrack(0);
1168 if (!integer_trail->Enqueue(
1176 unknown_min =
std::min(target, unknown_min);
1177 unknown_max =
std::max(target, unknown_max);
1183 sat_solver->Backtrack(0);
1211 std::vector<IntegerValue> assumption_weights,
1212 IntegerValue stratified_threshold, Model*
model,
1213 std::vector<std::vector<Literal>>* cores) {
1215 SatSolver* sat_solver =
model->GetOrCreate<SatSolver>();
1223 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1224 if (sat_solver->parameters().minimize_core()) {
1227 if (core.empty())
return sat_solver->UnsatStatus();
1228 cores->push_back(core);
1229 if (!sat_solver->parameters().find_multiple_cores())
break;
1233 std::vector<int> indices;
1235 std::set<Literal> temp(core.begin(), core.end());
1236 for (
int i = 0; i < assumptions.size(); ++i) {
1238 indices.push_back(i);
1248 IntegerValue min_weight = assumption_weights[indices.front()];
1249 for (
const int i : indices) {
1250 min_weight =
std::min(min_weight, assumption_weights[i]);
1252 for (
const int i : indices) {
1253 assumption_weights[i] -= min_weight;
1259 for (
int i = 0; i < assumptions.size(); ++i) {
1260 if (assumption_weights[i] < stratified_threshold)
continue;
1261 assumptions[new_size] = assumptions[i];
1262 assumption_weights[new_size] = assumption_weights[i];
1265 assumptions.resize(new_size);
1266 assumption_weights.resize(new_size);
1267 }
while (!assumptions.empty());
1274 std::vector<Literal> assumptions, Model*
model,
1275 std::vector<std::vector<Literal>>* cores) {
1277 SatSolver* sat_solver =
model->GetOrCreate<SatSolver>();
1278 TimeLimit* limit =
model->GetOrCreate<TimeLimit>();
1285 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1286 if (sat_solver->parameters().minimize_core()) {
1289 CHECK(!core.empty());
1290 cores->push_back(core);
1291 if (!sat_solver->parameters().find_multiple_cores())
break;
1295 CHECK(!core.empty());
1296 auto* random =
model->GetOrCreate<ModelRandomGenerator>();
1297 const Literal random_literal =
1298 core[absl::Uniform<int>(*random, 0, core.size())];
1299 for (
int i = 0; i < assumptions.size(); ++i) {
1300 if (assumptions[i] == random_literal) {
1301 std::swap(assumptions[i], assumptions.back());
1302 assumptions.pop_back();
1306 }
while (!assumptions.empty());
1313 IntegerVariable objective_var,
1314 const std::vector<IntegerVariable>& variables,
1316 std::function<
void()> feasible_solution_observer,
Model*
model)
1323 objective_var_(objective_var),
1324 feasible_solution_observer_(std::move(feasible_solution_observer)) {
1326 for (
int i = 0; i < variables.size(); ++i) {
1334 terms_.back().depth = 0;
1346 bool CoreBasedOptimizer::ProcessSolution() {
1349 IntegerValue objective(0);
1350 for (ObjectiveTerm& term : terms_) {
1352 objective += term.weight *
value;
1367 if (feasible_solution_observer_ !=
nullptr) {
1368 feasible_solution_observer_();
1378 return integer_trail_->
Enqueue(
1382 bool CoreBasedOptimizer::PropagateObjectiveBounds() {
1384 bool some_bound_were_tightened =
true;
1385 while (some_bound_were_tightened) {
1386 some_bound_were_tightened =
false;
1390 IntegerValue implied_objective_lb(0);
1391 for (ObjectiveTerm& term : terms_) {
1392 const IntegerValue var_lb = integer_trail_->
LowerBound(term.var);
1393 term.old_var_lb = var_lb;
1394 implied_objective_lb += term.weight * var_lb.value();
1398 if (implied_objective_lb > integer_trail_->
LowerBound(objective_var_)) {
1400 objective_var_, implied_objective_lb),
1405 some_bound_were_tightened =
true;
1414 const IntegerValue gap =
1415 integer_trail_->
UpperBound(objective_var_) - implied_objective_lb;
1417 for (
const ObjectiveTerm& term : terms_) {
1418 if (term.weight == 0)
continue;
1419 const IntegerValue var_lb = integer_trail_->
LowerBound(term.var);
1420 const IntegerValue var_ub = integer_trail_->
UpperBound(term.var);
1421 if (var_lb == var_ub)
continue;
1428 if (gap / term.weight < var_ub - var_lb) {
1429 some_bound_were_tightened =
true;
1430 const IntegerValue new_ub = var_lb + gap / term.weight;
1452 void CoreBasedOptimizer::ComputeNextStratificationThreshold() {
1453 std::vector<IntegerValue> weights;
1454 for (ObjectiveTerm& term : terms_) {
1455 if (term.weight >= stratification_threshold_)
continue;
1456 if (term.weight == 0)
continue;
1460 if (var_lb == var_ub)
continue;
1462 weights.push_back(term.weight);
1464 if (weights.empty()) {
1465 stratification_threshold_ = IntegerValue(0);
1470 stratification_threshold_ =
1471 weights[static_cast<int>(std::floor(0.9 * weights.size()))];
1474 bool CoreBasedOptimizer::CoverOptimization() {
1477 constexpr
double max_dtime_per_core = 0.5;
1484 for (
const ObjectiveTerm& term : terms_) {
1488 if (term.depth == 0)
continue;
1494 const IntegerVariable
var = term.var;
1505 const double deterministic_limit =
1517 VLOG(1) <<
"cover_opt var:" <<
var <<
" domain:[" 1519 if (!ProcessSolution())
return false;
1538 if (!PropagateObjectiveBounds())
return false;
1547 std::map<LiteralIndex, int> literal_to_term_index;
1566 std::vector<int> term_indices;
1567 std::vector<IntegerLiteral> integer_assumptions;
1568 std::vector<IntegerValue> assumption_weights;
1569 IntegerValue objective_offset(0);
1570 bool some_assumptions_were_skipped =
false;
1571 for (
int i = 0; i < terms_.size(); ++i) {
1572 const ObjectiveTerm term = terms_[i];
1575 if (term.weight == 0)
continue;
1581 const IntegerValue var_lb = integer_trail_->
LowerBound(term.var);
1582 const IntegerValue var_ub = integer_trail_->
UpperBound(term.var);
1583 if (var_lb == var_ub) {
1584 objective_offset += term.weight * var_lb.value();
1589 if (term.weight >= stratification_threshold_) {
1590 integer_assumptions.push_back(
1592 assumption_weights.push_back(term.weight);
1593 term_indices.push_back(i);
1595 some_assumptions_were_skipped =
true;
1600 if (term_indices.empty() && some_assumptions_were_skipped) {
1601 ComputeNextStratificationThreshold();
1606 if (term_indices.size() <= 2 && !some_assumptions_were_skipped) {
1607 VLOG(1) <<
"Switching to linear scan...";
1608 if (!already_switched_to_linear_scan_) {
1609 already_switched_to_linear_scan_ =
true;
1610 std::vector<IntegerVariable> constraint_vars;
1611 std::vector<int64_t> constraint_coeffs;
1612 for (
const int index : term_indices) {
1613 constraint_vars.push_back(terms_[
index].
var);
1614 constraint_coeffs.push_back(terms_[
index].
weight.value());
1616 constraint_vars.push_back(objective_var_);
1617 constraint_coeffs.push_back(-1);
1619 -objective_offset.value()));
1623 objective_var_, feasible_solution_observer_, model_);
1629 for (
const ObjectiveTerm& term : terms_) {
1630 max_depth =
std::max(max_depth, term.depth);
1632 const int64_t lb = integer_trail_->
LowerBound(objective_var_).value();
1633 const int64_t ub = integer_trail_->
UpperBound(objective_var_).value();
1637 : static_cast<int>(std::ceil(
1638 100.0 * (ub - lb) /
std::max(std::abs(ub), std::abs(lb))));
1639 VLOG(1) << absl::StrCat(
"unscaled_next_obj_range:[", lb,
",", ub,
1642 gap,
"%",
" assumptions:", term_indices.size(),
1643 " strat:", stratification_threshold_.value(),
1644 " depth:", max_depth);
1648 std::vector<Literal> assumptions;
1649 literal_to_term_index.clear();
1650 for (
int i = 0; i < integer_assumptions.size(); ++i) {
1652 integer_assumptions[i]));
1660 literal_to_term_index[assumptions.back().Index()] = term_indices[i];
1668 std::vector<std::vector<Literal>> cores;
1670 FindCores(assumptions, assumption_weights, stratification_threshold_,
1676 if (cores.empty()) {
1677 ComputeNextStratificationThreshold();
1686 for (
const std::vector<Literal>& core : cores) {
1689 if (core.size() == 1)
continue;
1694 bool ignore_this_core =
false;
1696 IntegerValue max_weight(0);
1697 IntegerValue new_var_lb(1);
1698 IntegerValue new_var_ub(0);
1700 for (
const Literal lit : core) {
1705 if (terms_[
index].old_var_lb <
1707 ignore_this_core =
true;
1718 if (ignore_this_core)
continue;
1720 VLOG(1) << absl::StrFormat(
1721 "core:%u weight:[%d,%d] domain:[%d,%d] depth:%d", core.size(),
1722 min_weight.value(), max_weight.value(), new_var_lb.value(),
1723 new_var_ub.value(), new_depth);
1727 const IntegerVariable new_var =
1729 terms_.push_back({new_var, min_weight, new_depth});
1730 terms_.back().cover_ub = new_var_ub;
1734 std::vector<IntegerVariable> constraint_vars;
1735 std::vector<int64_t> constraint_coeffs;
1736 for (
const Literal lit : core) {
1738 terms_[
index].weight -= min_weight;
1739 constraint_vars.push_back(terms_[
index].
var);
1740 constraint_coeffs.push_back(1);
1742 constraint_vars.push_back(new_var);
1743 constraint_coeffs.push_back(-1);
1761 const std::function<
void()>& feasible_solution_observer,
Model*
model) {
1762 #if !defined(__PORTABLE_PLATFORM__) && defined(USE_SCIP) 1764 IntegerVariable objective_var = objective_definition.
objective_var;
1765 std::vector<IntegerVariable> variables = objective_definition.
vars;
1773 const auto process_solution = [&]() {
1776 IntegerValue objective(0);
1777 for (
int i = 0; i < variables.size(); ++i) {
1781 if (objective > integer_trail->UpperBound(objective_var))
return true;
1783 if (feasible_solution_observer !=
nullptr) {
1784 feasible_solution_observer();
1791 if (!integer_trail->Enqueue(
1806 const int num_variables_in_objective = variables.size();
1807 for (
int i = 0; i < num_variables_in_objective; ++i) {
1812 const IntegerVariable
var = variables[i];
1830 std::map<LiteralIndex, std::vector<int>> assumption_to_indices;
1833 std::map<std::pair<int, double>,
int> created_var;
1839 for (
int iter = 0;; ++iter) {
1847 const IntegerValue mip_objective(
1848 static_cast<int64_t>(std::round(
response.objective_value())));
1850 <<
" variables: " << hs_model.
variable_size() <<
" hs_lower_bound: " 1852 <<
" strat: " << stratified_threshold;
1858 if (!integer_trail->Enqueue(
1867 std::vector<Literal> assumptions;
1868 assumption_to_indices.clear();
1869 IntegerValue next_stratified_threshold(0);
1870 for (
int i = 0; i < num_variables_in_objective; ++i) {
1871 const IntegerValue hs_value(
1872 static_cast<int64_t>(
response.variable_value(i)));
1873 if (hs_value == integer_trail->UpperBound(variables[i]))
continue;
1877 next_stratified_threshold =
1882 assumptions.push_back(integer_encoder->GetOrCreateAssociatedLiteral(
1884 assumption_to_indices[assumptions.back().Index()].push_back(i);
1889 if (assumptions.empty() && next_stratified_threshold > 0) {
1890 CHECK_LT(next_stratified_threshold, stratified_threshold);
1891 stratified_threshold = next_stratified_threshold;
1900 std::vector<std::vector<Literal>> cores;
1901 result = FindMultipleCoresForMaxHs(assumptions,
model, &cores);
1907 if (cores.empty()) {
1910 stratified_threshold = next_stratified_threshold;
1911 if (stratified_threshold == 0)
break;
1921 for (
const std::vector<Literal>& core : cores) {
1922 if (core.size() == 1) {
1923 for (
const int index :
1926 integer_trail->LowerBound(variables[
index]).value());
1933 ct->set_lower_bound(1.0);
1934 for (
const Literal lit : core) {
1935 for (
const int index :
1937 const double lb = integer_trail->LowerBound(variables[
index]).value();
1939 if (hs_value == lb) {
1941 ct->add_coefficient(1.0);
1942 ct->set_lower_bound(
ct->lower_bound() + lb);
1944 const std::pair<int, double> key = {
index, hs_value};
1947 created_var[key] = new_var_index;
1964 ct->add_coefficient(1.0);
1972 #else // !__PORTABLE_PLATFORM__ && USE_SCIP 1974 #endif // !__PORTABLE_PLATFORM__ && USE_SCIP SatSolver::Status SolveWithFuMalik(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
bool AddObjectiveConstraint(const LinearBooleanProblem &problem, bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, SatSolver *solver)
static void SolveWithProto(const MPModelRequest &model_request, MPSolutionResponse *response, const std::atomic< bool > *interrupt=nullptr)
Solves the model encoded by a MPModelRequest protocol buffer and fills the solution encoded as a MPSo...
void set_lower_bound(double value)
int constraint_size() const
void SetParameters(const SatParameters ¶meters)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
void set_max_time_in_seconds(double value)
const Collection::value_type::second_type & FindOrDieNoPrint(const Collection &collection, const typename Collection::value_type::first_type &key)
SatSolver::Status SolveWithCardinalityEncoding(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
const SatParameters & parameters() const
double AddOffsetAndScaleObjectiveValue(const LinearBooleanProblem &problem, Coefficient v)
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
::PROTOBUF_NAMESPACE_ID::int64 coefficients(int index) const
void ResetDecisionHeuristic()
std::vector< IntegerVariable > vars
const Coefficient kCoefficientMax(std::numeric_limits< Coefficient::ValueType >::max())
#define CHECK_GE(val1, val2)
void RandomizeDecisionHeuristic(URBG *random, SatParameters *parameters)
Class that owns everything related to a particular optimization model.
ModelSharedTimeLimit * time_limit
std::vector< Literal > GetLastIncompatibleDecisions()
bool minimize_core() const
void SetAssumptionLevel(int assumption_level)
#define CHECK_GT(val1, val2)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
EncodingNode * MergeAllNodesWithDeque(Coefficient upper_bound, const std::vector< EncodingNode * > &nodes, SatSolver *solver, std::deque< EncodingNode > *repository)
#define VLOG(verboselevel)
::PROTOBUF_NAMESPACE_ID::int32 num_variables() const
void set_max_number_of_conflicts(::PROTOBUF_NAMESPACE_ID::int64 value)
SatSolver::Status MinimizeWithHittingSetAndLazyEncoding(const ObjectiveDefinition &objective_definition, const std::function< void()> &feasible_solution_observer, Model *model)
IntegerValue LowerBound(IntegerVariable i) const
bool LiteralIsFalse(Literal literal) const
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
bool LiteralIsTrue(Literal literal) const
double max_time_in_seconds() const
bool cover_optimization() const
void set_max_deterministic_time(double value)
const ::operations_research::sat::LinearObjective & objective() const
int EnqueueDecisionAndBacktrackOnConflict(Literal true_literal)
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
static constexpr SolverType SCIP_MIXED_INTEGER_PROGRAMMING
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void SetNumVariables(int num_variables)
bool AddUnitClause(Literal true_literal)
void set_solver_specific_parameters(ArgT0 &&arg0, ArgT... args)
int constraints_size() const
CoreBasedOptimizer(IntegerVariable objective_var, const std::vector< IntegerVariable > &variables, const std::vector< IntegerValue > &coefficients, std::function< void()> feasible_solution_observer, Model *model)
bool AddBinaryClause(Literal a, Literal b)
std::vector< IntegerValue > coeffs
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void ExtractAssignment(const LinearBooleanProblem &problem, const SatSolver &solver, std::vector< bool > *assignment)
SatSolver::Status SolveWithRandomParameters(LogBehavior log, const LinearBooleanProblem &problem, int num_times, SatSolver *solver, std::vector< bool > *solution)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Coefficient ComputeCoreMinWeight(const std::vector< EncodingNode * > &nodes, const std::vector< Literal > &core)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
void set_upper_bound(double value)
#define CHECK_LT(val1, val2)
double ScaleIntegerObjective(IntegerValue value) const
void add_coefficient(double value)
bool AddTernaryClause(Literal a, Literal b, Literal c)
absl::Cleanup< absl::decay_t< Callback > > MakeCleanup(Callback &&callback)
::operations_research::MPConstraintProto * add_constraint()
int variable_size() const
SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
Literal GetOrCreateAssociatedLiteral(IntegerLiteral i_lit)
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
::PROTOBUF_NAMESPACE_ID::int32 literals(int index) const
void set_is_integer(bool value)
#define CHECK_LE(val1, val2)
bool LimitReached() const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
SatSolver::Status SolveWithLinearScan(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
bool ContainsKey(const Collection &collection, const Key &key)
int literals_size() const
const Collection::value_type::second_type & FindOrDie(const Collection &collection, const typename Collection::value_type::first_type &key)
bool IsAssignmentValid(const LinearBooleanProblem &problem, const std::vector< bool > &assignment)
IntegerVariable objective_var
void Backtrack(int target_level)
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
SharedResponseManager * response
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions)
Coefficient ComputeObjectiveValue(const LinearBooleanProblem &problem, const std::vector< bool > &assignment)
static constexpr MaxSatStratificationAlgorithm STRATIFICATION_NONE
Coefficient MaxNodeWeightSmallerThan(const std::vector< EncodingNode * > &nodes, Coefficient upper_bound)
#define CHECK_EQ(val1, val2)
::operations_research::MPModelProto * mutable_model()
SatSolver::Status SolveWithCardinalityEncodingAndCore(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
std::vector< EncodingNode * > CreateInitialEncodingNodes(const std::vector< Literal > &literals, const std::vector< Coefficient > &coeffs, Coefficient *offset, std::deque< EncodingNode > *repository)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
const VariablesAssignment & Assignment() const
Literal literal(int i) const
#define DCHECK(condition)
void set_lower_bound(double value)
SatSolver::Status SolveIntegerProblem(Model *model)
double GetTimeLeft() const
double GetElapsedDeterministicTime() const
Returns the elapsed deterministic time since the construction of this object.
::PROTOBUF_NAMESPACE_ID::int32 binary_search_num_conflicts() const
SatSolver::Status ResetAndSolveIntegerProblem(const std::vector< Literal > &assumptions, Model *model)
T Add(std::function< T(Model *)> f)
This makes it possible to have a nicer API on the client side, and it allows both of these forms:
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
std::tuple< int64_t, int64_t, const double > Coefficient
bool IsCurrentlyIgnored(IntegerVariable i) const
::operations_research::MPVariableProto * add_variable()
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
void set_objective_coefficient(double value)
std::string ProtobufShortDebugString(const P &message)
::operations_research::MPVariableProto * mutable_variable(int index)
void RestrictObjectiveDomainWithBinarySearch(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
IntegerValue UpperBound(IntegerVariable i) const
SatSolver::Status SolveWithWPM1(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
int CurrentDecisionLevel() const
bool AddProblemClause(absl::Span< const Literal > literals)
bool IsModelUnsat() const
Collection of objects used to extend the Constraint Solver library.
void UseObjectiveForSatAssignmentPreference(const LinearBooleanProblem &problem, SatSolver *solver)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
absl::Span< const double > coefficients
int coefficients_size() const
void ProcessCore(const std::vector< Literal > &core, Coefficient min_weight, std::deque< EncodingNode > *repository, std::vector< EncodingNode * > *nodes, SatSolver *solver)
::operations_research::sat::SatParameters_MaxSatStratificationAlgorithm max_sat_stratification() const
void set_random_seed(::PROTOBUF_NAMESPACE_ID::int32 value)
int MoveOneUnprocessedLiteralLast(const std::set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
void set_solver_type(::operations_research::MPModelRequest_SolverType value)
#define VLOG_IS_ON(verboselevel)
SatSolver::Status Optimize()
static constexpr MaxSatStratificationAlgorithm STRATIFICATION_DESCENT
void set_log_search_progress(bool value)
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
void MinimizeCoreWithPropagation(TimeLimit *limit, SatSolver *solver, std::vector< Literal > *core)
void add_var_index(::PROTOBUF_NAMESPACE_ID::int32 value)
#define CHECK_NE(val1, val2)
bool stop_after_first_solution() const
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
std::vector< Literal > ReduceNodesAndExtractAssumptions(Coefficient upper_bound, Coefficient stratified_lower_bound, Coefficient *lower_bound, std::vector< EncodingNode * > *nodes, SatSolver *solver)
double max_deterministic_time() const
static constexpr MaxSatStratificationAlgorithm STRATIFICATION_ASCENT