26#include "absl/base/attributes.h"
27#include "absl/container/btree_set.h"
28#include "absl/container/flat_hash_map.h"
29#include "absl/meta/type_traits.h"
30#include "absl/strings/str_cat.h"
31#include "absl/strings/str_format.h"
32#include "absl/types/span.h"
44#include "ortools/sat/sat_parameters.pb.h"
57 owned_model_.reset(model_);
67 track_binary_clauses_(false),
70 parameters_(
model->GetOrCreate<SatParameters>()),
74 clause_activity_increment_(1.0),
75 same_reason_identifier_(*trail_),
76 is_relevant_for_core_computation_(true),
77 problem_is_pure_sat_(true),
78 drat_proof_handler_(nullptr),
80 InitializePropagators();
87 CHECK_GE(num_variables, num_variables_);
89 num_variables_ = num_variables;
90 binary_implication_graph_->
Resize(num_variables);
91 clauses_propagator_->
Resize(num_variables);
92 trail_->
Resize(num_variables);
94 pb_constraints_->
Resize(num_variables);
95 same_reason_identifier_.
Resize(num_variables);
100 decisions_.resize(num_variables + 1);
145bool SatSolver::IsMemoryLimitReached()
const {
146 const int64_t memory_usage =
148 const int64_t kMegaByte = 1024 * 1024;
149 return memory_usage > kMegaByte * parameters_->max_memory_in_mb();
152bool SatSolver::SetModelUnsat() {
153 model_is_unsat_ =
true;
158 if (model_is_unsat_)
return false;
160 if (literals.empty())
return SetModelUnsat();
162 if (literals.size() == 2) {
169 return SetModelUnsat();
172 if (!clauses_propagator_->
AddClause(literals)) {
174 return SetModelUnsat();
205 if (model_is_unsat_)
return false;
208 literals_scratchpad_.clear();
209 for (
const Literal l : literals) {
212 literals_scratchpad_.push_back(l);
215 AddProblemClauseInternal(literals_scratchpad_);
221 if (!PropagationIsDone() && !
Propagate()) {
222 return SetModelUnsat();
227bool SatSolver::AddProblemClauseInternal(absl::Span<const Literal> literals) {
231 for (
const Literal l : literals) {
236 if (literals.empty())
return SetModelUnsat();
238 if (literals.size() == 1) {
239 if (drat_proof_handler_ !=
nullptr) {
242 drat_proof_handler_->
AddClause({literals[0]});
245 }
else if (literals.size() == 2) {
247 if (literals[0] == literals[1]) {
250 }
else if (literals[0] == literals[1].Negated()) {
254 AddBinaryClauseInternal(literals[0], literals[1],
258 if (!clauses_propagator_->
AddClause(literals, trail_)) {
259 return SetModelUnsat();
266bool SatSolver::AddLinearConstraintInternal(
267 const std::vector<LiteralWithCoeff>& cst,
Coefficient rhs,
271 if (rhs < 0)
return SetModelUnsat();
272 if (rhs >= max_value)
return true;
279 const Coefficient min_coeff = cst.front().coefficient;
280 const Coefficient max_coeff = cst.back().coefficient;
284 if (max_value - min_coeff <= rhs) {
286 literals_scratchpad_.clear();
287 for (
const LiteralWithCoeff& term : cst) {
288 literals_scratchpad_.push_back(term.literal.Negated());
290 return AddProblemClauseInternal(literals_scratchpad_);
295 if (!parameters_->use_pb_resolution() && max_coeff <= rhs &&
296 2 * min_coeff > rhs) {
297 literals_scratchpad_.clear();
298 for (
const LiteralWithCoeff& term : cst) {
299 literals_scratchpad_.push_back(term.literal);
301 if (!binary_implication_graph_->
AddAtMostOne(literals_scratchpad_)) {
302 return SetModelUnsat();
307 problem_is_pure_sat_ =
false;
314void SatSolver::CanonicalizeLinear(std::vector<LiteralWithCoeff>* cst,
321 for (
const LiteralWithCoeff& term : *cst) {
327 (*cst)[
index] = term;
345 bool use_upper_bound,
347 std::vector<LiteralWithCoeff>* cst) {
350 if (model_is_unsat_)
return false;
354 if (use_upper_bound) {
356 CanonicalizeLinear(cst, &bound_shift, &max_value);
359 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
360 return SetModelUnsat();
364 if (use_lower_bound) {
368 CanonicalizeLinear(cst, &bound_shift, &max_value);
371 for (
int i = 0; i < cst->size(); ++i) {
372 (*cst)[i].literal = (*cst)[i].literal.Negated();
376 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
377 return SetModelUnsat();
385 if (!PropagationIsDone() && !
Propagate()) {
386 return SetModelUnsat();
391int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation(
392 const std::vector<Literal>& literals,
bool is_redundant) {
395 if (literals.size() == 1) {
403 if (literals.size() == 2) {
404 if (track_binary_clauses_) {
406 CHECK(binary_clauses_.
Add(BinaryClause(literals[0], literals[1])));
408 if (shared_binary_clauses_callback_ !=
nullptr) {
409 shared_binary_clauses_callback_(literals[0], literals[1]);
416 CleanClauseDatabaseIfNeeded();
420 const int lbd = ComputeLbd(literals);
421 if (is_redundant && lbd > parameters_->clause_cleanup_lbd_bound()) {
422 --num_learned_clause_before_cleanup_;
430 BumpClauseActivity(clause);
439 problem_is_pure_sat_ =
false;
441 external_propagators_.push_back(propagator);
442 InitializePropagators();
447 CHECK(last_propagator_ ==
nullptr);
448 problem_is_pure_sat_ =
false;
450 last_propagator_ = propagator;
451 InitializePropagators();
455 BooleanVariable
var)
const {
465SatClause* SatSolver::ReasonClauseOrNull(BooleanVariable
var)
const {
467 const AssignmentInfo& info = trail_->
Info(
var);
469 return clauses_propagator_->
ReasonClause(info.trail_index);
475 debug_assignment_.
Resize(num_variables_.value());
476 for (BooleanVariable i(0); i < num_variables_; ++i) {
483 bool export_clause) {
484 if (track_binary_clauses_) {
489 if (export_clause && shared_binary_clauses_callback_ !=
nullptr) {
490 shared_binary_clauses_callback_(
a,
b);
496bool SatSolver::ClauseIsValidUnderDebugAssignment(
497 const std::vector<Literal>& clause)
const {
498 for (Literal l : clause) {
507bool SatSolver::PBConstraintIsValidUnderDebugAssignment(
508 const std::vector<LiteralWithCoeff>& cst,
const Coefficient rhs)
const {
510 for (LiteralWithCoeff term : cst) {
515 sum += term.coefficient;
525bool ClauseSubsumption(
const std::vector<Literal>&
a, SatClause*
b) {
526 std::vector<Literal> superset(
b->begin(),
b->end());
527 std::vector<Literal> subset(
a.begin(),
a.end());
528 std::sort(superset.begin(), superset.end());
529 std::sort(subset.begin(), subset.end());
530 return std::includes(superset.begin(), superset.end(), subset.begin(),
539 DCHECK(PropagationIsDone());
543 CHECK_GE(current_decision_level_, assumption_level_);
546 EnqueueNewDecision(true_literal);
548 return last_decision_or_backtrack_trail_index_;
552 if (model_is_unsat_)
return false;
562 if (model_is_unsat_)
return false;
564 const int old_decision_level = current_decision_level_;
565 if (!PropagateAndStopAfterOneConflictResolution()) {
566 if (model_is_unsat_)
return false;
567 if (current_decision_level_ == old_decision_level) {
568 CHECK(!assumptions_.empty());
575 CHECK(PropagationIsDone());
580 if (model_is_unsat_)
return false;
581 assumption_level_ = 0;
582 assumptions_.clear();
588 const std::vector<Literal>& assumptions) {
590 if (assumptions.empty())
return true;
597 DCHECK(assumptions_.empty());
598 assumption_level_ = 1;
599 assumptions_ = assumptions;
605 if (model_is_unsat_)
return false;
611 CHECK_EQ(current_decision_level_, 0);
612 last_decision_or_backtrack_trail_index_ = trail_->
Index();
615 ++current_decision_level_;
619 int num_decisions = 0;
620 for (
const Literal lit : assumptions_) {
621 if (
Assignment().LiteralIsTrue(lit))
continue;
625 if (num_decisions == 0) {
627 current_decision_level_ = 0;
637 if (num_decisions == 0) {
638 current_decision_level_ = 0;
647 DCHECK(assumptions_.empty());
649 const int64_t old_num_branches = counters_.num_branches;
651 ReapplyDecisionsUpTo(assumption_level_ - 1, &unused);
652 counters_.num_branches = old_num_branches;
657bool SatSolver::PropagateAndStopAfterOneConflictResolution() {
661 ++counters_.num_failures;
662 const int conflict_trail_index = trail_->
Index();
663 const int conflict_decision_level = current_decision_level_;
666 same_reason_identifier_.
Clear();
667 const int max_trail_index = ComputeMaxTrailIndex(trail_->
FailingClause());
668 if (!assumptions_.empty() && !trail_->
FailingClause().empty()) {
675 const int highest_level =
676 DecisionLevel((*trail_)[max_trail_index].Variable());
677 if (highest_level == 1)
return false;
680 ComputeFirstUIPConflict(max_trail_index, &learned_conflict_,
681 &reason_used_to_infer_the_conflict_,
685 if (learned_conflict_.empty())
return SetModelUnsat();
686 DCHECK(IsConflictValid(learned_conflict_));
687 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
695 if (parameters_->also_bump_variables_in_conflict_reasons()) {
696 ComputeUnionOfReasons(learned_conflict_, &extra_reason_literals_);
706 BumpReasonActivities(reason_used_to_infer_the_conflict_);
710 UpdateClauseActivityIncrement();
714 const int period = parameters_->glucose_decay_increment_period();
715 const double max_decay = parameters_->glucose_max_decay();
716 if (counters_.num_failures % period == 0 &&
717 parameters_->variable_activity_decay() < max_decay) {
718 parameters_->set_variable_activity_decay(
719 parameters_->variable_activity_decay() +
720 parameters_->glucose_decay_increment());
726 bool compute_pb_conflict =
false;
727 if (parameters_->use_pb_resolution()) {
729 if (!compute_pb_conflict) {
730 for (Literal lit : reason_used_to_infer_the_conflict_) {
731 if (ReasonPbConstraintOrNull(lit.Variable()) !=
nullptr) {
732 compute_pb_conflict =
true;
741 if (compute_pb_conflict) {
751 pb_conflict_.
AddToRhs(num_literals - 1);
760 int pb_backjump_level;
761 ComputePBConflict(max_trail_index, initial_slack, &pb_conflict_,
763 if (pb_backjump_level == -1)
return SetModelUnsat();
766 std::vector<LiteralWithCoeff> cst;
768 DCHECK(PBConstraintIsValidUnderDebugAssignment(cst, pb_conflict_.
Rhs()));
772 bool conflict_is_a_clause = (pb_conflict_.
Rhs() == cst.size() - 1);
773 if (conflict_is_a_clause) {
774 for (LiteralWithCoeff term : cst) {
776 conflict_is_a_clause =
false;
782 if (!conflict_is_a_clause) {
789 CHECK_GT(trail_->
Index(), last_decision_or_backtrack_trail_index_);
790 counters_.num_learned_pb_literals += cst.size();
796 if (pb_backjump_level < ComputeBacktrackLevel(learned_conflict_)) {
797 subsumed_clauses_.clear();
798 learned_conflict_.clear();
802 for (LiteralWithCoeff term : cst) {
805 const int level = trail_->
Info(term.literal.Variable()).
level;
806 if (level == 0)
continue;
807 if (level > max_level) {
809 max_index = learned_conflict_.size();
811 learned_conflict_.push_back(term.literal.Negated());
815 is_marked_.
Set(term.literal.Variable());
817 CHECK(!learned_conflict_.empty());
818 std::swap(learned_conflict_.front(), learned_conflict_[max_index]);
819 DCHECK(IsConflictValid(learned_conflict_));
828 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
829 if (!binary_implication_graph_->
IsEmpty()) {
830 if (parameters_->binary_minimization_algorithm() ==
831 SatParameters::BINARY_MINIMIZATION_FIRST) {
833 *trail_, &learned_conflict_, &is_marked_);
834 }
else if (parameters_->binary_minimization_algorithm() ==
836 BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION) {
838 *trail_, &learned_conflict_, &is_marked_,
841 DCHECK(IsConflictValid(learned_conflict_));
845 MinimizeConflict(&learned_conflict_, &reason_used_to_infer_the_conflict_);
848 if (!binary_implication_graph_->
IsEmpty()) {
852 switch (parameters_->binary_minimization_algorithm()) {
853 case SatParameters::NO_BINARY_MINIMIZATION:
854 ABSL_FALLTHROUGH_INTENDED;
855 case SatParameters::BINARY_MINIMIZATION_FIRST:
856 ABSL_FALLTHROUGH_INTENDED;
857 case SatParameters::BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION:
859 case SatParameters::BINARY_MINIMIZATION_WITH_REACHABILITY:
863 case SatParameters::EXPERIMENTAL_BINARY_MINIMIZATION:
865 *trail_, &learned_conflict_);
868 DCHECK(IsConflictValid(learned_conflict_));
882 counters_.num_literals_learned += learned_conflict_.size();
883 Backtrack(ComputeBacktrackLevel(learned_conflict_));
884 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
890 if (drat_proof_handler_ !=
nullptr) {
891 drat_proof_handler_->
AddClause(learned_conflict_);
896 bool is_redundant =
true;
897 if (!subsumed_clauses_.empty() &&
898 parameters_->subsumption_during_conflict_analysis()) {
899 for (SatClause* clause : subsumed_clauses_) {
900 DCHECK(ClauseSubsumption(learned_conflict_, clause));
902 is_redundant =
false;
907 counters_.num_subsumed_clauses += subsumed_clauses_.size();
911 const int conflict_lbd = AddLearnedClauseAndEnqueueUnitPropagation(
912 learned_conflict_, is_redundant);
913 restart_->
OnConflict(conflict_trail_index, conflict_decision_level,
919 int max_level,
int* first_propagation_index) {
921 DCHECK(assumptions_.empty());
922 int decision_index = current_decision_level_;
923 while (decision_index <= max_level) {
924 DCHECK_GE(decision_index, current_decision_level_);
925 const Literal previous_decision = decisions_[decision_index].literal;
927 if (
Assignment().LiteralIsTrue(previous_decision)) {
933 if (
Assignment().LiteralIsFalse(previous_decision)) {
941 const int old_level = current_decision_level_;
943 *first_propagation_index =
std::min(*first_propagation_index,
index);
945 if (current_decision_level_ <= old_level) {
957 decision_index = current_decision_level_;
965 CHECK(PropagationIsDone());
966 CHECK(assumptions_.empty());
971 int first_propagation_index = trail_->
Index();
973 return first_propagation_index;
978 CHECK(PropagationIsDone());
982 EnqueueNewDecision(true_literal);
1007 if (target_level == 0) counters_.num_restarts++;
1012 int target_trail_index = 0;
1013 while (current_decision_level_ > target_level) {
1014 --current_decision_level_;
1015 target_trail_index = decisions_[current_decision_level_].trail_index;
1018 Untrail(target_trail_index);
1019 last_decision_or_backtrack_trail_index_ = trail_->
Index();
1028 if (!
Propagate())
return SetModelUnsat();
1048 const std::vector<Literal>& assumptions) {
1051 return SolveInternal(time_limit_);
1055 SOLVER_LOG(logger_, RunningStatisticsString());
1063 assumption_level_ = assumption_level;
1066 if (!assumptions_.empty()) {
1068 assumptions_.clear();
1078void SatSolver::KeepAllClauseUsedToInfer(BooleanVariable variable) {
1080 if (trail_->
Info(variable).
level == 0)
return;
1082 std::vector<bool> is_marked(trail_index + 1,
false);
1083 is_marked[trail_index] =
true;
1085 for (; num > 0 && trail_index >= 0; --trail_index) {
1086 if (!is_marked[trail_index])
continue;
1087 is_marked[trail_index] =
false;
1090 const BooleanVariable
var = (*trail_)[trail_index].Variable();
1092 if (clause !=
nullptr) {
1095 for (
const Literal l : trail_->
Reason(
var)) {
1096 const AssignmentInfo& info = trail_->
Info(l.Variable());
1097 if (info.level == 0)
continue;
1098 if (!is_marked[info.trail_index]) {
1099 is_marked[info.trail_index] =
true;
1109void SatSolver::TryToMinimizeClause(SatClause* clause) {
1111 ++counters_.minimization_num_clauses;
1113 absl::btree_set<LiteralIndex> moved_last;
1114 std::vector<Literal> candidate(clause->begin(), clause->end());
1115 while (!model_is_unsat_) {
1122 if (target_level == -1)
break;
1126 const Literal
literal = candidate[level];
1128 candidate.erase(candidate.begin() + level);
1131 const int variable_level =
1133 if (variable_level == 0) {
1134 ProcessNewlyFixedVariablesForDratProof();
1135 counters_.minimization_num_true++;
1136 counters_.minimization_num_removed_literals += clause->size();
1138 clauses_propagator_->
Detach(clause);
1146 if (ReasonClauseOrNull(
literal.Variable()) != clause) {
1147 counters_.minimization_num_subsumed++;
1148 counters_.minimization_num_removed_literals += clause->size();
1151 KeepAllClauseUsedToInfer(
literal.Variable());
1153 clauses_propagator_->
Detach(clause);
1159 if (variable_level + 1 < candidate.size()) {
1160 candidate.resize(variable_level);
1166 ++counters_.minimization_num_decisions;
1168 if (!clause->IsAttached()) {
1172 if (model_is_unsat_)
return;
1175 if (candidate.empty()) {
1176 model_is_unsat_ =
true;
1179 moved_last.insert(candidate.back().Index());
1184 if (candidate.size() == clause->size())
return;
1186 if (candidate.size() == 1) {
1187 if (drat_proof_handler_ !=
nullptr) {
1188 drat_proof_handler_->
AddClause(candidate);
1190 if (!
Assignment().VariableIsAssigned(candidate[0].Variable())) {
1191 counters_.minimization_num_removed_literals += clause->size();
1198 if (candidate.size() == 2) {
1199 counters_.minimization_num_removed_literals += clause->size() - 2;
1202 AddBinaryClauseInternal(candidate[0], candidate[1],
true);
1203 clauses_propagator_->
Detach(clause);
1212 counters_.minimization_num_removed_literals +=
1213 clause->size() - candidate.size();
1218 model_is_unsat_ =
true;
1234 SOLVER_LOG(logger_,
"Number of variables: ", num_variables_.value());
1235 SOLVER_LOG(logger_,
"Number of clauses (size > 2): ",
1237 SOLVER_LOG(logger_,
"Number of binary clauses: ",
1239 SOLVER_LOG(logger_,
"Number of linear constraints: ",
1242 SOLVER_LOG(logger_,
"Number of watched clauses: ",
1248 int64_t next_minimization_num_restart =
1250 parameters_->minimize_with_propagation_restart_period();
1253 const int64_t kDisplayFrequency = 10000;
1254 int64_t next_display = parameters_->log_search_progress()
1256 :
std::numeric_limits<int64_t>::
max();
1259 const int64_t kMemoryCheckFrequency = 10000;
1260 int64_t next_memory_check =
1265 const int64_t kFailureLimit =
1266 parameters_->max_number_of_conflicts() ==
1269 : counters_.
num_failures + parameters_->max_number_of_conflicts();
1277 SOLVER_LOG(logger_,
"The time limit has been reached. Aborting.");
1282 SOLVER_LOG(logger_,
"The conflict limit has been reached. Aborting.");
1291 if (counters_.num_failures >= next_memory_check) {
1292 next_memory_check = NextMultipleOf(
num_failures(), kMemoryCheckFrequency);
1293 if (IsMemoryLimitReached()) {
1294 SOLVER_LOG(logger_,
"The memory limit has been reached. Aborting.");
1301 if (counters_.num_failures >= next_display) {
1302 SOLVER_LOG(logger_, RunningStatisticsString());
1303 next_display = NextMultipleOf(
num_failures(), kDisplayFrequency);
1306 const int old_level = current_decision_level_;
1307 if (!PropagateAndStopAfterOneConflictResolution()) {
1309 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1310 if (old_level == current_decision_level_) {
1311 CHECK(!assumptions_.empty());
1319 if (trail_->
Index() == num_variables_.value()) {
1329 restart_->
NumRestarts() >= next_minimization_num_restart) {
1330 next_minimization_num_restart =
1332 parameters_->minimize_with_propagation_restart_period();
1334 parameters_->minimize_with_propagation_num_decisions());
1338 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1339 if (trail_->
Index() == num_variables_.value()) {
1345 EnqueueNewDecision(decision_policy_->
NextBranch());
1353 block_clause_deletion_ =
true;
1355 const int64_t target_num_branches = counters_.num_branches + decisions_budget;
1356 while (counters_.num_branches < target_num_branches &&
1357 (time_limit_ ==
nullptr || !time_limit_->
LimitReached())) {
1359 if (to_minimize !=
nullptr) {
1360 TryToMinimizeClause(to_minimize);
1361 if (model_is_unsat_)
return;
1363 if (to_minimize ==
nullptr) {
1364 VLOG(1) <<
"Minimized all clauses, restarting from first one.";
1371 block_clause_deletion_ =
false;
1377 std::vector<Literal> unsat_assumptions;
1381 int trail_index = 0;
1389 unsat_assumptions.push_back(lit.Negated());
1394 is_marked_.
Set(lit.Variable());
1404 while (trail_index >= limit &&
1405 !is_marked_[(*trail_)[trail_index].Variable()]) {
1408 if (trail_index < limit)
break;
1409 const Literal marked_literal = (*trail_)[trail_index];
1414 unsat_assumptions.push_back(marked_literal);
1418 const BooleanVariable
var =
literal.Variable();
1419 const int level = DecisionLevel(
var);
1420 if (level > 0 && !is_marked_[
var]) is_marked_.
Set(
var);
1427 std::reverse(unsat_assumptions.begin(), unsat_assumptions.end());
1428 return unsat_assumptions;
1431void SatSolver::BumpReasonActivities(
const std::vector<Literal>& literals) {
1434 const BooleanVariable
var =
literal.Variable();
1435 if (DecisionLevel(
var) > 0) {
1437 if (clause !=
nullptr) {
1438 BumpClauseActivity(clause);
1440 UpperBoundedLinearConstraint* pb_constraint =
1441 ReasonPbConstraintOrNull(
var);
1442 if (pb_constraint !=
nullptr) {
1452void SatSolver::BumpClauseActivity(SatClause* clause) {
1463 const int new_lbd = ComputeLbd(*clause);
1464 if (new_lbd + 1 <= parameters_->clause_cleanup_lbd_bound()) {
1470 switch (parameters_->clause_cleanup_protection()) {
1471 case SatParameters::PROTECTION_NONE:
1473 case SatParameters::PROTECTION_ALWAYS:
1474 it->second.protected_during_next_cleanup =
true;
1476 case SatParameters::PROTECTION_LBD:
1481 if (new_lbd + 1 < it->second.lbd) {
1482 it->second.protected_during_next_cleanup =
true;
1483 it->second.lbd = new_lbd;
1488 const double activity = it->second.activity += clause_activity_increment_;
1489 if (activity > parameters_->max_clause_activity_value()) {
1490 RescaleClauseActivities(1.0 / parameters_->max_clause_activity_value());
1494void SatSolver::RescaleClauseActivities(
double scaling_factor) {
1496 clause_activity_increment_ *= scaling_factor;
1498 entry.second.activity *= scaling_factor;
1502void SatSolver::UpdateClauseActivityIncrement() {
1504 clause_activity_increment_ *= 1.0 / parameters_->clause_activity_decay();
1507bool SatSolver::IsConflictValid(
const std::vector<Literal>& literals) {
1509 if (literals.empty())
return false;
1510 const int highest_level = DecisionLevel(literals[0].Variable());
1511 for (
int i = 1; i < literals.size(); ++i) {
1512 const int level = DecisionLevel(literals[i].Variable());
1513 if (level <= 0 || level >= highest_level)
return false;
1518int SatSolver::ComputeBacktrackLevel(
const std::vector<Literal>& literals) {
1531 int backtrack_level = 0;
1532 for (
int i = 1; i < literals.size(); ++i) {
1533 const int level = DecisionLevel(literals[i].Variable());
1534 backtrack_level =
std::max(backtrack_level, level);
1536 DCHECK_LT(backtrack_level, DecisionLevel(literals[0].Variable()));
1538 return backtrack_level;
1541template <
typename LiteralList>
1542int SatSolver::ComputeLbd(
const LiteralList& literals) {
1545 parameters_->count_assumption_levels_in_lbd() ? 0 : assumption_level_;
1549 SatDecisionLevel(DecisionLevel(literals.begin()->Variable()) + 1));
1550 for (
const Literal
literal : literals) {
1551 const SatDecisionLevel level(DecisionLevel(
literal.Variable()));
1553 if (level > limit && !is_level_marked_[level]) {
1554 is_level_marked_.
Set(level);
1560std::string SatSolver::StatusString(Status
status)
const {
1561 const double time_in_s = timer_.
Get();
1563 absl::StrFormat(
" time: %fs\n", time_in_s) +
1566 " num failures: %d (%.0f /sec)\n", counters_.num_failures,
1567 static_cast<double>(counters_.num_failures) / time_in_s) +
1569 " num branches: %d (%.0f /sec)\n", counters_.num_branches,
1570 static_cast<double>(counters_.num_branches) / time_in_s) +
1571 absl::StrFormat(
" num propagations: %d (%.0f /sec)\n",
1574 absl::StrFormat(
" num binary propagations: %d\n",
1576 absl::StrFormat(
" num binary inspections: %d\n",
1579 " num binary redundant implications: %d\n",
1582 " num classic minimizations: %d"
1583 " (literals removed: %d)\n",
1584 counters_.num_minimizations, counters_.num_literals_removed) +
1586 " num binary minimizations: %d"
1587 " (literals removed: %d)\n",
1590 absl::StrFormat(
" num inspected clauses: %d\n",
1592 absl::StrFormat(
" num inspected clause_literals: %d\n",
1595 " num learned literals: %d (avg: %.1f /clause)\n",
1596 counters_.num_literals_learned,
1597 1.0 * counters_.num_literals_learned / counters_.num_failures) +
1599 " num learned PB literals: %d (avg: %.1f /clause)\n",
1600 counters_.num_learned_pb_literals,
1601 1.0 * counters_.num_learned_pb_literals / counters_.num_failures) +
1602 absl::StrFormat(
" num subsumed clauses: %d\n",
1603 counters_.num_subsumed_clauses) +
1604 absl::StrFormat(
" minimization_num_clauses: %d\n",
1605 counters_.minimization_num_clauses) +
1606 absl::StrFormat(
" minimization_num_decisions: %d\n",
1607 counters_.minimization_num_decisions) +
1608 absl::StrFormat(
" minimization_num_true: %d\n",
1609 counters_.minimization_num_true) +
1610 absl::StrFormat(
" minimization_num_subsumed: %d\n",
1611 counters_.minimization_num_subsumed) +
1612 absl::StrFormat(
" minimization_num_removed_literals: %d\n",
1613 counters_.minimization_num_removed_literals) +
1614 absl::StrFormat(
" pb num threshold updates: %d\n",
1616 absl::StrFormat(
" pb num constraint lookups: %d\n",
1618 absl::StrFormat(
" pb num inspected constraint literals: %d\n",
1624std::string SatSolver::RunningStatisticsString()
const {
1625 const double time_in_s = timer_.
Get();
1626 return absl::StrFormat(
1627 "%6.2fs, mem:%s, fails:%d, depth:%d, clauses:%d, tmp:%d, bin:%u, "
1628 "restarts:%d, vars:%d",
1634 num_variables_.value() - num_processed_fixed_variables_);
1637void SatSolver::ProcessNewlyFixedVariablesForDratProof() {
1638 if (drat_proof_handler_ ==
nullptr)
return;
1652 for (; drat_num_processed_fixed_variables_ < trail_->
Index();
1653 ++drat_num_processed_fixed_variables_) {
1654 temp = (*trail_)[drat_num_processed_fixed_variables_];
1655 drat_proof_handler_->
AddClause({&temp, 1});
1662 int num_detached_clauses = 0;
1665 ProcessNewlyFixedVariablesForDratProof();
1671 if (!clause->IsAttached())
continue;
1673 const size_t old_size = clause->size();
1674 if (clause->RemoveFixedLiteralsAndTestIfTrue(trail_->
Assignment())) {
1677 ++num_detached_clauses;
1681 const size_t new_size = clause->size();
1682 if (new_size == old_size)
continue;
1684 if (drat_proof_handler_ !=
nullptr) {
1686 drat_proof_handler_->
AddClause({clause->begin(), new_size});
1687 drat_proof_handler_->
DeleteClause({clause->begin(), old_size});
1690 if (new_size == 2) {
1694 AddBinaryClauseInternal(clause->FirstLiteral(), clause->SecondLiteral(),
1704 if (num_detached_clauses > 0 || num_binary > 0) {
1705 VLOG(1) << trail_->
Index() <<
" fixed variables at level 0. "
1706 <<
"Detached " << num_detached_clauses <<
" clauses. " << num_binary
1707 <<
" converted to binary.";
1716 num_processed_fixed_variables_ = trail_->
Index();
1720bool SatSolver::PropagationIsDone()
const {
1722 if (propagator->IsEmpty())
continue;
1723 if (!propagator->PropagationIsDone(*trail_))
return false;
1738 non_empty_propagators_.clear();
1740 if (!propagator->IsEmpty()) {
1741 non_empty_propagators_.push_back(propagator);
1753 const int old_index = trail_->
Index();
1755 DCHECK(propagator->PropagatePreconditionsAreSatisfied(*trail_));
1756 if (!propagator->Propagate(trail_))
return false;
1757 if (trail_->
Index() > old_index)
break;
1759 if (trail_->
Index() == old_index)
break;
1764void SatSolver::InitializePropagators() {
1765 propagators_.clear();
1766 propagators_.push_back(binary_implication_graph_);
1767 propagators_.push_back(clauses_propagator_);
1768 propagators_.push_back(pb_constraints_);
1769 for (
int i = 0; i < external_propagators_.size(); ++i) {
1770 propagators_.push_back(external_propagators_[i]);
1772 if (last_propagator_ !=
nullptr) {
1773 propagators_.push_back(last_propagator_);
1777bool SatSolver::ResolvePBConflict(BooleanVariable
var,
1778 MutableUpperBoundedLinearConstraint* conflict,
1783 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1786 UpperBoundedLinearConstraint* pb_reason = ReasonPbConstraintOrNull(
var);
1787 if (pb_reason !=
nullptr) {
1788 pb_reason->ResolvePBConflict(*trail_,
var, conflict, slack);
1796 const int algorithm = 1;
1797 switch (algorithm) {
1801 conflict->ReduceSlackTo(*trail_, trail_index, *slack,
Coefficient(0));
1805 multiplier = *slack + 1;
1809 multiplier = conflict->GetCoefficient(
var);
1819 conflict->AddTerm(
literal.Negated(), multiplier);
1822 conflict->AddToRhs((num_literals - 1) * multiplier);
1826 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1830void SatSolver::EnqueueNewDecision(Literal
literal) {
1841 const double kMinDeterministicTimeBetweenCleanups = 1.0;
1842 if (num_processed_fixed_variables_ < trail_->
Index() &&
1844 deterministic_time_of_last_fixed_variables_cleanup_ +
1845 kMinDeterministicTimeBetweenCleanups) {
1850 counters_.num_branches++;
1851 last_decision_or_backtrack_trail_index_ = trail_->
Index();
1852 decisions_[current_decision_level_] = Decision(trail_->
Index(),
literal);
1853 ++current_decision_level_;
1858void SatSolver::Untrail(
int target_trail_index) {
1861 for (SatPropagator* propagator : propagators_) {
1862 if (propagator->IsEmpty())
continue;
1863 propagator->Untrail(*trail_, target_trail_index);
1865 decision_policy_->
Untrail(target_trail_index);
1866 trail_->
Untrail(target_trail_index);
1869std::string SatSolver::DebugString(
const SatClause& clause)
const {
1871 for (
const Literal
literal : clause) {
1872 if (!result.empty()) {
1873 result.append(
" || ");
1875 const std::string
value =
1880 result.append(absl::StrFormat(
"%s(%s)",
literal.DebugString(),
value));
1885int SatSolver::ComputeMaxTrailIndex(absl::Span<const Literal> clause)
const {
1887 int trail_index = -1;
1888 for (
const Literal
literal : clause) {
1898void SatSolver::ComputeFirstUIPConflict(
1899 int max_trail_index, std::vector<Literal>* conflict,
1900 std::vector<Literal>* reason_used_to_infer_the_conflict,
1901 std::vector<SatClause*>* subsumed_clauses) {
1909 reason_used_to_infer_the_conflict->clear();
1910 subsumed_clauses->clear();
1911 if (max_trail_index == -1)
return;
1917 int trail_index = max_trail_index;
1918 const int highest_level = DecisionLevel((*trail_)[trail_index].Variable());
1919 if (highest_level == 0)
return;
1936 absl::Span<const Literal> clause_to_expand = trail_->
FailingClause();
1938 DCHECK(!clause_to_expand.empty());
1939 int num_literal_at_highest_level_that_needs_to_be_processed = 0;
1941 int num_new_vars_at_positive_level = 0;
1942 int num_vars_at_positive_level_in_clause_to_expand = 0;
1943 for (
const Literal
literal : clause_to_expand) {
1944 const BooleanVariable
var =
literal.Variable();
1945 const int level = DecisionLevel(
var);
1946 if (level > 0) ++num_vars_at_positive_level_in_clause_to_expand;
1947 if (!is_marked_[
var]) {
1949 if (level == highest_level) {
1950 ++num_new_vars_at_positive_level;
1951 ++num_literal_at_highest_level_that_needs_to_be_processed;
1952 }
else if (level > 0) {
1953 ++num_new_vars_at_positive_level;
1959 reason_used_to_infer_the_conflict->push_back(
literal);
1966 if (num_new_vars_at_positive_level > 0) {
1969 subsumed_clauses->clear();
1976 if (sat_clause !=
nullptr &&
1977 num_vars_at_positive_level_in_clause_to_expand ==
1979 num_literal_at_highest_level_that_needs_to_be_processed) {
1980 subsumed_clauses->push_back(sat_clause);
1984 DCHECK_GT(num_literal_at_highest_level_that_needs_to_be_processed, 0);
1985 while (!is_marked_[(*trail_)[trail_index].Variable()]) {
1988 DCHECK_EQ(DecisionLevel((*trail_)[trail_index].Variable()),
1992 if (num_literal_at_highest_level_that_needs_to_be_processed == 1) {
1996 conflict->push_back((*trail_)[trail_index].Negated());
1999 std::swap(conflict->back(), conflict->front());
2003 const Literal
literal = (*trail_)[trail_index];
2004 reason_used_to_infer_the_conflict->push_back(
literal);
2010 clause_to_expand = {};
2014 sat_clause = ReasonClauseOrNull(
literal.Variable());
2016 --num_literal_at_highest_level_that_needs_to_be_processed;
2021void SatSolver::ComputeUnionOfReasons(
const std::vector<Literal>&
input,
2022 std::vector<Literal>* literals) {
2025 for (
const Literal l :
input) tmp_mark_.
Set(l.Variable());
2026 for (
const Literal l :
input) {
2027 for (
const Literal r : trail_->
Reason(l.Variable())) {
2028 if (!tmp_mark_[r.Variable()]) {
2029 tmp_mark_.
Set(r.Variable());
2030 literals->push_back(r);
2034 for (
const Literal l :
input) tmp_mark_.
Clear(l.Variable());
2035 for (
const Literal l : *literals) tmp_mark_.
Clear(l.Variable());
2039void SatSolver::ComputePBConflict(
int max_trail_index,
2041 MutableUpperBoundedLinearConstraint* conflict,
2042 int* pb_backjump_level) {
2044 int trail_index = max_trail_index;
2050 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1));
2051 CHECK_LT(slack, 0) <<
"We don't have a conflict!";
2054 int backjump_level = 0;
2056 const BooleanVariable
var = (*trail_)[trail_index].Variable();
2059 if (conflict->GetCoefficient(
var) > 0 &&
2061 if (parameters_->minimize_reduction_during_pb_resolution()) {
2066 conflict->ReduceGivenCoefficient(
var);
2070 slack += conflict->GetCoefficient(
var);
2074 if (slack < 0)
continue;
2080 const int current_level = DecisionLevel(
var);
2081 int i = trail_index;
2083 const BooleanVariable previous_var = (*trail_)[i].Variable();
2084 if (conflict->GetCoefficient(previous_var) > 0 &&
2086 conflict->GetLiteral(previous_var))) {
2091 if (i < 0 || DecisionLevel((*trail_)[i].Variable()) < current_level) {
2092 backjump_level = i < 0 ? 0 : DecisionLevel((*trail_)[i].Variable());
2098 const bool clause_used = ResolvePBConflict(
var, conflict, &slack);
2109 ? conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1)
2114 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2115 conflict->ReduceCoefficients();
2121 if (parameters_->minimize_reduction_during_pb_resolution()) {
2123 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1);
2125 slack = conflict->ReduceCoefficientsAndComputeSlackForTrailPrefix(
2126 *trail_, trail_index + 1);
2131 if (conflict->Rhs() < 0) {
2132 *pb_backjump_level = -1;
2140 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2141 conflict->ReduceCoefficients();
2146 std::vector<Coefficient> sum_for_le_level(backjump_level + 2,
Coefficient(0));
2147 std::vector<Coefficient> max_coeff_for_ge_level(backjump_level + 2,
2151 for (BooleanVariable
var : conflict->PossibleNonZeros()) {
2153 if (
coeff == 0)
continue;
2157 DecisionLevel(
var) > backjump_level) {
2158 max_coeff_for_ge_level[backjump_level + 1] =
2159 std::max(max_coeff_for_ge_level[backjump_level + 1],
coeff);
2161 const int level = DecisionLevel(
var);
2163 sum_for_le_level[level] +=
coeff;
2165 max_coeff_for_ge_level[level] =
2171 for (
int i = 1; i < sum_for_le_level.size(); ++i) {
2172 sum_for_le_level[i] += sum_for_le_level[i - 1];
2174 for (
int i = max_coeff_for_ge_level.size() - 2; i >= 0; --i) {
2175 max_coeff_for_ge_level[i] =
2176 std::max(max_coeff_for_ge_level[i], max_coeff_for_ge_level[i + 1]);
2181 if (sum_for_le_level[0] > conflict->Rhs()) {
2182 *pb_backjump_level = -1;
2185 for (
int i = 0; i <= backjump_level; ++i) {
2186 const Coefficient level_sum = sum_for_le_level[i];
2187 CHECK_LE(level_sum, conflict->Rhs());
2188 if (conflict->Rhs() - level_sum < max_coeff_for_ge_level[i + 1]) {
2189 *pb_backjump_level = i;
2193 LOG(
FATAL) <<
"The code should never reach here.";
2196void SatSolver::MinimizeConflict(
2197 std::vector<Literal>* conflict,
2198 std::vector<Literal>* reason_used_to_infer_the_conflict) {
2201 const int old_size = conflict->size();
2202 switch (parameters_->minimization_algorithm()) {
2203 case SatParameters::NONE:
2205 case SatParameters::SIMPLE: {
2206 MinimizeConflictSimple(conflict);
2209 case SatParameters::RECURSIVE: {
2210 MinimizeConflictRecursively(conflict);
2213 case SatParameters::EXPERIMENTAL: {
2214 MinimizeConflictExperimental(conflict);
2218 if (conflict->size() < old_size) {
2219 ++counters_.num_minimizations;
2220 counters_.num_literals_removed += old_size - conflict->size();
2231void SatSolver::MinimizeConflictSimple(std::vector<Literal>* conflict) {
2238 for (
int i = 1; i < conflict->size(); ++i) {
2239 const BooleanVariable
var = (*conflict)[i].Variable();
2240 bool can_be_removed =
false;
2241 if (DecisionLevel(
var) != current_level) {
2243 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2244 if (!reason.empty()) {
2245 can_be_removed =
true;
2246 for (Literal
literal : reason) {
2247 if (DecisionLevel(
literal.Variable()) == 0)
continue;
2248 if (!is_marked_[
literal.Variable()]) {
2249 can_be_removed =
false;
2255 if (!can_be_removed) {
2256 (*conflict)[
index] = (*conflict)[i];
2260 conflict->erase(conflict->begin() +
index, conflict->end());
2269void SatSolver::MinimizeConflictRecursively(std::vector<Literal>* conflict) {
2303 const int level = DecisionLevel(
var);
2304 min_trail_index_per_level_[level] =
std::min(
2312 for (
int i = 1; i < conflict->size(); ++i) {
2313 const BooleanVariable
var = (*conflict)[i].Variable();
2314 const AssignmentInfo& info = trail_->
Info(
var);
2317 info.trail_index <= min_trail_index_per_level_[info.level] ||
2318 !CanBeInferedFromConflictVariables(
var)) {
2321 is_independent_.
Set(
var);
2322 (*conflict)[
index] = (*conflict)[i];
2326 conflict->resize(
index);
2330 const int threshold = min_trail_index_per_level_.size() / 2;
2333 min_trail_index_per_level_[DecisionLevel(
var)] =
2337 min_trail_index_per_level_.clear();
2341bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) {
2344 DCHECK(is_marked_[variable]);
2345 const BooleanVariable v =
2347 if (v != variable)
return !is_independent_[v];
2360 dfs_stack_.push_back(variable);
2361 variable_to_process_.clear();
2362 variable_to_process_.push_back(variable);
2366 const BooleanVariable
var =
literal.Variable();
2368 if (is_marked_[
var])
continue;
2369 const AssignmentInfo& info = trail_->
Info(
var);
2370 if (info.level == 0) {
2378 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2382 variable_to_process_.push_back(
var);
2386 while (!variable_to_process_.empty()) {
2387 const BooleanVariable current_var = variable_to_process_.back();
2388 if (current_var == dfs_stack_.back()) {
2391 if (dfs_stack_.size() > 1) {
2392 DCHECK(!is_marked_[current_var]);
2393 is_marked_.
Set(current_var);
2395 variable_to_process_.pop_back();
2396 dfs_stack_.pop_back();
2401 if (is_marked_[current_var]) {
2402 variable_to_process_.pop_back();
2408 DCHECK(!is_independent_[current_var]);
2412 const BooleanVariable v =
2414 if (v != current_var) {
2415 if (is_independent_[v])
break;
2417 variable_to_process_.pop_back();
2423 dfs_stack_.push_back(current_var);
2424 bool abort_early =
false;
2426 const BooleanVariable
var =
literal.Variable();
2428 const AssignmentInfo& info = trail_->
Info(
var);
2429 if (info.level == 0 || is_marked_[
var])
continue;
2430 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2432 is_independent_[
var]) {
2436 variable_to_process_.push_back(
var);
2438 if (abort_early)
break;
2442 for (
const BooleanVariable
var : dfs_stack_) {
2443 is_independent_.
Set(
var);
2445 return dfs_stack_.empty();
2450struct WeightedVariable {
2451 WeightedVariable(BooleanVariable v,
int w) :
var(v),
weight(w) {}
2459struct VariableWithLargerWeightFirst {
2460 bool operator()(
const WeightedVariable& wv1,
2461 const WeightedVariable& wv2)
const {
2462 return (wv1.weight > wv2.weight ||
2463 (wv1.weight == wv2.weight && wv1.var < wv2.var));
2479void SatSolver::MinimizeConflictExperimental(std::vector<Literal>* conflict) {
2486 std::vector<WeightedVariable> variables_sorted_by_level;
2487 for (Literal
literal : *conflict) {
2488 const BooleanVariable
var =
literal.Variable();
2490 const int level = DecisionLevel(
var);
2491 if (level < current_level) {
2492 variables_sorted_by_level.push_back(WeightedVariable(
var, level));
2495 std::sort(variables_sorted_by_level.begin(), variables_sorted_by_level.end(),
2496 VariableWithLargerWeightFirst());
2499 std::vector<BooleanVariable> to_remove;
2500 for (WeightedVariable weighted_var : variables_sorted_by_level) {
2501 const BooleanVariable
var = weighted_var.var;
2505 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2506 if (reason.empty())
continue;
2510 std::vector<Literal> not_contained_literals;
2511 for (
const Literal reason_literal : reason) {
2512 const BooleanVariable reason_var = reason_literal.Variable();
2515 if (DecisionLevel(reason_var) == 0)
continue;
2520 if (!is_marked_[reason_var]) {
2521 not_contained_literals.push_back(reason_literal);
2522 if (not_contained_literals.size() > 1)
break;
2525 if (not_contained_literals.empty()) {
2530 to_remove.push_back(
var);
2531 }
else if (not_contained_literals.size() == 1) {
2534 to_remove.push_back(
var);
2535 is_marked_.
Set(not_contained_literals.front().Variable());
2536 conflict->push_back(not_contained_literals.front());
2541 for (BooleanVariable
var : to_remove) {
2547 for (
int i = 0; i < conflict->size(); ++i) {
2548 const Literal
literal = (*conflict)[i];
2549 if (is_marked_[
literal.Variable()]) {
2554 conflict->erase(conflict->begin() +
index, conflict->end());
2557void SatSolver::CleanClauseDatabaseIfNeeded() {
2558 if (num_learned_clause_before_cleanup_ > 0)
return;
2563 typedef std::pair<SatClause*, ClauseInfo> Entry;
2564 std::vector<Entry> entries;
2566 for (
auto& entry : clauses_info) {
2567 if (ClauseIsUsedAsReason(entry.first))
continue;
2568 if (entry.second.protected_during_next_cleanup) {
2569 entry.second.protected_during_next_cleanup =
false;
2572 entries.push_back(entry);
2574 const int num_protected_clauses = clauses_info.size() - entries.size();
2576 if (parameters_->clause_cleanup_ordering() == SatParameters::CLAUSE_LBD) {
2578 std::sort(entries.begin(), entries.end(),
2579 [](
const Entry&
a,
const Entry&
b) {
2580 if (a.second.lbd == b.second.lbd) {
2581 return a.second.activity < b.second.activity;
2583 return a.second.lbd >
b.second.lbd;
2587 std::sort(entries.begin(), entries.end(),
2588 [](
const Entry&
a,
const Entry&
b) {
2589 if (a.second.activity == b.second.activity) {
2590 return a.second.lbd > b.second.lbd;
2592 return a.second.activity <
b.second.activity;
2597 int num_kept_clauses =
2598 (parameters_->clause_cleanup_target() > 0)
2599 ?
std::min(
static_cast<int>(entries.size()),
2600 parameters_->clause_cleanup_target())
2601 :
static_cast<int>(parameters_->clause_cleanup_ratio() *
2602 static_cast<double>(entries.size()));
2604 int num_deleted_clauses = entries.size() - num_kept_clauses;
2609 while (num_deleted_clauses > 0) {
2610 const ClauseInfo&
a = entries[num_deleted_clauses].second;
2611 const ClauseInfo&
b = entries[num_deleted_clauses - 1].second;
2612 if (
a.activity !=
b.activity ||
a.lbd !=
b.lbd)
break;
2613 --num_deleted_clauses;
2616 if (num_deleted_clauses > 0) {
2617 entries.resize(num_deleted_clauses);
2618 for (
const Entry& entry : entries) {
2619 SatClause* clause = entry.first;
2620 counters_.num_literals_forgotten += clause->size();
2621 clauses_propagator_->LazyDetach(clause);
2623 clauses_propagator_->CleanUpWatchers();
2627 if (!block_clause_deletion_) {
2628 clauses_propagator_->DeleteRemovedClauses();
2632 num_learned_clause_before_cleanup_ = parameters_->clause_cleanup_period();
2633 VLOG(1) <<
"Database cleanup, #protected:" << num_protected_clauses
2634 <<
" #kept:" << num_kept_clauses
2635 <<
" #deleted:" << num_deleted_clauses;
2640 case SatSolver::ASSUMPTIONS_UNSAT:
2641 return "ASSUMPTIONS_UNSAT";
2642 case SatSolver::INFEASIBLE:
2643 return "INFEASIBLE";
2644 case SatSolver::FEASIBLE:
2646 case SatSolver::LIMIT_REACHED:
2647 return "LIMIT_REACHED";
2651 LOG(DFATAL) <<
"Invalid SatSolver::Status " <<
status;
2656 std::vector<Literal> result;
2659 for (
const Literal lit : *core) {
2661 result.push_back(lit);
2665 if (result.size() < core->size()) {
2666 VLOG(1) <<
"minimization " << core->size() <<
" -> " << result.size();
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_GT(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
void SetLogToStdOut(bool enable)
bool LoggingIsEnabled() const
void EnableLogging(bool enable)
void Set(IntegerType index)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
int NumberOfSetCallsWithDifferentArguments() const
void Clear(IntegerType index)
void ClearAndResize(IntegerType size)
std::string StatString() const
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
void ResetLimitFromParameters(const Parameters ¶meters)
Sets new time limits.
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
const std::vector< BinaryClause > & newly_added() const
bool Propagate(Trail *trail) final
void AddBinaryClause(Literal a, Literal b)
void MinimizeConflictWithReachability(std::vector< Literal > *c)
bool AddBinaryClauseDuringSearch(Literal a, Literal b)
void MinimizeConflictFirstWithTransitiveReduction(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked, absl::BitGenRef random)
int64_t num_inspections() const
int64_t num_redundant_implications() const
void MinimizeConflictFirst(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked)
int64_t num_literals_removed() const
int64_t num_propagations() const
void RemoveFixedVariables()
int64_t num_minimization() const
bool IsEmpty() const final
int64_t num_implications() const
ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span< const Literal > at_most_one)
void MinimizeConflictExperimental(const Trail &trail, std::vector< Literal > *c)
void Resize(int num_variables)
void DeleteClause(absl::Span< const Literal > clause)
void AddClause(absl::Span< const Literal > clause)
BooleanVariable Variable() const
SatClause * NextClauseToMinimize()
absl::flat_hash_map< SatClause *, ClauseInfo > * mutable_clauses_info()
SatClause * AddRemovableClause(const std::vector< Literal > &literals, Trail *trail)
int64_t num_inspected_clauses() const
int64_t num_clauses() const
bool AddClause(absl::Span< const Literal > literals, Trail *trail)
SatClause * ReasonClause(int trail_index) const
bool IsRemovable(SatClause *const clause) const
ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(SatClause *clause, absl::Span< const Literal > new_clause)
int64_t num_watched_clauses() const
void LazyDetach(SatClause *clause)
int64_t num_removable_clauses() const
const std::vector< SatClause * > & AllClausesInCreationOrder() const
int64_t num_inspected_clause_literals() const
void ResetToMinimizeIndex()
void DeleteRemovedClauses()
void Detach(SatClause *clause)
void Resize(int num_variables)
Class that owns everything related to a particular optimization model.
void Register(T *non_owned_class)
Register a non-owned class that will be "singleton" in the model.
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
Coefficient ComputeSlackForTrailPrefix(const Trail &trail, int trail_index) const
void AddTerm(Literal literal, Coefficient coeff)
void AddToRhs(Coefficient value)
void ClearAndResize(int num_variables)
void CopyIntoVector(std::vector< LiteralWithCoeff > *output)
int NumberOfConstraints() const
void ClearConflictingConstraint()
int64_t num_inspected_constraint_literals() const
bool AddConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
UpperBoundedLinearConstraint * ConflictingConstraint()
int64_t num_threshold_updates() const
UpperBoundedLinearConstraint * ReasonPbConstraint(int trail_index) const
void UpdateActivityIncrement()
void BumpActivity(UpperBoundedLinearConstraint *constraint)
int64_t num_constraint_lookups() const
void Resize(int num_variables)
bool AddLearnedConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
std::string InfoString() const
void OnConflict(int conflict_trail_index, int conflict_decision_level, int conflict_lbd)
void IncreaseNumVariables(int num_variables)
void UpdateVariableActivityIncrement()
void Untrail(int target_trail_index)
void BumpVariableActivities(const std::vector< Literal > &literals)
void BeforeConflict(int trail_index)
void UpdateWeightedSign(const std::vector< LiteralWithCoeff > &terms, Coefficient rhs)
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
bool EnqueueDecisionIfNotConflicting(Literal true_literal)
void SetNumVariables(int num_variables)
bool AddTernaryClause(Literal a, Literal b, Literal c)
void AddLastPropagator(SatPropagator *propagator)
const SatParameters & parameters() const
bool AddClauseDuringSearch(absl::Span< const Literal > literals)
Status SolveWithTimeLimit(TimeLimit *time_limit)
void ProcessNewlyFixedVariables()
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions)
void AddPropagator(SatPropagator *propagator)
const VariablesAssignment & Assignment() const
const std::vector< BinaryClause > & NewlyAddedBinaryClauses()
bool AddBinaryClauses(const std::vector< BinaryClause > &clauses)
const Trail & LiteralTrail() const
Status UnsatStatus() const
void SetAssumptionLevel(int assumption_level)
void SaveDebugAssignment()
void AdvanceDeterministicTime(TimeLimit *limit)
int64_t num_restarts() const
void MinimizeSomeClauses(int decisions_budget)
int64_t num_branches() const
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
void SetParameters(const SatParameters ¶meters)
bool AddBinaryClause(Literal a, Literal b)
int EnqueueDecisionAndBacktrackOnConflict(Literal true_literal)
int64_t num_propagations() const
void Backtrack(int target_level)
bool RestoreSolverToAssumptionLevel()
int64_t num_failures() const
std::vector< Literal > GetLastIncompatibleDecisions()
bool ReapplyAssumptionsIfNeeded()
bool ResetWithGivenAssumptions(const std::vector< Literal > &assumptions)
int CurrentDecisionLevel() const
double deterministic_time() const
bool AddProblemClause(absl::Span< const Literal > literals)
bool AddUnitClause(Literal true_literal)
void ClearNewlyAddedBinaryClauses()
void RegisterPropagator(SatPropagator *propagator)
SatClause * FailingSatClause() const
int64_t NumberOfEnqueues() const
const VariablesAssignment & Assignment() const
int AssignmentType(BooleanVariable var) const
absl::Span< const Literal > Reason(BooleanVariable var) const
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
void Untrail(int target_trail_index)
std::vector< Literal > * MutableConflict()
const AssignmentInfo & Info(BooleanVariable var) const
absl::Span< const Literal > FailingClause() const
void SetDecisionLevel(int level)
void Resize(int num_variables)
void EnqueueWithUnitReason(Literal true_literal)
void EnqueueSearchDecision(Literal true_literal)
void AddToConflict(MutableUpperBoundedLinearConstraint *conflict)
BooleanVariable FirstVariableWithSameReason(BooleanVariable var)
void Resize(int num_variables)
bool LiteralIsAssigned(Literal literal) const
bool VariableIsAssigned(BooleanVariable var) const
bool LiteralIsTrue(Literal literal) const
void AssignFromTrueLiteral(Literal literal)
Literal GetTrueLiteralForAssignedVariable(BooleanVariable var) const
bool LiteralIsFalse(Literal literal) const
int NumberOfVariables() const
void Resize(int num_variables)
SharedClausesManager * clauses
ModelSharedTimeLimit * time_limit
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
std::tuple< int64_t, int64_t, const double > Coefficient
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
Coefficient ComputeNegatedCanonicalRhs(Coefficient lower_bound, Coefficient bound_shift, Coefficient max_value)
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
std::string SatStatusString(SatSolver::Status status)
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
bool BooleanLinearExpressionIsCanonical(const std::vector< LiteralWithCoeff > &cst)
int MoveOneUnprocessedLiteralLast(const absl::btree_set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
const int kUnsatTrailIndex
int64_t MemoryUsageProcess()
Collection of objects used to extend the Constraint Solver library.
std::string ProtobufShortDebugString(const P &message)
std::string MemoryUsage()
bool SafeAddInto(IntegerType a, IntegerType *b)
static int input(yyscan_t yyscanner)
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
static constexpr int kSearchDecision
#define SOLVER_LOG(logger,...)
#define VLOG_IS_ON(verboselevel)