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)
62 void Log(
const std::string&
message) {
76std::string CnfObjectiveLine(
const LinearBooleanProblem& problem,
78 const double scaled_objective =
80 return absl::StrFormat(
"o %d",
static_cast<int64_t
>(scaled_objective));
83struct LiteralWithCoreIndex {
92template <
typename Vector>
93void 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];
136class 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;
1346bool 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(
1382bool 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;
1452void 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()))];
1474bool 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);
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_GT(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
#define VLOG(verboselevel)
void set_lower_bound(double value)
void add_var_index(::PROTOBUF_NAMESPACE_ID::int32 value)
void add_coefficient(double value)
int variable_size() const
::operations_research::MPVariableProto * add_variable()
::operations_research::MPVariableProto * mutable_variable(int index)
::operations_research::MPConstraintProto * add_constraint()
int constraint_size() const
::operations_research::MPModelProto * mutable_model()
void set_solver_type(::operations_research::MPModelRequest_SolverType value)
static constexpr SolverType SCIP_MIXED_INTEGER_PROGRAMMING
void set_solver_specific_parameters(ArgT0 &&arg0, ArgT... args)
static void SolveWithProto(const MPModelRequest &model_request, MPSolutionResponse *response, std::atomic< bool > *interrupt=nullptr)
Solves the model encoded by a MPModelRequest protocol buffer and fills the solution encoded as a MPSo...
void set_is_integer(bool value)
void set_objective_coefficient(double value)
void set_lower_bound(double value)
void set_upper_bound(double value)
double GetTimeLeft() const
bool LimitReached() const
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
double GetElapsedDeterministicTime() const
Returns the elapsed deterministic time since the construction of this object.
CoreBasedOptimizer(IntegerVariable objective_var, const std::vector< IntegerVariable > &variables, const std::vector< IntegerValue > &coefficients, std::function< void()> feasible_solution_observer, Model *model)
SatSolver::Status Optimize()
Literal literal(int i) const
Literal GetOrCreateAssociatedLiteral(IntegerLiteral i_lit)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
bool IsCurrentlyIgnored(IntegerVariable i) const
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
IntegerValue LowerBound(IntegerVariable i) const
const ::operations_research::sat::LinearObjective & objective() const
::PROTOBUF_NAMESPACE_ID::int32 num_variables() const
int constraints_size() const
::PROTOBUF_NAMESPACE_ID::int64 coefficients(int index) const
int literals_size() const
::PROTOBUF_NAMESPACE_ID::int32 literals(int index) const
int coefficients_size() const
Class that owns everything related to a particular optimization 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:
double max_deterministic_time() const
bool minimize_core() const
::PROTOBUF_NAMESPACE_ID::int32 binary_search_num_conflicts() const
bool stop_after_first_solution() const
void set_max_number_of_conflicts(::PROTOBUF_NAMESPACE_ID::int64 value)
static constexpr MaxSatStratificationAlgorithm STRATIFICATION_NONE
bool cover_optimization() const
void set_max_deterministic_time(double value)
::operations_research::sat::SatParameters_MaxSatStratificationAlgorithm max_sat_stratification() const
void set_random_seed(::PROTOBUF_NAMESPACE_ID::int32 value)
void set_log_search_progress(bool value)
double max_time_in_seconds() const
void set_max_time_in_seconds(double value)
static constexpr MaxSatStratificationAlgorithm STRATIFICATION_ASCENT
static constexpr MaxSatStratificationAlgorithm STRATIFICATION_DESCENT
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
void SetNumVariables(int num_variables)
bool AddTernaryClause(Literal a, Literal b, Literal c)
const SatParameters & parameters() const
void ResetDecisionHeuristic()
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions)
const VariablesAssignment & Assignment() const
void SetAssumptionLevel(int assumption_level)
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
void SetParameters(const SatParameters ¶meters)
bool AddBinaryClause(Literal a, Literal b)
int EnqueueDecisionAndBacktrackOnConflict(Literal true_literal)
void Backtrack(int target_level)
std::vector< Literal > GetLastIncompatibleDecisions()
bool IsModelUnsat() const
int CurrentDecisionLevel() const
bool AddProblemClause(absl::Span< const Literal > literals)
bool AddUnitClause(Literal true_literal)
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
SharedResponseManager * response
ModelSharedTimeLimit * time_limit
absl::Span< const double > coefficients
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
absl::Cleanup< absl::decay_t< Callback > > MakeCleanup(Callback &&callback)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
const Collection::value_type::second_type & FindOrDie(const Collection &collection, const typename Collection::value_type::first_type &key)
const Collection::value_type::second_type & FindOrDieNoPrint(const Collection &collection, const typename Collection::value_type::first_type &key)
bool ContainsKey(const Collection &collection, const Key &key)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
std::tuple< int64_t, int64_t, const double > Coefficient
bool AddObjectiveConstraint(const LinearBooleanProblem &problem, bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, SatSolver *solver)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void RestrictObjectiveDomainWithBinarySearch(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
double AddOffsetAndScaleObjectiveValue(const LinearBooleanProblem &problem, Coefficient v)
SatSolver::Status ResetAndSolveIntegerProblem(const std::vector< Literal > &assumptions, Model *model)
SatSolver::Status SolveWithCardinalityEncodingAndCore(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
Coefficient ComputeCoreMinWeight(const std::vector< EncodingNode * > &nodes, const std::vector< Literal > &core)
EncodingNode * MergeAllNodesWithDeque(Coefficient upper_bound, const std::vector< EncodingNode * > &nodes, SatSolver *solver, std::deque< EncodingNode > *repository)
std::function< void(Model *)> WeightedSumLowerOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t upper_bound)
int MoveOneUnprocessedLiteralLast(const std::set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
std::function< int64_t(const Model &)> LowerBound(IntegerVariable v)
std::vector< Literal > ReduceNodesAndExtractAssumptions(Coefficient upper_bound, Coefficient stratified_lower_bound, Coefficient *lower_bound, std::vector< EncodingNode * > *nodes, SatSolver *solver)
void UseObjectiveForSatAssignmentPreference(const LinearBooleanProblem &problem, SatSolver *solver)
SatSolver::Status SolveWithLinearScan(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
SatSolver::Status MinimizeWithHittingSetAndLazyEncoding(const ObjectiveDefinition &objective_definition, const std::function< void()> &feasible_solution_observer, Model *model)
SatSolver::Status SolveIntegerProblem(Model *model)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
SatSolver::Status SolveWithWPM1(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
bool IsAssignmentValid(const LinearBooleanProblem &problem, const std::vector< bool > &assignment)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
void MinimizeCoreWithPropagation(TimeLimit *limit, SatSolver *solver, std::vector< Literal > *core)
void ProcessCore(const std::vector< Literal > &core, Coefficient min_weight, std::deque< EncodingNode > *repository, std::vector< EncodingNode * > *nodes, SatSolver *solver)
Coefficient ComputeObjectiveValue(const LinearBooleanProblem &problem, const std::vector< bool > &assignment)
SatSolver::Status SolveWithFuMalik(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
Coefficient MaxNodeWeightSmallerThan(const std::vector< EncodingNode * > &nodes, Coefficient upper_bound)
SatSolver::Status SolveWithRandomParameters(LogBehavior log, const LinearBooleanProblem &problem, int num_times, SatSolver *solver, std::vector< bool > *solution)
SatSolver::Status SolveWithCardinalityEncoding(LogBehavior log, const LinearBooleanProblem &problem, SatSolver *solver, std::vector< bool > *solution)
void ExtractAssignment(const LinearBooleanProblem &problem, const SatSolver &solver, std::vector< bool > *assignment)
std::vector< EncodingNode * > CreateInitialEncodingNodes(const std::vector< Literal > &literals, const std::vector< Coefficient > &coeffs, Coefficient *offset, std::deque< EncodingNode > *repository)
void RandomizeDecisionHeuristic(URBG *random, SatParameters *parameters)
const Coefficient kCoefficientMax(std::numeric_limits< Coefficient::ValueType >::max())
SatSolver::Status MinimizeIntegerVariableWithLinearScanAndLazyEncoding(IntegerVariable objective_var, const std::function< void()> &feasible_solution_observer, Model *model)
Collection of objects used to extend the Constraint Solver library.
std::string ProtobufShortDebugString(const P &message)
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
std::vector< IntegerValue > coeffs
std::vector< IntegerVariable > vars
IntegerVariable objective_var
double ScaleIntegerObjective(IntegerValue value) const
#define VLOG_IS_ON(verboselevel)