26 #include "absl/base/attributes.h"
27 #include "absl/container/btree_set.h"
28 #include "absl/container/flat_hash_map.h"
29 #include "absl/meta/type_traits.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/str_format.h"
32 #include "absl/types/span.h"
45 #include "ortools/sat/sat_parameters.pb.h"
58 owned_model_.reset(model_);
68 track_binary_clauses_(false),
71 parameters_(
model->GetOrCreate<SatParameters>()),
75 clause_activity_increment_(1.0),
76 same_reason_identifier_(*trail_),
77 is_relevant_for_core_computation_(true),
78 problem_is_pure_sat_(true),
79 drat_proof_handler_(nullptr),
81 InitializePropagators();
88 CHECK_GE(num_variables, num_variables_);
90 num_variables_ = num_variables;
91 binary_implication_graph_->
Resize(num_variables);
92 clauses_propagator_->
Resize(num_variables);
93 trail_->
Resize(num_variables);
95 pb_constraints_->
Resize(num_variables);
96 same_reason_identifier_.
Resize(num_variables);
101 decisions_.resize(num_variables + 1);
146 bool SatSolver::IsMemoryLimitReached()
const {
147 const int64_t memory_usage =
149 const int64_t kMegaByte = 1024 * 1024;
150 return memory_usage > kMegaByte * parameters_->max_memory_in_mb();
153 bool SatSolver::SetModelUnsat() {
154 model_is_unsat_ =
true;
159 if (model_is_unsat_)
return false;
161 if (literals.empty())
return SetModelUnsat();
163 if (literals.size() == 2) {
170 return SetModelUnsat();
173 if (!clauses_propagator_->
AddClause(literals)) {
175 return SetModelUnsat();
207 if (model_is_unsat_)
return false;
210 literals_scratchpad_.clear();
211 for (
const Literal l : literals) {
214 literals_scratchpad_.push_back(l);
219 for (
int i = 0; i + 1 < literals_scratchpad_.size(); ++i) {
220 if (literals_scratchpad_[i] == literals_scratchpad_[i + 1].Negated()) {
226 AddProblemClauseInternal(literals_scratchpad_);
232 if (!PropagationIsDone() && !
Propagate()) {
233 return SetModelUnsat();
238 bool SatSolver::AddProblemClauseInternal(absl::Span<const Literal> literals) {
242 for (
const Literal l : literals) {
247 if (literals.empty())
return SetModelUnsat();
249 if (literals.size() == 1) {
250 if (drat_proof_handler_ !=
nullptr) {
253 drat_proof_handler_->
AddClause({literals[0]});
256 }
else if (literals.size() == 2) {
258 if (literals[0] == literals[1]) {
261 }
else if (literals[0] == literals[1].Negated()) {
265 AddBinaryClauseInternal(literals[0], literals[1],
269 if (!clauses_propagator_->
AddClause(literals, trail_)) {
270 return SetModelUnsat();
277 bool SatSolver::AddLinearConstraintInternal(
278 const std::vector<LiteralWithCoeff>& cst,
Coefficient rhs,
282 if (rhs < 0)
return SetModelUnsat();
283 if (rhs >= max_value)
return true;
290 const Coefficient min_coeff = cst.front().coefficient;
291 const Coefficient max_coeff = cst.back().coefficient;
295 if (max_value - min_coeff <= rhs) {
297 literals_scratchpad_.clear();
298 for (
const LiteralWithCoeff& term : cst) {
299 literals_scratchpad_.push_back(term.literal.Negated());
301 return AddProblemClauseInternal(literals_scratchpad_);
306 if (!parameters_->use_pb_resolution() && max_coeff <= rhs &&
307 2 * min_coeff > rhs) {
308 literals_scratchpad_.clear();
309 for (
const LiteralWithCoeff& term : cst) {
310 literals_scratchpad_.push_back(term.literal);
312 if (!binary_implication_graph_->
AddAtMostOne(literals_scratchpad_)) {
313 return SetModelUnsat();
318 problem_is_pure_sat_ =
false;
325 void SatSolver::CanonicalizeLinear(std::vector<LiteralWithCoeff>* cst,
332 for (
const LiteralWithCoeff& term : *cst) {
335 CHECK(
SafeAddInto(-term.coefficient, &fixed_variable_shift));
338 (*cst)[
index] = term;
351 CHECK(
SafeAddInto(fixed_variable_shift, bound_shift));
356 bool use_upper_bound,
358 std::vector<LiteralWithCoeff>* cst) {
361 if (model_is_unsat_)
return false;
365 if (use_upper_bound) {
367 CanonicalizeLinear(cst, &bound_shift, &max_value);
370 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
371 return SetModelUnsat();
375 if (use_lower_bound) {
379 CanonicalizeLinear(cst, &bound_shift, &max_value);
382 for (
int i = 0; i < cst->size(); ++i) {
383 (*cst)[i].literal = (*cst)[i].literal.Negated();
387 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
388 return SetModelUnsat();
396 if (!PropagationIsDone() && !
Propagate()) {
397 return SetModelUnsat();
402 int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation(
403 const std::vector<Literal>& literals,
bool is_redundant) {
406 if (literals.size() == 1) {
414 if (literals.size() == 2) {
415 if (track_binary_clauses_) {
417 CHECK(binary_clauses_.
Add(BinaryClause(literals[0], literals[1])));
419 if (shared_binary_clauses_callback_ !=
nullptr) {
420 shared_binary_clauses_callback_(literals[0], literals[1]);
427 CleanClauseDatabaseIfNeeded();
431 const int lbd = ComputeLbd(literals);
432 if (is_redundant && lbd > parameters_->clause_cleanup_lbd_bound()) {
433 --num_learned_clause_before_cleanup_;
441 BumpClauseActivity(clause);
443 CHECK(clauses_propagator_->
AddClause(literals, trail_));
450 problem_is_pure_sat_ =
false;
452 external_propagators_.push_back(propagator);
453 InitializePropagators();
458 CHECK(last_propagator_ ==
nullptr);
459 problem_is_pure_sat_ =
false;
461 last_propagator_ = propagator;
462 InitializePropagators();
466 BooleanVariable
var)
const {
476 SatClause* SatSolver::ReasonClauseOrNull(BooleanVariable
var)
const {
478 const AssignmentInfo& info = trail_->
Info(
var);
480 return clauses_propagator_->
ReasonClause(info.trail_index);
486 debug_assignment_.
Resize(num_variables_.value());
487 for (BooleanVariable i(0); i < num_variables_; ++i) {
494 bool export_clause) {
495 if (track_binary_clauses_) {
500 if (export_clause && shared_binary_clauses_callback_ !=
nullptr) {
501 shared_binary_clauses_callback_(
a,
b);
507 bool SatSolver::ClauseIsValidUnderDebugAssignment(
508 const std::vector<Literal>& clause)
const {
509 for (Literal l : clause) {
518 bool SatSolver::PBConstraintIsValidUnderDebugAssignment(
519 const std::vector<LiteralWithCoeff>& cst,
const Coefficient rhs)
const {
521 for (LiteralWithCoeff term : cst) {
526 sum += term.coefficient;
536 bool ClauseSubsumption(
const std::vector<Literal>&
a, SatClause*
b) {
537 std::vector<Literal> superset(
b->begin(),
b->end());
538 std::vector<Literal> subset(
a.begin(),
a.end());
539 std::sort(superset.begin(), superset.end());
540 std::sort(subset.begin(), subset.end());
541 return std::includes(superset.begin(), superset.end(), subset.begin(),
550 DCHECK(PropagationIsDone());
554 CHECK_GE(current_decision_level_, assumption_level_);
557 EnqueueNewDecision(true_literal);
559 return last_decision_or_backtrack_trail_index_;
563 if (model_is_unsat_)
return false;
573 if (model_is_unsat_)
return false;
575 const int old_decision_level = current_decision_level_;
576 if (!PropagateAndStopAfterOneConflictResolution()) {
577 if (model_is_unsat_)
return false;
578 if (current_decision_level_ == old_decision_level) {
579 CHECK(!assumptions_.empty());
586 CHECK(PropagationIsDone());
591 if (model_is_unsat_)
return false;
592 assumption_level_ = 0;
593 assumptions_.clear();
599 const std::vector<Literal>& assumptions) {
601 if (assumptions.empty())
return true;
608 DCHECK(assumptions_.empty());
609 assumption_level_ = 1;
610 assumptions_ = assumptions;
616 if (model_is_unsat_)
return false;
622 CHECK_EQ(current_decision_level_, 0);
623 last_decision_or_backtrack_trail_index_ = trail_->
Index();
626 ++current_decision_level_;
630 int num_decisions = 0;
631 for (
const Literal lit : assumptions_) {
632 if (
Assignment().LiteralIsTrue(lit))
continue;
636 if (num_decisions == 0) {
638 current_decision_level_ = 0;
648 if (num_decisions == 0) {
649 current_decision_level_ = 0;
658 DCHECK(assumptions_.empty());
659 const int64_t old_num_branches = counters_.num_branches;
661 counters_.num_branches = old_num_branches;
666 bool SatSolver::PropagateAndStopAfterOneConflictResolution() {
669 if (model_is_unsat_)
return false;
671 ++counters_.num_failures;
672 const int conflict_trail_index = trail_->
Index();
673 const int conflict_decision_level = current_decision_level_;
676 same_reason_identifier_.
Clear();
677 const int max_trail_index = ComputeMaxTrailIndex(trail_->
FailingClause());
678 if (!assumptions_.empty() && !trail_->
FailingClause().empty()) {
685 const int highest_level =
686 DecisionLevel((*trail_)[max_trail_index].Variable());
687 if (highest_level == 1)
return false;
690 ComputeFirstUIPConflict(max_trail_index, &learned_conflict_,
691 &reason_used_to_infer_the_conflict_,
695 if (learned_conflict_.empty())
return SetModelUnsat();
696 DCHECK(IsConflictValid(learned_conflict_));
697 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
705 if (parameters_->also_bump_variables_in_conflict_reasons()) {
706 ComputeUnionOfReasons(learned_conflict_, &extra_reason_literals_);
716 BumpReasonActivities(reason_used_to_infer_the_conflict_);
720 UpdateClauseActivityIncrement();
724 const int period = parameters_->glucose_decay_increment_period();
725 const double max_decay = parameters_->glucose_max_decay();
726 if (counters_.num_failures % period == 0 &&
727 parameters_->variable_activity_decay() < max_decay) {
728 parameters_->set_variable_activity_decay(
729 parameters_->variable_activity_decay() +
730 parameters_->glucose_decay_increment());
736 bool compute_pb_conflict =
false;
737 if (parameters_->use_pb_resolution()) {
739 if (!compute_pb_conflict) {
740 for (Literal lit : reason_used_to_infer_the_conflict_) {
741 if (ReasonPbConstraintOrNull(lit.Variable()) !=
nullptr) {
742 compute_pb_conflict =
true;
751 if (compute_pb_conflict) {
761 pb_conflict_.
AddToRhs(num_literals - 1);
770 int pb_backjump_level;
771 ComputePBConflict(max_trail_index, initial_slack, &pb_conflict_,
773 if (pb_backjump_level == -1)
return SetModelUnsat();
776 std::vector<LiteralWithCoeff> cst;
778 DCHECK(PBConstraintIsValidUnderDebugAssignment(cst, pb_conflict_.
Rhs()));
782 bool conflict_is_a_clause = (pb_conflict_.
Rhs() == cst.size() - 1);
783 if (conflict_is_a_clause) {
784 for (LiteralWithCoeff term : cst) {
786 conflict_is_a_clause =
false;
792 if (!conflict_is_a_clause) {
799 CHECK_GT(trail_->
Index(), last_decision_or_backtrack_trail_index_);
800 counters_.num_learned_pb_literals += cst.size();
806 if (pb_backjump_level < ComputeBacktrackLevel(learned_conflict_)) {
807 subsumed_clauses_.clear();
808 learned_conflict_.clear();
812 for (LiteralWithCoeff term : cst) {
813 DCHECK(
Assignment().LiteralIsTrue(term.literal));
814 DCHECK_EQ(term.coefficient, 1);
815 const int level = trail_->
Info(term.literal.Variable()).
level;
816 if (level == 0)
continue;
817 if (level > max_level) {
819 max_index = learned_conflict_.size();
821 learned_conflict_.push_back(term.literal.Negated());
825 is_marked_.
Set(term.literal.Variable());
827 CHECK(!learned_conflict_.empty());
828 std::swap(learned_conflict_.front(), learned_conflict_[max_index]);
829 DCHECK(IsConflictValid(learned_conflict_));
838 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
839 if (!binary_implication_graph_->
IsEmpty()) {
840 if (parameters_->binary_minimization_algorithm() ==
841 SatParameters::BINARY_MINIMIZATION_FIRST) {
843 *trail_, &learned_conflict_, &is_marked_);
844 }
else if (parameters_->binary_minimization_algorithm() ==
846 BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION) {
848 *trail_, &learned_conflict_,
851 DCHECK(IsConflictValid(learned_conflict_));
855 MinimizeConflict(&learned_conflict_, &reason_used_to_infer_the_conflict_);
858 if (!binary_implication_graph_->
IsEmpty()) {
862 switch (parameters_->binary_minimization_algorithm()) {
863 case SatParameters::NO_BINARY_MINIMIZATION:
864 ABSL_FALLTHROUGH_INTENDED;
865 case SatParameters::BINARY_MINIMIZATION_FIRST:
866 ABSL_FALLTHROUGH_INTENDED;
867 case SatParameters::BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION:
869 case SatParameters::BINARY_MINIMIZATION_WITH_REACHABILITY:
873 case SatParameters::EXPERIMENTAL_BINARY_MINIMIZATION:
875 *trail_, &learned_conflict_);
878 DCHECK(IsConflictValid(learned_conflict_));
892 counters_.num_literals_learned += learned_conflict_.size();
893 Backtrack(ComputeBacktrackLevel(learned_conflict_));
894 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
900 if (drat_proof_handler_ !=
nullptr) {
901 drat_proof_handler_->
AddClause(learned_conflict_);
906 bool is_redundant =
true;
907 if (!subsumed_clauses_.empty() &&
908 parameters_->subsumption_during_conflict_analysis()) {
909 for (SatClause* clause : subsumed_clauses_) {
910 DCHECK(ClauseSubsumption(learned_conflict_, clause));
912 is_redundant =
false;
917 counters_.num_subsumed_clauses += subsumed_clauses_.size();
921 const int conflict_lbd = AddLearnedClauseAndEnqueueUnitPropagation(
922 learned_conflict_, is_redundant);
923 restart_->
OnConflict(conflict_trail_index, conflict_decision_level,
929 int max_level,
int* first_propagation_index) {
931 DCHECK(assumptions_.empty());
932 int decision_index = current_decision_level_;
933 while (decision_index <= max_level) {
934 DCHECK_GE(decision_index, current_decision_level_);
935 const Literal previous_decision = decisions_[decision_index].literal;
937 if (
Assignment().LiteralIsTrue(previous_decision)) {
943 if (
Assignment().LiteralIsFalse(previous_decision)) {
951 const int old_level = current_decision_level_;
953 if (first_propagation_index !=
nullptr) {
954 *first_propagation_index =
std::min(*first_propagation_index,
index);
957 if (current_decision_level_ <= old_level) {
969 decision_index = current_decision_level_;
976 Literal true_literal,
int* first_propagation_index) {
978 CHECK(PropagationIsDone());
979 CHECK(assumptions_.empty());
983 if (first_propagation_index !=
nullptr) {
984 *first_propagation_index = trail_->
Index();
991 CHECK(PropagationIsDone());
995 EnqueueNewDecision(true_literal);
1016 DCHECK_GE(target_level, 0);
1020 if (target_level == 0) counters_.num_restarts++;
1025 current_decision_level_ = target_level;
1026 const int target_trail_index =
1027 decisions_[current_decision_level_].trail_index;
1029 Untrail(target_trail_index);
1030 last_decision_or_backtrack_trail_index_ = trail_->
Index();
1039 if (!
Propagate())
return SetModelUnsat();
1059 const std::vector<Literal>& assumptions) {
1062 return SolveInternal(time_limit_);
1066 SOLVER_LOG(logger_, RunningStatisticsString());
1072 CHECK_GE(assumption_level, 0);
1074 assumption_level_ = assumption_level;
1077 if (!assumptions_.empty()) {
1078 CHECK_EQ(assumption_level, 0);
1079 assumptions_.clear();
1089 void SatSolver::KeepAllClauseUsedToInfer(BooleanVariable variable) {
1090 CHECK(
Assignment().VariableIsAssigned(variable));
1091 if (trail_->
Info(variable).
level == 0)
return;
1093 std::vector<bool> is_marked(trail_index + 1,
false);
1094 is_marked[trail_index] =
true;
1096 for (; num > 0 && trail_index >= 0; --trail_index) {
1097 if (!is_marked[trail_index])
continue;
1098 is_marked[trail_index] =
false;
1101 const BooleanVariable
var = (*trail_)[trail_index].Variable();
1103 if (clause !=
nullptr) {
1106 for (
const Literal l : trail_->
Reason(
var)) {
1107 const AssignmentInfo& info = trail_->
Info(l.Variable());
1108 if (info.level == 0)
continue;
1109 if (!is_marked[info.trail_index]) {
1110 is_marked[info.trail_index] =
true;
1120 void SatSolver::TryToMinimizeClause(SatClause* clause) {
1122 ++counters_.minimization_num_clauses;
1124 absl::btree_set<LiteralIndex> moved_last;
1125 std::vector<Literal> candidate(clause->begin(), clause->end());
1126 while (!model_is_unsat_) {
1133 if (target_level == -1)
break;
1137 const Literal
literal = candidate[level];
1139 candidate.erase(candidate.begin() + level);
1142 const int variable_level =
1144 if (variable_level == 0) {
1145 ProcessNewlyFixedVariablesForDratProof();
1146 counters_.minimization_num_true++;
1147 counters_.minimization_num_removed_literals += clause->size();
1149 clauses_propagator_->
Detach(clause);
1157 if (ReasonClauseOrNull(
literal.Variable()) != clause) {
1158 counters_.minimization_num_subsumed++;
1159 counters_.minimization_num_removed_literals += clause->size();
1162 KeepAllClauseUsedToInfer(
literal.Variable());
1164 clauses_propagator_->
Detach(clause);
1170 if (variable_level + 1 < candidate.size()) {
1171 candidate.resize(variable_level);
1177 ++counters_.minimization_num_decisions;
1179 if (!clause->IsAttached()) {
1183 if (model_is_unsat_)
return;
1186 if (candidate.empty()) {
1187 model_is_unsat_ =
true;
1190 moved_last.insert(candidate.back().Index());
1195 if (candidate.size() == clause->size())
return;
1197 if (candidate.size() == 1) {
1198 if (drat_proof_handler_ !=
nullptr) {
1199 drat_proof_handler_->
AddClause(candidate);
1201 if (!
Assignment().VariableIsAssigned(candidate[0].Variable())) {
1202 counters_.minimization_num_removed_literals += clause->size();
1209 if (candidate.size() == 2) {
1210 counters_.minimization_num_removed_literals += clause->size() - 2;
1213 AddBinaryClauseInternal(candidate[0], candidate[1],
true);
1214 clauses_propagator_->
Detach(clause);
1223 counters_.minimization_num_removed_literals +=
1224 clause->size() - candidate.size();
1229 model_is_unsat_ =
true;
1245 SOLVER_LOG(logger_,
"Number of variables: ", num_variables_.value());
1246 SOLVER_LOG(logger_,
"Number of clauses (size > 2): ",
1248 SOLVER_LOG(logger_,
"Number of binary clauses: ",
1250 SOLVER_LOG(logger_,
"Number of linear constraints: ",
1253 SOLVER_LOG(logger_,
"Number of watched clauses: ",
1259 int64_t next_minimization_num_restart =
1261 parameters_->minimize_with_propagation_restart_period();
1264 const int64_t kDisplayFrequency = 10000;
1265 int64_t next_display = parameters_->log_search_progress()
1267 : std::numeric_limits<int64_t>::
max();
1270 const int64_t kMemoryCheckFrequency = 10000;
1271 int64_t next_memory_check =
1276 const int64_t kFailureLimit =
1277 parameters_->max_number_of_conflicts() ==
1280 : counters_.
num_failures + parameters_->max_number_of_conflicts();
1288 SOLVER_LOG(logger_,
"The time limit has been reached. Aborting.");
1293 SOLVER_LOG(logger_,
"The conflict limit has been reached. Aborting.");
1302 if (counters_.num_failures >= next_memory_check) {
1303 next_memory_check = NextMultipleOf(
num_failures(), kMemoryCheckFrequency);
1304 if (IsMemoryLimitReached()) {
1305 SOLVER_LOG(logger_,
"The memory limit has been reached. Aborting.");
1312 if (counters_.num_failures >= next_display) {
1313 SOLVER_LOG(logger_, RunningStatisticsString());
1314 next_display = NextMultipleOf(
num_failures(), kDisplayFrequency);
1317 const int old_level = current_decision_level_;
1318 if (!PropagateAndStopAfterOneConflictResolution()) {
1320 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1321 if (old_level == current_decision_level_) {
1322 CHECK(!assumptions_.empty());
1330 if (trail_->
Index() == num_variables_.value()) {
1340 restart_->
NumRestarts() >= next_minimization_num_restart) {
1341 next_minimization_num_restart =
1343 parameters_->minimize_with_propagation_restart_period();
1345 parameters_->minimize_with_propagation_num_decisions());
1349 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1350 if (trail_->
Index() == num_variables_.value()) {
1356 EnqueueNewDecision(decision_policy_->
NextBranch());
1364 block_clause_deletion_ =
true;
1366 const int64_t target_num_branches = counters_.num_branches + decisions_budget;
1367 while (counters_.num_branches < target_num_branches &&
1368 (time_limit_ ==
nullptr || !time_limit_->
LimitReached())) {
1370 if (to_minimize !=
nullptr) {
1371 TryToMinimizeClause(to_minimize);
1372 if (model_is_unsat_)
return;
1374 if (to_minimize ==
nullptr) {
1375 VLOG(1) <<
"Minimized all clauses, restarting from first one.";
1382 block_clause_deletion_ =
false;
1388 std::vector<Literal> unsat_assumptions;
1392 int trail_index = 0;
1400 unsat_assumptions.push_back(lit.Negated());
1405 is_marked_.
Set(lit.Variable());
1407 CHECK_LE(num_true, 1);
1412 CHECK_LT(trail_index, trail_->
Index());
1415 while (trail_index >= limit &&
1416 !is_marked_[(*trail_)[trail_index].Variable()]) {
1419 if (trail_index < limit)
break;
1420 const Literal marked_literal = (*trail_)[trail_index];
1425 unsat_assumptions.push_back(marked_literal);
1429 const BooleanVariable
var =
literal.Variable();
1430 const int level = DecisionLevel(
var);
1431 if (level > 0 && !is_marked_[
var]) is_marked_.
Set(
var);
1438 std::reverse(unsat_assumptions.begin(), unsat_assumptions.end());
1439 return unsat_assumptions;
1442 void SatSolver::BumpReasonActivities(
const std::vector<Literal>& literals) {
1445 const BooleanVariable
var =
literal.Variable();
1446 if (DecisionLevel(
var) > 0) {
1448 if (clause !=
nullptr) {
1449 BumpClauseActivity(clause);
1451 UpperBoundedLinearConstraint* pb_constraint =
1452 ReasonPbConstraintOrNull(
var);
1453 if (pb_constraint !=
nullptr) {
1463 void SatSolver::BumpClauseActivity(SatClause* clause) {
1474 const int new_lbd = ComputeLbd(*clause);
1475 if (new_lbd + 1 <= parameters_->clause_cleanup_lbd_bound()) {
1481 switch (parameters_->clause_cleanup_protection()) {
1482 case SatParameters::PROTECTION_NONE:
1484 case SatParameters::PROTECTION_ALWAYS:
1485 it->second.protected_during_next_cleanup =
true;
1487 case SatParameters::PROTECTION_LBD:
1492 if (new_lbd + 1 < it->second.lbd) {
1493 it->second.protected_during_next_cleanup =
true;
1494 it->second.lbd = new_lbd;
1499 const double activity = it->second.activity += clause_activity_increment_;
1500 if (activity > parameters_->max_clause_activity_value()) {
1501 RescaleClauseActivities(1.0 / parameters_->max_clause_activity_value());
1505 void SatSolver::RescaleClauseActivities(
double scaling_factor) {
1507 clause_activity_increment_ *= scaling_factor;
1509 entry.second.activity *= scaling_factor;
1513 void SatSolver::UpdateClauseActivityIncrement() {
1515 clause_activity_increment_ *= 1.0 / parameters_->clause_activity_decay();
1518 bool SatSolver::IsConflictValid(
const std::vector<Literal>& literals) {
1520 if (literals.empty())
return false;
1521 const int highest_level = DecisionLevel(literals[0].Variable());
1522 for (
int i = 1; i < literals.size(); ++i) {
1523 const int level = DecisionLevel(literals[i].Variable());
1524 if (level <= 0 || level >= highest_level)
return false;
1529 int SatSolver::ComputeBacktrackLevel(
const std::vector<Literal>& literals) {
1542 int backtrack_level = 0;
1543 for (
int i = 1; i < literals.size(); ++i) {
1544 const int level = DecisionLevel(literals[i].Variable());
1545 backtrack_level =
std::max(backtrack_level, level);
1547 DCHECK_LT(backtrack_level, DecisionLevel(literals[0].Variable()));
1549 return backtrack_level;
1552 template <
typename LiteralList>
1553 int SatSolver::ComputeLbd(
const LiteralList& literals) {
1556 parameters_->count_assumption_levels_in_lbd() ? 0 : assumption_level_;
1560 SatDecisionLevel(DecisionLevel(literals.begin()->Variable()) + 1));
1561 for (
const Literal
literal : literals) {
1562 const SatDecisionLevel level(DecisionLevel(
literal.Variable()));
1563 DCHECK_GE(level, 0);
1564 if (level > limit && !is_level_marked_[level]) {
1565 is_level_marked_.
Set(level);
1571 std::string SatSolver::StatusString(Status
status)
const {
1572 const double time_in_s = timer_.
Get();
1574 absl::StrFormat(
" time: %fs\n", time_in_s) +
1577 " num failures: %d (%.0f /sec)\n", counters_.num_failures,
1578 static_cast<double>(counters_.num_failures) / time_in_s) +
1580 " num branches: %d (%.0f /sec)\n", counters_.num_branches,
1581 static_cast<double>(counters_.num_branches) / time_in_s) +
1582 absl::StrFormat(
" num propagations: %d (%.0f /sec)\n",
1585 absl::StrFormat(
" num binary propagations: %d\n",
1587 absl::StrFormat(
" num binary inspections: %d\n",
1590 " num binary redundant implications: %d\n",
1593 " num classic minimizations: %d"
1594 " (literals removed: %d)\n",
1595 counters_.num_minimizations, counters_.num_literals_removed) +
1597 " num binary minimizations: %d"
1598 " (literals removed: %d)\n",
1601 absl::StrFormat(
" num inspected clauses: %d\n",
1603 absl::StrFormat(
" num inspected clause_literals: %d\n",
1606 " num learned literals: %d (avg: %.1f /clause)\n",
1607 counters_.num_literals_learned,
1608 1.0 * counters_.num_literals_learned / counters_.num_failures) +
1610 " num learned PB literals: %d (avg: %.1f /clause)\n",
1611 counters_.num_learned_pb_literals,
1612 1.0 * counters_.num_learned_pb_literals / counters_.num_failures) +
1613 absl::StrFormat(
" num subsumed clauses: %d\n",
1614 counters_.num_subsumed_clauses) +
1615 absl::StrFormat(
" minimization_num_clauses: %d\n",
1616 counters_.minimization_num_clauses) +
1617 absl::StrFormat(
" minimization_num_decisions: %d\n",
1618 counters_.minimization_num_decisions) +
1619 absl::StrFormat(
" minimization_num_true: %d\n",
1620 counters_.minimization_num_true) +
1621 absl::StrFormat(
" minimization_num_subsumed: %d\n",
1622 counters_.minimization_num_subsumed) +
1623 absl::StrFormat(
" minimization_num_removed_literals: %d\n",
1624 counters_.minimization_num_removed_literals) +
1625 absl::StrFormat(
" pb num threshold updates: %d\n",
1627 absl::StrFormat(
" pb num constraint lookups: %d\n",
1629 absl::StrFormat(
" pb num inspected constraint literals: %d\n",
1635 std::string SatSolver::RunningStatisticsString()
const {
1636 const double time_in_s = timer_.
Get();
1637 return absl::StrFormat(
1638 "%6.2fs, mem:%s, fails:%d, depth:%d, clauses:%d, tmp:%d, bin:%u, "
1639 "restarts:%d, vars:%d",
1645 num_variables_.value() - num_processed_fixed_variables_);
1648 void SatSolver::ProcessNewlyFixedVariablesForDratProof() {
1649 if (drat_proof_handler_ ==
nullptr)
return;
1663 for (; drat_num_processed_fixed_variables_ < trail_->
Index();
1664 ++drat_num_processed_fixed_variables_) {
1665 temp = (*trail_)[drat_num_processed_fixed_variables_];
1666 drat_proof_handler_->
AddClause({&temp, 1});
1673 int num_detached_clauses = 0;
1676 ProcessNewlyFixedVariablesForDratProof();
1682 if (!clause->IsAttached())
continue;
1684 const size_t old_size = clause->size();
1685 if (clause->RemoveFixedLiteralsAndTestIfTrue(trail_->
Assignment())) {
1688 ++num_detached_clauses;
1692 const size_t new_size = clause->size();
1693 if (new_size == old_size)
continue;
1695 if (drat_proof_handler_ !=
nullptr) {
1696 CHECK_GT(new_size, 0);
1697 drat_proof_handler_->
AddClause({clause->begin(), new_size});
1698 drat_proof_handler_->
DeleteClause({clause->begin(), old_size});
1701 if (new_size == 2) {
1705 AddBinaryClauseInternal(clause->FirstLiteral(), clause->SecondLiteral(),
1715 if (num_detached_clauses > 0 || num_binary > 0) {
1716 VLOG(1) << trail_->
Index() <<
" fixed variables at level 0. "
1717 <<
"Detached " << num_detached_clauses <<
" clauses. " << num_binary
1718 <<
" converted to binary.";
1725 CHECK(binary_implication_graph_->
Propagate(trail_));
1727 num_processed_fixed_variables_ = trail_->
Index();
1731 bool SatSolver::PropagationIsDone()
const {
1733 if (propagator->IsEmpty())
continue;
1734 if (!propagator->PropagationIsDone(*trail_))
return false;
1749 non_empty_propagators_.clear();
1751 if (!propagator->IsEmpty()) {
1752 non_empty_propagators_.push_back(propagator);
1764 const int old_index = trail_->
Index();
1766 DCHECK(propagator->PropagatePreconditionsAreSatisfied(*trail_));
1767 if (!propagator->Propagate(trail_))
return false;
1768 if (trail_->
Index() > old_index)
break;
1770 if (trail_->
Index() == old_index)
break;
1775 void SatSolver::InitializePropagators() {
1776 propagators_.clear();
1777 propagators_.push_back(binary_implication_graph_);
1778 propagators_.push_back(clauses_propagator_);
1779 propagators_.push_back(pb_constraints_);
1780 for (
int i = 0; i < external_propagators_.size(); ++i) {
1781 propagators_.push_back(external_propagators_[i]);
1783 if (last_propagator_ !=
nullptr) {
1784 propagators_.push_back(last_propagator_);
1788 bool SatSolver::ResolvePBConflict(BooleanVariable
var,
1789 MutableUpperBoundedLinearConstraint* conflict,
1794 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1797 UpperBoundedLinearConstraint* pb_reason = ReasonPbConstraintOrNull(
var);
1798 if (pb_reason !=
nullptr) {
1799 pb_reason->ResolvePBConflict(*trail_,
var, conflict, slack);
1807 const int algorithm = 1;
1808 switch (algorithm) {
1812 conflict->ReduceSlackTo(*trail_, trail_index, *slack,
Coefficient(0));
1816 multiplier = *slack + 1;
1820 multiplier = conflict->GetCoefficient(
var);
1830 conflict->AddTerm(
literal.Negated(), multiplier);
1833 conflict->AddToRhs((num_literals - 1) * multiplier);
1837 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1841 void SatSolver::EnqueueNewDecision(Literal
literal) {
1852 const double kMinDeterministicTimeBetweenCleanups = 1.0;
1853 if (num_processed_fixed_variables_ < trail_->
Index() &&
1855 deterministic_time_of_last_fixed_variables_cleanup_ +
1856 kMinDeterministicTimeBetweenCleanups) {
1861 counters_.num_branches++;
1862 last_decision_or_backtrack_trail_index_ = trail_->
Index();
1863 decisions_[current_decision_level_] = Decision(trail_->
Index(),
literal);
1864 ++current_decision_level_;
1869 void SatSolver::Untrail(
int target_trail_index) {
1871 DCHECK_LT(target_trail_index, trail_->
Index());
1872 for (SatPropagator* propagator : propagators_) {
1873 if (propagator->IsEmpty())
continue;
1874 propagator->Untrail(*trail_, target_trail_index);
1876 decision_policy_->
Untrail(target_trail_index);
1877 trail_->
Untrail(target_trail_index);
1880 std::string SatSolver::DebugString(
const SatClause& clause)
const {
1882 for (
const Literal
literal : clause) {
1883 if (!result.empty()) {
1884 result.append(
" || ");
1886 const std::string
value =
1891 result.append(absl::StrFormat(
"%s(%s)",
literal.DebugString(),
value));
1896 int SatSolver::ComputeMaxTrailIndex(absl::Span<const Literal> clause)
const {
1898 int trail_index = -1;
1899 for (
const Literal
literal : clause) {
1909 void SatSolver::ComputeFirstUIPConflict(
1910 int max_trail_index, std::vector<Literal>* conflict,
1911 std::vector<Literal>* reason_used_to_infer_the_conflict,
1912 std::vector<SatClause*>* subsumed_clauses) {
1920 reason_used_to_infer_the_conflict->clear();
1921 subsumed_clauses->clear();
1922 if (max_trail_index == -1)
return;
1927 DCHECK_EQ(max_trail_index, ComputeMaxTrailIndex(trail_->
FailingClause()));
1928 int trail_index = max_trail_index;
1929 const int highest_level = DecisionLevel((*trail_)[trail_index].Variable());
1930 if (highest_level == 0)
return;
1947 absl::Span<const Literal> clause_to_expand = trail_->
FailingClause();
1949 DCHECK(!clause_to_expand.empty());
1950 int num_literal_at_highest_level_that_needs_to_be_processed = 0;
1952 int num_new_vars_at_positive_level = 0;
1953 int num_vars_at_positive_level_in_clause_to_expand = 0;
1954 for (
const Literal
literal : clause_to_expand) {
1955 const BooleanVariable
var =
literal.Variable();
1956 const int level = DecisionLevel(
var);
1957 if (level > 0) ++num_vars_at_positive_level_in_clause_to_expand;
1958 if (!is_marked_[
var]) {
1960 if (level == highest_level) {
1961 ++num_new_vars_at_positive_level;
1962 ++num_literal_at_highest_level_that_needs_to_be_processed;
1963 }
else if (level > 0) {
1964 ++num_new_vars_at_positive_level;
1970 reason_used_to_infer_the_conflict->push_back(
literal);
1977 if (num_new_vars_at_positive_level > 0) {
1980 subsumed_clauses->clear();
1987 if (sat_clause !=
nullptr &&
1988 num_vars_at_positive_level_in_clause_to_expand ==
1990 num_literal_at_highest_level_that_needs_to_be_processed) {
1991 subsumed_clauses->push_back(sat_clause);
1995 DCHECK_GT(num_literal_at_highest_level_that_needs_to_be_processed, 0);
1996 while (!is_marked_[(*trail_)[trail_index].Variable()]) {
1998 DCHECK_GE(trail_index, 0);
1999 DCHECK_EQ(DecisionLevel((*trail_)[trail_index].Variable()),
2003 if (num_literal_at_highest_level_that_needs_to_be_processed == 1) {
2007 conflict->push_back((*trail_)[trail_index].Negated());
2010 std::swap(conflict->back(), conflict->front());
2014 const Literal
literal = (*trail_)[trail_index];
2015 reason_used_to_infer_the_conflict->push_back(
literal);
2021 clause_to_expand = {};
2025 sat_clause = ReasonClauseOrNull(
literal.Variable());
2027 --num_literal_at_highest_level_that_needs_to_be_processed;
2032 void SatSolver::ComputeUnionOfReasons(
const std::vector<Literal>&
input,
2033 std::vector<Literal>* literals) {
2036 for (
const Literal l :
input) tmp_mark_.
Set(l.Variable());
2037 for (
const Literal l :
input) {
2038 for (
const Literal r : trail_->
Reason(l.Variable())) {
2039 if (!tmp_mark_[r.Variable()]) {
2040 tmp_mark_.
Set(r.Variable());
2041 literals->push_back(r);
2045 for (
const Literal l :
input) tmp_mark_.
Clear(l.Variable());
2046 for (
const Literal l : *literals) tmp_mark_.
Clear(l.Variable());
2050 void SatSolver::ComputePBConflict(
int max_trail_index,
2052 MutableUpperBoundedLinearConstraint* conflict,
2053 int* pb_backjump_level) {
2055 int trail_index = max_trail_index;
2061 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1));
2062 CHECK_LT(slack, 0) <<
"We don't have a conflict!";
2065 int backjump_level = 0;
2067 const BooleanVariable
var = (*trail_)[trail_index].Variable();
2070 if (conflict->GetCoefficient(
var) > 0 &&
2072 if (parameters_->minimize_reduction_during_pb_resolution()) {
2077 conflict->ReduceGivenCoefficient(
var);
2081 slack += conflict->GetCoefficient(
var);
2085 if (slack < 0)
continue;
2091 const int current_level = DecisionLevel(
var);
2092 int i = trail_index;
2094 const BooleanVariable previous_var = (*trail_)[i].Variable();
2095 if (conflict->GetCoefficient(previous_var) > 0 &&
2097 conflict->GetLiteral(previous_var))) {
2102 if (i < 0 || DecisionLevel((*trail_)[i].Variable()) < current_level) {
2103 backjump_level = i < 0 ? 0 : DecisionLevel((*trail_)[i].Variable());
2109 const bool clause_used = ResolvePBConflict(
var, conflict, &slack);
2120 ? conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1)
2125 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2126 conflict->ReduceCoefficients();
2132 if (parameters_->minimize_reduction_during_pb_resolution()) {
2134 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1);
2136 slack = conflict->ReduceCoefficientsAndComputeSlackForTrailPrefix(
2137 *trail_, trail_index + 1);
2140 DCHECK_EQ(slack, slack_only_for_debug);
2142 if (conflict->Rhs() < 0) {
2143 *pb_backjump_level = -1;
2151 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2152 conflict->ReduceCoefficients();
2157 std::vector<Coefficient> sum_for_le_level(backjump_level + 2,
Coefficient(0));
2158 std::vector<Coefficient> max_coeff_for_ge_level(backjump_level + 2,
2162 for (BooleanVariable
var : conflict->PossibleNonZeros()) {
2164 if (coeff == 0)
continue;
2168 DecisionLevel(
var) > backjump_level) {
2169 max_coeff_for_ge_level[backjump_level + 1] =
2170 std::max(max_coeff_for_ge_level[backjump_level + 1], coeff);
2172 const int level = DecisionLevel(
var);
2174 sum_for_le_level[level] += coeff;
2176 max_coeff_for_ge_level[level] =
2177 std::max(max_coeff_for_ge_level[level], coeff);
2182 for (
int i = 1; i < sum_for_le_level.size(); ++i) {
2183 sum_for_le_level[i] += sum_for_le_level[i - 1];
2185 for (
int i = max_coeff_for_ge_level.size() - 2; i >= 0; --i) {
2186 max_coeff_for_ge_level[i] =
2187 std::max(max_coeff_for_ge_level[i], max_coeff_for_ge_level[i + 1]);
2192 if (sum_for_le_level[0] > conflict->Rhs()) {
2193 *pb_backjump_level = -1;
2196 for (
int i = 0; i <= backjump_level; ++i) {
2197 const Coefficient level_sum = sum_for_le_level[i];
2198 CHECK_LE(level_sum, conflict->Rhs());
2199 if (conflict->Rhs() - level_sum < max_coeff_for_ge_level[i + 1]) {
2200 *pb_backjump_level = i;
2204 LOG(FATAL) <<
"The code should never reach here.";
2207 void SatSolver::MinimizeConflict(
2208 std::vector<Literal>* conflict,
2209 std::vector<Literal>* reason_used_to_infer_the_conflict) {
2212 const int old_size = conflict->size();
2213 switch (parameters_->minimization_algorithm()) {
2214 case SatParameters::NONE:
2216 case SatParameters::SIMPLE: {
2217 MinimizeConflictSimple(conflict);
2220 case SatParameters::RECURSIVE: {
2221 MinimizeConflictRecursively(conflict);
2224 case SatParameters::EXPERIMENTAL: {
2225 MinimizeConflictExperimental(conflict);
2229 if (conflict->size() < old_size) {
2230 ++counters_.num_minimizations;
2231 counters_.num_literals_removed += old_size - conflict->size();
2242 void SatSolver::MinimizeConflictSimple(std::vector<Literal>* conflict) {
2249 for (
int i = 1; i < conflict->size(); ++i) {
2250 const BooleanVariable
var = (*conflict)[i].Variable();
2251 bool can_be_removed =
false;
2252 if (DecisionLevel(
var) != current_level) {
2254 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2255 if (!reason.empty()) {
2256 can_be_removed =
true;
2257 for (Literal
literal : reason) {
2258 if (DecisionLevel(
literal.Variable()) == 0)
continue;
2259 if (!is_marked_[
literal.Variable()]) {
2260 can_be_removed =
false;
2266 if (!can_be_removed) {
2267 (*conflict)[
index] = (*conflict)[i];
2271 conflict->erase(conflict->begin() +
index, conflict->end());
2280 void SatSolver::MinimizeConflictRecursively(std::vector<Literal>* conflict) {
2314 const int level = DecisionLevel(
var);
2315 min_trail_index_per_level_[level] =
std::min(
2323 for (
int i = 1; i < conflict->size(); ++i) {
2324 const BooleanVariable
var = (*conflict)[i].Variable();
2325 const AssignmentInfo& info = trail_->
Info(
var);
2328 info.trail_index <= min_trail_index_per_level_[info.level] ||
2329 !CanBeInferedFromConflictVariables(
var)) {
2332 is_independent_.
Set(
var);
2333 (*conflict)[
index] = (*conflict)[i];
2337 conflict->resize(
index);
2341 const int threshold = min_trail_index_per_level_.size() / 2;
2344 min_trail_index_per_level_[DecisionLevel(
var)] =
2348 min_trail_index_per_level_.clear();
2352 bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) {
2355 DCHECK(is_marked_[variable]);
2356 const BooleanVariable v =
2358 if (v != variable)
return !is_independent_[v];
2371 dfs_stack_.push_back(variable);
2372 variable_to_process_.clear();
2373 variable_to_process_.push_back(variable);
2377 const BooleanVariable
var =
literal.Variable();
2378 DCHECK_NE(
var, variable);
2379 if (is_marked_[
var])
continue;
2380 const AssignmentInfo& info = trail_->
Info(
var);
2381 if (info.level == 0) {
2389 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2393 variable_to_process_.push_back(
var);
2397 while (!variable_to_process_.empty()) {
2398 const BooleanVariable current_var = variable_to_process_.back();
2399 if (current_var == dfs_stack_.back()) {
2402 if (dfs_stack_.size() > 1) {
2403 DCHECK(!is_marked_[current_var]);
2404 is_marked_.
Set(current_var);
2406 variable_to_process_.pop_back();
2407 dfs_stack_.pop_back();
2412 if (is_marked_[current_var]) {
2413 variable_to_process_.pop_back();
2419 DCHECK(!is_independent_[current_var]);
2423 const BooleanVariable v =
2425 if (v != current_var) {
2426 if (is_independent_[v])
break;
2427 DCHECK(is_marked_[v]);
2428 variable_to_process_.pop_back();
2434 dfs_stack_.push_back(current_var);
2435 bool abort_early =
false;
2437 const BooleanVariable
var =
literal.Variable();
2438 DCHECK_NE(
var, current_var);
2439 const AssignmentInfo& info = trail_->
Info(
var);
2440 if (info.level == 0 || is_marked_[
var])
continue;
2441 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2443 is_independent_[
var]) {
2447 variable_to_process_.push_back(
var);
2449 if (abort_early)
break;
2453 for (
const BooleanVariable
var : dfs_stack_) {
2454 is_independent_.
Set(
var);
2456 return dfs_stack_.empty();
2461 struct WeightedVariable {
2462 WeightedVariable(BooleanVariable v,
int w) :
var(v),
weight(w) {}
2470 struct VariableWithLargerWeightFirst {
2471 bool operator()(
const WeightedVariable& wv1,
2472 const WeightedVariable& wv2)
const {
2473 return (wv1.weight > wv2.weight ||
2474 (wv1.weight == wv2.weight && wv1.var < wv2.var));
2490 void SatSolver::MinimizeConflictExperimental(std::vector<Literal>* conflict) {
2497 std::vector<WeightedVariable> variables_sorted_by_level;
2498 for (Literal
literal : *conflict) {
2499 const BooleanVariable
var =
literal.Variable();
2501 const int level = DecisionLevel(
var);
2502 if (level < current_level) {
2503 variables_sorted_by_level.push_back(WeightedVariable(
var, level));
2506 std::sort(variables_sorted_by_level.begin(), variables_sorted_by_level.end(),
2507 VariableWithLargerWeightFirst());
2510 std::vector<BooleanVariable> to_remove;
2511 for (WeightedVariable weighted_var : variables_sorted_by_level) {
2512 const BooleanVariable
var = weighted_var.var;
2516 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2517 if (reason.empty())
continue;
2521 std::vector<Literal> not_contained_literals;
2522 for (
const Literal reason_literal : reason) {
2523 const BooleanVariable reason_var = reason_literal.Variable();
2526 if (DecisionLevel(reason_var) == 0)
continue;
2531 if (!is_marked_[reason_var]) {
2532 not_contained_literals.push_back(reason_literal);
2533 if (not_contained_literals.size() > 1)
break;
2536 if (not_contained_literals.empty()) {
2541 to_remove.push_back(
var);
2542 }
else if (not_contained_literals.size() == 1) {
2545 to_remove.push_back(
var);
2546 is_marked_.
Set(not_contained_literals.front().Variable());
2547 conflict->push_back(not_contained_literals.front());
2552 for (BooleanVariable
var : to_remove) {
2558 for (
int i = 0; i < conflict->size(); ++i) {
2559 const Literal
literal = (*conflict)[i];
2560 if (is_marked_[
literal.Variable()]) {
2565 conflict->erase(conflict->begin() +
index, conflict->end());
2568 void SatSolver::CleanClauseDatabaseIfNeeded() {
2569 if (num_learned_clause_before_cleanup_ > 0)
return;
2574 typedef std::pair<SatClause*, ClauseInfo> Entry;
2575 std::vector<Entry> entries;
2577 for (
auto& entry : clauses_info) {
2578 if (ClauseIsUsedAsReason(entry.first))
continue;
2579 if (entry.second.protected_during_next_cleanup) {
2580 entry.second.protected_during_next_cleanup =
false;
2583 entries.push_back(entry);
2585 const int num_protected_clauses = clauses_info.size() - entries.size();
2587 if (parameters_->clause_cleanup_ordering() == SatParameters::CLAUSE_LBD) {
2589 std::sort(entries.begin(), entries.end(),
2590 [](
const Entry&
a,
const Entry&
b) {
2591 if (a.second.lbd == b.second.lbd) {
2592 return a.second.activity < b.second.activity;
2594 return a.second.lbd >
b.second.lbd;
2598 std::sort(entries.begin(), entries.end(),
2599 [](
const Entry&
a,
const Entry&
b) {
2600 if (a.second.activity == b.second.activity) {
2601 return a.second.lbd > b.second.lbd;
2603 return a.second.activity <
b.second.activity;
2608 int num_kept_clauses =
2609 (parameters_->clause_cleanup_target() > 0)
2610 ?
std::min(
static_cast<int>(entries.size()),
2611 parameters_->clause_cleanup_target())
2612 :
static_cast<int>(parameters_->clause_cleanup_ratio() *
2613 static_cast<double>(entries.size()));
2615 int num_deleted_clauses = entries.size() - num_kept_clauses;
2620 while (num_deleted_clauses > 0) {
2621 const ClauseInfo&
a = entries[num_deleted_clauses].second;
2622 const ClauseInfo&
b = entries[num_deleted_clauses - 1].second;
2623 if (
a.activity !=
b.activity ||
a.lbd !=
b.lbd)
break;
2624 --num_deleted_clauses;
2627 if (num_deleted_clauses > 0) {
2628 entries.resize(num_deleted_clauses);
2629 for (
const Entry& entry : entries) {
2630 SatClause* clause = entry.first;
2631 counters_.num_literals_forgotten += clause->size();
2632 clauses_propagator_->LazyDetach(clause);
2634 clauses_propagator_->CleanUpWatchers();
2638 if (!block_clause_deletion_) {
2639 clauses_propagator_->DeleteRemovedClauses();
2643 num_learned_clause_before_cleanup_ = parameters_->clause_cleanup_period();
2644 VLOG(1) <<
"Database cleanup, #protected:" << num_protected_clauses
2645 <<
" #kept:" << num_kept_clauses
2646 <<
" #deleted:" << num_deleted_clauses;
2651 case SatSolver::ASSUMPTIONS_UNSAT:
2652 return "ASSUMPTIONS_UNSAT";
2654 return "INFEASIBLE";
2657 case SatSolver::LIMIT_REACHED:
2658 return "LIMIT_REACHED";
2662 LOG(DFATAL) <<
"Invalid SatSolver::Status " <<
status;
2667 std::vector<Literal> result;
2670 for (
const Literal lit : *core) {
2672 result.push_back(lit);
2676 if (result.size() < core->size()) {
2677 VLOG(1) <<
"minimization " << core->size() <<
" -> " << result.size();
void SetLogToStdOut(bool enable)
bool LoggingIsEnabled() const
void EnableLogging(bool enable)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Set(IntegerType index)
int NumberOfSetCallsWithDifferentArguments() const
void Clear(IntegerType index)
void ClearAndResize(IntegerType size)
std::string StatString() const
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
void ResetLimitFromParameters(const Parameters ¶meters)
Sets new time limits.
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
const std::vector< BinaryClause > & newly_added() const
bool Propagate(Trail *trail) final
void AddBinaryClause(Literal a, Literal b)
void MinimizeConflictWithReachability(std::vector< Literal > *c)
bool AddBinaryClauseDuringSearch(Literal a, Literal b)
void MinimizeConflictFirstWithTransitiveReduction(const Trail &trail, std::vector< Literal > *c, absl::BitGenRef random)
int64_t num_inspections() const
int64_t num_redundant_implications() const
void MinimizeConflictFirst(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked)
int64_t num_literals_removed() const
int64_t num_propagations() const
void RemoveFixedVariables()
int64_t num_minimization() const
bool IsEmpty() const final
int64_t num_implications() const
ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span< const Literal > at_most_one)
void MinimizeConflictExperimental(const Trail &trail, std::vector< Literal > *c)
void Resize(int num_variables)
void DeleteClause(absl::Span< const Literal > clause)
void AddClause(absl::Span< const Literal > clause)
BooleanVariable Variable() const
const std::vector< SatClause * > & AllClausesInCreationOrder() const
absl::flat_hash_map< SatClause *, ClauseInfo > * mutable_clauses_info()
SatClause * AddRemovableClause(const std::vector< Literal > &literals, Trail *trail)
int64_t num_inspected_clauses() const
int64_t num_clauses() const
SatClause * NextClauseToMinimize()
bool AddClause(absl::Span< const Literal > literals, Trail *trail)
SatClause * ReasonClause(int trail_index) const
bool IsRemovable(SatClause *const clause) const
ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(SatClause *clause, absl::Span< const Literal > new_clause)
int64_t num_watched_clauses() const
void LazyDetach(SatClause *clause)
int64_t num_removable_clauses() const
int64_t num_inspected_clause_literals() const
void ResetToMinimizeIndex()
void DeleteRemovedClauses()
void Detach(SatClause *clause)
void Resize(int num_variables)
Class that owns everything related to a particular optimization model.
void Register(T *non_owned_class)
Register a non-owned class that will be "singleton" in the model.
T * GetOrCreate()
Returns an object of type T that is unique to this model (like a "local" singleton).
Coefficient ComputeSlackForTrailPrefix(const Trail &trail, int trail_index) const
void AddTerm(Literal literal, Coefficient coeff)
void AddToRhs(Coefficient value)
void ClearAndResize(int num_variables)
void CopyIntoVector(std::vector< LiteralWithCoeff > *output)
int NumberOfConstraints() const
void ClearConflictingConstraint()
int64_t num_inspected_constraint_literals() const
bool AddConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
int64_t num_threshold_updates() const
UpperBoundedLinearConstraint * ConflictingConstraint()
UpperBoundedLinearConstraint * ReasonPbConstraint(int trail_index) const
void UpdateActivityIncrement()
void BumpActivity(UpperBoundedLinearConstraint *constraint)
int64_t num_constraint_lookups() const
void Resize(int num_variables)
bool AddLearnedConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
std::string InfoString() const
void OnConflict(int conflict_trail_index, int conflict_decision_level, int conflict_lbd)
void IncreaseNumVariables(int num_variables)
void UpdateVariableActivityIncrement()
void Untrail(int target_trail_index)
void BumpVariableActivities(const std::vector< Literal > &literals)
void BeforeConflict(int trail_index)
void UpdateWeightedSign(const std::vector< LiteralWithCoeff > &terms, Coefficient rhs)
const Trail & LiteralTrail() const
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
bool EnqueueDecisionIfNotConflicting(Literal true_literal)
void SetNumVariables(int num_variables)
bool AddTernaryClause(Literal a, Literal b, Literal c)
void AddLastPropagator(SatPropagator *propagator)
const SatParameters & parameters() const
bool AddClauseDuringSearch(absl::Span< const Literal > literals)
Status SolveWithTimeLimit(TimeLimit *time_limit)
void ProcessNewlyFixedVariables()
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions)
void AddPropagator(SatPropagator *propagator)
const std::vector< BinaryClause > & NewlyAddedBinaryClauses()
bool AddBinaryClauses(const std::vector< BinaryClause > &clauses)
Status UnsatStatus() const
void SetAssumptionLevel(int assumption_level)
void SaveDebugAssignment()
void AdvanceDeterministicTime(TimeLimit *limit)
int64_t num_restarts() const
void MinimizeSomeClauses(int decisions_budget)
int64_t num_branches() const
const VariablesAssignment & Assignment() const
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
void SetParameters(const SatParameters ¶meters)
bool AddBinaryClause(Literal a, Literal b)
int64_t num_propagations() const
void Backtrack(int target_level)
bool RestoreSolverToAssumptionLevel()
int64_t num_failures() const
bool AddProblemClause(absl::Span< const Literal > literals, bool is_safe=true)
std::vector< Literal > GetLastIncompatibleDecisions()
bool ReapplyAssumptionsIfNeeded()
bool ResetWithGivenAssumptions(const std::vector< Literal > &assumptions)
int CurrentDecisionLevel() const
double deterministic_time() const
Status EnqueueDecisionAndBacktrackOnConflict(Literal true_literal, int *first_propagation_index=nullptr)
bool AddUnitClause(Literal true_literal)
void ClearNewlyAddedBinaryClauses()
absl::Span< const Literal > FailingClause() const
void RegisterPropagator(SatPropagator *propagator)
const AssignmentInfo & Info(BooleanVariable var) const
int64_t NumberOfEnqueues() const
SatClause * FailingSatClause() const
int AssignmentType(BooleanVariable var) const
std::vector< Literal > * MutableConflict()
absl::Span< const Literal > Reason(BooleanVariable var) const
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
const VariablesAssignment & Assignment() const
void Untrail(int target_trail_index)
void SetDecisionLevel(int level)
void Resize(int num_variables)
void EnqueueWithUnitReason(Literal true_literal)
void EnqueueSearchDecision(Literal true_literal)
void AddToConflict(MutableUpperBoundedLinearConstraint *conflict)
BooleanVariable FirstVariableWithSameReason(BooleanVariable var)
void Resize(int num_variables)
bool LiteralIsAssigned(Literal literal) const
bool VariableIsAssigned(BooleanVariable var) const
bool LiteralIsTrue(Literal literal) const
void AssignFromTrueLiteral(Literal literal)
Literal GetTrueLiteralForAssignedVariable(BooleanVariable var) const
bool LiteralIsFalse(Literal literal) const
int NumberOfVariables() const
void Resize(int num_variables)
SharedClausesManager * clauses
ModelSharedTimeLimit * time_limit
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
std::tuple< int64_t, int64_t, const double > Coefficient
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
Coefficient ComputeNegatedCanonicalRhs(Coefficient lower_bound, Coefficient bound_shift, Coefficient max_value)
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
std::string SatStatusString(SatSolver::Status status)
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
bool BooleanLinearExpressionIsCanonical(const std::vector< LiteralWithCoeff > &cst)
int MoveOneUnprocessedLiteralLast(const absl::btree_set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
const int kUnsatTrailIndex
int64_t MemoryUsageProcess()
Collection of objects used to extend the Constraint Solver library.
std::string ProtobufShortDebugString(const P &message)
std::string MemoryUsage()
bool SafeAddInto(IntegerType a, IntegerType *b)
static int input(yyscan_t yyscanner)
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
static constexpr int kSearchDecision
#define SOLVER_LOG(logger,...)
#define VLOG(verboselevel)
#define VLOG_IS_ON(verboselevel)