21 #include <type_traits>
24 #include "absl/strings/str_format.h"
38 owned_model_.reset(model_);
47 track_binary_clauses_(false),
50 parameters_(
model->GetOrCreate<SatParameters>()),
53 clause_activity_increment_(1.0),
54 same_reason_identifier_(*trail_),
55 is_relevant_for_core_computation_(true),
56 problem_is_pure_sat_(true),
57 drat_proof_handler_(nullptr),
59 InitializePropagators();
66 CHECK_GE(num_variables, num_variables_);
68 num_variables_ = num_variables;
69 binary_implication_graph_->
Resize(num_variables);
70 clauses_propagator_->
Resize(num_variables);
71 trail_->
Resize(num_variables);
73 pb_constraints_->
Resize(num_variables);
74 same_reason_identifier_.
Resize(num_variables);
79 decisions_.resize(num_variables + 1);
120 bool SatSolver::IsMemoryLimitReached()
const {
121 const int64 memory_usage =
123 const int64 kMegaByte = 1024 * 1024;
124 return memory_usage > kMegaByte * parameters_->max_memory_in_mb();
127 bool SatSolver::SetModelUnsat() {
128 model_is_unsat_ =
true;
133 if (model_is_unsat_)
return false;
135 if (literals.empty())
return SetModelUnsat();
137 if (literals.size() == 2) {
142 return SetModelUnsat();
146 InitializePropagators();
149 if (!clauses_propagator_->
AddClause(literals)) {
151 return SetModelUnsat();
165 if (model_is_unsat_)
return false;
168 if (drat_proof_handler_ !=
nullptr) {
171 drat_proof_handler_->
AddClause({true_literal});
174 if (!
Propagate())
return SetModelUnsat();
180 tmp_pb_constraint_.clear();
184 true, Coefficient(1),
185 false, Coefficient(0),
186 &tmp_pb_constraint_);
191 tmp_pb_constraint_.clear();
196 true, Coefficient(1),
197 false, Coefficient(0),
198 &tmp_pb_constraint_);
207 tmp_pb_constraint_.clear();
212 true, Coefficient(1),
213 false, Coefficient(0),
214 &tmp_pb_constraint_);
217 bool SatSolver::AddProblemClauseInternal(absl::Span<const Literal> literals) {
224 CHECK_GT(literals.size(), 0);
225 if (literals.size() == 1) {
232 if (parameters_->treat_binary_clauses_separately() && literals.size() == 2) {
233 AddBinaryClauseInternal(literals[0], literals[1]);
235 if (!clauses_propagator_->
AddClause(literals, trail_)) {
236 return SetModelUnsat();
242 bool SatSolver::AddLinearConstraintInternal(
243 const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
244 Coefficient max_value) {
247 if (rhs < 0)
return SetModelUnsat();
248 if (rhs >= max_value)
return true;
255 const Coefficient min_coeff = cst.front().coefficient;
256 const Coefficient max_coeff = cst.back().coefficient;
260 if (max_value - min_coeff <= rhs) {
262 literals_scratchpad_.clear();
263 for (
const LiteralWithCoeff& term : cst) {
264 literals_scratchpad_.push_back(term.literal.Negated());
266 return AddProblemClauseInternal(literals_scratchpad_);
271 if (parameters_->treat_binary_clauses_separately() &&
272 !parameters_->use_pb_resolution() && max_coeff <= rhs &&
273 2 * min_coeff > rhs) {
274 literals_scratchpad_.clear();
275 for (
const LiteralWithCoeff& term : cst) {
276 literals_scratchpad_.push_back(term.literal);
278 if (!binary_implication_graph_->
AddAtMostOne(literals_scratchpad_)) {
279 return SetModelUnsat();
284 InitializePropagators();
288 problem_is_pure_sat_ =
false;
292 const bool result = pb_constraints_->
AddConstraint(cst, rhs, trail_);
293 InitializePropagators();
298 Coefficient lower_bound,
299 bool use_upper_bound,
300 Coefficient upper_bound,
301 std::vector<LiteralWithCoeff>* cst) {
304 if (model_is_unsat_)
return false;
307 Coefficient fixed_variable_shift(0);
313 CHECK(
SafeAddInto(-term.coefficient, &fixed_variable_shift));
316 (*cst)[
index] = term;
324 Coefficient bound_shift;
325 Coefficient max_value;
328 CHECK(
SafeAddInto(fixed_variable_shift, &bound_shift));
330 if (use_upper_bound) {
331 const Coefficient rhs =
333 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
334 return SetModelUnsat();
337 if (use_lower_bound) {
339 for (
int i = 0; i < cst->size(); ++i) {
340 (*cst)[i].literal = (*cst)[i].literal.Negated();
342 const Coefficient rhs =
344 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
345 return SetModelUnsat();
353 if (!PropagationIsDone() && !
Propagate()) {
354 return SetModelUnsat();
359 int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation(
360 const std::vector<Literal>& literals,
bool is_redundant) {
363 if (literals.size() == 1) {
371 if (literals.size() == 2 && parameters_->treat_binary_clauses_separately()) {
372 if (track_binary_clauses_) {
373 CHECK(binary_clauses_.
Add(BinaryClause(literals[0], literals[1])));
378 InitializePropagators();
382 CleanClauseDatabaseIfNeeded();
386 const int lbd = ComputeLbd(literals);
387 if (is_redundant && lbd > parameters_->clause_cleanup_lbd_bound()) {
388 --num_learned_clause_before_cleanup_;
396 BumpClauseActivity(clause);
398 CHECK(clauses_propagator_->
AddClause(literals, trail_));
405 problem_is_pure_sat_ =
false;
407 external_propagators_.push_back(propagator);
408 InitializePropagators();
413 CHECK(last_propagator_ ==
nullptr);
414 problem_is_pure_sat_ =
false;
416 last_propagator_ = propagator;
417 InitializePropagators();
421 BooleanVariable
var)
const {
431 SatClause* SatSolver::ReasonClauseOrNull(BooleanVariable
var)
const {
433 const AssignmentInfo& info = trail_->
Info(
var);
435 return clauses_propagator_->
ReasonClause(info.trail_index);
441 debug_assignment_.
Resize(num_variables_.value());
442 for (BooleanVariable i(0); i < num_variables_; ++i) {
453 InitializePropagators();
457 bool SatSolver::ClauseIsValidUnderDebugAssignement(
458 const std::vector<Literal>& clause)
const {
459 for (Literal l : clause) {
468 bool SatSolver::PBConstraintIsValidUnderDebugAssignment(
469 const std::vector<LiteralWithCoeff>& cst,
const Coefficient rhs)
const {
470 Coefficient sum(0.0);
471 for (LiteralWithCoeff term : cst) {
476 sum += term.coefficient;
486 bool ClauseSubsumption(
const std::vector<Literal>&
a, SatClause*
b) {
487 std::vector<Literal> superset(
b->begin(),
b->end());
488 std::vector<Literal> subset(
a.begin(),
a.end());
489 std::sort(superset.begin(), superset.end());
490 std::sort(subset.begin(), subset.end());
491 return std::includes(superset.begin(), superset.end(), subset.begin(),
500 CHECK(PropagationIsDone());
501 EnqueueNewDecision(true_literal);
502 while (!PropagateAndStopAfterOneConflictResolution()) {
505 CHECK(PropagationIsDone());
506 return last_decision_or_backtrack_trail_index_;
510 if (model_is_unsat_)
return false;
520 if (model_is_unsat_)
return false;
521 while (!PropagateAndStopAfterOneConflictResolution()) {
522 if (model_is_unsat_)
return false;
528 if (model_is_unsat_)
return false;
529 assumption_level_ = 0;
535 const std::vector<Literal>& assumptions) {
544 std::min<int>(assumptions.size(), num_variables_.value() + 1);
545 for (
int i = 0; i < assumption_level_; ++i) {
546 decisions_[i].literal = assumptions[i];
553 if (model_is_unsat_)
return false;
557 const int64 old_num_branches = counters_.num_branches;
559 ReapplyDecisionsUpTo(assumption_level_ - 1, &unused);
560 counters_.num_branches = old_num_branches;
565 bool SatSolver::PropagateAndStopAfterOneConflictResolution() {
569 ++counters_.num_failures;
570 const int conflict_trail_index = trail_->
Index();
571 const int conflict_decision_level = current_decision_level_;
574 same_reason_identifier_.
Clear();
575 const int max_trail_index = ComputeMaxTrailIndex(trail_->
FailingClause());
576 ComputeFirstUIPConflict(max_trail_index, &learned_conflict_,
577 &reason_used_to_infer_the_conflict_,
581 if (learned_conflict_.empty())
return SetModelUnsat();
582 DCHECK(IsConflictValid(learned_conflict_));
583 DCHECK(ClauseIsValidUnderDebugAssignement(learned_conflict_));
591 if (parameters_->also_bump_variables_in_conflict_reasons()) {
592 ComputeUnionOfReasons(learned_conflict_, &extra_reason_literals_);
602 BumpReasonActivities(reason_used_to_infer_the_conflict_);
606 UpdateClauseActivityIncrement();
610 const int period = parameters_->glucose_decay_increment_period();
611 const double max_decay = parameters_->glucose_max_decay();
612 if (counters_.num_failures % period == 0 &&
613 parameters_->variable_activity_decay() < max_decay) {
614 parameters_->set_variable_activity_decay(
615 parameters_->variable_activity_decay() +
616 parameters_->glucose_decay_increment());
622 bool compute_pb_conflict =
false;
623 if (parameters_->use_pb_resolution()) {
625 if (!compute_pb_conflict) {
626 for (Literal lit : reason_used_to_infer_the_conflict_) {
627 if (ReasonPbConstraintOrNull(lit.Variable()) !=
nullptr) {
628 compute_pb_conflict =
true;
637 if (compute_pb_conflict) {
639 Coefficient initial_slack(-1);
642 Coefficient num_literals(0);
647 pb_conflict_.
AddToRhs(num_literals - 1);
656 int pb_backjump_level;
657 ComputePBConflict(max_trail_index, initial_slack, &pb_conflict_,
659 if (pb_backjump_level == -1)
return SetModelUnsat();
662 std::vector<LiteralWithCoeff> cst;
664 DCHECK(PBConstraintIsValidUnderDebugAssignment(cst, pb_conflict_.
Rhs()));
668 bool conflict_is_a_clause = (pb_conflict_.
Rhs() == cst.size() - 1);
669 if (conflict_is_a_clause) {
670 for (LiteralWithCoeff term : cst) {
671 if (term.coefficient != Coefficient(1)) {
672 conflict_is_a_clause =
false;
678 if (!conflict_is_a_clause) {
687 CHECK_GT(trail_->
Index(), last_decision_or_backtrack_trail_index_);
688 counters_.num_learned_pb_literals += cst.size();
694 if (pb_backjump_level < ComputeBacktrackLevel(learned_conflict_)) {
695 subsumed_clauses_.clear();
696 learned_conflict_.clear();
700 for (LiteralWithCoeff term : cst) {
701 DCHECK(
Assignment().LiteralIsTrue(term.literal));
702 DCHECK_EQ(term.coefficient, 1);
703 const int level = trail_->
Info(term.literal.Variable()).
level;
704 if (level == 0)
continue;
705 if (level > max_level) {
707 max_index = learned_conflict_.size();
709 learned_conflict_.push_back(term.literal.Negated());
713 is_marked_.
Set(term.literal.Variable());
715 CHECK(!learned_conflict_.empty());
716 std::swap(learned_conflict_.front(), learned_conflict_[max_index]);
717 DCHECK(IsConflictValid(learned_conflict_));
726 DCHECK(ClauseIsValidUnderDebugAssignement(learned_conflict_));
727 if (!binary_implication_graph_->
IsEmpty()) {
728 if (parameters_->binary_minimization_algorithm() ==
729 SatParameters::BINARY_MINIMIZATION_FIRST) {
731 *trail_, &learned_conflict_, &is_marked_);
732 }
else if (parameters_->binary_minimization_algorithm() ==
734 BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION) {
736 *trail_, &learned_conflict_, &is_marked_,
739 DCHECK(IsConflictValid(learned_conflict_));
743 MinimizeConflict(&learned_conflict_, &reason_used_to_infer_the_conflict_);
746 if (!binary_implication_graph_->
IsEmpty()) {
750 switch (parameters_->binary_minimization_algorithm()) {
751 case SatParameters::NO_BINARY_MINIMIZATION:
752 ABSL_FALLTHROUGH_INTENDED;
753 case SatParameters::BINARY_MINIMIZATION_FIRST:
754 ABSL_FALLTHROUGH_INTENDED;
755 case SatParameters::BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION:
757 case SatParameters::BINARY_MINIMIZATION_WITH_REACHABILITY:
761 case SatParameters::EXPERIMENTAL_BINARY_MINIMIZATION:
763 *trail_, &learned_conflict_);
766 DCHECK(IsConflictValid(learned_conflict_));
780 counters_.num_literals_learned += learned_conflict_.size();
781 Backtrack(ComputeBacktrackLevel(learned_conflict_));
782 DCHECK(ClauseIsValidUnderDebugAssignement(learned_conflict_));
788 if (drat_proof_handler_ !=
nullptr) {
789 drat_proof_handler_->
AddClause(learned_conflict_);
794 bool is_redundant =
true;
795 if (!subsumed_clauses_.empty() &&
796 parameters_->subsumption_during_conflict_analysis()) {
797 for (SatClause* clause : subsumed_clauses_) {
798 DCHECK(ClauseSubsumption(learned_conflict_, clause));
800 is_redundant =
false;
805 counters_.num_subsumed_clauses += subsumed_clauses_.size();
809 const int conflict_lbd = AddLearnedClauseAndEnqueueUnitPropagation(
810 learned_conflict_, is_redundant);
811 restart_->
OnConflict(conflict_trail_index, conflict_decision_level,
817 int max_level,
int* first_propagation_index) {
819 int decision_index = current_decision_level_;
820 while (decision_index <= max_level) {
821 DCHECK_GE(decision_index, current_decision_level_);
822 const Literal previous_decision = decisions_[decision_index].literal;
824 if (
Assignment().LiteralIsTrue(previous_decision)) {
830 if (
Assignment().LiteralIsFalse(previous_decision)) {
832 decisions_[current_decision_level_].literal = previous_decision;
837 const int old_level = current_decision_level_;
839 *first_propagation_index =
std::min(*first_propagation_index,
index);
841 if (current_decision_level_ <= old_level) {
853 decision_index = current_decision_level_;
861 CHECK(PropagationIsDone());
866 int first_propagation_index = trail_->
Index();
868 return first_propagation_index;
873 CHECK(PropagationIsDone());
877 EnqueueNewDecision(true_literal);
898 DCHECK_GE(target_level, 0);
904 int target_trail_index = 0;
905 while (current_decision_level_ > target_level) {
906 --current_decision_level_;
907 target_trail_index = decisions_[current_decision_level_].trail_index;
909 Untrail(target_trail_index);
910 last_decision_or_backtrack_trail_index_ = trail_->
Index();
919 return SetModelUnsat();
921 AddBinaryClauseInternal(c.a, c.b);
923 if (!
Propagate())
return SetModelUnsat();
943 const std::vector<Literal>& assumptions) {
946 return SolveInternal(time_limit_);
950 if (parameters_->log_search_progress()) {
951 LOG(INFO) << RunningStatisticsString();
952 LOG(INFO) << StatusString(status);
958 CHECK_GE(assumption_level, 0);
960 assumption_level_ = assumption_level;
969 void SatSolver::KeepAllClauseUsedToInfer(BooleanVariable variable) {
970 CHECK(
Assignment().VariableIsAssigned(variable));
971 if (trail_->
Info(variable).
level == 0)
return;
973 std::vector<bool> is_marked(trail_index + 1,
false);
974 is_marked[trail_index] =
true;
976 for (; num > 0 && trail_index >= 0; --trail_index) {
977 if (!is_marked[trail_index])
continue;
978 is_marked[trail_index] =
false;
981 const BooleanVariable
var = (*trail_)[trail_index].Variable();
983 if (clause !=
nullptr) {
986 for (
const Literal l : trail_->
Reason(
var)) {
987 const AssignmentInfo& info = trail_->
Info(l.Variable());
988 if (info.level == 0)
continue;
989 if (!is_marked[info.trail_index]) {
990 is_marked[info.trail_index] =
true;
1000 void SatSolver::TryToMinimizeClause(SatClause* clause) {
1002 ++counters_.minimization_num_clauses;
1004 std::set<LiteralIndex> moved_last;
1005 std::vector<Literal> candidate(clause->begin(), clause->end());
1006 while (!model_is_unsat_) {
1013 if (target_level == -1)
break;
1017 const Literal
literal = candidate[level];
1019 candidate.erase(candidate.begin() + level);
1022 const int variable_level =
1024 if (variable_level == 0) {
1025 ProcessNewlyFixedVariablesForDratProof();
1026 counters_.minimization_num_true++;
1027 counters_.minimization_num_removed_literals += clause->size();
1029 clauses_propagator_->
Detach(clause);
1037 if (ReasonClauseOrNull(
literal.Variable()) != clause) {
1038 counters_.minimization_num_subsumed++;
1039 counters_.minimization_num_removed_literals += clause->size();
1042 KeepAllClauseUsedToInfer(
literal.Variable());
1044 clauses_propagator_->
Detach(clause);
1050 if (variable_level + 1 < candidate.size()) {
1051 candidate.resize(variable_level);
1057 ++counters_.minimization_num_decisions;
1059 if (!clause->IsAttached()) {
1063 if (model_is_unsat_)
return;
1066 if (candidate.empty()) {
1067 model_is_unsat_ =
true;
1070 moved_last.insert(candidate.back().Index());
1075 if (candidate.size() == clause->size())
return;
1077 if (candidate.size() == 1) {
1078 if (drat_proof_handler_ !=
nullptr) {
1079 drat_proof_handler_->
AddClause(candidate);
1081 if (!
Assignment().VariableIsAssigned(candidate[0].Variable())) {
1082 counters_.minimization_num_removed_literals += clause->size();
1089 if (parameters_->treat_binary_clauses_separately() && candidate.size() == 2) {
1090 counters_.minimization_num_removed_literals += clause->size() - 2;
1093 AddBinaryClauseInternal(candidate[0], candidate[1]);
1094 clauses_propagator_->
Detach(clause);
1103 counters_.minimization_num_removed_literals +=
1104 clause->size() - candidate.size();
1109 model_is_unsat_ =
true;
1123 if (parameters_->log_search_progress()) {
1124 LOG(INFO) <<
"Initial memory usage: " <<
MemoryUsage();
1125 LOG(INFO) <<
"Number of variables: " << num_variables_;
1126 LOG(INFO) <<
"Number of clauses (size > 2): "
1128 LOG(INFO) <<
"Number of binary clauses: "
1130 LOG(INFO) <<
"Number of linear constraints: "
1132 LOG(INFO) <<
"Number of fixed variables: " << trail_->
Index();
1133 LOG(INFO) <<
"Number of watched clauses: "
1139 int64 next_minimization_num_restart =
1141 parameters_->minimize_with_propagation_restart_period();
1144 const int64 kDisplayFrequency = 10000;
1145 int64 next_display = parameters_->log_search_progress()
1147 : std::numeric_limits<
int64>::
max();
1150 const int64 kMemoryCheckFrequency = 10000;
1151 int64 next_memory_check =
1156 const int64 kFailureLimit =
1157 parameters_->max_number_of_conflicts() ==
1160 : counters_.
num_failures + parameters_->max_number_of_conflicts();
1168 if (parameters_->log_search_progress()) {
1169 LOG(INFO) <<
"The time limit has been reached. Aborting.";
1175 if (parameters_->log_search_progress()) {
1176 LOG(INFO) <<
"The conflict limit has been reached. Aborting.";
1186 if (counters_.num_failures >= next_memory_check) {
1187 next_memory_check = NextMultipleOf(
num_failures(), kMemoryCheckFrequency);
1188 if (IsMemoryLimitReached()) {
1189 if (parameters_->log_search_progress()) {
1190 LOG(INFO) <<
"The memory limit has been reached. Aborting.";
1198 if (counters_.num_failures >= next_display) {
1199 LOG(INFO) << RunningStatisticsString();
1200 next_display = NextMultipleOf(
num_failures(), kDisplayFrequency);
1203 if (!PropagateAndStopAfterOneConflictResolution()) {
1205 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1211 if (trail_->
Index() == num_variables_.value()) {
1221 restart_->
NumRestarts() >= next_minimization_num_restart) {
1222 next_minimization_num_restart =
1224 parameters_->minimize_with_propagation_restart_period();
1226 parameters_->minimize_with_propagation_num_decisions());
1230 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1231 if (trail_->
Index() == num_variables_.value()) {
1237 EnqueueNewDecision(decision_policy_->
NextBranch());
1245 block_clause_deletion_ =
true;
1247 const int64 target_num_branches = counters_.num_branches + decisions_budget;
1248 while (counters_.num_branches < target_num_branches &&
1249 (time_limit_ ==
nullptr || !time_limit_->
LimitReached())) {
1251 if (to_minimize !=
nullptr) {
1252 TryToMinimizeClause(to_minimize);
1253 if (model_is_unsat_)
return;
1255 if (to_minimize ==
nullptr) {
1256 VLOG(1) <<
"Minimized all clauses, restarting from first one.";
1263 block_clause_deletion_ =
false;
1270 std::vector<Literal> unsat_assumptions;
1286 unsat_assumptions.push_back(decisions_[i].
literal);
1288 return unsat_assumptions;
1291 unsat_assumptions.push_back(false_assumption);
1298 int trail_index = trail_->
Info(false_assumption.
Variable()).trail_index;
1301 CHECK_LT(trail_index, trail_->
Index());
1304 while (trail_index >= 0 && !is_marked_[(*trail_)[trail_index].Variable()]) {
1307 if (trail_index < limit)
break;
1308 const Literal marked_literal = (*trail_)[trail_index];
1313 unsat_assumptions.push_back(marked_literal);
1317 const BooleanVariable
var =
literal.Variable();
1318 const int level = DecisionLevel(
var);
1319 if (level > 0 && !is_marked_[
var]) is_marked_.
Set(
var);
1326 std::reverse(unsat_assumptions.begin(), unsat_assumptions.end());
1327 return unsat_assumptions;
1330 void SatSolver::BumpReasonActivities(
const std::vector<Literal>& literals) {
1333 const BooleanVariable
var =
literal.Variable();
1334 if (DecisionLevel(
var) > 0) {
1336 if (clause !=
nullptr) {
1337 BumpClauseActivity(clause);
1339 UpperBoundedLinearConstraint* pb_constraint =
1340 ReasonPbConstraintOrNull(
var);
1341 if (pb_constraint !=
nullptr) {
1351 void SatSolver::BumpClauseActivity(SatClause* clause) {
1362 const int new_lbd = ComputeLbd(*clause);
1363 if (new_lbd + 1 <= parameters_->clause_cleanup_lbd_bound()) {
1369 switch (parameters_->clause_cleanup_protection()) {
1370 case SatParameters::PROTECTION_NONE:
1372 case SatParameters::PROTECTION_ALWAYS:
1373 it->second.protected_during_next_cleanup =
true;
1375 case SatParameters::PROTECTION_LBD:
1380 if (new_lbd + 1 < it->second.lbd) {
1381 it->second.protected_during_next_cleanup =
true;
1382 it->second.lbd = new_lbd;
1387 const double activity = it->second.activity += clause_activity_increment_;
1388 if (activity > parameters_->max_clause_activity_value()) {
1389 RescaleClauseActivities(1.0 / parameters_->max_clause_activity_value());
1393 void SatSolver::RescaleClauseActivities(
double scaling_factor) {
1395 clause_activity_increment_ *= scaling_factor;
1397 entry.second.activity *= scaling_factor;
1401 void SatSolver::UpdateClauseActivityIncrement() {
1403 clause_activity_increment_ *= 1.0 / parameters_->clause_activity_decay();
1406 bool SatSolver::IsConflictValid(
const std::vector<Literal>& literals) {
1408 if (literals.empty())
return false;
1409 const int highest_level = DecisionLevel(literals[0].Variable());
1410 for (
int i = 1; i < literals.size(); ++i) {
1411 const int level = DecisionLevel(literals[i].Variable());
1412 if (level <= 0 || level >= highest_level)
return false;
1417 int SatSolver::ComputeBacktrackLevel(
const std::vector<Literal>& literals) {
1430 int backtrack_level = 0;
1431 for (
int i = 1; i < literals.size(); ++i) {
1432 const int level = DecisionLevel(literals[i].Variable());
1433 backtrack_level =
std::max(backtrack_level, level);
1435 DCHECK_LT(backtrack_level, DecisionLevel(literals[0].Variable()));
1437 return backtrack_level;
1440 template <
typename LiteralList>
1441 int SatSolver::ComputeLbd(
const LiteralList& literals) {
1444 parameters_->count_assumption_levels_in_lbd() ? 0 : assumption_level_;
1448 SatDecisionLevel(DecisionLevel(literals.begin()->Variable()) + 1));
1449 for (
const Literal
literal : literals) {
1450 const SatDecisionLevel level(DecisionLevel(
literal.Variable()));
1451 DCHECK_GE(level, 0);
1452 if (level > limit && !is_level_marked_[level]) {
1453 is_level_marked_.
Set(level);
1459 std::string SatSolver::StatusString(Status status)
const {
1460 const double time_in_s = timer_.
Get();
1462 absl::StrFormat(
" time: %fs\n", time_in_s) +
1465 " num failures: %d (%.0f /sec)\n", counters_.num_failures,
1466 static_cast<double>(counters_.num_failures) / time_in_s) +
1468 " num branches: %d (%.0f /sec)\n", counters_.num_branches,
1469 static_cast<double>(counters_.num_branches) / time_in_s) +
1470 absl::StrFormat(
" num propagations: %d (%.0f /sec)\n",
1473 absl::StrFormat(
" num binary propagations: %d\n",
1475 absl::StrFormat(
" num binary inspections: %d\n",
1478 " num binary redundant implications: %d\n",
1481 " num classic minimizations: %d"
1482 " (literals removed: %d)\n",
1483 counters_.num_minimizations, counters_.num_literals_removed) +
1485 " num binary minimizations: %d"
1486 " (literals removed: %d)\n",
1489 absl::StrFormat(
" num inspected clauses: %d\n",
1491 absl::StrFormat(
" num inspected clause_literals: %d\n",
1494 " num learned literals: %d (avg: %.1f /clause)\n",
1495 counters_.num_literals_learned,
1496 1.0 * counters_.num_literals_learned / counters_.num_failures) +
1498 " num learned PB literals: %d (avg: %.1f /clause)\n",
1499 counters_.num_learned_pb_literals,
1500 1.0 * counters_.num_learned_pb_literals / counters_.num_failures) +
1501 absl::StrFormat(
" num subsumed clauses: %d\n",
1502 counters_.num_subsumed_clauses) +
1503 absl::StrFormat(
" minimization_num_clauses: %d\n",
1504 counters_.minimization_num_clauses) +
1505 absl::StrFormat(
" minimization_num_decisions: %d\n",
1506 counters_.minimization_num_decisions) +
1507 absl::StrFormat(
" minimization_num_true: %d\n",
1508 counters_.minimization_num_true) +
1509 absl::StrFormat(
" minimization_num_subsumed: %d\n",
1510 counters_.minimization_num_subsumed) +
1511 absl::StrFormat(
" minimization_num_removed_literals: %d\n",
1512 counters_.minimization_num_removed_literals) +
1513 absl::StrFormat(
" pb num threshold updates: %d\n",
1515 absl::StrFormat(
" pb num constraint lookups: %d\n",
1517 absl::StrFormat(
" pb num inspected constraint literals: %d\n",
1523 std::string SatSolver::RunningStatisticsString()
const {
1524 const double time_in_s = timer_.
Get();
1525 return absl::StrFormat(
1526 "%6.2fs, mem:%s, fails:%d, depth:%d, clauses:%d, tmp:%d, bin:%u, "
1527 "restarts:%d, vars:%d",
1533 num_variables_.value() - num_processed_fixed_variables_);
1536 void SatSolver::ProcessNewlyFixedVariablesForDratProof() {
1537 if (drat_proof_handler_ ==
nullptr)
return;
1551 for (; drat_num_processed_fixed_variables_ < trail_->
Index();
1552 ++drat_num_processed_fixed_variables_) {
1553 temp = (*trail_)[drat_num_processed_fixed_variables_];
1554 drat_proof_handler_->
AddClause({&temp, 1});
1561 int num_detached_clauses = 0;
1564 ProcessNewlyFixedVariablesForDratProof();
1570 if (!clause->IsAttached())
continue;
1572 const size_t old_size = clause->size();
1573 if (clause->RemoveFixedLiteralsAndTestIfTrue(trail_->
Assignment())) {
1576 ++num_detached_clauses;
1580 const size_t new_size = clause->size();
1581 if (new_size == old_size)
continue;
1583 if (drat_proof_handler_ !=
nullptr) {
1584 CHECK_GT(new_size, 0);
1585 drat_proof_handler_->
AddClause({clause->begin(), new_size});
1586 drat_proof_handler_->
DeleteClause({clause->begin(), old_size});
1589 if (new_size == 2 && parameters_->treat_binary_clauses_separately()) {
1593 AddBinaryClauseInternal(clause->FirstLiteral(), clause->SecondLiteral());
1602 if (num_detached_clauses > 0 || num_binary > 0) {
1603 VLOG(1) << trail_->
Index() <<
" fixed variables at level 0. "
1604 <<
"Detached " << num_detached_clauses <<
" clauses. " << num_binary
1605 <<
" converted to binary.";
1610 num_processed_fixed_variables_ = trail_->
Index();
1627 const int old_index = trail_->
Index();
1629 DCHECK(propagator->PropagatePreconditionsAreSatisfied(*trail_));
1630 if (!propagator->Propagate(trail_))
return false;
1631 if (trail_->
Index() > old_index)
break;
1633 if (trail_->
Index() == old_index)
break;
1638 void SatSolver::InitializePropagators() {
1639 propagators_.clear();
1650 if (!binary_implication_graph_->
IsEmpty()) {
1651 propagators_.push_back(binary_implication_graph_);
1653 propagators_.push_back(clauses_propagator_);
1655 propagators_.push_back(pb_constraints_);
1657 for (
int i = 0; i < external_propagators_.size(); ++i) {
1658 propagators_.push_back(external_propagators_[i]);
1660 if (last_propagator_ !=
nullptr) {
1661 propagators_.push_back(last_propagator_);
1665 bool SatSolver::PropagationIsDone()
const {
1666 for (SatPropagator* propagator : propagators_) {
1667 if (!propagator->PropagationIsDone(*trail_))
return false;
1672 bool SatSolver::ResolvePBConflict(BooleanVariable
var,
1673 MutableUpperBoundedLinearConstraint* conflict,
1674 Coefficient* slack) {
1678 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1681 UpperBoundedLinearConstraint* pb_reason = ReasonPbConstraintOrNull(
var);
1682 if (pb_reason !=
nullptr) {
1683 pb_reason->ResolvePBConflict(*trail_,
var, conflict, slack);
1688 Coefficient multiplier(1);
1691 const int algorithm = 1;
1692 switch (algorithm) {
1696 conflict->ReduceSlackTo(*trail_, trail_index, *slack, Coefficient(0));
1700 multiplier = *slack + 1;
1704 multiplier = conflict->GetCoefficient(
var);
1707 Coefficient num_literals(1);
1714 conflict->AddTerm(
literal.Negated(), multiplier);
1717 conflict->AddToRhs((num_literals - 1) * multiplier);
1721 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1725 void SatSolver::EnqueueNewDecision(Literal
literal) {
1736 const double kMinDeterministicTimeBetweenCleanups = 1.0;
1737 if (num_processed_fixed_variables_ < trail_->
Index() &&
1739 deterministic_time_of_last_fixed_variables_cleanup_ +
1740 kMinDeterministicTimeBetweenCleanups) {
1745 counters_.num_branches++;
1746 last_decision_or_backtrack_trail_index_ = trail_->
Index();
1747 decisions_[current_decision_level_] = Decision(trail_->
Index(),
literal);
1748 ++current_decision_level_;
1753 void SatSolver::Untrail(
int target_trail_index) {
1755 DCHECK_LT(target_trail_index, trail_->
Index());
1756 for (SatPropagator* propagator : propagators_) {
1757 propagator->Untrail(*trail_, target_trail_index);
1759 decision_policy_->
Untrail(target_trail_index);
1760 trail_->
Untrail(target_trail_index);
1763 std::string SatSolver::DebugString(
const SatClause& clause)
const {
1765 for (
const Literal
literal : clause) {
1766 if (!result.empty()) {
1767 result.append(
" || ");
1769 const std::string
value =
1774 result.append(absl::StrFormat(
"%s(%s)",
literal.DebugString(),
value));
1779 int SatSolver::ComputeMaxTrailIndex(absl::Span<const Literal> clause)
const {
1781 int trail_index = -1;
1782 for (
const Literal
literal : clause) {
1792 void SatSolver::ComputeFirstUIPConflict(
1793 int max_trail_index, std::vector<Literal>* conflict,
1794 std::vector<Literal>* reason_used_to_infer_the_conflict,
1795 std::vector<SatClause*>* subsumed_clauses) {
1803 reason_used_to_infer_the_conflict->clear();
1804 subsumed_clauses->clear();
1805 if (max_trail_index == -1)
return;
1810 DCHECK_EQ(max_trail_index, ComputeMaxTrailIndex(trail_->
FailingClause()));
1811 int trail_index = max_trail_index;
1812 const int highest_level = DecisionLevel((*trail_)[trail_index].Variable());
1813 if (highest_level == 0)
return;
1830 absl::Span<const Literal> clause_to_expand = trail_->
FailingClause();
1832 DCHECK(!clause_to_expand.empty());
1833 int num_literal_at_highest_level_that_needs_to_be_processed = 0;
1835 int num_new_vars_at_positive_level = 0;
1836 int num_vars_at_positive_level_in_clause_to_expand = 0;
1837 for (
const Literal
literal : clause_to_expand) {
1838 const BooleanVariable
var =
literal.Variable();
1839 const int level = DecisionLevel(
var);
1840 if (level > 0) ++num_vars_at_positive_level_in_clause_to_expand;
1841 if (!is_marked_[
var]) {
1843 if (level == highest_level) {
1844 ++num_new_vars_at_positive_level;
1845 ++num_literal_at_highest_level_that_needs_to_be_processed;
1846 }
else if (level > 0) {
1847 ++num_new_vars_at_positive_level;
1853 reason_used_to_infer_the_conflict->push_back(
literal);
1860 if (num_new_vars_at_positive_level > 0) {
1863 subsumed_clauses->clear();
1870 if (sat_clause !=
nullptr &&
1871 num_vars_at_positive_level_in_clause_to_expand ==
1873 num_literal_at_highest_level_that_needs_to_be_processed) {
1874 subsumed_clauses->push_back(sat_clause);
1878 DCHECK_GT(num_literal_at_highest_level_that_needs_to_be_processed, 0);
1879 while (!is_marked_[(*trail_)[trail_index].Variable()]) {
1881 DCHECK_GE(trail_index, 0);
1882 DCHECK_EQ(DecisionLevel((*trail_)[trail_index].Variable()),
1886 if (num_literal_at_highest_level_that_needs_to_be_processed == 1) {
1890 conflict->push_back((*trail_)[trail_index].Negated());
1893 std::swap(conflict->back(), conflict->front());
1897 const Literal
literal = (*trail_)[trail_index];
1898 reason_used_to_infer_the_conflict->push_back(
literal);
1904 clause_to_expand = {};
1908 sat_clause = ReasonClauseOrNull(
literal.Variable());
1910 --num_literal_at_highest_level_that_needs_to_be_processed;
1915 void SatSolver::ComputeUnionOfReasons(
const std::vector<Literal>&
input,
1916 std::vector<Literal>* literals) {
1919 for (
const Literal l :
input) tmp_mark_.
Set(l.Variable());
1920 for (
const Literal l :
input) {
1921 for (
const Literal r : trail_->
Reason(l.Variable())) {
1922 if (!tmp_mark_[r.Variable()]) {
1923 tmp_mark_.
Set(r.Variable());
1924 literals->push_back(r);
1928 for (
const Literal l :
input) tmp_mark_.
Clear(l.Variable());
1929 for (
const Literal l : *literals) tmp_mark_.
Clear(l.Variable());
1933 void SatSolver::ComputePBConflict(
int max_trail_index,
1934 Coefficient initial_slack,
1935 MutableUpperBoundedLinearConstraint* conflict,
1936 int* pb_backjump_level) {
1938 int trail_index = max_trail_index;
1942 Coefficient slack = initial_slack;
1944 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1));
1945 CHECK_LT(slack, 0) <<
"We don't have a conflict!";
1948 int backjump_level = 0;
1950 const BooleanVariable
var = (*trail_)[trail_index].Variable();
1953 if (conflict->GetCoefficient(
var) > 0 &&
1955 if (parameters_->minimize_reduction_during_pb_resolution()) {
1960 conflict->ReduceGivenCoefficient(
var);
1964 slack += conflict->GetCoefficient(
var);
1968 if (slack < 0)
continue;
1974 const int current_level = DecisionLevel(
var);
1975 int i = trail_index;
1977 const BooleanVariable previous_var = (*trail_)[i].Variable();
1978 if (conflict->GetCoefficient(previous_var) > 0 &&
1980 conflict->GetLiteral(previous_var))) {
1985 if (i < 0 || DecisionLevel((*trail_)[i].Variable()) < current_level) {
1986 backjump_level = i < 0 ? 0 : DecisionLevel((*trail_)[i].Variable());
1992 const bool clause_used = ResolvePBConflict(
var, conflict, &slack);
2001 const Coefficient slack_only_for_debug =
2003 ? conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1)
2008 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2009 conflict->ReduceCoefficients();
2015 if (parameters_->minimize_reduction_during_pb_resolution()) {
2017 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1);
2019 slack = conflict->ReduceCoefficientsAndComputeSlackForTrailPrefix(
2020 *trail_, trail_index + 1);
2023 DCHECK_EQ(slack, slack_only_for_debug);
2025 if (conflict->Rhs() < 0) {
2026 *pb_backjump_level = -1;
2034 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2035 conflict->ReduceCoefficients();
2040 std::vector<Coefficient> sum_for_le_level(backjump_level + 2, Coefficient(0));
2041 std::vector<Coefficient> max_coeff_for_ge_level(backjump_level + 2,
2044 Coefficient max_sum(0);
2045 for (BooleanVariable
var : conflict->PossibleNonZeros()) {
2046 const Coefficient coeff = conflict->GetCoefficient(
var);
2047 if (coeff == 0)
continue;
2051 DecisionLevel(
var) > backjump_level) {
2052 max_coeff_for_ge_level[backjump_level + 1] =
2053 std::max(max_coeff_for_ge_level[backjump_level + 1], coeff);
2055 const int level = DecisionLevel(
var);
2057 sum_for_le_level[level] += coeff;
2059 max_coeff_for_ge_level[level] =
2060 std::max(max_coeff_for_ge_level[level], coeff);
2065 for (
int i = 1; i < sum_for_le_level.size(); ++i) {
2066 sum_for_le_level[i] += sum_for_le_level[i - 1];
2068 for (
int i = max_coeff_for_ge_level.size() - 2; i >= 0; --i) {
2069 max_coeff_for_ge_level[i] =
2070 std::max(max_coeff_for_ge_level[i], max_coeff_for_ge_level[i + 1]);
2075 if (sum_for_le_level[0] > conflict->Rhs()) {
2076 *pb_backjump_level = -1;
2079 for (
int i = 0; i <= backjump_level; ++i) {
2080 const Coefficient level_sum = sum_for_le_level[i];
2081 CHECK_LE(level_sum, conflict->Rhs());
2082 if (conflict->Rhs() - level_sum < max_coeff_for_ge_level[i + 1]) {
2083 *pb_backjump_level = i;
2087 LOG(FATAL) <<
"The code should never reach here.";
2090 void SatSolver::MinimizeConflict(
2091 std::vector<Literal>* conflict,
2092 std::vector<Literal>* reason_used_to_infer_the_conflict) {
2095 const int old_size = conflict->size();
2096 switch (parameters_->minimization_algorithm()) {
2097 case SatParameters::NONE:
2099 case SatParameters::SIMPLE: {
2100 MinimizeConflictSimple(conflict);
2103 case SatParameters::RECURSIVE: {
2104 MinimizeConflictRecursively(conflict);
2107 case SatParameters::EXPERIMENTAL: {
2108 MinimizeConflictExperimental(conflict);
2112 if (conflict->size() < old_size) {
2113 ++counters_.num_minimizations;
2114 counters_.num_literals_removed += old_size - conflict->size();
2125 void SatSolver::MinimizeConflictSimple(std::vector<Literal>* conflict) {
2132 for (
int i = 1; i < conflict->size(); ++i) {
2133 const BooleanVariable
var = (*conflict)[i].Variable();
2134 bool can_be_removed =
false;
2135 if (DecisionLevel(
var) != current_level) {
2137 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2138 if (!reason.empty()) {
2139 can_be_removed =
true;
2140 for (Literal
literal : reason) {
2141 if (DecisionLevel(
literal.Variable()) == 0)
continue;
2142 if (!is_marked_[
literal.Variable()]) {
2143 can_be_removed =
false;
2149 if (!can_be_removed) {
2150 (*conflict)[
index] = (*conflict)[i];
2154 conflict->erase(conflict->begin() +
index, conflict->end());
2163 void SatSolver::MinimizeConflictRecursively(std::vector<Literal>* conflict) {
2197 const int level = DecisionLevel(
var);
2198 min_trail_index_per_level_[level] =
std::min(
2206 for (
int i = 1; i < conflict->size(); ++i) {
2207 const BooleanVariable
var = (*conflict)[i].Variable();
2210 min_trail_index_per_level_[DecisionLevel(
var)] ||
2211 !CanBeInferedFromConflictVariables(
var)) {
2214 is_independent_.
Set(
var);
2215 (*conflict)[
index] = (*conflict)[i];
2219 conflict->resize(
index);
2223 const int threshold = min_trail_index_per_level_.size() / 2;
2226 min_trail_index_per_level_[DecisionLevel(
var)] =
2230 min_trail_index_per_level_.clear();
2234 bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) {
2237 DCHECK(is_marked_[variable]);
2238 const BooleanVariable v =
2240 if (v != variable)
return !is_independent_[v];
2253 dfs_stack_.push_back(variable);
2254 variable_to_process_.clear();
2255 variable_to_process_.push_back(variable);
2259 const BooleanVariable
var =
literal.Variable();
2260 DCHECK_NE(
var, variable);
2261 if (is_marked_[
var])
continue;
2262 const int level = DecisionLevel(
var);
2272 is_independent_[
var]) {
2275 variable_to_process_.push_back(
var);
2279 while (!variable_to_process_.empty()) {
2280 const BooleanVariable current_var = variable_to_process_.back();
2281 if (current_var == dfs_stack_.back()) {
2284 if (dfs_stack_.size() > 1) {
2285 DCHECK(!is_marked_[current_var]);
2286 is_marked_.
Set(current_var);
2288 variable_to_process_.pop_back();
2289 dfs_stack_.pop_back();
2294 if (is_marked_[current_var]) {
2295 variable_to_process_.pop_back();
2301 DCHECK(!is_independent_[current_var]);
2305 const BooleanVariable v =
2307 if (v != current_var) {
2308 if (is_independent_[v])
break;
2309 DCHECK(is_marked_[v]);
2310 variable_to_process_.pop_back();
2316 dfs_stack_.push_back(current_var);
2317 bool abort_early =
false;
2319 const BooleanVariable
var =
literal.Variable();
2320 DCHECK_NE(
var, current_var);
2321 const int level = DecisionLevel(
var);
2322 if (level == 0 || is_marked_[
var])
continue;
2324 is_independent_[
var]) {
2328 variable_to_process_.push_back(
var);
2330 if (abort_early)
break;
2334 for (
const BooleanVariable
var : dfs_stack_) {
2335 is_independent_.
Set(
var);
2337 return dfs_stack_.empty();
2342 struct WeightedVariable {
2343 WeightedVariable(BooleanVariable v,
int w) :
var(v),
weight(w) {}
2351 struct VariableWithLargerWeightFirst {
2352 bool operator()(
const WeightedVariable& wv1,
2353 const WeightedVariable& wv2)
const {
2354 return (wv1.weight > wv2.weight ||
2355 (wv1.weight == wv2.weight && wv1.var < wv2.var));
2371 void SatSolver::MinimizeConflictExperimental(std::vector<Literal>* conflict) {
2378 std::vector<WeightedVariable> variables_sorted_by_level;
2379 for (Literal
literal : *conflict) {
2380 const BooleanVariable
var =
literal.Variable();
2382 const int level = DecisionLevel(
var);
2383 if (level < current_level) {
2384 variables_sorted_by_level.push_back(WeightedVariable(
var, level));
2387 std::sort(variables_sorted_by_level.begin(), variables_sorted_by_level.end(),
2388 VariableWithLargerWeightFirst());
2391 std::vector<BooleanVariable> to_remove;
2392 for (WeightedVariable weighted_var : variables_sorted_by_level) {
2393 const BooleanVariable
var = weighted_var.var;
2397 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2398 if (reason.empty())
continue;
2402 std::vector<Literal> not_contained_literals;
2403 for (
const Literal reason_literal : reason) {
2404 const BooleanVariable reason_var = reason_literal.Variable();
2407 if (DecisionLevel(reason_var) == 0)
continue;
2412 if (!is_marked_[reason_var]) {
2413 not_contained_literals.push_back(reason_literal);
2414 if (not_contained_literals.size() > 1)
break;
2417 if (not_contained_literals.empty()) {
2422 to_remove.push_back(
var);
2423 }
else if (not_contained_literals.size() == 1) {
2426 to_remove.push_back(
var);
2427 is_marked_.
Set(not_contained_literals.front().Variable());
2428 conflict->push_back(not_contained_literals.front());
2433 for (BooleanVariable
var : to_remove) {
2439 for (
int i = 0; i < conflict->size(); ++i) {
2440 const Literal
literal = (*conflict)[i];
2441 if (is_marked_[
literal.Variable()]) {
2446 conflict->erase(conflict->begin() +
index, conflict->end());
2449 void SatSolver::CleanClauseDatabaseIfNeeded() {
2450 if (num_learned_clause_before_cleanup_ > 0)
return;
2455 typedef std::pair<SatClause*, ClauseInfo> Entry;
2456 std::vector<Entry> entries;
2458 for (
auto& entry : clauses_info) {
2459 if (ClauseIsUsedAsReason(entry.first))
continue;
2460 if (entry.second.protected_during_next_cleanup) {
2461 entry.second.protected_during_next_cleanup =
false;
2464 entries.push_back(entry);
2466 const int num_protected_clauses = clauses_info.size() - entries.size();
2468 if (parameters_->clause_cleanup_ordering() == SatParameters::CLAUSE_LBD) {
2470 std::sort(entries.begin(), entries.end(),
2471 [](
const Entry&
a,
const Entry&
b) {
2472 if (a.second.lbd == b.second.lbd) {
2473 return a.second.activity < b.second.activity;
2475 return a.second.lbd >
b.second.lbd;
2479 std::sort(entries.begin(), entries.end(),
2480 [](
const Entry&
a,
const Entry&
b) {
2481 if (a.second.activity == b.second.activity) {
2482 return a.second.lbd > b.second.lbd;
2484 return a.second.activity <
b.second.activity;
2489 int num_kept_clauses =
std::min(
static_cast<int>(entries.size()),
2490 parameters_->clause_cleanup_target());
2491 int num_deleted_clauses = entries.size() - num_kept_clauses;
2496 while (num_deleted_clauses > 0) {
2497 const ClauseInfo&
a = entries[num_deleted_clauses].second;
2498 const ClauseInfo&
b = entries[num_deleted_clauses - 1].second;
2499 if (
a.activity !=
b.activity ||
a.lbd !=
b.lbd)
break;
2500 --num_deleted_clauses;
2503 if (num_deleted_clauses > 0) {
2504 entries.resize(num_deleted_clauses);
2505 for (
const Entry& entry : entries) {
2506 SatClause* clause = entry.first;
2507 counters_.num_literals_forgotten += clause->size();
2508 clauses_propagator_->LazyDetach(clause);
2510 clauses_propagator_->CleanUpWatchers();
2514 if (!block_clause_deletion_) {
2515 clauses_propagator_->DeleteRemovedClauses();
2519 num_learned_clause_before_cleanup_ = parameters_->clause_cleanup_period();
2520 VLOG(1) <<
"Database cleanup, #protected:" << num_protected_clauses
2521 <<
" #kept:" << num_kept_clauses
2522 <<
" #deleted:" << num_deleted_clauses;
2527 case SatSolver::ASSUMPTIONS_UNSAT:
2528 return "ASSUMPTIONS_UNSAT";
2530 return "INFEASIBLE";
2533 case SatSolver::LIMIT_REACHED:
2534 return "LIMIT_REACHED";
2538 LOG(DFATAL) <<
"Invalid SatSolver::Status " << status;