28#include "absl/random/bit_gen_ref.h"
29#include "absl/random/random.h"
30#include "absl/strings/str_cat.h"
31#include "absl/strings/str_format.h"
39#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.";
766 absl::BitGenRef random,
SatSolver* solver, std::vector<bool>* solution) {
775 int max_number_of_conflicts = 5;
781 for (
int i = 0; i < num_times; ++i) {
791 const bool use_obj = absl::Bernoulli(random, 1.0 / 4);
810 std::vector<bool> candidate;
814 if (objective < best) {
815 *solution = candidate;
817 logger.Log(CnfObjectiveLine(problem, objective));
822 objective - 1, solver)) {
826 min_seen =
std::min(min_seen, objective);
827 max_seen =
std::max(max_seen, objective);
829 logger.Log(absl::StrCat(
830 "c ", objective.value(),
" [", min_seen.value(),
", ", max_seen.value(),
831 "] objective_preference: ", use_obj ?
"true" :
"false",
" ",
845 std::vector<bool>* solution) {
852 if (!solution->empty()) {
861 objective - 1, solver)) {
884 logger.Log(CnfObjectiveLine(problem, objective));
890 std::vector<bool>* solution) {
892 std::deque<EncodingNode> repository;
896 std::vector<EncodingNode*>
nodes =
907 if (!solution->empty()) {
914 logger.Log(absl::StrFormat(
"c #weights:%u #vars:%d #constraints:%d",
922 logger.Log(absl::StrFormat(
"c encoding depth:%d", root->
depth()));
928 const int index = offset.value() + objective.value();
952 logger.Log(CnfObjectiveLine(problem, objective));
958 std::vector<bool>* solution) {
964 std::deque<EncodingNode> repository;
965 std::vector<EncodingNode*>
nodes =
972 if (!solution->empty()) {
978 logger.Log(absl::StrFormat(
"c #weights:%u #vars:%d #constraints:%d",
988 stratified_lower_bound =
std::max(stratified_lower_bound, n->weight());
994 std::string previous_core_info =
"";
995 for (
int iter = 0;; ++iter) {
1001 const std::string gap_string =
1006 absl::StrFormat(
"c iter:%d [%s] lb:%d%s assumptions:%u depth:%d", iter,
1010 gap_string,
nodes.size(), max_depth));
1017 std::vector<bool> temp_solution;
1022 *solution = temp_solution;
1023 logger.Log(CnfObjectiveLine(problem, obj));
1029 stratified_lower_bound =
1031 if (stratified_lower_bound > 0)
continue;
1043 previous_core_info =
1044 absl::StrFormat(
"core:%u mw:%d", core.size(), min_weight.value());
1047 if (stratified_lower_bound < min_weight &&
1050 stratified_lower_bound = min_weight;
1059 IntegerVariable objective_var,
1060 const std::function<
void()>& feasible_solution_observer,
Model*
model) {
1071 const IntegerValue objective = integer_trail->LowerBound(objective_var);
1074 if (feasible_solution_observer !=
nullptr) {
1075 feasible_solution_observer();
1083 if (!integer_trail->Enqueue(
1092 IntegerVariable objective_var,
1093 const std::function<
void()>& feasible_solution_observer,
Model*
model) {
1110 IntegerValue unknown_min = integer_trail->UpperBound(objective_var);
1111 IntegerValue unknown_max = integer_trail->LowerBound(objective_var);
1113 sat_solver->Backtrack(0);
1114 const IntegerValue lb = integer_trail->LowerBound(objective_var);
1115 const IntegerValue ub = integer_trail->UpperBound(objective_var);
1116 unknown_min =
std::min(unknown_min, ub);
1117 unknown_max =
std::max(unknown_max, lb);
1120 IntegerValue target;
1121 if (lb < unknown_min) {
1122 target = lb + (unknown_min - lb) / 2;
1123 }
else if (unknown_max < ub) {
1124 target = ub - (ub - unknown_max) / 2;
1126 VLOG(1) <<
"Binary-search, done.";
1129 VLOG(1) <<
"Binary-search, objective: [" << lb <<
"," << ub <<
"]"
1130 <<
" tried: [" << unknown_min <<
"," << unknown_max <<
"]"
1131 <<
" target: obj<=" << target;
1134 const Literal assumption = integer_encoder->GetOrCreateAssociatedLiteral(
1148 sat_solver->Backtrack(0);
1149 if (!integer_trail->Enqueue(
1158 const IntegerValue objective = integer_trail->LowerBound(objective_var);
1159 if (feasible_solution_observer !=
nullptr) {
1160 feasible_solution_observer();
1165 sat_solver->Backtrack(0);
1166 if (!integer_trail->Enqueue(
1174 unknown_min =
std::min(target, unknown_min);
1175 unknown_max =
std::max(target, unknown_max);
1181 sat_solver->Backtrack(0);
1209 std::vector<IntegerValue> assumption_weights,
1210 IntegerValue stratified_threshold, Model*
model,
1211 std::vector<std::vector<Literal>>* cores) {
1213 SatSolver* sat_solver =
model->GetOrCreate<SatSolver>();
1221 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1222 if (sat_solver->parameters().minimize_core()) {
1225 if (core.empty())
return sat_solver->UnsatStatus();
1226 cores->push_back(core);
1227 if (!sat_solver->parameters().find_multiple_cores())
break;
1231 std::vector<int> indices;
1233 std::set<Literal> temp(core.begin(), core.end());
1234 for (
int i = 0; i < assumptions.size(); ++i) {
1236 indices.push_back(i);
1246 IntegerValue min_weight = assumption_weights[indices.front()];
1247 for (
const int i : indices) {
1248 min_weight =
std::min(min_weight, assumption_weights[i]);
1250 for (
const int i : indices) {
1251 assumption_weights[i] -= min_weight;
1257 for (
int i = 0; i < assumptions.size(); ++i) {
1258 if (assumption_weights[i] < stratified_threshold)
continue;
1259 assumptions[new_size] = assumptions[i];
1260 assumption_weights[new_size] = assumption_weights[i];
1263 assumptions.resize(new_size);
1264 assumption_weights.resize(new_size);
1265 }
while (!assumptions.empty());
1272 std::vector<Literal> assumptions, Model*
model,
1273 std::vector<std::vector<Literal>>* cores) {
1275 SatSolver* sat_solver =
model->GetOrCreate<SatSolver>();
1276 TimeLimit* limit =
model->GetOrCreate<TimeLimit>();
1283 std::vector<Literal> core = sat_solver->GetLastIncompatibleDecisions();
1284 if (sat_solver->parameters().minimize_core()) {
1287 CHECK(!core.empty());
1288 cores->push_back(core);
1289 if (!sat_solver->parameters().find_multiple_cores())
break;
1293 CHECK(!core.empty());
1294 auto* random =
model->GetOrCreate<ModelRandomGenerator>();
1295 const Literal random_literal =
1296 core[absl::Uniform<int>(*random, 0, core.size())];
1297 for (
int i = 0; i < assumptions.size(); ++i) {
1298 if (assumptions[i] == random_literal) {
1299 std::swap(assumptions[i], assumptions.back());
1300 assumptions.pop_back();
1304 }
while (!assumptions.empty());
1311 IntegerVariable objective_var,
1312 const std::vector<IntegerVariable>& variables,
1314 std::function<
void()> feasible_solution_observer,
Model*
model)
1321 objective_var_(objective_var),
1322 feasible_solution_observer_(
std::move(feasible_solution_observer)) {
1324 for (
int i = 0; i < variables.size(); ++i) {
1332 terms_.back().depth = 0;
1344bool CoreBasedOptimizer::ProcessSolution() {
1347 IntegerValue objective(0);
1348 for (ObjectiveTerm& term : terms_) {
1350 objective += term.weight *
value;
1365 if (feasible_solution_observer_ !=
nullptr) {
1366 feasible_solution_observer_();
1376 return integer_trail_->
Enqueue(
1380bool CoreBasedOptimizer::PropagateObjectiveBounds() {
1382 bool some_bound_were_tightened =
true;
1383 while (some_bound_were_tightened) {
1384 some_bound_were_tightened =
false;
1388 IntegerValue implied_objective_lb(0);
1389 for (ObjectiveTerm& term : terms_) {
1390 const IntegerValue var_lb = integer_trail_->
LowerBound(term.var);
1391 term.old_var_lb = var_lb;
1392 implied_objective_lb += term.weight * var_lb.value();
1396 if (implied_objective_lb > integer_trail_->
LowerBound(objective_var_)) {
1398 objective_var_, implied_objective_lb),
1403 some_bound_were_tightened =
true;
1412 const IntegerValue gap =
1413 integer_trail_->
UpperBound(objective_var_) - implied_objective_lb;
1415 for (
const ObjectiveTerm& term : terms_) {
1416 if (term.weight == 0)
continue;
1417 const IntegerValue var_lb = integer_trail_->
LowerBound(term.var);
1418 const IntegerValue var_ub = integer_trail_->
UpperBound(term.var);
1419 if (var_lb == var_ub)
continue;
1426 if (gap / term.weight < var_ub - var_lb) {
1427 some_bound_were_tightened =
true;
1428 const IntegerValue new_ub = var_lb + gap / term.weight;
1450void CoreBasedOptimizer::ComputeNextStratificationThreshold() {
1451 std::vector<IntegerValue> weights;
1452 for (ObjectiveTerm& term : terms_) {
1453 if (term.weight >= stratification_threshold_)
continue;
1454 if (term.weight == 0)
continue;
1458 if (var_lb == var_ub)
continue;
1460 weights.push_back(term.weight);
1462 if (weights.empty()) {
1463 stratification_threshold_ = IntegerValue(0);
1468 stratification_threshold_ =
1469 weights[
static_cast<int>(std::floor(0.9 * weights.size()))];
1472bool CoreBasedOptimizer::CoverOptimization() {
1475 constexpr double max_dtime_per_core = 0.5;
1482 for (
const ObjectiveTerm& term : terms_) {
1486 if (term.depth == 0)
continue;
1492 const IntegerVariable
var = term.var;
1503 const double deterministic_limit =
1515 VLOG(1) <<
"cover_opt var:" <<
var <<
" domain:["
1517 if (!ProcessSolution())
return false;
1536 if (!PropagateObjectiveBounds())
return false;
1545 std::map<LiteralIndex, int> literal_to_term_index;
1564 std::vector<int> term_indices;
1565 std::vector<IntegerLiteral> integer_assumptions;
1566 std::vector<IntegerValue> assumption_weights;
1567 IntegerValue objective_offset(0);
1568 bool some_assumptions_were_skipped =
false;
1569 for (
int i = 0; i < terms_.size(); ++i) {
1570 const ObjectiveTerm term = terms_[i];
1573 if (term.weight == 0)
continue;
1579 const IntegerValue var_lb = integer_trail_->
LowerBound(term.var);
1580 const IntegerValue var_ub = integer_trail_->
UpperBound(term.var);
1581 if (var_lb == var_ub) {
1582 objective_offset += term.weight * var_lb.value();
1587 if (term.weight >= stratification_threshold_) {
1588 integer_assumptions.push_back(
1590 assumption_weights.push_back(term.weight);
1591 term_indices.push_back(i);
1593 some_assumptions_were_skipped =
true;
1598 if (term_indices.empty() && some_assumptions_were_skipped) {
1599 ComputeNextStratificationThreshold();
1604 if (term_indices.size() <= 2 && !some_assumptions_were_skipped) {
1605 VLOG(1) <<
"Switching to linear scan...";
1606 if (!already_switched_to_linear_scan_) {
1607 already_switched_to_linear_scan_ =
true;
1608 std::vector<IntegerVariable> constraint_vars;
1609 std::vector<int64_t> constraint_coeffs;
1610 for (
const int index : term_indices) {
1611 constraint_vars.push_back(terms_[
index].
var);
1612 constraint_coeffs.push_back(terms_[
index].
weight.value());
1614 constraint_vars.push_back(objective_var_);
1615 constraint_coeffs.push_back(-1);
1617 -objective_offset.value()));
1621 objective_var_, feasible_solution_observer_, model_);
1627 for (
const ObjectiveTerm& term : terms_) {
1628 max_depth =
std::max(max_depth, term.depth);
1630 const int64_t lb = integer_trail_->
LowerBound(objective_var_).value();
1631 const int64_t ub = integer_trail_->
UpperBound(objective_var_).value();
1635 :
static_cast<int>(std::ceil(
1636 100.0 * (ub - lb) /
std::max(std::abs(ub), std::abs(lb))));
1637 VLOG(1) << absl::StrCat(
"unscaled_next_obj_range:[", lb,
",", ub,
1640 gap,
"%",
" assumptions:", term_indices.size(),
1641 " strat:", stratification_threshold_.value(),
1642 " depth:", max_depth);
1646 std::vector<Literal> assumptions;
1647 literal_to_term_index.clear();
1648 for (
int i = 0; i < integer_assumptions.size(); ++i) {
1650 integer_assumptions[i]));
1658 literal_to_term_index[assumptions.back().Index()] = term_indices[i];
1666 std::vector<std::vector<Literal>> cores;
1668 FindCores(assumptions, assumption_weights, stratification_threshold_,
1674 if (cores.empty()) {
1675 ComputeNextStratificationThreshold();
1684 for (
const std::vector<Literal>& core : cores) {
1687 if (core.size() == 1)
continue;
1692 bool ignore_this_core =
false;
1694 IntegerValue max_weight(0);
1695 IntegerValue new_var_lb(1);
1696 IntegerValue new_var_ub(0);
1698 for (
const Literal lit : core) {
1703 if (terms_[
index].old_var_lb <
1705 ignore_this_core =
true;
1716 if (ignore_this_core)
continue;
1718 VLOG(1) << absl::StrFormat(
1719 "core:%u weight:[%d,%d] domain:[%d,%d] depth:%d", core.size(),
1720 min_weight.value(), max_weight.value(), new_var_lb.value(),
1721 new_var_ub.value(), new_depth);
1725 const IntegerVariable new_var =
1727 terms_.push_back({new_var, min_weight, new_depth});
1728 terms_.back().cover_ub = new_var_ub;
1732 std::vector<IntegerVariable> constraint_vars;
1733 std::vector<int64_t> constraint_coeffs;
1734 for (
const Literal lit : core) {
1736 terms_[
index].weight -= min_weight;
1737 constraint_vars.push_back(terms_[
index].
var);
1738 constraint_coeffs.push_back(1);
1740 constraint_vars.push_back(new_var);
1741 constraint_coeffs.push_back(-1);
1759 const std::function<
void()>& feasible_solution_observer,
Model*
model) {
1760#if !defined(__PORTABLE_PLATFORM__) && defined(USE_SCIP)
1762 IntegerVariable objective_var = objective_definition.
objective_var;
1763 std::vector<IntegerVariable> variables = objective_definition.
vars;
1771 const auto process_solution = [&]() {
1774 IntegerValue objective(0);
1775 for (
int i = 0; i < variables.size(); ++i) {
1779 if (objective > integer_trail->UpperBound(objective_var))
return true;
1781 if (feasible_solution_observer !=
nullptr) {
1782 feasible_solution_observer();
1789 if (!integer_trail->Enqueue(
1804 const int num_variables_in_objective = variables.size();
1805 for (
int i = 0; i < num_variables_in_objective; ++i) {
1810 const IntegerVariable
var = variables[i];
1828 std::map<LiteralIndex, std::vector<int>> assumption_to_indices;
1831 std::map<std::pair<int, double>,
int> created_var;
1837 for (
int iter = 0;; ++iter) {
1845 const IntegerValue mip_objective(
1846 static_cast<int64_t
>(std::round(
response.objective_value())));
1848 <<
" variables: " << hs_model.
variable_size() <<
" hs_lower_bound: "
1850 <<
" strat: " << stratified_threshold;
1856 if (!integer_trail->Enqueue(
1865 std::vector<Literal> assumptions;
1866 assumption_to_indices.clear();
1867 IntegerValue next_stratified_threshold(0);
1868 for (
int i = 0; i < num_variables_in_objective; ++i) {
1869 const IntegerValue hs_value(
1870 static_cast<int64_t
>(
response.variable_value(i)));
1871 if (hs_value == integer_trail->UpperBound(variables[i]))
continue;
1875 next_stratified_threshold =
1880 assumptions.push_back(integer_encoder->GetOrCreateAssociatedLiteral(
1882 assumption_to_indices[assumptions.back().Index()].push_back(i);
1887 if (assumptions.empty() && next_stratified_threshold > 0) {
1888 CHECK_LT(next_stratified_threshold, stratified_threshold);
1889 stratified_threshold = next_stratified_threshold;
1898 std::vector<std::vector<Literal>> cores;
1899 result = FindMultipleCoresForMaxHs(assumptions,
model, &cores);
1905 if (cores.empty()) {
1908 stratified_threshold = next_stratified_threshold;
1909 if (stratified_threshold == 0)
break;
1919 for (
const std::vector<Literal>& core : cores) {
1920 if (core.size() == 1) {
1921 for (
const int index :
1924 integer_trail->LowerBound(variables[
index]).value());
1931 ct->set_lower_bound(1.0);
1932 for (
const Literal lit : core) {
1933 for (
const int index :
1935 const double lb = integer_trail->LowerBound(variables[
index]).value();
1937 if (hs_value == lb) {
1939 ct->add_coefficient(1.0);
1940 ct->set_lower_bound(
ct->lower_bound() + lb);
1942 const std::pair<int, double> key = {
index, hs_value};
1945 created_var[key] = new_var_index;
1962 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 add_var_index(int32_t value)
void set_lower_bound(double 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
int32_t num_variables() const
int constraints_size() const
int literals_size() const
int32_t literals(int index) const
int64_t coefficients(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
bool stop_after_first_solution() const
static constexpr MaxSatStratificationAlgorithm STRATIFICATION_NONE
bool cover_optimization() const
int32_t binary_search_num_conflicts() const
void set_max_number_of_conflicts(int64_t value)
void set_max_deterministic_time(double value)
::operations_research::sat::SatParameters_MaxSatStratificationAlgorithm max_sat_stratification() const
void set_random_seed(int32_t 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
void RandomizeDecisionHeuristic(absl::BitGenRef random, SatParameters *parameters)
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)
SatSolver::Status SolveWithRandomParameters(LogBehavior log, const LinearBooleanProblem &problem, int num_times, absl::BitGenRef random, 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 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)
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)