26#include "absl/algorithm/container.h"
27#include "absl/container/flat_hash_map.h"
28#include "absl/log/check.h"
29#include "absl/log/log.h"
30#include "absl/log/vlog_is_on.h"
31#include "absl/strings/str_cat.h"
32#include "absl/strings/str_format.h"
33#include "absl/types/span.h"
60 owned_model_.reset(model_);
71 track_binary_clauses_(false),
78 clause_activity_increment_(1.0),
79 same_reason_identifier_(*trail_),
80 is_relevant_for_core_computation_(true),
83 trail_->EnableChronologicalBacktracking(
84 parameters_->use_chronological_backtracking());
85 InitializePropagators();
92 CHECK_GE(num_variables, num_variables_);
94 num_variables_ = num_variables;
95 binary_implication_graph_->Resize(num_variables);
96 clauses_propagator_->Resize(num_variables);
97 trail_->Resize(num_variables);
98 decision_policy_->IncreaseNumVariables(num_variables);
99 pb_constraints_->Resize(num_variables);
100 same_reason_identifier_.Resize(num_variables);
108 return trail_->NumberOfEnqueues() - counters_.num_branches;
115 return counters_.num_backtracks_to_root;
125 return 1e-8 * (8.0 * trail_->NumberOfEnqueues() +
126 1.0 * binary_implication_graph_->num_inspections() +
127 4.0 * clauses_propagator_->num_inspected_clauses() +
128 1.0 * clauses_propagator_->num_inspected_clause_literals() +
131 20.0 * pb_constraints_->num_constraint_lookups() +
132 2.0 * pb_constraints_->num_threshold_updates() +
133 1.0 * pb_constraints_->num_inspected_constraint_literals());
145 time_limit_->ResetLimitFromParameters(
parameters);
146 logger_->EnableLogging(
parameters.log_search_progress() || VLOG_IS_ON(1));
147 logger_->SetLogToStdOut(
parameters.log_to_stdout());
150bool SatSolver::IsMemoryLimitReached()
const {
151 const int64_t memory_usage =
153 const int64_t kMegaByte = 1024 * 1024;
157bool SatSolver::SetModelUnsat() {
158 model_is_unsat_ =
true;
163 if (model_is_unsat_)
return false;
166 if (trail_->CurrentDecisionLevel() == 0) {
170 const int index = trail_->Index();
171 if (literals.empty())
return SetModelUnsat();
173 if (literals.size() == 2) {
177 if (!binary_implication_graph_->AddBinaryClause(literals[0], literals[1])) {
179 return SetModelUnsat();
182 if (!clauses_propagator_->AddClause(literals)) {
184 return SetModelUnsat();
190 if (parameters_->use_new_integer_conflict_resolution())
return true;
195 if (trail_->Index() == index)
return true;
221 if (model_is_unsat_)
return false;
225 tmp_literals_.clear();
226 if (lrat_proof_handler_ !=
nullptr) {
227 tmp_clause_ids_.clear();
229 const Literal rep = binary_implication_graph_->RepresentativeOf(l);
230 if (trail_->Assignment().LiteralIsTrue(rep))
return true;
231 if (trail_->Assignment().LiteralIsFalse(rep)) {
232 tmp_clause_ids_.push_back(trail_->GetUnitClauseId(rep.
Variable()));
235 tmp_clause_ids_.push_back(
236 binary_implication_graph_->GetClauseId(l.Negated(), rep));
238 if (!trail_->Assignment().LiteralIsFalse(rep)) {
239 tmp_literals_.push_back(rep);
244 l = binary_implication_graph_->RepresentativeOf(l);
245 if (trail_->Assignment().LiteralIsTrue(l))
return true;
246 if (trail_->Assignment().LiteralIsFalse(l))
continue;
247 tmp_literals_.push_back(l);
253 for (
int i = 0;
i + 1 < tmp_literals_.size(); ++
i) {
254 if (tmp_literals_[
i] == tmp_literals_[
i + 1].Negated()) {
259 if (lrat_proof_handler_ !=
nullptr) {
261 id = clause_id_generator_->GetNextId();
263 lrat_proof_handler_->AddImportedClause(
id, literals);
265 lrat_proof_handler_->AddProblemClause(
id, literals);
269 if (!tmp_clause_ids_.empty()) {
270 tmp_clause_ids_.push_back(
id);
271 ClauseId new_id = clause_id_generator_->GetNextId();
272 lrat_proof_handler_->AddInferredClause(new_id, tmp_literals_,
274 lrat_proof_handler_->DeleteClause(
id, literals);
279 return AddProblemClauseInternal(
id, tmp_literals_);
282bool SatSolver::AddProblemClauseInternal(ClauseId
id,
283 absl::Span<const Literal> literals) {
286 for (
const Literal l : literals) {
291 if (literals.empty())
return SetModelUnsat();
293 if (literals.size() == 1) {
295 }
else if (literals.size() == 2) {
297 if (literals[0] == literals[1]) {
299 trail_->EnqueueWithUnitReason(
id, literals[0]);
300 }
else if (literals[0] == literals[1].Negated()) {
304 AddBinaryClauseInternal(
id, literals[0], literals[1]);
307 if (!clauses_propagator_->AddClause(
id, literals, trail_, -1)) {
308 return SetModelUnsat();
319 return SetModelUnsat();
324bool SatSolver::AddLinearConstraintInternal(
325 const std::vector<Literal>& enforcement_literals,
326 const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
327 Coefficient max_value) {
332 if (enforcement_literals.empty()) {
333 return SetModelUnsat();
335 tmp_literals_.clear();
336 for (
const Literal& literal : enforcement_literals) {
337 tmp_literals_.push_back(literal.Negated());
339 return AddProblemClauseInternal(
kNoClauseId, tmp_literals_);
342 if (rhs >= max_value)
return true;
345 const Coefficient min_coeff = cst.front().coefficient;
346 const Coefficient max_coeff = cst.back().coefficient;
350 if (max_value - min_coeff <= rhs) {
352 if (enforcement_literals.empty()) {
353 tmp_literals_.clear();
354 for (
const LiteralWithCoeff& term : cst) {
355 tmp_literals_.push_back(term.literal.Negated());
357 return AddProblemClauseInternal(
kNoClauseId, tmp_literals_);
359 std::vector<Literal> literals;
360 for (
const Literal& literal : enforcement_literals) {
361 literals.push_back(literal.Negated());
363 for (
const LiteralWithCoeff& term : cst) {
364 literals.push_back(term.literal.Negated());
372 if (!parameters_->use_pb_resolution() && max_coeff <= rhs &&
373 2 * min_coeff > rhs && enforcement_literals.empty()) {
374 tmp_literals_.clear();
375 for (
const LiteralWithCoeff& term : cst) {
376 tmp_literals_.push_back(term.literal);
378 if (!binary_implication_graph_->AddAtMostOne(tmp_literals_)) {
379 return SetModelUnsat();
390 return pb_constraints_->AddConstraint(enforcement_literals, cst, rhs, trail_);
393void SatSolver::CanonicalizeLinear(std::vector<LiteralWithCoeff>* cst,
394 Coefficient* bound_shift,
395 Coefficient* max_value) {
400 for (
const LiteralWithCoeff& term : *cst) {
401 if (trail_->Assignment().LiteralIsFalse(term.literal))
continue;
402 if (trail_->Assignment().LiteralIsTrue(term.literal)) {
403 CHECK(
SafeAddInto(-term.coefficient, &fixed_variable_shift));
406 (*cst)[index] = term;
419 CHECK(
SafeAddInto(fixed_variable_shift, bound_shift));
423 Coefficient lower_bound,
424 bool use_upper_bound,
425 Coefficient upper_bound,
426 std::vector<Literal>* enforcement_literals,
427 std::vector<LiteralWithCoeff>* cst) {
430 if (model_is_unsat_)
return false;
433 int num_enforcement_literals = 0;
434 for (
int i = 0;
i < enforcement_literals->size(); ++
i) {
435 const Literal literal = (*enforcement_literals)[
i];
436 if (trail_->Assignment().LiteralIsFalse(literal)) {
439 if (!trail_->Assignment().LiteralIsTrue(literal)) {
440 (*enforcement_literals)[num_enforcement_literals++] = literal;
443 enforcement_literals->resize(num_enforcement_literals);
445 Coefficient bound_shift(0);
447 if (use_upper_bound) {
448 Coefficient max_value(0);
449 CanonicalizeLinear(cst, &bound_shift, &max_value);
450 const Coefficient rhs =
452 if (!AddLinearConstraintInternal(*enforcement_literals, *cst, rhs,
454 return SetModelUnsat();
458 if (use_lower_bound) {
461 Coefficient max_value(0);
462 CanonicalizeLinear(cst, &bound_shift, &max_value);
465 for (
int i = 0;
i < cst->size(); ++
i) {
466 (*cst)[
i].literal = (*cst)[
i].literal.Negated();
468 const Coefficient rhs =
470 if (!AddLinearConstraintInternal(*enforcement_literals, *cst, rhs,
472 return SetModelUnsat();
481 return SetModelUnsat();
486int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation(
487 ClauseId clause_id, absl::Span<const Literal> literals,
bool is_redundant,
488 int min_lbd_of_subsumed_clauses) {
495 if (literals.size() == 1) {
497 if (
Assignment().LiteralIsTrue(literals[0]))
return 1;
498 CHECK(!
Assignment().LiteralIsFalse(literals[0]));
509 if (literals.size() == 2) {
510 if (track_binary_clauses_) {
512 CHECK(binary_clauses_.
Add(BinaryClause(literals[0], literals[1])));
514 CHECK(binary_implication_graph_->AddBinaryClause(clause_id, literals[0],
519 CleanClauseDatabaseIfNeeded();
523 const int lbd = std::min(min_lbd_of_subsumed_clauses, ComputeLbd(literals));
524 if (is_redundant && lbd > parameters_->clause_cleanup_lbd_bound()) {
525 --num_learned_clause_before_cleanup_;
527 SatClause* clause = clauses_propagator_->AddRemovableClause(
528 clause_id, literals, trail_, lbd);
529 BumpClauseActivity(clause);
531 CHECK(clauses_propagator_->AddClause(clause_id, literals, trail_, lbd));
538 trail_->RegisterPropagator(propagator);
539 external_propagators_.push_back(propagator);
540 InitializePropagators();
545 CHECK(last_propagator_ ==
nullptr);
546 trail_->RegisterPropagator(propagator);
547 last_propagator_ = propagator;
548 InitializePropagators();
552 BooleanVariable var)
const {
563 debug_assignment_.Resize(num_variables_.value());
564 for (BooleanVariable
i(0);
i < num_variables_; ++
i) {
565 debug_assignment_.AssignFromTrueLiteral(
566 trail_->Assignment().GetTrueLiteralForAssignedVariable(
i));
571 debug_assignment_.Resize(num_variables_.value());
572 for (BooleanVariable var(0); var < num_variables_; ++var) {
573 if (!debug_assignment_.VariableIsAssigned(var))
continue;
574 debug_assignment_.UnassignLiteral(
Literal(var,
true));
577 debug_assignment_.AssignFromTrueLiteral(l);
581 for (BooleanVariable var(0); var < num_variables_; ++var) {
582 CHECK(debug_assignment_.VariableIsAssigned(var));
586void SatSolver::AddBinaryClauseInternal(ClauseId
id,
Literal a,
Literal b) {
587 if (track_binary_clauses_) {
598bool SatSolver::ClauseIsValidUnderDebugAssignment(
599 absl::Span<const Literal> clause)
const {
600 if (debug_assignment_.NumberOfVariables() == 0)
return true;
601 for (Literal l : clause) {
602 if (l.Variable() >= debug_assignment_.NumberOfVariables() ||
603 debug_assignment_.LiteralIsTrue(l)) {
610bool SatSolver::PBConstraintIsValidUnderDebugAssignment(
611 absl::Span<const LiteralWithCoeff> cst,
const Coefficient rhs)
const {
613 for (LiteralWithCoeff term : cst) {
614 if (term.literal.Variable() >= debug_assignment_.NumberOfVariables()) {
617 if (debug_assignment_.LiteralIsTrue(term.literal)) {
618 sum += term.coefficient;
625 Literal true_literal, std::optional<ConflictCallback> callback) {
632 CHECK_GE(trail_->CurrentDecisionLevel(), assumption_level_);
635 EnqueueNewDecision(true_literal);
638 return last_decision_or_backtrack_trail_index_;
642 if (model_is_unsat_)
return false;
645 const int old_decision_level = trail_->CurrentDecisionLevel();
648 if (model_is_unsat_)
return false;
649 if (trail_->CurrentDecisionLevel() == old_decision_level) {
650 CHECK(!assumptions_.empty());
654 if (++num_loop % 16 == 0 && time_limit_->LimitReached()) {
670 if (model_is_unsat_)
return false;
671 assumption_level_ = 0;
672 assumptions_.clear();
678 const std::vector<Literal>& assumptions) {
680 if (assumptions.empty())
return true;
687 DCHECK(assumptions_.empty());
688 assumption_level_ = 1;
689 assumptions_ = assumptions;
695 if (model_is_unsat_)
return false;
702 CHECK_EQ(trail_->CurrentDecisionLevel(), 0);
703 last_decision_or_backtrack_trail_index_ = trail_->Index();
706 int num_decisions = 0;
707 for (
const Literal lit : assumptions_) {
708 if (
Assignment().LiteralIsTrue(lit))
continue;
711 *trail_->MutableConflict() = {lit.Negated(), lit};
715 trail_->EnqueueAssumption(lit);
719 if (num_decisions == 0) {
730 DCHECK(assumptions_.empty());
731 const int64_t old_num_branches = counters_.num_branches;
733 counters_.num_branches = old_num_branches;
739 std::optional<ConflictCallback> callback) {
741 if (model_is_unsat_)
return;
743 const int conflict_trail_index = trail_->Index();
749 learned_conflict_.clear();
750 subsumed_clauses_.clear();
751 same_reason_identifier_.Clear();
753 subsuming_lrat_index_.clear();
754 subsuming_clauses_.clear();
755 subsuming_groups_.clear();
756 subsumed_clauses_.clear();
758 if (trail_->GetConflictResolutionFunction() ==
nullptr) {
759 const int max_trail_index = ComputeMaxTrailIndex(trail_->FailingClause());
760 if (!assumptions_.empty() && !trail_->FailingClause().empty()) {
767 int highest_level = 0;
768 for (
const Literal l : trail_->FailingClause()) {
770 std::max<int>(highest_level, trail_->Info(l.Variable()).level);
772 if (highest_level == assumption_level_)
return;
775 ComputeFirstUIPConflict(max_trail_index, &learned_conflict_,
776 &reason_used_to_infer_the_conflict_);
778 trail_->GetConflictResolutionFunction()(&learned_conflict_,
779 &reason_used_to_infer_the_conflict_,
781 if (!assumptions_.empty() && !learned_conflict_.empty() &&
782 AssignmentLevel(learned_conflict_[0].
Variable()) <= assumption_level_) {
784 *trail_->MutableConflict() = learned_conflict_;
788 CHECK(IsConflictValid(learned_conflict_));
791 is_marked_.ClearAndResize(num_variables_);
792 for (
const Literal l : learned_conflict_) {
793 is_marked_.Set(l.Variable());
795 for (
const Literal l : reason_used_to_infer_the_conflict_) {
796 is_marked_.Set(l.Variable());
800 DCHECK(IsConflictValid(learned_conflict_));
801 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
803 std::vector<ClauseId>* clause_ids_for_1iup = &tmp_clause_ids_for_1uip_;
804 if (lrat_proof_handler_ !=
nullptr) {
805 clause_ids_for_1iup->clear();
806 AppendLratProofFromReasons(reason_used_to_infer_the_conflict_,
807 clause_ids_for_1iup);
808 AppendLratProofForFailingClause(clause_ids_for_1iup);
812 if (learned_conflict_.empty()) {
814 if (lrat_proof_handler_ !=
nullptr) {
815 clause_id = clause_id_generator_->GetNextId();
816 if (!lrat_proof_handler_->AddInferredClause(clause_id, learned_conflict_,
817 *clause_ids_for_1iup)) {
818 VLOG(1) <<
"WARNING: invalid LRAT inferred clause!";
821 if (callback.has_value()) {
822 (*callback)(clause_id, learned_conflict_);
824 return (
void)SetModelUnsat();
831 decision_policy_->BumpVariableActivities(learned_conflict_);
832 decision_policy_->BumpVariableActivities(reason_used_to_infer_the_conflict_);
833 if (parameters_->also_bump_variables_in_conflict_reasons()) {
834 ComputeUnionOfReasons(learned_conflict_, &extra_reason_literals_);
835 decision_policy_->BumpVariableActivities(extra_reason_literals_);
842 if (trail_->FailingSatClause() !=
nullptr) {
843 BumpClauseActivity(trail_->FailingSatClause());
845 BumpReasonActivities(reason_used_to_infer_the_conflict_);
846 UpdateClauseActivityIncrement();
849 decision_policy_->UpdateVariableActivityIncrement();
850 pb_constraints_->UpdateActivityIncrement();
853 const int period = parameters_->glucose_decay_increment_period();
854 const double max_decay = parameters_->glucose_max_decay();
855 if (counters_.num_failures % period == 0 &&
856 parameters_->variable_activity_decay() < max_decay) {
857 parameters_->set_variable_activity_decay(
858 parameters_->variable_activity_decay() +
859 parameters_->glucose_decay_increment());
865 bool compute_pb_conflict =
false;
866 if (parameters_->use_pb_resolution()) {
867 compute_pb_conflict = (pb_constraints_->ConflictingConstraint() !=
nullptr);
868 if (!compute_pb_conflict) {
869 for (
Literal lit : reason_used_to_infer_the_conflict_) {
870 if (ReasonPbConstraintOrNull(lit.Variable()) !=
nullptr) {
871 compute_pb_conflict =
true;
880 if (compute_pb_conflict) {
881 const int max_trail_index = ComputeMaxTrailIndex(trail_->FailingClause());
882 pb_conflict_.ClearAndResize(num_variables_.value());
883 Coefficient initial_slack(-1);
884 if (pb_constraints_->ConflictingConstraint() ==
nullptr) {
886 Coefficient num_literals(0);
887 for (
Literal literal : trail_->FailingClause()) {
888 pb_conflict_.AddTerm(literal.Negated(), Coefficient(1.0));
891 pb_conflict_.AddToRhs(num_literals - 1);
894 pb_constraints_->ConflictingConstraint()->AddToConflict(&pb_conflict_);
895 pb_constraints_->ClearConflictingConstraint();
897 pb_conflict_.ComputeSlackForTrailPrefix(*trail_, max_trail_index + 1);
900 int pb_backjump_level;
901 ComputePBConflict(max_trail_index, initial_slack, &pb_conflict_,
903 if (pb_backjump_level == -1)
return (
void)SetModelUnsat();
906 std::vector<LiteralWithCoeff> cst;
907 pb_conflict_.CopyIntoVector(&cst);
908 DCHECK(PBConstraintIsValidUnderDebugAssignment(cst, pb_conflict_.Rhs()));
912 bool conflict_is_a_clause = (pb_conflict_.Rhs() == cst.size() - 1);
913 if (conflict_is_a_clause) {
915 if (term.coefficient != Coefficient(1)) {
916 conflict_is_a_clause =
false;
922 if (!conflict_is_a_clause) {
924 DCHECK_GT(pb_constraints_->NumberOfConstraints(), 0);
927 CHECK(pb_constraints_->AddLearnedConstraint(cst, pb_conflict_.Rhs(),
929 CHECK_GT(trail_->Index(), last_decision_or_backtrack_trail_index_);
930 counters_.num_learned_pb_literals += cst.size();
936 if (pb_backjump_level < ComputePropagationLevel(learned_conflict_)) {
937 subsumed_clauses_.clear();
938 learned_conflict_.clear();
939 is_marked_.ClearAndResize(num_variables_);
943 DCHECK(
Assignment().LiteralIsTrue(term.literal));
944 DCHECK_EQ(term.coefficient, 1);
945 const int level = trail_->Info(term.literal.Variable()).level;
946 if (level == 0)
continue;
947 if (level > max_level) {
949 max_index = learned_conflict_.size();
951 learned_conflict_.push_back(term.literal.Negated());
955 is_marked_.Set(term.literal.Variable());
957 CHECK(!learned_conflict_.empty());
958 std::swap(learned_conflict_.front(), learned_conflict_[max_index]);
959 DCHECK(IsConflictValid(learned_conflict_));
968 std::vector<ClauseId>* clause_ids_for_minimization =
969 &tmp_clause_ids_for_minimization_;
970 clause_ids_for_minimization->clear();
973 binary_implication_graph_->ClearImpliedLiterals();
974 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
975 if (!binary_implication_graph_->IsEmpty()) {
976 switch (parameters_->binary_minimization_algorithm()) {
980 binary_implication_graph_->MinimizeConflictFirst(
981 *trail_, &learned_conflict_, &is_marked_,
982 clause_ids_for_minimization,
false);
985 binary_implication_graph_->MinimizeConflictFirst(
986 *trail_, &learned_conflict_, &is_marked_,
987 clause_ids_for_minimization,
true);
990 DCHECK(IsConflictValid(learned_conflict_));
994 MinimizeConflict(&learned_conflict_, clause_ids_for_minimization);
1000 ClauseId learned_conflict_clause_id =
kNoClauseId;
1001 if (lrat_proof_handler_ !=
nullptr) {
1002 if (!clause_ids_for_minimization->empty()) {
1007 tmp_clause_id_set_.clear();
1008 tmp_clause_id_set_.insert(clause_ids_for_minimization->begin(),
1009 clause_ids_for_minimization->end());
1010 clause_ids_for_minimization->reserve(clause_ids_for_minimization->size() +
1011 clause_ids_for_1iup->size());
1012 for (
const ClauseId clause_id : *clause_ids_for_1iup) {
1013 if (!tmp_clause_id_set_.contains(clause_id)) {
1014 clause_ids_for_minimization->push_back(clause_id);
1017 clause_ids_for_1iup = clause_ids_for_minimization;
1019 learned_conflict_clause_id = clause_id_generator_->GetNextId();
1020 if (!lrat_proof_handler_->AddInferredClause(learned_conflict_clause_id,
1022 *clause_ids_for_1iup)) {
1023 VLOG(1) <<
"WARNING: invalid LRAT inferred clause!";
1026 if (callback.has_value()) {
1027 (*callback)(learned_conflict_clause_id, learned_conflict_);
1038 decision_policy_->BeforeConflict(trail_->Index());
1042 const auto [is_redundant, min_lbd_of_subsumed_clauses] =
1043 SubsumptionsInConflictResolution(learned_conflict_clause_id,
1045 reason_used_to_infer_the_conflict_);
1048 counters_.num_literals_learned += learned_conflict_.size();
1049 const int conflict_level =
1050 trail_->Info(learned_conflict_[0].
Variable()).level;
1052 const bool should_backjump =
1053 !trail_->ChronologicalBacktrackingEnabled() ||
1054 (
num_failures() > parameters_->chronological_backtrack_min_conflicts() &&
1055 backjump_levels > parameters_->max_backjump_levels());
1056 const int backtrack_level = should_backjump
1057 ? ComputePropagationLevel(learned_conflict_)
1058 : std::max(0, conflict_level - 1);
1060 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
1064 learned_clauses_.push_back({learned_conflict_clause_id, is_redundant,
1065 min_lbd_of_subsumed_clauses,
1066 std::move(learned_conflict_)});
1070 for (
auto& [
id, is_redundant, min_lbd, clause] : learned_clauses_) {
1071 if (clause.empty())
return (
void)SetModelUnsat();
1078 bool some_change =
false;
1079 tmp_clause_ids_.clear();
1081 const Literal rep = binary_implication_graph_->RepresentativeOf(lit);
1084 if (lrat_proof_handler_ !=
nullptr) {
1086 tmp_clause_ids_.push_back(
1087 binary_implication_graph_->GetClauseId(lit.Negated(), rep));
1088 CHECK_NE(tmp_clause_ids_.back(),
kNoClauseId) << lit <<
" " << rep;
1098 for (
int i = 1;
i < clause.size(); ++
i) {
1099 CHECK_NE(clause[
i], clause[
i - 1].Negated()) <<
"trivial new clause?";
1102 if (lrat_proof_handler_ !=
nullptr) {
1105 const ClauseId new_id = clause_id_generator_->GetNextId();
1106 tmp_clause_ids_.push_back(
id);
1107 lrat_proof_handler_->AddInferredClause(new_id, clause, tmp_clause_ids_);
1115 for (
const Literal l : clause) {
1116 if (
Assignment().LiteralIsFalse(l)) ++num_false;
1118 if (num_false == clause.size() || clause.size() == 1) {
1120 for (
const Literal l : clause) {
1121 const int level = AssignmentLevel(l.Variable());
1122 max_level = std::max(max_level, level);
1124 int propag_level = 0;
1125 for (
const Literal l : clause) {
1126 const int level = AssignmentLevel(l.Variable());
1127 if (level < max_level) {
1128 propag_level = std::max(propag_level, level);
1136 int best_lbd = std::numeric_limits<int>::max();
1137 for (
const auto& [
id, is_redundant, min_lbd, clause] : learned_clauses_) {
1138 DCHECK((lrat_proof_handler_ ==
nullptr) || (
id !=
kNoClauseId));
1139 const int lbd = AddLearnedClauseAndEnqueueUnitPropagation(
1140 id, clause, is_redundant, min_lbd);
1141 best_lbd = std::min(best_lbd, lbd);
1143 restart_->OnConflict(conflict_trail_index, conflict_level, best_lbd);
1150bool ClauseSubsumption(absl::Span<const Literal> a,
SatClause*
b) {
1151 std::vector<Literal> superset(
b->begin(),
b->end());
1152 std::vector<Literal> subset(a.begin(), a.end());
1153 std::sort(superset.begin(), superset.end());
1154 std::sort(subset.begin(), subset.end());
1155 return std::includes(superset.begin(), superset.end(), subset.begin(),
1161std::pair<bool, int> SatSolver::SubsumptionsInConflictResolution(
1162 ClauseId learned_conflict_id, absl::Span<const Literal> conflict,
1163 absl::Span<const Literal> reason_used) {
1165 learned_clauses_.clear();
1169 tmp_literal_set_.
Resize(Literal(num_variables_,
true).Index());
1170 for (
const Literal l : conflict) tmp_literal_set_.
Set(l);
1171 const auto in_conflict = tmp_literal_set_.
const_view();
1179 std::vector<SatClause*> subsumed_by_decisions;
1180 bool decision_is_redundant =
true;
1181 int decision_min_lbd = std::numeric_limits<int>::max();
1182 int decisions_clause_size = 0;
1183 if (assumption_level_ == 0 &&
1189 ++decisions_clause_size;
1190 tmp_decision_set_.
Set(l.Negated());
1195 tmp_decision_set_.Resize(Literal(num_variables_,
true).
Index());
1196 int max_non_decision_level = 0;
1197 for (
const Literal l : conflict) {
1198 const auto& info = trail_->Info(l.Variable());
1200 max_non_decision_level =
1201 std::max<int>(max_non_decision_level, info.
level);
1205 for (
int i = 0;
i < max_non_decision_level; ++
i) {
1207 const Literal l =
Decisions()[
i].literal.Negated();
1208 ++decisions_clause_size;
1209 tmp_decision_set_.Set(l);
1211 for (
const Literal l : conflict) {
1212 const auto& info = trail_->Info(l.Variable());
1214 !tmp_decision_set_[l]) {
1215 ++decisions_clause_size;
1216 tmp_decision_set_.Set(l);
1227 int reason_index = 0;
1228 for (
int i = 0;
i < subsuming_groups_.size(); ++
i) {
1232 const int limit = subsuming_clauses_[
i].size() - conflict.size();
1234 for (
const Literal l : subsuming_clauses_[
i]) {
1235 if (!in_conflict[l]) {
1237 if (missing > limit)
break;
1242 if (missing <= limit)
continue;
1246 if (lrat_proof_handler_ !=
nullptr) {
1247 tmp_clause_ids_.clear();
1248 is_marked_.ClearAndResize(num_variables_);
1250 AppendLratProofFromReasons(
1251 reason_used.subspan(reason_index,
1252 subsuming_lrat_index_[
i] - reason_index),
1255 AppendLratProofForFailingClause(&tmp_clause_ids_);
1257 tmp_clause_ids_.push_back(last_clause_id);
1260 new_id = clause_id_generator_->GetNextId();
1261 last_clause_id = new_id;
1262 reason_index = subsuming_lrat_index_[
i];
1263 lrat_proof_handler_->AddInferredClause(new_id, subsuming_clauses_[
i],
1268 bool new_clause_is_redundant =
true;
1269 int new_clause_min_lbd = std::numeric_limits<int>::max();
1270 for (SatClause* clause : subsuming_groups_[
i]) {
1271 CHECK_NE(clause->size(), 0);
1272 if (clauses_propagator_->IsRemovable(clause)) {
1273 new_clause_min_lbd =
1274 std::min(new_clause_min_lbd,
1275 clauses_propagator_->LbdOrZeroIfNotRemovable(clause));
1277 new_clause_is_redundant =
false;
1279 DCHECK(ClauseSubsumption(subsuming_clauses_[
i], clause));
1280 clauses_propagator_->LazyDelete(
1286 learned_clauses_.push_back(
1287 {new_id, new_clause_is_redundant, new_clause_min_lbd,
1288 std::vector<Literal>(subsuming_clauses_[
i].
begin(),
1289 subsuming_clauses_[
i].
end())});
1292 bool is_redundant =
true;
1293 int min_lbd_of_subsumed_clauses = std::numeric_limits<int>::max();
1294 const auto in_decision = tmp_decision_set_.const_view();
1295 const auto maybe_subsume = [&is_redundant, &min_lbd_of_subsumed_clauses,
1296 in_conflict, conflict, in_decision,
1297 decisions_clause_size, &subsumed_by_decisions,
1298 &decision_is_redundant, &decision_min_lbd,
1299 this](SatClause* clause,
1301 if (clause ==
nullptr || clause->empty())
return;
1304 ++counters_.num_subsumed_clauses;
1305 DCHECK(ClauseSubsumption(conflict, clause));
1306 if (clauses_propagator_->IsRemovable(clause)) {
1307 min_lbd_of_subsumed_clauses =
1308 std::min(min_lbd_of_subsumed_clauses,
1309 clauses_propagator_->LbdOrZeroIfNotRemovable(clause));
1311 is_redundant =
false;
1313 clauses_propagator_->LazyDelete(clause, source);
1317 if (decisions_clause_size > 0 &&
1319 clause->AsSpan())) {
1320 if (clauses_propagator_->IsRemovable(clause)) {
1322 std::min(decision_min_lbd,
1323 clauses_propagator_->LbdOrZeroIfNotRemovable(clause));
1325 decision_is_redundant =
false;
1327 subsumed_by_decisions.push_back(clause);
1337 if (parameters_->subsumption_during_conflict_analysis()) {
1338 for (
const Literal l : reason_used) {
1341 maybe_subsume(clauses_propagator_->ReasonClauseOrNull(l.Variable()),
1346 if (parameters_->eagerly_subsume_last_n_conflicts() > 0) {
1347 for (SatClause* clause : clauses_propagator_->LastNClauses(
1348 parameters_->eagerly_subsume_last_n_conflicts())) {
1353 if (!subsumed_by_decisions.empty()) {
1355 std::vector<Literal> decision_clause;
1357 DCHECK(in_decision[l.Negated()]);
1358 decision_clause.push_back(l.Negated());
1363 if (lrat_proof_handler_ !=
nullptr) {
1364 tmp_clause_ids_.clear();
1365 clauses_propagator_->AppendClauseIdsFixing(conflict, &tmp_clause_ids_);
1366 tmp_clause_ids_.push_back(learned_conflict_id);
1368 new_clause_id = clause_id_generator_->GetNextId();
1369 lrat_proof_handler_->AddInferredClause(new_clause_id, decision_clause,
1374 for (SatClause* clause : subsumed_by_decisions) {
1375 if (clause->empty())
continue;
1376 DCHECK(ClauseSubsumption(decision_clause, clause));
1377 clauses_propagator_->LazyDelete(
1382 learned_clauses_.push_back({new_clause_id, decision_is_redundant,
1383 decision_min_lbd, decision_clause});
1387 for (
const Literal l : conflict) tmp_literal_set_.Clear(l);
1388 if (decisions_clause_size > 0) {
1390 tmp_decision_set_.Clear(
Decisions()[
i].literal.Negated());
1394 clauses_propagator_->CleanUpWatchers();
1395 return {is_redundant, min_lbd_of_subsumed_clauses};
1398void SatSolver::AppendLratProofForFixedLiterals(
1399 absl::Span<const Literal> literals, std::vector<ClauseId>* clause_ids) {
1400 for (
const Literal literal : literals) {
1401 const BooleanVariable var = literal.Variable();
1402 if (!is_marked_[var] && trail_->AssignmentLevel(literal) == 0) {
1403 is_marked_.Set(var);
1404 clause_ids->push_back(trail_->GetUnitClauseId(var));
1410void SatSolver::AppendLratProofForFailingClause(
1411 std::vector<ClauseId>* clause_ids) {
1413 AppendLratProofForFixedLiterals(trail_->FailingClause(), clause_ids);
1417 const SatClause* failing_sat_clause = trail_->FailingSatClause();
1418 if (failing_sat_clause !=
nullptr) {
1419 failing_clause_id = clauses_propagator_->GetClauseId(failing_sat_clause);
1420 }
else if (trail_->FailingClauseId() !=
kNoClauseId) {
1421 failing_clause_id = trail_->FailingClauseId();
1423 absl::Span<const Literal> failing_clause = trail_->FailingClause();
1424 if (failing_clause.size() == 2) {
1425 failing_clause_id = binary_implication_graph_->GetClauseId(
1426 failing_clause[0], failing_clause[1]);
1430 failing_clause_id = clause_id_generator_->GetNextId();
1431 lrat_proof_handler_->AddAssumedClause(failing_clause_id,
1432 trail_->FailingClause());
1434 clause_ids->push_back(failing_clause_id);
1437void SatSolver::AppendLratProofFromReasons(absl::Span<const Literal> reasons,
1438 std::vector<ClauseId>* clause_ids) {
1441 for (
const Literal literal : reasons) {
1442 DCHECK_NE(trail_->AssignmentLevel(literal), 0);
1443 AppendLratProofForFixedLiterals(trail_->Reason(literal.Variable()),
1450 for (
int i = reasons.size() - 1;
i >= 0; --
i) {
1451 const Literal literal = reasons[
i];
1452 ClauseId clause_id = clauses_propagator_->ReasonClauseId(literal);
1454 clause_id = clause_id_generator_->GetNextId();
1455 DCHECK_NE(trail_->AssignmentLevel(literal), 0);
1456 lrat_proof_handler_->AddAssumedClause(clause_id,
1457 trail_->Reason(literal.Variable()));
1459 clause_ids->push_back(clause_id);
1464 int max_level,
int* first_propagation_index) {
1466 DCHECK(assumptions_.empty());
1467 int decision_index = trail_->CurrentDecisionLevel();
1468 const auto& decisions = trail_->Decisions();
1469 while (decision_index <= max_level) {
1470 DCHECK_GE(decision_index, trail_->CurrentDecisionLevel());
1471 const Literal previous_decision = decisions[decision_index].literal;
1473 if (
Assignment().LiteralIsTrue(previous_decision)) {
1479 if (
Assignment().LiteralIsFalse(previous_decision)) {
1481 *trail_->MutableConflict() = {previous_decision.Negated(),
1487 const int old_level = trail_->CurrentDecisionLevel();
1489 if (first_propagation_index !=
nullptr) {
1490 *first_propagation_index = std::min(*first_propagation_index, index);
1493 if (trail_->CurrentDecisionLevel() <= old_level) {
1505 decision_index = trail_->CurrentDecisionLevel();
1512 Literal true_literal,
int* first_propagation_index) {
1515 CHECK(assumptions_.empty());
1519 if (first_propagation_index !=
nullptr) {
1520 *first_propagation_index = trail_->Index();
1527 if (model_is_unsat_)
return false;
1531 EnqueueNewDecision(true_literal);
1551 DCHECK_GE(target_level, 0);
1556 counters_.num_backtracks++;
1557 if (target_level == 0) {
1558 counters_.num_backtracks_to_root++;
1562 const int target_trail_index = trail_->PrepareBacktrack(target_level);
1563 DCHECK_LT(target_trail_index, trail_->Index());
1565 if (propagator->IsEmpty())
continue;
1566 propagator->Untrail(*trail_, target_trail_index);
1568 decision_policy_->Untrail(target_trail_index);
1569 trail_->Untrail(target_trail_index);
1571 last_decision_or_backtrack_trail_index_ = trail_->Index();
1580 if (!
Propagate())
return SetModelUnsat();
1585 return binary_clauses_.newly_added();
1589 binary_clauses_.ClearNewlyAdded();
1594int64_t NextMultipleOf(int64_t value, int64_t interval) {
1595 return interval * (1 + value / interval);
1600 const std::vector<Literal>& assumptions, int64_t max_number_of_conflicts) {
1604 return SolveInternal(time_limit_,
1605 max_number_of_conflicts >= 0
1606 ? max_number_of_conflicts
1607 : parameters_->max_number_of_conflicts());
1611 SOLVER_LOG(logger_, RunningStatisticsString());
1617 CHECK_GE(assumption_level, 0);
1619 assumption_level_ = assumption_level;
1622 if (!assumptions_.empty()) {
1623 CHECK_EQ(assumption_level, 0);
1624 assumptions_.clear();
1629 return SolveInternal(time_limit ==
nullptr ? time_limit_ : time_limit,
1630 parameters_->max_number_of_conflicts());
1634 return SolveInternal(time_limit_, parameters_->max_number_of_conflicts());
1638 int64_t max_number_of_conflicts) {
1650 SOLVER_LOG(logger_,
"Number of variables: ", num_variables_.value());
1651 SOLVER_LOG(logger_,
"Number of clauses (size > 2): ",
1653 SOLVER_LOG(logger_,
"Number of binary clauses: ",
1655 SOLVER_LOG(logger_,
"Number of linear constraints: ",
1658 SOLVER_LOG(logger_,
"Number of watched clauses: ",
1664 const int64_t kDisplayFrequency = 10000;
1667 :
std::numeric_limits<int64_t>::max();
1670 const int64_t kMemoryCheckFrequency = 10000;
1671 int64_t next_memory_check =
1676 const int64_t kFailureLimit =
1677 max_number_of_conflicts == std::numeric_limits<int64_t>::max()
1678 ? std::numeric_limits<int64_t>::max()
1684 if (time_limit !=
nullptr) {
1687 SOLVER_LOG(logger_,
"The time limit has been reached. Aborting.");
1692 SOLVER_LOG(logger_,
"The conflict limit has been reached. Aborting.");
1701 if (counters_.num_failures >= next_memory_check) {
1702 next_memory_check = NextMultipleOf(
num_failures(), kMemoryCheckFrequency);
1703 if (IsMemoryLimitReached()) {
1704 SOLVER_LOG(logger_,
"The memory limit has been reached. Aborting.");
1711 if (counters_.num_failures >= next_display) {
1712 SOLVER_LOG(logger_, RunningStatisticsString());
1713 next_display = NextMultipleOf(
num_failures(), kDisplayFrequency);
1716 const int old_level = trail_->CurrentDecisionLevel();
1720 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1721 if (old_level == trail_->CurrentDecisionLevel()) {
1722 CHECK(!assumptions_.empty());
1730 if (trail_->Index() == num_variables_.value()) {
1734 if (restart_->ShouldRestart()) {
1735 ++counters_.num_restarts;
1742 EnqueueNewDecision(decision_policy_->NextBranch());
1748 std::vector<Literal>* clause = trail_->MutableConflict();
1750 for (
int i = 0;
i < clause->size(); ++
i) {
1751 const Literal literal = (*clause)[
i];
1756 std::swap((*clause)[
i], (*clause)[num_true++]);
1759 CHECK_LE(num_true, 1);
1760 std::vector<Literal> result =
1762 for (
int i = 0;
i < num_true; ++
i) {
1763 result.push_back((*clause)[
i].Negated());
1769 absl::Span<const Literal> literals) {
1771 std::vector<Literal> unsat_assumptions;
1773 tmp_mark_.ClearAndResize(num_variables_);
1775 int trail_index = 0;
1776 for (
const Literal lit : literals) {
1779 std::max(trail_index, trail_->Info(lit.Variable()).trail_index);
1780 tmp_mark_.Set(lit.Variable());
1784 const auto& decisions = trail_->Decisions();
1787 CHECK_LT(trail_index, trail_->Index());
1790 while (trail_index >= limit &&
1791 !tmp_mark_[(*trail_)[trail_index].
Variable()]) {
1794 if (trail_index < limit)
break;
1795 const Literal marked_literal = (*trail_)[trail_index];
1798 if (trail_->AssignmentType(marked_literal.
Variable()) ==
1800 unsat_assumptions.push_back(marked_literal);
1803 for (
const Literal literal : trail_->Reason(marked_literal.
Variable())) {
1804 const BooleanVariable var = literal.Variable();
1805 const int level = AssignmentLevel(var);
1806 if (level > 0 && !tmp_mark_[var]) tmp_mark_.Set(var);
1813 std::reverse(unsat_assumptions.begin(), unsat_assumptions.end());
1814 return unsat_assumptions;
1817void SatSolver::BumpReasonActivities(absl::Span<const Literal> literals) {
1819 for (
const Literal literal : literals) {
1820 const BooleanVariable var = literal.Variable();
1821 if (AssignmentLevel(var) > 0) {
1823 if (clause !=
nullptr) {
1824 BumpClauseActivity(clause);
1826 UpperBoundedLinearConstraint* pb_constraint =
1827 ReasonPbConstraintOrNull(var);
1828 if (pb_constraint !=
nullptr) {
1838void SatSolver::BumpClauseActivity(
SatClause* clause) {
1843 auto it = clauses_propagator_->mutable_clauses_info()->find(clause);
1844 if (it == clauses_propagator_->mutable_clauses_info()->end())
return;
1846 it->second.num_cleanup_rounds_since_last_bumped = 0;
1849 const double activity = it->second.activity += clause_activity_increment_;
1850 if (activity > parameters_->max_clause_activity_value()) {
1851 RescaleClauseActivities(1.0 / parameters_->max_clause_activity_value());
1859 clauses_propagator_->ChangeLbdIfBetter(clause, ComputeLbd(clause->AsSpan()));
1862void SatSolver::RescaleClauseActivities(
double scaling_factor) {
1864 clause_activity_increment_ *= scaling_factor;
1865 clauses_propagator_->RescaleClauseActivities(scaling_factor);
1868void SatSolver::UpdateClauseActivityIncrement() {
1870 clause_activity_increment_ *= 1.0 / parameters_->clause_activity_decay();
1873bool SatSolver::IsConflictValid(absl::Span<const Literal> literals) {
1875 if (literals.empty())
return true;
1876 const int highest_level = AssignmentLevel(literals[0].Variable());
1877 if (!trail_->Assignment().LiteralIsFalse(literals[0])) {
1878 VLOG(2) <<
"not false " << literals[0];
1881 for (
int i = 1;
i < literals.size(); ++
i) {
1882 if (!trail_->Assignment().LiteralIsFalse(literals[
i])) {
1883 VLOG(2) <<
"not false " << literals[
i];
1886 const int level = AssignmentLevel(literals[
i].Variable());
1887 if (level <= 0 || level >= highest_level) {
1888 VLOG(2) <<
"Another at highest level or at level zero. level:" << level
1889 <<
" highest: " << highest_level;
1896int SatSolver::ComputePropagationLevel(absl::Span<const Literal> literals) {
1909 int propagation_level = 0;
1910 for (
int i = 1;
i < literals.size(); ++
i) {
1911 const int level = AssignmentLevel(literals[
i].Variable());
1912 propagation_level = std::max(propagation_level, level);
1914 DCHECK_LT(propagation_level, AssignmentLevel(literals[0].Variable()));
1916 return propagation_level;
1926int SatSolver::ComputeLbd(absl::Span<const Literal> literals) {
1929 parameters_->count_assumption_levels_in_lbd() ? 0 : assumption_level_;
1931 for (
const Literal literal : literals) {
1932 max_level = std::max(max_level, AssignmentLevel(literal.Variable()));
1934 if (max_level <= limit)
return 0;
1936 int num_at_max_level = 0;
1937 is_level_marked_.ClearAndResize(SatDecisionLevel(max_level + 1));
1938 for (
const Literal literal : literals) {
1939 const SatDecisionLevel level(AssignmentLevel(literal.Variable()));
1940 DCHECK_GE(level, 0);
1941 num_at_max_level += (level == max_level) ? 1 : 0;
1942 if (level > limit) is_level_marked_.Set(level);
1945 return is_level_marked_.NumberOfSetCallsWithDifferentArguments() +
1946 (num_at_max_level > 1 ? 1 : 0);
1949std::string SatSolver::StatusString(Status status)
const {
1950 const double time_in_s = timer_.Get();
1952 absl::StrFormat(
" time: %fs\n", time_in_s) +
1955 " num failures: %d (%.0f /sec)\n", counters_.num_failures,
1956 static_cast<double>(counters_.num_failures) / time_in_s) +
1958 " num branches: %d (%.0f /sec)\n", counters_.num_branches,
1959 static_cast<double>(counters_.num_branches) / time_in_s) +
1960 absl::StrFormat(
" num propagations: %d (%.0f /sec)\n",
1963 absl::StrFormat(
" num binary propagations: %d\n",
1964 binary_implication_graph_->num_propagations()) +
1965 absl::StrFormat(
" num binary inspections: %d\n",
1966 binary_implication_graph_->num_inspections()) +
1968 " num binary redundant implications: %d\n",
1969 binary_implication_graph_->num_redundant_implications()) +
1971 " num classic minimizations: %d"
1972 " (literals removed: %d)\n",
1973 counters_.num_minimizations, counters_.num_literals_removed) +
1975 " num binary minimizations: %d"
1976 " (literals removed: %d)\n",
1977 binary_implication_graph_->num_minimization(),
1978 binary_implication_graph_->num_literals_removed()) +
1979 absl::StrFormat(
" num inspected clauses: %d\n",
1980 clauses_propagator_->num_inspected_clauses()) +
1981 absl::StrFormat(
" num inspected clause_literals: %d\n",
1982 clauses_propagator_->num_inspected_clause_literals()) +
1984 " num learned literals: %d (avg: %.1f /clause)\n",
1985 counters_.num_literals_learned,
1986 1.0 * counters_.num_literals_learned / counters_.num_failures) +
1988 " num learned PB literals: %d (avg: %.1f /clause)\n",
1989 counters_.num_learned_pb_literals,
1990 1.0 * counters_.num_learned_pb_literals / counters_.num_failures) +
1991 absl::StrFormat(
" num subsumed clauses: %d\n",
1992 counters_.num_subsumed_clauses) +
1993 absl::StrFormat(
" pb num threshold updates: %d\n",
1994 pb_constraints_->num_threshold_updates()) +
1995 absl::StrFormat(
" pb num constraint lookups: %d\n",
1996 pb_constraints_->num_constraint_lookups()) +
1997 absl::StrFormat(
" pb num inspected constraint literals: %d\n",
1998 pb_constraints_->num_inspected_constraint_literals()) +
1999 restart_->InfoString() +
2003std::string SatSolver::RunningStatisticsString()
const {
2004 const double time_in_s = timer_.Get();
2005 return absl::StrFormat(
2006 "%6.2fs, mem:%s, fails:%d, depth:%d, clauses:%d, tmp:%d, bin:%u, "
2007 "restarts:%d, vars:%d",
2009 clauses_propagator_->num_clauses() -
2010 clauses_propagator_->num_removable_clauses(),
2011 clauses_propagator_->num_removable_clauses(),
2012 binary_implication_graph_->ComputeNumImplicationsForLog(),
2013 restart_->NumRestarts(),
2014 num_variables_.value() - num_processed_fixed_variables_);
2020 if (num_processed_fixed_variables_ == trail_->Index())
return;
2021 int num_detached_clauses = 0;
2027 const int saved_index = trail_->Index();
2028 for (
SatClause* clause : clauses_propagator_->AllClausesInCreationOrder()) {
2029 if (clause->IsRemoved())
continue;
2031 const size_t old_size = clause->size();
2032 if (clauses_propagator_->RemoveFixedLiteralsAndTestIfTrue(clause)) {
2033 ++num_detached_clauses;
2037 const size_t new_size = clause->size();
2038 if (new_size == old_size)
continue;
2041 if (lrat_proof_handler_ !=
nullptr) {
2042 std::vector<ClauseId>& clause_ids = tmp_clause_ids_for_minimization_;
2044 for (
int i = new_size;
i < old_size; ++
i) {
2045 const Literal fixed_literal = *(clause->begin() +
i);
2046 clause_ids.push_back(trail_->GetUnitClauseId(fixed_literal.
Variable()));
2049 const ClauseId old_clause_id = clauses_propagator_->GetClauseId(clause);
2050 clause_ids.push_back(old_clause_id);
2051 new_clause_id = clause_id_generator_->GetNextId();
2052 lrat_proof_handler_->AddInferredClause(
2053 new_clause_id, {clause->begin(), new_size}, clause_ids);
2060 lrat_proof_handler_->DeleteClause(old_clause_id,
2061 {clause->begin(), old_size});
2062 clauses_propagator_->SetClauseId(clause, new_clause_id);
2066 if (new_size == 2) {
2070 AddBinaryClauseInternal(new_clause_id, clause->FirstLiteral(),
2071 clause->SecondLiteral());
2072 clauses_propagator_->LazyDelete(
2083 DCHECK_EQ(trail_->Index(), saved_index);
2089 clauses_propagator_->CleanUpWatchers();
2090 if (num_detached_clauses > 0 || num_binary > 0) {
2091 VLOG(1) << trail_->Index() <<
" fixed variables at level 0. " <<
"Detached "
2092 << num_detached_clauses <<
" clauses. " << num_binary
2093 <<
" converted to binary.";
2100 CHECK(binary_implication_graph_->Propagate(trail_));
2101 binary_implication_graph_->RemoveFixedVariables();
2102 num_processed_fixed_variables_ = trail_->Index();
2108 if (time_limit_->LimitReached())
return true;
2110 if (propagator->IsEmpty())
continue;
2111 if (!propagator->PropagationIsDone(*trail_))
return false;
2128 non_empty_propagators_.clear();
2130 if (!propagator->IsEmpty()) {
2131 non_empty_propagators_.push_back(propagator);
2143 const int old_index = trail_->Index();
2145 DCHECK(propagator->PropagatePreconditionsAreSatisfied(*trail_));
2146 if (!propagator->Propagate(trail_))
return false;
2147 if (trail_->Index() > old_index)
break;
2149 if (trail_->Index() == old_index)
break;
2160void SatSolver::InitializePropagators() {
2161 propagators_.clear();
2162 propagators_.push_back(binary_implication_graph_);
2163 propagators_.push_back(clauses_propagator_);
2164 propagators_.push_back(enforcement_propagator_);
2165 propagators_.push_back(pb_constraints_);
2166 for (
int i = 0;
i < external_propagators_.size(); ++
i) {
2167 propagators_.push_back(external_propagators_[
i]);
2169 if (last_propagator_ !=
nullptr) {
2170 propagators_.push_back(last_propagator_);
2174bool SatSolver::ResolvePBConflict(BooleanVariable var,
2176 Coefficient* slack) {
2177 const int trail_index = trail_->Info(var).trail_index;
2180 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
2183 UpperBoundedLinearConstraint* pb_reason = ReasonPbConstraintOrNull(var);
2184 if (pb_reason !=
nullptr) {
2185 pb_reason->ResolvePBConflict(*trail_, var, conflict, slack);
2193 const int algorithm = 1;
2194 switch (algorithm) {
2198 conflict->ReduceSlackTo(*trail_, trail_index, *slack,
Coefficient(0));
2202 multiplier = *slack + 1;
2206 multiplier = conflict->GetCoefficient(var);
2211 trail_->Assignment().GetTrueLiteralForAssignedVariable(var).Negated(),
2213 for (Literal literal : trail_->Reason(var)) {
2214 DCHECK_NE(literal.Variable(), var);
2215 DCHECK(
Assignment().LiteralIsFalse(literal));
2216 conflict->AddTerm(literal.Negated(), multiplier);
2219 conflict->AddToRhs((num_literals - 1) * multiplier);
2223 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
2227void SatSolver::EnqueueNewDecision(
Literal literal) {
2229 CHECK(!
Assignment().VariableIsAssigned(literal.Variable()));
2238 const double kMinDeterministicTimeBetweenCleanups = 1.0;
2239 if (num_processed_fixed_variables_ < trail_->
Index() &&
2241 deterministic_time_of_last_fixed_variables_cleanup_ +
2242 kMinDeterministicTimeBetweenCleanups) {
2247 counters_.num_branches++;
2248 last_decision_or_backtrack_trail_index_ = trail_->Index();
2249 trail_->EnqueueSearchDecision(literal);
2252std::string SatSolver::DebugString(
const SatClause& clause)
const {
2254 for (
const Literal literal : clause) {
2255 if (!result.empty()) {
2256 result.append(
" || ");
2258 const std::string value =
2259 trail_->Assignment().LiteralIsTrue(literal)
2261 : (trail_->Assignment().LiteralIsFalse(literal) ?
"false"
2263 result.append(absl::StrFormat(
"%s(%s)", literal.DebugString(), value));
2268int SatSolver::ComputeMaxTrailIndex(absl::Span<const Literal> clause)
const {
2270 int trail_index = -1;
2271 for (
const Literal literal : clause) {
2273 std::max(trail_index, trail_->Info(literal.Variable()).trail_index);
2281void SatSolver::ComputeFirstUIPConflict(
2282 int max_trail_index, std::vector<Literal>* conflict,
2283 std::vector<Literal>* reason_used_to_infer_the_conflict) {
2285 const int64_t conflict_id = counters_.num_failures;
2287 Literal previous_literal;
2291 is_marked_.ClearAndResize(num_variables_);
2294 reason_used_to_infer_the_conflict->clear();
2295 if (max_trail_index == -1)
return;
2297 absl::Span<const Literal> conflict_or_reason_to_expand =
2298 trail_->FailingClause();
2303 DCHECK_EQ(max_trail_index, ComputeMaxTrailIndex(trail_->FailingClause()));
2304 int highest_level = trail_->Info((*trail_)[max_trail_index].Variable()).level;
2305 if (trail_->ChronologicalBacktrackingEnabled()) {
2306 for (
const Literal literal : conflict_or_reason_to_expand) {
2308 std::max(highest_level, AssignmentLevel(literal.Variable()));
2311 if (highest_level == 0)
return;
2314 struct LiteralWithIndex {
2318 bool operator<(
const LiteralWithIndex& other)
const {
2319 return index < other.index;
2322 std::vector<LiteralWithIndex> last_level_heap;
2338 SatClause* sat_clause = trail_->FailingSatClause();
2339 DCHECK(!conflict_or_reason_to_expand.empty());
2341 const int old_conflict_size = conflict->size();
2342 const int old_heap_size = last_level_heap.size();
2344 int num_new_vars_at_positive_level = 0;
2345 int num_vars_at_positive_level_in_clause_to_expand = 0;
2346 for (
const Literal literal : conflict_or_reason_to_expand) {
2347 const BooleanVariable var = literal.Variable();
2348 const int level = AssignmentLevel(var);
2349 if (level == 0)
continue;
2350 DCHECK_LE(level, highest_level);
2351 ++num_vars_at_positive_level_in_clause_to_expand;
2352 if (!is_marked_[var]) {
2353 is_marked_.Set(var);
2354 ++num_new_vars_at_positive_level;
2355 if (level == highest_level) {
2356 last_level_heap.push_back({literal, trail_->Info(var).trail_index});
2360 DCHECK(trail_->Assignment().LiteralIsFalse(literal));
2361 conflict->push_back(literal);
2371 if (num_new_vars_at_positive_level > 0) {
2372 if (parameters_->extra_subsumption_during_conflict_analysis() &&
2373 !subsumed_clauses_.empty() &&
2374 reason_used_to_infer_the_conflict->size() > 1) {
2376 tmp_literals_.clear();
2377 tmp_literals_.push_back(previous_literal.Negated());
2378 for (
int i = 0;
i < old_conflict_size; ++
i) {
2379 tmp_literals_.push_back((*conflict)[
i]);
2381 for (
int i = 0;
i < old_heap_size; ++
i) {
2382 tmp_literals_.push_back(last_level_heap[
i].literal);
2385 for (SatClause* clause : subsumed_clauses_) {
2386 CHECK(ClauseSubsumption(tmp_literals_, clause))
2387 << tmp_literals_ <<
" " << clause->AsSpan();
2391 subsuming_lrat_index_.push_back(
2392 reason_used_to_infer_the_conflict->size() - 1);
2393 subsuming_clauses_.Add(tmp_literals_);
2394 subsuming_groups_.Add(subsumed_clauses_);
2396 subsumed_clauses_.clear();
2400 for (
int i = old_heap_size + 1;
i <= last_level_heap.size(); ++
i) {
2401 std::push_heap(last_level_heap.begin(), last_level_heap.begin() +
i);
2411 if (sat_clause !=
nullptr &&
2412 num_vars_at_positive_level_in_clause_to_expand ==
2413 conflict->size() + last_level_heap.size()) {
2414 subsumed_clauses_.push_back(sat_clause);
2417 DCHECK(!last_level_heap.empty());
2418 const Literal literal = (*trail_)[last_level_heap.front().index];
2419 DCHECK(is_marked_[literal.Variable()]);
2421 if (last_level_heap.size() == 1) {
2425 conflict->push_back(literal.Negated());
2428 std::swap(conflict->back(), conflict->front());
2432 reason_used_to_infer_the_conflict->push_back(literal);
2437 if (same_reason_identifier_.FirstVariableWithSameReason(
2438 literal.Variable()) != literal.Variable()) {
2439 conflict_or_reason_to_expand = {};
2441 conflict_or_reason_to_expand =
2442 trail_->Reason(literal.Variable(), conflict_id);
2444 sat_clause = clauses_propagator_->ReasonClauseOrNull(literal.Variable());
2446 previous_literal = literal;
2447 absl::c_pop_heap(last_level_heap);
2448 last_level_heap.pop_back();
2452void SatSolver::ComputeUnionOfReasons(absl::Span<const Literal>
input,
2453 std::vector<Literal>* literals) {
2454 tmp_mark_.ClearAndResize(num_variables_);
2456 for (
const Literal l :
input) tmp_mark_.Set(l.Variable());
2457 for (
const Literal l :
input) {
2458 for (
const Literal r : trail_->Reason(l.Variable())) {
2459 if (!tmp_mark_[r.Variable()]) {
2460 tmp_mark_.Set(r.Variable());
2461 literals->push_back(r);
2465 for (
const Literal l :
input) tmp_mark_.Clear(l.Variable());
2466 for (
const Literal l : *literals) tmp_mark_.Clear(l.Variable());
2470void SatSolver::ComputePBConflict(
int max_trail_index,
2471 Coefficient initial_slack,
2473 int* pb_backjump_level) {
2475 int trail_index = max_trail_index;
2481 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1));
2482 CHECK_LT(slack, 0) <<
"We don't have a conflict!";
2485 int backjump_level = 0;
2487 const BooleanVariable var = (*trail_)[trail_index].Variable();
2490 if (conflict->GetCoefficient(var) > 0 &&
2491 trail_->Assignment().LiteralIsTrue(conflict->GetLiteral(var))) {
2492 if (parameters_->minimize_reduction_during_pb_resolution()) {
2497 conflict->ReduceGivenCoefficient(var);
2501 slack += conflict->GetCoefficient(var);
2505 if (slack < 0)
continue;
2511 const int current_level = AssignmentLevel(var);
2512 int i = trail_index;
2514 const BooleanVariable previous_var = (*trail_)[
i].Variable();
2515 if (conflict->GetCoefficient(previous_var) > 0 &&
2516 trail_->Assignment().LiteralIsTrue(
2517 conflict->GetLiteral(previous_var))) {
2522 if (
i < 0 || AssignmentLevel((*trail_)[
i].Variable()) < current_level) {
2523 backjump_level =
i < 0 ? 0 : AssignmentLevel((*trail_)[
i].Variable());
2529 const bool clause_used = ResolvePBConflict(var, conflict, &slack);
2540 ? conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1)
2545 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2546 conflict->ReduceCoefficients();
2552 if (parameters_->minimize_reduction_during_pb_resolution()) {
2554 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1);
2556 slack = conflict->ReduceCoefficientsAndComputeSlackForTrailPrefix(
2557 *trail_, trail_index + 1);
2560 DCHECK_EQ(slack, slack_only_for_debug);
2562 if (conflict->Rhs() < 0) {
2563 *pb_backjump_level = -1;
2571 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2572 conflict->ReduceCoefficients();
2577 std::vector<Coefficient> sum_for_le_level(backjump_level + 2,
Coefficient(0));
2578 std::vector<Coefficient> max_coeff_for_ge_level(backjump_level + 2,
2582 for (BooleanVariable var : conflict->PossibleNonZeros()) {
2583 const Coefficient coeff = conflict->GetCoefficient(var);
2584 if (coeff == 0)
continue;
2587 if (!trail_->Assignment().VariableIsAssigned(var) ||
2588 AssignmentLevel(var) > backjump_level) {
2589 max_coeff_for_ge_level[backjump_level + 1] =
2590 std::max(max_coeff_for_ge_level[backjump_level + 1], coeff);
2592 const int level = AssignmentLevel(var);
2593 if (trail_->Assignment().LiteralIsTrue(conflict->GetLiteral(var))) {
2594 sum_for_le_level[level] += coeff;
2596 max_coeff_for_ge_level[level] =
2597 std::max(max_coeff_for_ge_level[level], coeff);
2602 for (
int i = 1;
i < sum_for_le_level.size(); ++
i) {
2603 sum_for_le_level[
i] += sum_for_le_level[
i - 1];
2605 for (
int i = max_coeff_for_ge_level.size() - 2;
i >= 0; --
i) {
2606 max_coeff_for_ge_level[
i] =
2607 std::max(max_coeff_for_ge_level[
i], max_coeff_for_ge_level[
i + 1]);
2612 if (sum_for_le_level[0] > conflict->Rhs()) {
2613 *pb_backjump_level = -1;
2616 for (
int i = 0;
i <= backjump_level; ++
i) {
2618 CHECK_LE(level_sum, conflict->Rhs());
2619 if (conflict->Rhs() - level_sum < max_coeff_for_ge_level[
i + 1]) {
2620 *pb_backjump_level =
i;
2624 LOG(FATAL) <<
"The code should never reach here.";
2627void SatSolver::MinimizeConflict(std::vector<Literal>* conflict,
2628 std::vector<ClauseId>* clause_ids) {
2631 const int old_size = conflict->size();
2632 switch (parameters_->minimization_algorithm()) {
2636 MinimizeConflictSimple(conflict, clause_ids);
2640 MinimizeConflictRecursively(conflict, clause_ids);
2644 if (conflict->size() < old_size) {
2645 ++counters_.num_minimizations;
2646 counters_.num_literals_removed += old_size - conflict->size();
2658void SatSolver::MinimizeConflictSimple(std::vector<Literal>* conflict,
2659 std::vector<ClauseId>* clause_ids) {
2666 tmp_literals_.clear();
2667 for (
int i = 1;
i < conflict->size(); ++
i) {
2668 const BooleanVariable var = (*conflict)[
i].Variable();
2669 bool can_be_removed =
false;
2670 if (AssignmentLevel(var) != current_level) {
2672 const absl::Span<const Literal> reason = trail_->Reason(var);
2673 if (!reason.empty()) {
2674 can_be_removed =
true;
2675 for (Literal literal : reason) {
2676 if (AssignmentLevel(literal.Variable()) == 0)
continue;
2677 if (!is_marked_[literal.Variable()]) {
2678 can_be_removed =
false;
2682 if (can_be_removed && lrat_proof_handler_ !=
nullptr) {
2687 binary_implication_graph_->AppendImplicationChains(reason,
2692 tmp_literals_.push_back((*conflict)[
i].Negated());
2696 if (!can_be_removed) {
2697 (*conflict)[index] = (*conflict)[
i];
2701 conflict->erase(conflict->begin() + index, conflict->end());
2702 if (!tmp_literals_.empty()) {
2706 std::sort(tmp_literals_.begin(), tmp_literals_.end(),
2707 [&](Literal a, Literal
b) {
2708 return trail_->Info(a.Variable()).trail_index <
2709 trail_->Info(b.Variable()).trail_index;
2711 for (
const Literal literal : tmp_literals_) {
2712 clause_ids->push_back(clauses_propagator_->ReasonClauseId(literal));
2724void SatSolver::MinimizeConflictRecursively(std::vector<Literal>* conflict,
2725 std::vector<ClauseId>* clause_ids) {
2738 is_independent_.ClearAndResize(num_variables_);
2746 std::numeric_limits<int>::max());
2758 for (BooleanVariable var : is_marked_.PositionsSetAtLeastOnce()) {
2759 const int level = AssignmentLevel(var);
2760 min_trail_index_per_level_[level] = std::min(
2761 min_trail_index_per_level_[level], trail_->Info(var).trail_index);
2768 TimeLimitCheckEveryNCalls time_limit_check(100, time_limit_);
2770 std::vector<Literal>& removed_literals = tmp_literals_;
2771 if (lrat_proof_handler_ !=
nullptr) {
2772 removed_literals.clear();
2773 is_marked_for_lrat_.CopyFrom(is_marked_);
2776 for (
int i = 1;
i < conflict->size(); ++
i) {
2777 const BooleanVariable var = (*conflict)[
i].Variable();
2778 const AssignmentInfo& info = trail_->Info(var);
2779 if (time_limit_check.LimitReached() ||
2781 info.trail_index <= min_trail_index_per_level_[info.level] ||
2782 !CanBeInferredFromConflictVariables(var)) {
2785 is_independent_.Set(var);
2786 (*conflict)[index] = (*conflict)[
i];
2788 }
else if (lrat_proof_handler_ !=
nullptr) {
2789 removed_literals.push_back((*conflict)[
i]);
2792 conflict->resize(index);
2794 if (lrat_proof_handler_ !=
nullptr && !removed_literals.empty()) {
2798 std::sort(removed_literals.begin(), removed_literals.end(),
2799 [&](Literal a, Literal
b) {
2800 return trail_->Info(a.Variable()).trail_index <
2801 trail_->Info(b.Variable()).trail_index;
2803 for (
const Literal literal : removed_literals) {
2804 AppendInferenceChain(literal.Variable(), clause_ids);
2810 const int threshold = min_trail_index_per_level_.size() / 2;
2811 if (is_marked_.PositionsSetAtLeastOnce().size() < threshold) {
2812 for (BooleanVariable var : is_marked_.PositionsSetAtLeastOnce()) {
2813 min_trail_index_per_level_[AssignmentLevel(var)] =
2814 std::numeric_limits<int>::max();
2817 min_trail_index_per_level_.clear();
2821bool SatSolver::CanBeInferredFromConflictVariables(BooleanVariable variable) {
2824 DCHECK(is_marked_[variable]);
2825 const BooleanVariable v =
2826 same_reason_identifier_.FirstVariableWithSameReason(variable);
2827 if (v != variable)
return !is_independent_[v];
2840 dfs_stack_.push_back(variable);
2841 variable_to_process_.clear();
2842 variable_to_process_.push_back(variable);
2845 for (
const Literal literal : trail_->Reason(variable)) {
2846 const BooleanVariable var = literal.Variable();
2847 DCHECK_NE(var, variable);
2848 if (is_marked_[var])
continue;
2849 const AssignmentInfo& info = trail_->Info(var);
2850 if (info.level == 0) {
2855 is_marked_.Set(var);
2858 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2862 variable_to_process_.push_back(var);
2866 while (!variable_to_process_.empty()) {
2867 const BooleanVariable current_var = variable_to_process_.back();
2868 if (current_var == dfs_stack_.back()) {
2871 if (dfs_stack_.size() > 1) {
2872 DCHECK(!is_marked_[current_var]);
2873 is_marked_.Set(current_var);
2875 variable_to_process_.pop_back();
2876 dfs_stack_.pop_back();
2881 if (is_marked_[current_var]) {
2882 variable_to_process_.pop_back();
2888 DCHECK(!is_independent_[current_var]);
2892 const BooleanVariable v =
2893 same_reason_identifier_.FirstVariableWithSameReason(current_var);
2894 if (v != current_var) {
2895 if (is_independent_[v])
break;
2896 DCHECK(is_marked_[v]);
2897 variable_to_process_.pop_back();
2903 dfs_stack_.push_back(current_var);
2904 bool abort_early =
false;
2905 for (Literal literal : trail_->Reason(current_var)) {
2906 const BooleanVariable var = literal.Variable();
2907 DCHECK_NE(var, current_var) << trail_->Info(var).DebugString()
2908 <<
" old: " << trail_->AssignmentType(var);
2909 const AssignmentInfo& info = trail_->Info(var);
2910 if (info.level == 0 || is_marked_[var])
continue;
2911 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2913 is_independent_[var]) {
2917 variable_to_process_.push_back(var);
2919 if (abort_early)
break;
2923 for (
const BooleanVariable var : dfs_stack_) {
2924 is_independent_.Set(var);
2926 return dfs_stack_.empty();
2929void SatSolver::AppendInferenceChain(BooleanVariable variable,
2930 std::vector<ClauseId>* clause_ids) {
2931 DCHECK(is_marked_[variable]);
2932 DCHECK(is_marked_for_lrat_[variable]);
2937 dfs_stack_.push_back(variable);
2938 variable_to_process_.clear();
2939 variable_to_process_.push_back(variable);
2942 const auto expand_variable = [&](BooleanVariable variable_to_expand) {
2943 for (
const Literal literal : trail_->Reason(variable_to_expand)) {
2944 const BooleanVariable var = literal.Variable();
2945 const AssignmentInfo& info = trail_->Info(var);
2946 if (is_marked_for_lrat_[var] || info.level == 0) {
2951 binary_implication_graph_->AppendImplicationChains({literal},
2953 is_marked_for_lrat_.Set(var);
2956 variable_to_process_.push_back(var);
2959 expand_variable(variable);
2962 while (!variable_to_process_.empty()) {
2963 const BooleanVariable current_var = variable_to_process_.back();
2964 DCHECK(is_marked_[current_var]);
2965 if (current_var == dfs_stack_.back()) {
2968 variable_to_process_.pop_back();
2969 dfs_stack_.pop_back();
2971 const Literal current_literal =
2972 trail_->Assignment().GetTrueLiteralForAssignedVariable(current_var);
2973 clause_ids->push_back(
2974 clauses_propagator_->ReasonClauseId(current_literal));
2976 is_marked_for_lrat_.Set(current_var);
2981 if (is_marked_for_lrat_[current_var]) {
2982 variable_to_process_.pop_back();
2988 const BooleanVariable v =
2989 same_reason_identifier_.FirstVariableWithSameReason(current_var);
2990 if (v != current_var) {
2991 DCHECK(is_marked_for_lrat_[v]);
2992 variable_to_process_.pop_back();
2998 dfs_stack_.push_back(current_var);
2999 expand_variable(current_var);
3005struct WeightedVariable {
3006 WeightedVariable(BooleanVariable v,
int w) : var(v), weight(
w) {}
3008 BooleanVariable var;
3014struct VariableWithLargerWeightFirst {
3015 bool operator()(
const WeightedVariable& wv1,
3016 const WeightedVariable& wv2)
const {
3017 return (wv1.weight > wv2.weight ||
3018 (wv1.weight == wv2.weight && wv1.var < wv2.var));
3023void SatSolver::CleanClauseDatabaseIfNeeded() {
3024 if (num_learned_clause_before_cleanup_ > 0)
return;
3029 typedef std::pair<SatClause*, ClauseInfo> Entry;
3030 std::vector<Entry> entries;
3031 auto& clauses_info = *(clauses_propagator_->mutable_clauses_info());
3032 for (
auto& entry : clauses_info) {
3033 DCHECK(!entry.first->empty());
3034 entry.second.num_cleanup_rounds_since_last_bumped++;
3035 if (clauses_propagator_->ClauseIsUsedAsReason(entry.first))
continue;
3037 if (entry.second.lbd <= parameters_->clause_cleanup_lbd_tier1() &&
3038 entry.second.num_cleanup_rounds_since_last_bumped <= 32) {
3042 if (entry.second.lbd <= parameters_->clause_cleanup_lbd_tier2() &&
3043 entry.second.num_cleanup_rounds_since_last_bumped <= 1) {
3048 DCHECK_LE(entry.second.lbd, entry.first->size());
3049 entries.push_back(entry);
3051 const int num_protected_clauses =
3052 clauses_propagator_->num_removable_clauses() - entries.size();
3056 std::sort(entries.begin(), entries.end(),
3057 [](
const Entry& a,
const Entry&
b) {
3058 if (a.second.lbd == b.second.lbd) {
3059 return a.second.activity < b.second.activity;
3061 return a.second.lbd >
b.second.lbd;
3065 std::sort(entries.begin(), entries.end(),
3066 [](
const Entry& a,
const Entry&
b) {
3067 if (a.second.activity == b.second.activity) {
3068 return a.second.lbd > b.second.lbd;
3070 return a.second.activity <
b.second.activity;
3075 int num_kept_clauses =
3076 (parameters_->clause_cleanup_target() > 0)
3077 ? std::min(
static_cast<int>(entries.size()),
3078 parameters_->clause_cleanup_target())
3079 : static_cast<int>(parameters_->clause_cleanup_ratio() *
3080 static_cast<double>(entries.size()));
3082 int num_deleted_clauses = entries.size() - num_kept_clauses;
3087 if (num_kept_clauses > 0) {
3088 while (num_deleted_clauses > 0) {
3089 const ClauseInfo& a = entries[num_deleted_clauses].second;
3090 const ClauseInfo&
b = entries[num_deleted_clauses - 1].second;
3091 if (a.activity !=
b.activity || a.lbd !=
b.lbd)
break;
3092 --num_deleted_clauses;
3096 if (num_deleted_clauses > 0) {
3097 entries.resize(num_deleted_clauses);
3098 for (
const Entry& entry : entries) {
3099 SatClause* clause = entry.first;
3100 counters_.num_literals_forgotten += clause->size();
3101 clauses_propagator_->LazyDelete(clause,
3102 DeletionSourceForStat::GARBAGE_COLLECTED);
3104 clauses_propagator_->CleanUpWatchers();
3108 if (!block_clause_deletion_) {
3109 clauses_propagator_->DeleteRemovedClauses();
3113 num_learned_clause_before_cleanup_ =
3114 parameters_->clause_cleanup_period() +
3115 (++counters_.num_cleanup_rounds) *
3116 parameters_->clause_cleanup_period_increment();
3117 VLOG(1) <<
"Database cleanup, #protected:" << num_protected_clauses
3118 <<
" #kept:" << num_kept_clauses
3119 <<
" #deleted:" << num_deleted_clauses;
3120 counters_.num_deleted_clauses += num_deleted_clauses;
3126 return "ASSUMPTIONS_UNSAT";
3128 return "INFEASIBLE";
3132 return "LIMIT_REACHED";
3136 LOG(DFATAL) <<
"Invalid SatSolver::Status " << status;
3141 std::vector<Literal> result;
3143 for (
const Literal lit : *core) {
3145 result.push_back(lit);
3149 if (result.size() < core->size()) {
3150 VLOG(1) <<
"minimization " << core->size() <<
" -> " << result.size();
void Resize(IndexType size)
ConstView const_view() const
bool LoggingIsEnabled() const
bool AddBinaryClause(ClauseId id, Literal a, Literal b, bool delete_non_representative_id=true)
int64_t ComputeNumImplicationsForLog() const
int64_t num_clauses() const
int64_t num_watched_clauses() const
SatClause * ReasonClauseOrNull(BooleanVariable var) const
BooleanVariable Variable() const
int NumberOfConstraints() const
UpperBoundedLinearConstraint * ReasonPbConstraint(int trail_index) const
void BumpActivity(UpperBoundedLinearConstraint *constraint)
static constexpr ConflictMinimizationAlgorithm NONE
::int64_t max_memory_in_mb() const
static constexpr ClauseOrdering CLAUSE_LBD
static constexpr BinaryMinizationAlgorithm NO_BINARY_MINIMIZATION
bool decision_subsumption_during_conflict_analysis() const
static constexpr ConflictMinimizationAlgorithm SIMPLE
bool log_search_progress() const
static constexpr BinaryMinizationAlgorithm BINARY_MINIMIZATION_FROM_UIP
static constexpr BinaryMinizationAlgorithm BINARY_MINIMIZATION_FROM_UIP_AND_DECISIONS
static constexpr ConflictMinimizationAlgorithm RECURSIVE
Status EnqueueDecisionAndBacktrackOnConflict(Literal true_literal, int *first_propagation_index=nullptr)
void LoadDebugSolution(absl::Span< const Literal > solution)
Status SolveWithTimeLimit(TimeLimit *time_limit)
double deterministic_time() const
const std::vector< BinaryClause > & NewlyAddedBinaryClauses()
bool AddProblemClause(absl::Span< const Literal > literals, bool shared=false)
Status UnsatStatus() const
bool AddBinaryClauses(absl::Span< const BinaryClause > clauses)
void ProcessNewlyFixedVariables()
bool ResetWithGivenAssumptions(const std::vector< Literal > &assumptions)
int64_t num_branches() const
const std::vector< LiteralWithTrailIndex > & Decisions() const
std::vector< Literal > GetLastIncompatibleDecisions()
bool AddBinaryClause(Literal a, Literal b)
int64_t num_failures() const
bool ModelIsUnsat() const
void Backtrack(int target_level)
bool ReapplyAssumptionsIfNeeded()
void ClearNewlyAddedBinaryClauses()
int64_t num_propagations() const
int64_t num_backtracks() const
const SatParameters & parameters() const
bool EnqueueDecisionIfNotConflicting(Literal true_literal)
bool AddClauseDuringSearch(absl::Span< const Literal > literals)
ABSL_MUST_USE_RESULT bool Propagate()
std::vector< Literal > GetDecisionsFixing(absl::Span< const Literal > literals)
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< Literal > *enforcement_literals, std::vector< LiteralWithCoeff > *cst)
void SetAssumptionLevel(int assumption_level)
ABSL_MUST_USE_RESULT bool FinishPropagation(std::optional< ConflictCallback > callback=std::nullopt)
int64_t num_restarts() const
ABSL_MUST_USE_RESULT bool AddUnitClause(Literal true_literal)
bool AddTernaryClause(Literal a, Literal b, Literal c)
int64_t num_backtracks_to_root() const
void AdvanceDeterministicTime(TimeLimit *limit)
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions, int64_t max_number_of_conflicts=-1)
const VariablesAssignment & Assignment() const
int CurrentDecisionLevel() const
ABSL_MUST_USE_RESULT bool ResetToLevelZero()
void SaveDebugAssignment()
void AddLastPropagator(SatPropagator *propagator)
void ProcessCurrentConflict(std::optional< ConflictCallback > callback=std::nullopt)
bool BacktrackAndPropagateReimplications(int target_level)
void SetNumVariables(int num_variables)
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal, std::optional< ConflictCallback > callback=std::nullopt)
void AddPropagator(SatPropagator *propagator)
bool PropagationIsDone() const
void SetParameters(const SatParameters ¶meters)
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
int AssignmentType(BooleanVariable var) const
void EnqueueWithUnitReason(Literal true_literal)
bool ChronologicalBacktrackingEnabled() const
const AssignmentInfo & Info(BooleanVariable var) const
const VariablesAssignment & Assignment() const
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
std::tuple< int64_t, int64_t, const double > Coefficient
std::string SatStatusString(SatSolver::Status status)
Coefficient ComputeNegatedCanonicalRhs(Coefficient lower_bound, Coefficient bound_shift, Coefficient max_value)
bool BooleanLinearExpressionIsCanonical(absl::Span< const Literal > enforcement_literals, absl::Span< const LiteralWithCoeff > cst)
constexpr ClauseId kNoClauseId(0)
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
bool IsStrictlyIncluded(Bitset64< LiteralIndex >::ConstView in_subset, int subset_size, absl::Span< const Literal > superset)
@ SUBSUMPTION_CONFLICT_EXTRA
const int kUnsatTrailIndex
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
int64_t MemoryUsageProcess()
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
ClosedInterval::Iterator end(ClosedInterval interval)
std::string ProtobufShortDebugString(const P &message)
std::string MemoryUsage()
ClosedInterval::Iterator begin(ClosedInterval interval)
bool SafeAddInto(IntegerType a, IntegerType *b)
trees with all degrees equal w the current value of w
static int input(yyscan_t yyscanner)
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
static constexpr int kSearchDecision
#define SOLVER_LOG(logger,...)