25#include "absl/base/attributes.h"
26#include "absl/container/btree_set.h"
27#include "absl/container/flat_hash_map.h"
28#include "absl/log/check.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 drat_proof_handler_(nullptr),
80 InitializePropagators();
87 CHECK_GE(num_variables, num_variables_);
89 num_variables_ = num_variables;
90 binary_implication_graph_->
Resize(num_variables);
91 clauses_propagator_->
Resize(num_variables);
92 trail_->
Resize(num_variables);
94 pb_constraints_->
Resize(num_variables);
95 same_reason_identifier_.
Resize(num_variables);
100 decisions_.resize(num_variables + 1);
147bool SatSolver::IsMemoryLimitReached()
const {
148 const int64_t memory_usage =
150 const int64_t kMegaByte = 1024 * 1024;
151 return memory_usage > kMegaByte * parameters_->max_memory_in_mb();
154bool SatSolver::SetModelUnsat() {
155 model_is_unsat_ =
true;
160 if (model_is_unsat_)
return false;
168 if (literals.empty())
return SetModelUnsat();
170 if (literals.size() == 2) {
174 if (!binary_implication_graph_->
AddBinaryClause(literals[0], literals[1])) {
176 return SetModelUnsat();
179 if (!clauses_propagator_->
AddClause(literals)) {
181 return SetModelUnsat();
212 if (model_is_unsat_)
return false;
216 literals_scratchpad_.clear();
217 for (
const Literal l : literals) {
220 literals_scratchpad_.push_back(l);
223 literals_scratchpad_.assign(literals.begin(), literals.end());
228 for (
int i = 0;
i + 1 < literals_scratchpad_.size(); ++
i) {
229 if (literals_scratchpad_[
i] == literals_scratchpad_[
i + 1].Negated()) {
235 if (!AddProblemClauseInternal(literals_scratchpad_))
return false;
241 if (!PropagationIsDone() && !
Propagate()) {
242 return SetModelUnsat();
247bool SatSolver::AddProblemClauseInternal(absl::Span<const Literal> literals) {
250 for (
const Literal l : literals) {
255 if (literals.empty())
return SetModelUnsat();
257 if (literals.size() == 1) {
258 if (drat_proof_handler_ !=
nullptr) {
261 drat_proof_handler_->
AddClause({literals[0]});
264 }
else if (literals.size() == 2) {
266 if (literals[0] == literals[1]) {
269 }
else if (literals[0] == literals[1].Negated()) {
273 AddBinaryClauseInternal(literals[0], literals[1]);
276 if (!clauses_propagator_->
AddClause(literals, trail_, -1)) {
277 return SetModelUnsat();
284bool SatSolver::AddLinearConstraintInternal(
285 const std::vector<LiteralWithCoeff>& cst, Coefficient rhs,
286 Coefficient max_value) {
289 if (rhs < 0)
return SetModelUnsat();
290 if (rhs >= max_value)
return true;
293 const Coefficient min_coeff = cst.front().coefficient;
294 const Coefficient max_coeff = cst.back().coefficient;
298 if (max_value - min_coeff <= rhs) {
300 literals_scratchpad_.clear();
301 for (
const LiteralWithCoeff& term : cst) {
302 literals_scratchpad_.push_back(term.literal.Negated());
304 return AddProblemClauseInternal(literals_scratchpad_);
309 if (!parameters_->use_pb_resolution() && max_coeff <= rhs &&
310 2 * min_coeff > rhs) {
311 literals_scratchpad_.clear();
312 for (
const LiteralWithCoeff& term : cst) {
313 literals_scratchpad_.push_back(term.literal);
315 if (!binary_implication_graph_->
AddAtMostOne(literals_scratchpad_)) {
316 return SetModelUnsat();
326void SatSolver::CanonicalizeLinear(std::vector<LiteralWithCoeff>* cst,
327 Coefficient* bound_shift,
328 Coefficient* max_value) {
330 Coefficient fixed_variable_shift(0);
333 for (
const LiteralWithCoeff& term : *cst) {
336 CHECK(
SafeAddInto(-term.coefficient, &fixed_variable_shift));
339 (*cst)[
index] = term;
347 Coefficient bound_delta(0);
352 CHECK(
SafeAddInto(fixed_variable_shift, bound_shift));
357 bool use_upper_bound,
359 std::vector<LiteralWithCoeff>* cst) {
362 if (model_is_unsat_)
return false;
364 Coefficient bound_shift(0);
366 if (use_upper_bound) {
367 Coefficient max_value(0);
368 CanonicalizeLinear(cst, &bound_shift, &max_value);
369 const Coefficient rhs =
371 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
372 return SetModelUnsat();
376 if (use_lower_bound) {
379 Coefficient max_value(0);
380 CanonicalizeLinear(cst, &bound_shift, &max_value);
383 for (
int i = 0;
i < cst->size(); ++
i) {
384 (*cst)[
i].literal = (*cst)[
i].literal.Negated();
386 const Coefficient rhs =
388 if (!AddLinearConstraintInternal(*cst, rhs, max_value)) {
389 return SetModelUnsat();
397 if (!PropagationIsDone() && !
Propagate()) {
398 return SetModelUnsat();
403int SatSolver::AddLearnedClauseAndEnqueueUnitPropagation(
404 const std::vector<Literal>& literals,
bool is_redundant) {
407 if (literals.size() == 1) {
415 if (literals.size() == 2) {
416 if (track_binary_clauses_) {
418 CHECK(binary_clauses_.
Add(BinaryClause(literals[0], literals[1])));
420 CHECK(binary_implication_graph_->
AddBinaryClause(literals[0], literals[1]));
424 CleanClauseDatabaseIfNeeded();
428 const int lbd = ComputeLbd(literals);
429 if (is_redundant && lbd > parameters_->clause_cleanup_lbd_bound()) {
430 --num_learned_clause_before_cleanup_;
438 BumpClauseActivity(clause);
440 CHECK(clauses_propagator_->
AddClause(literals, trail_, lbd));
448 external_propagators_.push_back(propagator);
449 InitializePropagators();
454 CHECK(last_propagator_ ==
nullptr);
456 last_propagator_ = propagator;
457 InitializePropagators();
461 BooleanVariable
var)
const {
471SatClause* SatSolver::ReasonClauseOrNull(BooleanVariable
var)
const {
473 const AssignmentInfo& info = trail_->
Info(
var);
475 return clauses_propagator_->
ReasonClause(info.trail_index);
481 debug_assignment_.
Resize(num_variables_.value());
482 for (BooleanVariable
i(0);
i < num_variables_; ++
i) {
489 debug_assignment_.
Resize(num_variables_.value());
490 for (BooleanVariable
var(0);
var < num_variables_; ++
var) {
499 for (BooleanVariable
var(0);
var < num_variables_; ++
var) {
505 if (track_binary_clauses_) {
516bool SatSolver::ClauseIsValidUnderDebugAssignment(
517 absl::Span<const Literal> clause)
const {
519 for (Literal l : clause) {
528bool SatSolver::PBConstraintIsValidUnderDebugAssignment(
529 const std::vector<LiteralWithCoeff>& cst,
const Coefficient rhs)
const {
530 Coefficient sum(0.0);
531 for (LiteralWithCoeff term : cst) {
536 sum += term.coefficient;
546bool ClauseSubsumption(
const std::vector<Literal>&
a, SatClause*
b) {
547 std::vector<Literal> superset(
b->begin(),
b->end());
548 std::vector<Literal> subset(
a.begin(),
a.end());
549 std::sort(superset.begin(), superset.end());
550 std::sort(subset.begin(), subset.end());
551 return std::includes(superset.begin(), superset.end(), subset.begin(),
560 DCHECK(PropagationIsDone());
564 CHECK_GE(current_decision_level_, assumption_level_);
567 EnqueueNewDecision(true_literal);
569 return last_decision_or_backtrack_trail_index_;
573 if (model_is_unsat_)
return false;
583 if (model_is_unsat_)
return false;
586 const int old_decision_level = current_decision_level_;
589 if (model_is_unsat_)
return false;
590 if (current_decision_level_ == old_decision_level) {
591 CHECK(!assumptions_.empty());
595 if (++num_loop % 16 == 0 && time_limit_->
LimitReached()) {
606 DCHECK(PropagationIsDone());
611 if (model_is_unsat_)
return false;
612 assumption_level_ = 0;
613 assumptions_.clear();
619 const std::vector<Literal>& assumptions) {
621 if (assumptions.empty())
return true;
628 DCHECK(assumptions_.empty());
629 assumption_level_ = 1;
630 assumptions_ = assumptions;
636 if (model_is_unsat_)
return false;
642 CHECK_EQ(current_decision_level_, 0);
643 last_decision_or_backtrack_trail_index_ = trail_->
Index();
646 ++current_decision_level_;
650 int num_decisions = 0;
656 if (num_decisions == 0) {
658 current_decision_level_ = 0;
668 if (num_decisions == 0) {
669 current_decision_level_ = 0;
678 DCHECK(assumptions_.empty());
679 const int64_t old_num_branches = counters_.
num_branches;
688 if (model_is_unsat_)
return;
691 const int conflict_trail_index = trail_->
Index();
692 const int conflict_decision_level = current_decision_level_;
695 same_reason_identifier_.
Clear();
696 const int max_trail_index = ComputeMaxTrailIndex(trail_->
FailingClause());
697 if (!assumptions_.empty() && !trail_->
FailingClause().empty()) {
704 const int highest_level =
705 DecisionLevel((*trail_)[max_trail_index].Variable());
706 if (highest_level == 1)
return;
709 ComputeFirstUIPConflict(max_trail_index, &learned_conflict_,
710 &reason_used_to_infer_the_conflict_,
714 if (learned_conflict_.empty())
return (
void)SetModelUnsat();
715 DCHECK(IsConflictValid(learned_conflict_));
716 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
724 if (parameters_->also_bump_variables_in_conflict_reasons()) {
725 ComputeUnionOfReasons(learned_conflict_, &extra_reason_literals_);
735 BumpReasonActivities(reason_used_to_infer_the_conflict_);
739 UpdateClauseActivityIncrement();
743 const int period = parameters_->glucose_decay_increment_period();
744 const double max_decay = parameters_->glucose_max_decay();
746 parameters_->variable_activity_decay() < max_decay) {
747 parameters_->set_variable_activity_decay(
748 parameters_->variable_activity_decay() +
749 parameters_->glucose_decay_increment());
755 bool compute_pb_conflict =
false;
756 if (parameters_->use_pb_resolution()) {
758 if (!compute_pb_conflict) {
759 for (
Literal lit : reason_used_to_infer_the_conflict_) {
760 if (ReasonPbConstraintOrNull(
lit.Variable()) !=
nullptr) {
761 compute_pb_conflict =
true;
770 if (compute_pb_conflict) {
772 Coefficient initial_slack(-1);
775 Coefficient num_literals(0);
780 pb_conflict_.
AddToRhs(num_literals - 1);
789 int pb_backjump_level;
790 ComputePBConflict(max_trail_index, initial_slack, &pb_conflict_,
792 if (pb_backjump_level == -1)
return (
void)SetModelUnsat();
795 std::vector<LiteralWithCoeff> cst;
797 DCHECK(PBConstraintIsValidUnderDebugAssignment(cst, pb_conflict_.
Rhs()));
801 bool conflict_is_a_clause = (pb_conflict_.
Rhs() == cst.size() - 1);
802 if (conflict_is_a_clause) {
804 if (term.coefficient != Coefficient(1)) {
805 conflict_is_a_clause =
false;
811 if (!conflict_is_a_clause) {
818 CHECK_GT(trail_->
Index(), last_decision_or_backtrack_trail_index_);
825 if (pb_backjump_level < ComputeBacktrackLevel(learned_conflict_)) {
826 subsumed_clauses_.clear();
827 learned_conflict_.clear();
832 DCHECK(
Assignment().LiteralIsTrue(term.literal));
833 DCHECK_EQ(term.coefficient, 1);
834 const int level = trail_->
Info(term.literal.Variable()).
level;
835 if (level == 0)
continue;
836 if (level > max_level) {
838 max_index = learned_conflict_.size();
840 learned_conflict_.push_back(term.literal.Negated());
844 is_marked_.
Set(term.literal.Variable());
846 CHECK(!learned_conflict_.empty());
847 std::swap(learned_conflict_.front(), learned_conflict_[max_index]);
848 DCHECK(IsConflictValid(learned_conflict_));
857 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
858 if (!binary_implication_graph_->
IsEmpty()) {
859 if (parameters_->binary_minimization_algorithm() ==
860 SatParameters::BINARY_MINIMIZATION_FIRST) {
862 *trail_, &learned_conflict_, &is_marked_);
863 }
else if (parameters_->binary_minimization_algorithm() ==
865 BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION) {
867 *trail_, &learned_conflict_,
870 DCHECK(IsConflictValid(learned_conflict_));
874 MinimizeConflict(&learned_conflict_);
877 if (!binary_implication_graph_->
IsEmpty()) {
881 switch (parameters_->binary_minimization_algorithm()) {
882 case SatParameters::NO_BINARY_MINIMIZATION:
883 ABSL_FALLTHROUGH_INTENDED;
884 case SatParameters::BINARY_MINIMIZATION_FIRST:
885 ABSL_FALLTHROUGH_INTENDED;
886 case SatParameters::BINARY_MINIMIZATION_FIRST_WITH_TRANSITIVE_REDUCTION:
888 case SatParameters::BINARY_MINIMIZATION_WITH_REACHABILITY:
892 case SatParameters::EXPERIMENTAL_BINARY_MINIMIZATION:
894 *trail_, &learned_conflict_);
897 DCHECK(IsConflictValid(learned_conflict_));
912 Backtrack(ComputeBacktrackLevel(learned_conflict_));
913 DCHECK(ClauseIsValidUnderDebugAssignment(learned_conflict_));
919 if (drat_proof_handler_ !=
nullptr) {
920 drat_proof_handler_->
AddClause(learned_conflict_);
929 if (parameters_->minimization_algorithm() == SatParameters::EXPERIMENTAL) {
930 subsumed_clauses_.clear();
935 bool is_redundant =
true;
936 if (!subsumed_clauses_.empty() &&
937 parameters_->subsumption_during_conflict_analysis()) {
938 for (
SatClause* clause : subsumed_clauses_) {
939 DCHECK(ClauseSubsumption(learned_conflict_, clause));
941 is_redundant =
false;
950 const int conflict_lbd = AddLearnedClauseAndEnqueueUnitPropagation(
951 learned_conflict_, is_redundant);
952 restart_->
OnConflict(conflict_trail_index, conflict_decision_level,
957 int max_level,
int* first_propagation_index) {
959 DCHECK(assumptions_.empty());
960 int decision_index = current_decision_level_;
961 while (decision_index <= max_level) {
962 DCHECK_GE(decision_index, current_decision_level_);
963 const Literal previous_decision = decisions_[decision_index].literal;
965 if (
Assignment().LiteralIsTrue(previous_decision)) {
971 if (
Assignment().LiteralIsFalse(previous_decision)) {
979 const int old_level = current_decision_level_;
981 if (first_propagation_index !=
nullptr) {
982 *first_propagation_index = std::min(*first_propagation_index,
index);
985 if (current_decision_level_ <= old_level) {
997 decision_index = current_decision_level_;
1004 Literal true_literal,
int* first_propagation_index) {
1006 CHECK(PropagationIsDone());
1007 CHECK(assumptions_.empty());
1011 if (first_propagation_index !=
nullptr) {
1012 *first_propagation_index = trail_->
Index();
1019 DCHECK(PropagationIsDone());
1023 EnqueueNewDecision(true_literal);
1043 DCHECK(target_level == 0 || !
Decisions().empty());
1045 DCHECK_GE(target_level, 0);
1055 current_decision_level_ = target_level;
1056 const int target_trail_index =
1057 decisions_[current_decision_level_].trail_index;
1059 DCHECK_LT(target_trail_index, trail_->
Index());
1061 if (propagator->IsEmpty())
continue;
1062 propagator->Untrail(*trail_, target_trail_index);
1064 decision_policy_->
Untrail(target_trail_index);
1065 trail_->
Untrail(target_trail_index);
1067 last_decision_or_backtrack_trail_index_ = trail_->
Index();
1076 if (!
Propagate())
return SetModelUnsat();
1096 const std::vector<Literal>& assumptions, int64_t max_number_of_conflicts) {
1099 return SolveInternal(time_limit_,
1100 max_number_of_conflicts >= 0
1101 ? max_number_of_conflicts
1102 : parameters_->max_number_of_conflicts());
1106 SOLVER_LOG(logger_, RunningStatisticsString());
1112 CHECK_GE(assumption_level, 0);
1114 assumption_level_ = assumption_level;
1117 if (!assumptions_.empty()) {
1118 CHECK_EQ(assumption_level, 0);
1119 assumptions_.clear();
1125 parameters_->max_number_of_conflicts());
1129 return SolveInternal(time_limit_, parameters_->max_number_of_conflicts());
1132void SatSolver::KeepAllClauseUsedToInfer(BooleanVariable variable) {
1133 CHECK(
Assignment().VariableIsAssigned(variable));
1134 if (trail_->
Info(variable).
level == 0)
return;
1136 std::vector<bool> is_marked(trail_index + 1,
false);
1137 is_marked[trail_index] =
true;
1139 for (; num > 0 && trail_index >= 0; --trail_index) {
1140 if (!is_marked[trail_index])
continue;
1141 is_marked[trail_index] =
false;
1144 const BooleanVariable
var = (*trail_)[trail_index].Variable();
1146 if (clause !=
nullptr) {
1153 for (
const Literal l : trail_->
Reason(
var)) {
1154 const AssignmentInfo& info = trail_->
Info(l.Variable());
1155 if (info.level == 0)
continue;
1156 if (!is_marked[info.trail_index]) {
1157 is_marked[info.trail_index] =
true;
1164bool SatSolver::SubsumptionIsInteresting(BooleanVariable variable) {
1168 const int binary_id = binary_implication_graph_->
PropagatorId();
1169 const int clause_id = clauses_propagator_->
PropagatorId();
1171 CHECK(
Assignment().VariableIsAssigned(variable));
1172 if (trail_->
Info(variable).
level == 0)
return true;
1174 std::vector<bool> is_marked(trail_index + 1,
false);
1175 is_marked[trail_index] =
true;
1177 int num_clause_to_mark_as_non_deletable = 0;
1178 for (; num > 0 && trail_index >= 0; --trail_index) {
1179 if (!is_marked[trail_index])
continue;
1180 is_marked[trail_index] =
false;
1183 const BooleanVariable
var = (*trail_)[trail_index].Variable();
1186 if (type != binary_id && type != clause_id)
return false;
1187 SatClause* clause = ReasonClauseOrNull(
var);
1188 if (clause !=
nullptr && clauses_propagator_->
IsRemovable(clause)) {
1189 ++num_clause_to_mark_as_non_deletable;
1191 for (
const Literal l : trail_->
Reason(
var)) {
1192 const AssignmentInfo& info = trail_->
Info(l.Variable());
1193 if (info.level == 0)
continue;
1194 if (!is_marked[info.trail_index]) {
1195 is_marked[info.trail_index] =
true;
1200 return num_clause_to_mark_as_non_deletable <= 1;
1206void SatSolver::TryToMinimizeClause(SatClause* clause) {
1207 CHECK(clause !=
nullptr);
1210 absl::btree_set<LiteralIndex> moved_last;
1211 std::vector<Literal> candidate(clause->begin(), clause->end());
1221 int longest_valid_prefix = 0;
1224 const Literal first_decision = decisions_[0].literal;
1225 for (
int i = 0;
i < candidate.size(); ++
i) {
1226 if (candidate[
i].Negated() == first_decision) {
1227 std::swap(candidate[0], candidate[
i]);
1228 longest_valid_prefix = 1;
1235 absl::flat_hash_map<LiteralIndex, int> indexing;
1236 for (
int i = 0;
i < candidate.size(); ++
i) {
1237 indexing[candidate[
i].NegatedIndex()] =
i;
1240 ++longest_valid_prefix) {
1242 indexing.find(decisions_[longest_valid_prefix].
literal.Index());
1243 if (it == indexing.end())
break;
1244 std::swap(candidate[longest_valid_prefix], candidate[it->second]);
1245 indexing[candidate[it->second].NegatedIndex()] = it->second;
1252 while (!model_is_unsat_) {
1259 if (target_level == -1)
break;
1264 const Literal
literal = candidate[level];
1266 candidate.erase(candidate.begin() + level);
1269 const int variable_level =
1271 if (variable_level == 0) {
1272 ProcessNewlyFixedVariablesForDratProof();
1276 clauses_propagator_->
Detach(clause);
1284 if (ReasonClauseOrNull(
literal.Variable()) != clause &&
1285 SubsumptionIsInteresting(
literal.Variable())) {
1288 KeepAllClauseUsedToInfer(
literal.Variable());
1290 clauses_propagator_->
Detach(clause);
1296 if (variable_level + 1 < candidate.size()) {
1297 candidate.resize(variable_level);
1305 if (clause->IsRemoved()) {
1309 if (model_is_unsat_)
return;
1312 if (candidate.empty()) {
1313 model_is_unsat_ =
true;
1316 moved_last.insert(candidate.back().Index());
1323 if (candidate.size() == clause->size())
return;
1326 if (candidate.size() == 1) {
1327 if (drat_proof_handler_ !=
nullptr) {
1328 drat_proof_handler_->
AddClause(candidate);
1330 if (!
Assignment().VariableIsAssigned(candidate[0].Variable())) {
1338 if (candidate.size() == 2) {
1342 AddBinaryClauseInternal(candidate[0], candidate[1]);
1343 clauses_propagator_->
Detach(clause);
1352 clause->size() - candidate.size();
1357 model_is_unsat_ =
true;
1362 int64_t max_number_of_conflicts) {
1374 SOLVER_LOG(logger_,
"Number of variables: ", num_variables_.value());
1375 SOLVER_LOG(logger_,
"Number of clauses (size > 2): ",
1377 SOLVER_LOG(logger_,
"Number of binary clauses: ",
1379 SOLVER_LOG(logger_,
"Number of linear constraints: ",
1382 SOLVER_LOG(logger_,
"Number of watched clauses: ",
1388 const int64_t kDisplayFrequency = 10000;
1389 int64_t next_display = parameters_->log_search_progress()
1391 :
std::numeric_limits<int64_t>::
max();
1394 const int64_t kMemoryCheckFrequency = 10000;
1395 int64_t next_memory_check =
1400 const int64_t kFailureLimit =
1401 max_number_of_conflicts == std::numeric_limits<int64_t>::max()
1402 ? std::numeric_limits<int64_t>::max()
1411 SOLVER_LOG(logger_,
"The time limit has been reached. Aborting.");
1416 SOLVER_LOG(logger_,
"The conflict limit has been reached. Aborting.");
1426 next_memory_check = NextMultipleOf(
num_failures(), kMemoryCheckFrequency);
1427 if (IsMemoryLimitReached()) {
1428 SOLVER_LOG(logger_,
"The memory limit has been reached. Aborting.");
1436 SOLVER_LOG(logger_, RunningStatisticsString());
1437 next_display = NextMultipleOf(
num_failures(), kDisplayFrequency);
1440 const int old_level = current_decision_level_;
1444 if (model_is_unsat_)
return StatusWithLog(
INFEASIBLE);
1445 if (old_level == current_decision_level_) {
1446 CHECK(!assumptions_.empty());
1454 if (trail_->
Index() == num_variables_.value()) {
1463 EnqueueNewDecision(decision_policy_->
NextBranch());
1469 CHECK(time_limit_ !=
nullptr);
1475 block_clause_deletion_ =
true;
1481 if (to_minimize !=
nullptr) {
1482 TryToMinimizeClause(to_minimize);
1483 if (model_is_unsat_)
return false;
1485 if (to_minimize ==
nullptr) {
1487 VLOG(1) <<
"Minimized all clauses, restarting from first one.";
1490 if (num_resets > 1)
break;
1501 block_clause_deletion_ =
false;
1508 std::vector<Literal> unsat_assumptions;
1512 int trail_index = 0;
1520 unsat_assumptions.push_back(
lit.Negated());
1525 is_marked_.
Set(
lit.Variable());
1527 CHECK_LE(num_true, 1);
1532 CHECK_LT(trail_index, trail_->
Index());
1535 while (trail_index >= limit &&
1536 !is_marked_[(*trail_)[trail_index].Variable()]) {
1539 if (trail_index < limit)
break;
1540 const Literal marked_literal = (*trail_)[trail_index];
1545 unsat_assumptions.push_back(marked_literal);
1549 const BooleanVariable
var =
literal.Variable();
1550 const int level = DecisionLevel(
var);
1551 if (level > 0 && !is_marked_[
var]) is_marked_.
Set(
var);
1558 std::reverse(unsat_assumptions.begin(), unsat_assumptions.end());
1559 return unsat_assumptions;
1562void SatSolver::BumpReasonActivities(
const std::vector<Literal>& literals) {
1565 const BooleanVariable
var =
literal.Variable();
1566 if (DecisionLevel(
var) > 0) {
1568 if (clause !=
nullptr) {
1569 BumpClauseActivity(clause);
1571 UpperBoundedLinearConstraint* pb_constraint =
1572 ReasonPbConstraintOrNull(
var);
1573 if (pb_constraint !=
nullptr) {
1583void SatSolver::BumpClauseActivity(SatClause* clause) {
1594 const int new_lbd = ComputeLbd(*clause);
1595 if (new_lbd + 1 <= parameters_->clause_cleanup_lbd_bound()) {
1601 switch (parameters_->clause_cleanup_protection()) {
1602 case SatParameters::PROTECTION_NONE:
1604 case SatParameters::PROTECTION_ALWAYS:
1605 it->second.protected_during_next_cleanup =
true;
1607 case SatParameters::PROTECTION_LBD:
1612 if (new_lbd + 1 < it->second.lbd) {
1613 it->second.protected_during_next_cleanup =
true;
1614 it->second.lbd = new_lbd;
1619 const double activity = it->second.activity += clause_activity_increment_;
1620 if (activity > parameters_->max_clause_activity_value()) {
1621 RescaleClauseActivities(1.0 / parameters_->max_clause_activity_value());
1625void SatSolver::RescaleClauseActivities(
double scaling_factor) {
1627 clause_activity_increment_ *= scaling_factor;
1629 entry.second.activity *= scaling_factor;
1633void SatSolver::UpdateClauseActivityIncrement() {
1635 clause_activity_increment_ *= 1.0 / parameters_->clause_activity_decay();
1638bool SatSolver::IsConflictValid(
const std::vector<Literal>& literals) {
1640 if (literals.empty())
return false;
1641 const int highest_level = DecisionLevel(literals[0].Variable());
1642 for (
int i = 1;
i < literals.size(); ++
i) {
1643 const int level = DecisionLevel(literals[
i].Variable());
1644 if (level <= 0 || level >= highest_level)
return false;
1649int SatSolver::ComputeBacktrackLevel(
const std::vector<Literal>& literals) {
1662 int backtrack_level = 0;
1663 for (
int i = 1;
i < literals.size(); ++
i) {
1664 const int level = DecisionLevel(literals[
i].Variable());
1665 backtrack_level = std::max(backtrack_level, level);
1667 DCHECK_LT(backtrack_level, DecisionLevel(literals[0].Variable()));
1669 return backtrack_level;
1672template <
typename LiteralList>
1673int SatSolver::ComputeLbd(
const LiteralList& literals) {
1676 parameters_->count_assumption_levels_in_lbd() ? 0 : assumption_level_;
1680 SatDecisionLevel(DecisionLevel(literals.begin()->Variable()) + 1));
1681 for (
const Literal
literal : literals) {
1682 const SatDecisionLevel level(DecisionLevel(
literal.Variable()));
1683 DCHECK_GE(level, 0);
1684 if (level > limit && !is_level_marked_[level]) {
1685 is_level_marked_.
Set(level);
1691std::string SatSolver::StatusString(Status
status)
const {
1692 const double time_in_s = timer_.
Get();
1694 absl::StrFormat(
" time: %fs\n", time_in_s) +
1697 " num failures: %d (%.0f /sec)\n", counters_.
num_failures,
1698 static_cast<double>(counters_.
num_failures) / time_in_s) +
1700 " num branches: %d (%.0f /sec)\n", counters_.
num_branches,
1701 static_cast<double>(counters_.
num_branches) / time_in_s) +
1702 absl::StrFormat(
" num propagations: %d (%.0f /sec)\n",
1705 absl::StrFormat(
" num binary propagations: %d\n",
1707 absl::StrFormat(
" num binary inspections: %d\n",
1710 " num binary redundant implications: %d\n",
1713 " num classic minimizations: %d"
1714 " (literals removed: %d)\n",
1717 " num binary minimizations: %d"
1718 " (literals removed: %d)\n",
1721 absl::StrFormat(
" num inspected clauses: %d\n",
1723 absl::StrFormat(
" num inspected clause_literals: %d\n",
1726 " num learned literals: %d (avg: %.1f /clause)\n",
1730 " num learned PB literals: %d (avg: %.1f /clause)\n",
1733 absl::StrFormat(
" num subsumed clauses: %d\n",
1735 absl::StrFormat(
" minimization_num_clauses: %d\n",
1737 absl::StrFormat(
" minimization_num_decisions: %d\n",
1739 absl::StrFormat(
" minimization_num_true: %d\n",
1741 absl::StrFormat(
" minimization_num_subsumed: %d\n",
1743 absl::StrFormat(
" minimization_num_removed_literals: %d\n",
1745 absl::StrFormat(
" pb num threshold updates: %d\n",
1747 absl::StrFormat(
" pb num constraint lookups: %d\n",
1749 absl::StrFormat(
" pb num inspected constraint literals: %d\n",
1755std::string SatSolver::RunningStatisticsString()
const {
1756 const double time_in_s = timer_.
Get();
1757 return absl::StrFormat(
1758 "%6.2fs, mem:%s, fails:%d, depth:%d, clauses:%d, tmp:%d, bin:%u, "
1759 "restarts:%d, vars:%d",
1765 num_variables_.value() - num_processed_fixed_variables_);
1768void SatSolver::ProcessNewlyFixedVariablesForDratProof() {
1769 if (drat_proof_handler_ ==
nullptr)
return;
1783 for (; drat_num_processed_fixed_variables_ < trail_->
Index();
1784 ++drat_num_processed_fixed_variables_) {
1785 temp = (*trail_)[drat_num_processed_fixed_variables_];
1786 drat_proof_handler_->
AddClause({&temp, 1});
1793 int num_detached_clauses = 0;
1796 ProcessNewlyFixedVariablesForDratProof();
1802 if (clause->IsRemoved())
continue;
1804 const size_t old_size = clause->size();
1805 if (clause->RemoveFixedLiteralsAndTestIfTrue(trail_->
Assignment())) {
1808 ++num_detached_clauses;
1812 const size_t new_size = clause->size();
1813 if (new_size == old_size)
continue;
1815 if (drat_proof_handler_ !=
nullptr) {
1816 CHECK_GT(new_size, 0);
1817 drat_proof_handler_->
AddClause({clause->begin(), new_size});
1818 drat_proof_handler_->
DeleteClause({clause->begin(), old_size});
1821 if (new_size == 2) {
1825 AddBinaryClauseInternal(clause->FirstLiteral(), clause->SecondLiteral());
1834 if (num_detached_clauses > 0 || num_binary > 0) {
1835 VLOG(1) << trail_->
Index() <<
" fixed variables at level 0. " <<
"Detached "
1836 << num_detached_clauses <<
" clauses. " << num_binary
1837 <<
" converted to binary.";
1844 CHECK(binary_implication_graph_->
Propagate(trail_));
1846 num_processed_fixed_variables_ = trail_->
Index();
1850bool SatSolver::PropagationIsDone()
const {
1852 if (propagator->IsEmpty())
continue;
1853 if (!propagator->PropagationIsDone(*trail_))
return false;
1870 non_empty_propagators_.clear();
1872 if (!propagator->IsEmpty()) {
1873 non_empty_propagators_.push_back(propagator);
1885 const int old_index = trail_->
Index();
1887 DCHECK(propagator->PropagatePreconditionsAreSatisfied(*trail_));
1888 if (!propagator->Propagate(trail_))
return false;
1889 if (trail_->
Index() > old_index)
break;
1891 if (trail_->
Index() == old_index)
break;
1897 if (PropagationIsDone())
return true;
1902void SatSolver::InitializePropagators() {
1903 propagators_.clear();
1904 propagators_.push_back(binary_implication_graph_);
1905 propagators_.push_back(clauses_propagator_);
1906 propagators_.push_back(pb_constraints_);
1907 for (
int i = 0;
i < external_propagators_.size(); ++
i) {
1908 propagators_.push_back(external_propagators_[
i]);
1910 if (last_propagator_ !=
nullptr) {
1911 propagators_.push_back(last_propagator_);
1915bool SatSolver::ResolvePBConflict(BooleanVariable
var,
1916 MutableUpperBoundedLinearConstraint* conflict,
1917 Coefficient* slack) {
1921 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1924 UpperBoundedLinearConstraint* pb_reason = ReasonPbConstraintOrNull(
var);
1925 if (pb_reason !=
nullptr) {
1926 pb_reason->ResolvePBConflict(*trail_,
var, conflict, slack);
1931 Coefficient multiplier(1);
1934 const int algorithm = 1;
1935 switch (algorithm) {
1939 conflict->ReduceSlackTo(*trail_, trail_index, *slack, Coefficient(0));
1943 multiplier = *slack + 1;
1947 multiplier = conflict->GetCoefficient(
var);
1950 Coefficient num_literals(1);
1957 conflict->AddTerm(
literal.Negated(), multiplier);
1960 conflict->AddToRhs((num_literals - 1) * multiplier);
1964 DCHECK_EQ(*slack, conflict->ComputeSlackForTrailPrefix(*trail_, trail_index));
1968void SatSolver::EnqueueNewDecision(Literal
literal) {
1979 const double kMinDeterministicTimeBetweenCleanups = 1.0;
1980 if (num_processed_fixed_variables_ < trail_->
Index() &&
1982 deterministic_time_of_last_fixed_variables_cleanup_ +
1983 kMinDeterministicTimeBetweenCleanups) {
1989 last_decision_or_backtrack_trail_index_ = trail_->
Index();
1990 decisions_[current_decision_level_] = Decision(trail_->
Index(),
literal);
1991 ++current_decision_level_;
1996std::string SatSolver::DebugString(
const SatClause& clause)
const {
1998 for (
const Literal
literal : clause) {
1999 if (!result.empty()) {
2000 result.append(
" || ");
2002 const std::string
value =
2007 result.append(absl::StrFormat(
"%s(%s)",
literal.DebugString(),
value));
2012int SatSolver::ComputeMaxTrailIndex(absl::Span<const Literal> clause)
const {
2014 int trail_index = -1;
2015 for (
const Literal
literal : clause) {
2025void SatSolver::ComputeFirstUIPConflict(
2026 int max_trail_index, std::vector<Literal>* conflict,
2027 std::vector<Literal>* reason_used_to_infer_the_conflict,
2028 std::vector<SatClause*>* subsumed_clauses) {
2037 reason_used_to_infer_the_conflict->clear();
2038 subsumed_clauses->clear();
2039 if (max_trail_index == -1)
return;
2044 DCHECK_EQ(max_trail_index, ComputeMaxTrailIndex(trail_->
FailingClause()));
2045 int trail_index = max_trail_index;
2046 const int highest_level = DecisionLevel((*trail_)[trail_index].Variable());
2047 if (highest_level == 0)
return;
2064 absl::Span<const Literal> clause_to_expand = trail_->
FailingClause();
2066 DCHECK(!clause_to_expand.empty());
2067 int num_literal_at_highest_level_that_needs_to_be_processed = 0;
2069 int num_new_vars_at_positive_level = 0;
2070 int num_vars_at_positive_level_in_clause_to_expand = 0;
2071 for (
const Literal
literal : clause_to_expand) {
2072 const BooleanVariable
var =
literal.Variable();
2073 const int level = DecisionLevel(
var);
2074 if (level == 0)
continue;
2075 ++num_vars_at_positive_level_in_clause_to_expand;
2076 if (!is_marked_[
var]) {
2078 ++num_new_vars_at_positive_level;
2079 if (level == highest_level) {
2080 ++num_literal_at_highest_level_that_needs_to_be_processed;
2092 if (num_new_vars_at_positive_level > 0) {
2095 subsumed_clauses->clear();
2102 if (sat_clause !=
nullptr &&
2103 num_vars_at_positive_level_in_clause_to_expand ==
2105 num_literal_at_highest_level_that_needs_to_be_processed) {
2106 subsumed_clauses->push_back(sat_clause);
2110 DCHECK_GT(num_literal_at_highest_level_that_needs_to_be_processed, 0);
2111 while (!is_marked_[(*trail_)[trail_index].Variable()]) {
2113 DCHECK_GE(trail_index, 0);
2114 DCHECK_EQ(DecisionLevel((*trail_)[trail_index].Variable()),
2118 if (num_literal_at_highest_level_that_needs_to_be_processed == 1) {
2122 conflict->push_back((*trail_)[trail_index].Negated());
2125 std::swap(conflict->back(), conflict->front());
2129 const Literal
literal = (*trail_)[trail_index];
2130 reason_used_to_infer_the_conflict->push_back(
literal);
2136 clause_to_expand = {};
2138 clause_to_expand = trail_->
Reason(
literal.Variable(), conflict_id);
2140 sat_clause = ReasonClauseOrNull(
literal.Variable());
2142 --num_literal_at_highest_level_that_needs_to_be_processed;
2147void SatSolver::ComputeUnionOfReasons(
const std::vector<Literal>&
input,
2148 std::vector<Literal>* literals) {
2151 for (
const Literal l :
input) tmp_mark_.
Set(l.Variable());
2152 for (
const Literal l :
input) {
2153 for (
const Literal r : trail_->
Reason(l.Variable())) {
2154 if (!tmp_mark_[r.Variable()]) {
2155 tmp_mark_.
Set(r.Variable());
2156 literals->push_back(r);
2160 for (
const Literal l :
input) tmp_mark_.
Clear(l.Variable());
2161 for (
const Literal l : *literals) tmp_mark_.
Clear(l.Variable());
2165void SatSolver::ComputePBConflict(
int max_trail_index,
2166 Coefficient initial_slack,
2167 MutableUpperBoundedLinearConstraint* conflict,
2168 int* pb_backjump_level) {
2170 int trail_index = max_trail_index;
2174 Coefficient slack = initial_slack;
2176 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1));
2177 CHECK_LT(slack, 0) <<
"We don't have a conflict!";
2180 int backjump_level = 0;
2182 const BooleanVariable
var = (*trail_)[trail_index].Variable();
2185 if (conflict->GetCoefficient(
var) > 0 &&
2187 if (parameters_->minimize_reduction_during_pb_resolution()) {
2192 conflict->ReduceGivenCoefficient(
var);
2196 slack += conflict->GetCoefficient(
var);
2200 if (slack < 0)
continue;
2206 const int current_level = DecisionLevel(
var);
2207 int i = trail_index;
2209 const BooleanVariable previous_var = (*trail_)[
i].Variable();
2210 if (conflict->GetCoefficient(previous_var) > 0 &&
2212 conflict->GetLiteral(previous_var))) {
2217 if (
i < 0 || DecisionLevel((*trail_)[
i].Variable()) < current_level) {
2218 backjump_level =
i < 0 ? 0 : DecisionLevel((*trail_)[
i].Variable());
2224 const bool clause_used = ResolvePBConflict(
var, conflict, &slack);
2233 const Coefficient slack_only_for_debug =
2235 ? conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1)
2240 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2241 conflict->ReduceCoefficients();
2247 if (parameters_->minimize_reduction_during_pb_resolution()) {
2249 conflict->ComputeSlackForTrailPrefix(*trail_, trail_index + 1);
2251 slack = conflict->ReduceCoefficientsAndComputeSlackForTrailPrefix(
2252 *trail_, trail_index + 1);
2255 DCHECK_EQ(slack, slack_only_for_debug);
2257 if (conflict->Rhs() < 0) {
2258 *pb_backjump_level = -1;
2266 if (!parameters_->minimize_reduction_during_pb_resolution()) {
2267 conflict->ReduceCoefficients();
2272 std::vector<Coefficient> sum_for_le_level(backjump_level + 2, Coefficient(0));
2273 std::vector<Coefficient> max_coeff_for_ge_level(backjump_level + 2,
2276 Coefficient max_sum(0);
2277 for (BooleanVariable
var : conflict->PossibleNonZeros()) {
2278 const Coefficient coeff = conflict->GetCoefficient(
var);
2279 if (coeff == 0)
continue;
2283 DecisionLevel(
var) > backjump_level) {
2284 max_coeff_for_ge_level[backjump_level + 1] =
2285 std::max(max_coeff_for_ge_level[backjump_level + 1], coeff);
2287 const int level = DecisionLevel(
var);
2289 sum_for_le_level[level] += coeff;
2291 max_coeff_for_ge_level[level] =
2292 std::max(max_coeff_for_ge_level[level], coeff);
2297 for (
int i = 1;
i < sum_for_le_level.size(); ++
i) {
2298 sum_for_le_level[
i] += sum_for_le_level[
i - 1];
2300 for (
int i = max_coeff_for_ge_level.size() - 2;
i >= 0; --
i) {
2301 max_coeff_for_ge_level[
i] =
2302 std::max(max_coeff_for_ge_level[
i], max_coeff_for_ge_level[
i + 1]);
2307 if (sum_for_le_level[0] > conflict->Rhs()) {
2308 *pb_backjump_level = -1;
2311 for (
int i = 0;
i <= backjump_level; ++
i) {
2312 const Coefficient level_sum = sum_for_le_level[
i];
2313 CHECK_LE(level_sum, conflict->Rhs());
2314 if (conflict->Rhs() - level_sum < max_coeff_for_ge_level[
i + 1]) {
2315 *pb_backjump_level =
i;
2319 LOG(FATAL) <<
"The code should never reach here.";
2322void SatSolver::MinimizeConflict(std::vector<Literal>* conflict) {
2325 const int old_size = conflict->size();
2326 switch (parameters_->minimization_algorithm()) {
2327 case SatParameters::NONE:
2329 case SatParameters::SIMPLE: {
2330 MinimizeConflictSimple(conflict);
2333 case SatParameters::RECURSIVE: {
2334 MinimizeConflictRecursively(conflict);
2337 case SatParameters::EXPERIMENTAL: {
2338 MinimizeConflictExperimental(conflict);
2342 if (conflict->size() < old_size) {
2355void SatSolver::MinimizeConflictSimple(std::vector<Literal>* conflict) {
2362 for (
int i = 1;
i < conflict->size(); ++
i) {
2363 const BooleanVariable
var = (*conflict)[
i].Variable();
2364 bool can_be_removed =
false;
2365 if (DecisionLevel(
var) != current_level) {
2367 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2368 if (!reason.empty()) {
2369 can_be_removed =
true;
2370 for (Literal
literal : reason) {
2371 if (DecisionLevel(
literal.Variable()) == 0)
continue;
2372 if (!is_marked_[
literal.Variable()]) {
2373 can_be_removed =
false;
2379 if (!can_be_removed) {
2380 (*conflict)[
index] = (*conflict)[
i];
2384 conflict->erase(conflict->begin() +
index, conflict->end());
2393void SatSolver::MinimizeConflictRecursively(std::vector<Literal>* conflict) {
2414 std::numeric_limits<int>::max());
2427 const int level = DecisionLevel(
var);
2428 min_trail_index_per_level_[level] = std::min(
2436 for (
int i = 1;
i < conflict->size(); ++
i) {
2437 const BooleanVariable
var = (*conflict)[
i].Variable();
2438 const AssignmentInfo& info = trail_->
Info(
var);
2441 info.trail_index <= min_trail_index_per_level_[info.level] ||
2442 !CanBeInferedFromConflictVariables(
var)) {
2445 is_independent_.
Set(
var);
2446 (*conflict)[
index] = (*conflict)[
i];
2450 conflict->resize(
index);
2454 const int threshold = min_trail_index_per_level_.size() / 2;
2457 min_trail_index_per_level_[DecisionLevel(
var)] =
2458 std::numeric_limits<int>::max();
2461 min_trail_index_per_level_.clear();
2465bool SatSolver::CanBeInferedFromConflictVariables(BooleanVariable variable) {
2468 DCHECK(is_marked_[variable]);
2469 const BooleanVariable v =
2471 if (v != variable)
return !is_independent_[v];
2484 dfs_stack_.push_back(variable);
2485 variable_to_process_.clear();
2486 variable_to_process_.push_back(variable);
2490 const BooleanVariable
var =
literal.Variable();
2491 DCHECK_NE(
var, variable);
2492 if (is_marked_[
var])
continue;
2493 const AssignmentInfo& info = trail_->
Info(
var);
2494 if (info.level == 0) {
2502 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2506 variable_to_process_.push_back(
var);
2510 while (!variable_to_process_.empty()) {
2511 const BooleanVariable current_var = variable_to_process_.back();
2512 if (current_var == dfs_stack_.back()) {
2515 if (dfs_stack_.size() > 1) {
2516 DCHECK(!is_marked_[current_var]);
2517 is_marked_.
Set(current_var);
2519 variable_to_process_.pop_back();
2520 dfs_stack_.pop_back();
2525 if (is_marked_[current_var]) {
2526 variable_to_process_.pop_back();
2532 DCHECK(!is_independent_[current_var]);
2536 const BooleanVariable v =
2538 if (v != current_var) {
2539 if (is_independent_[v])
break;
2540 DCHECK(is_marked_[v]);
2541 variable_to_process_.pop_back();
2547 dfs_stack_.push_back(current_var);
2548 bool abort_early =
false;
2550 const BooleanVariable
var =
literal.Variable();
2551 DCHECK_NE(
var, current_var);
2552 const AssignmentInfo& info = trail_->
Info(
var);
2553 if (info.level == 0 || is_marked_[
var])
continue;
2554 if (info.trail_index <= min_trail_index_per_level_[info.level] ||
2556 is_independent_[
var]) {
2560 variable_to_process_.push_back(
var);
2562 if (abort_early)
break;
2566 for (
const BooleanVariable
var : dfs_stack_) {
2567 is_independent_.
Set(
var);
2569 return dfs_stack_.empty();
2574struct WeightedVariable {
2575 WeightedVariable(BooleanVariable v,
int w) :
var(v),
weight(
w) {}
2583struct VariableWithLargerWeightFirst {
2584 bool operator()(
const WeightedVariable& wv1,
2585 const WeightedVariable& wv2)
const {
2586 return (wv1.weight > wv2.weight ||
2587 (wv1.weight == wv2.weight && wv1.var < wv2.var));
2603void SatSolver::MinimizeConflictExperimental(std::vector<Literal>* conflict) {
2610 std::vector<WeightedVariable> variables_sorted_by_level;
2611 for (Literal
literal : *conflict) {
2612 const BooleanVariable
var =
literal.Variable();
2614 const int level = DecisionLevel(
var);
2615 if (level < current_level) {
2616 variables_sorted_by_level.push_back(WeightedVariable(
var, level));
2619 std::sort(variables_sorted_by_level.begin(), variables_sorted_by_level.end(),
2620 VariableWithLargerWeightFirst());
2623 std::vector<BooleanVariable> to_remove;
2624 for (WeightedVariable weighted_var : variables_sorted_by_level) {
2625 const BooleanVariable
var = weighted_var.var;
2629 const absl::Span<const Literal> reason = trail_->
Reason(
var);
2630 if (reason.empty())
continue;
2634 std::vector<Literal> not_contained_literals;
2635 for (
const Literal reason_literal : reason) {
2636 const BooleanVariable reason_var = reason_literal.Variable();
2639 if (DecisionLevel(reason_var) == 0)
continue;
2644 if (!is_marked_[reason_var]) {
2645 not_contained_literals.push_back(reason_literal);
2646 if (not_contained_literals.size() > 1)
break;
2649 if (not_contained_literals.empty()) {
2654 to_remove.push_back(
var);
2655 }
else if (not_contained_literals.size() == 1) {
2658 to_remove.push_back(
var);
2659 is_marked_.
Set(not_contained_literals.front().Variable());
2660 conflict->push_back(not_contained_literals.front());
2665 for (BooleanVariable
var : to_remove) {
2671 for (
int i = 0;
i < conflict->size(); ++
i) {
2672 const Literal
literal = (*conflict)[
i];
2673 if (is_marked_[
literal.Variable()]) {
2678 conflict->erase(conflict->begin() +
index, conflict->end());
2681void SatSolver::CleanClauseDatabaseIfNeeded() {
2682 if (num_learned_clause_before_cleanup_ > 0)
return;
2687 typedef std::pair<SatClause*, ClauseInfo> Entry;
2688 std::vector<Entry> entries;
2690 for (
auto& entry : clauses_info) {
2691 if (ClauseIsUsedAsReason(entry.first))
continue;
2692 if (entry.second.protected_during_next_cleanup) {
2693 entry.second.protected_during_next_cleanup =
false;
2696 entries.push_back(entry);
2698 const int num_protected_clauses = clauses_info.size() - entries.size();
2700 if (parameters_->clause_cleanup_ordering() == SatParameters::CLAUSE_LBD) {
2702 std::sort(entries.begin(), entries.end(),
2703 [](
const Entry&
a,
const Entry&
b) {
2704 if (a.second.lbd == b.second.lbd) {
2705 return a.second.activity < b.second.activity;
2707 return a.second.lbd >
b.second.lbd;
2711 std::sort(entries.begin(), entries.end(),
2712 [](
const Entry&
a,
const Entry&
b) {
2713 if (a.second.activity == b.second.activity) {
2714 return a.second.lbd > b.second.lbd;
2716 return a.second.activity <
b.second.activity;
2721 int num_kept_clauses =
2722 (parameters_->clause_cleanup_target() > 0)
2723 ? std::min(
static_cast<int>(entries.size()),
2724 parameters_->clause_cleanup_target())
2725 : static_cast<int>(parameters_->clause_cleanup_ratio() *
2726 static_cast<double>(entries.
size()));
2728 int num_deleted_clauses = entries.size() - num_kept_clauses;
2733 if (num_kept_clauses > 0) {
2734 while (num_deleted_clauses > 0) {
2735 const ClauseInfo&
a = entries[num_deleted_clauses].second;
2736 const ClauseInfo&
b = entries[num_deleted_clauses - 1].second;
2737 if (
a.activity !=
b.activity ||
a.lbd !=
b.lbd)
break;
2738 --num_deleted_clauses;
2742 if (num_deleted_clauses > 0) {
2743 entries.resize(num_deleted_clauses);
2744 for (
const Entry& entry : entries) {
2745 SatClause* clause = entry.first;
2746 counters_.num_literals_forgotten += clause->size();
2747 clauses_propagator_->LazyDetach(clause);
2749 clauses_propagator_->CleanUpWatchers();
2753 if (!block_clause_deletion_) {
2754 clauses_propagator_->DeleteRemovedClauses();
2758 num_learned_clause_before_cleanup_ = parameters_->clause_cleanup_period();
2759 VLOG(1) <<
"Database cleanup, #protected:" << num_protected_clauses
2760 <<
" #kept:" << num_kept_clauses
2761 <<
" #deleted:" << num_deleted_clauses;
2766 case SatSolver::ASSUMPTIONS_UNSAT:
2767 return "ASSUMPTIONS_UNSAT";
2768 case SatSolver::INFEASIBLE:
2769 return "INFEASIBLE";
2770 case SatSolver::FEASIBLE:
2772 case SatSolver::LIMIT_REACHED:
2773 return "LIMIT_REACHED";
2777 LOG(DFATAL) <<
"Invalid SatSolver::Status " <<
status;
2782 std::vector<Literal> result;
2786 result.push_back(
lit);
2790 if (result.size() < core->size()) {
2791 VLOG(1) <<
"minimization " << core->size() <<
" -> " << result.size();
void EnableLogging(bool enable)
void SetLogToStdOut(bool enable)
Should all messages be displayed on stdout ?
bool LoggingIsEnabled() const
Returns true iff logging is enabled.
void ClearAndResize(IntegerType size)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
void Clear(IntegerType index)
void Set(IntegerType index)
int NumberOfSetCallsWithDifferentArguments() const
std::string StatString() const
double GetElapsedDeterministicTime() const
void ResetLimitFromParameters(const Parameters ¶meters)
const std::vector< BinaryClause > & newly_added() const
Returns the newly added BinaryClause since the last ClearNewlyAdded() call.
int64_t num_propagations() const
Number of literal propagated by this class (including conflicts).
void Resize(int num_variables)
Resizes the data structure.
int64_t num_implications() const
bool Propagate(Trail *trail) final
SatPropagator interface.
int64_t num_minimization() const
MinimizeClause() stats.
void MinimizeConflictWithReachability(std::vector< Literal > *c)
int64_t num_literals_removed() const
int64_t num_redundant_implications() const
Number of implications removed by transitive reduction.
bool IsEmpty() const final
Returns true if there is no constraints in this class.
bool AddBinaryClause(Literal a, Literal b)
void RemoveFixedVariables()
void MinimizeConflictExperimental(const Trail &trail, std::vector< Literal > *c)
void MinimizeConflictFirstWithTransitiveReduction(const Trail &trail, std::vector< Literal > *c, absl::BitGenRef random)
void MinimizeConflictFirst(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked)
ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span< const Literal > at_most_one)
int64_t num_inspections() const
Number of literals inspected by this class during propagation.
int64_t num_removable_clauses() const
void LazyDetach(SatClause *clause)
SatClause * NextClauseToMinimize()
void ResetToMinimizeIndex()
int64_t num_clauses() const
bool IsRemovable(SatClause *const clause) const
void Detach(SatClause *clause)
void DeleteRemovedClauses()
int64_t num_inspected_clauses() const
Total number of clauses inspected during calls to PropagateOnFalse().
bool AddClause(absl::Span< const Literal > literals, Trail *trail, int lbd)
Adds a new clause and perform initial propagation for this clause only.
int64_t num_inspected_clause_literals() const
int64_t num_watched_clauses() const
Number of clauses currently watched.
SatClause * ReasonClause(int trail_index) const
absl::flat_hash_map< SatClause *, ClauseInfo > * mutable_clauses_info()
SatClause * AddRemovableClause(absl::Span< const Literal > literals, Trail *trail, int lbd)
const std::vector< SatClause * > & AllClausesInCreationOrder() const
void Resize(int num_variables)
Must be called before adding clauses referring to such variables.
ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(SatClause *clause, absl::Span< const Literal > new_clause)
void AddClause(absl::Span< const Literal > clause)
void DeleteClause(absl::Span< const Literal > clause)
BooleanVariable Variable() const
void Register(T *non_owned_class)
Coefficient ComputeSlackForTrailPrefix(const Trail &trail, int trail_index) const
void AddToRhs(Coefficient value)
Adds a non-negative value to this constraint Rhs().
void CopyIntoVector(std::vector< LiteralWithCoeff > *output)
Copies this constraint into a vector<LiteralWithCoeff> representation.
void AddTerm(Literal literal, Coefficient coeff)
void ClearAndResize(int num_variables)
void UpdateActivityIncrement()
bool AddConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
int64_t num_constraint_lookups() const
Some statistics.
void Resize(int num_variables)
Changes the number of variables.
void ClearConflictingConstraint()
int NumberOfConstraints() const
Returns the number of constraints managed by this class.
UpperBoundedLinearConstraint * ReasonPbConstraint(int trail_index) const
int64_t num_inspected_constraint_literals() const
void BumpActivity(UpperBoundedLinearConstraint *constraint)
bool AddLearnedConstraint(const std::vector< LiteralWithCoeff > &cst, Coefficient rhs, Trail *trail)
int64_t num_threshold_updates() const
UpperBoundedLinearConstraint * ConflictingConstraint()
Contain the logic to decide when to restart a SAT tree search.
int NumRestarts() const
Returns the number of restarts since the last Reset().
void Reset()
Resets the policy using the current model parameters.
std::string InfoString() const
Returns a string with the current restart statistics.
void OnConflict(int conflict_trail_index, int conflict_decision_level, int conflict_lbd)
void BumpVariableActivities(absl::Span< const Literal > literals)
void Untrail(int target_trail_index)
Called on Untrail() so that we can update the set of possible decisions.
void IncreaseNumVariables(int num_variables)
void UpdateVariableActivityIncrement()
void BeforeConflict(int trail_index)
Base class for all the SAT constraints.
Status EnqueueDecisionAndBacktrackOnConflict(Literal true_literal, int *first_propagation_index=nullptr)
bool AddLinearConstraint(bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, std::vector< LiteralWithCoeff > *cst)
Status SolveWithTimeLimit(TimeLimit *time_limit)
double deterministic_time() const
bool AddBinaryClauses(const std::vector< BinaryClause > &clauses)
bool AddProblemClause(absl::Span< const Literal > literals, bool is_safe=true)
bool MinimizeByPropagation(double dtime)
const std::vector< BinaryClause > & NewlyAddedBinaryClauses()
void ProcessCurrentConflict()
Status UnsatStatus() const
void ProcessNewlyFixedVariables()
Simplifies the problem when new variables are assigned at level 0.
bool ResetWithGivenAssumptions(const std::vector< Literal > &assumptions)
int64_t num_branches() const
Some statistics since the creation of the solver.
void LoadDebugSolution(const std::vector< Literal > &solution)
std::vector< Literal > GetLastIncompatibleDecisions()
bool RestoreSolverToAssumptionLevel()
bool AddBinaryClause(Literal a, Literal b)
Same as AddProblemClause() below, but for small clauses.
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
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()
void SetAssumptionLevel(int assumption_level)
int64_t num_restarts() const
ABSL_MUST_USE_RESULT bool AddUnitClause(Literal true_literal)
bool AddTernaryClause(Literal a, Literal b, Literal c)
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)
const std::vector< Decision > & Decisions() const
ABSL_MUST_USE_RESULT bool FinishPropagation()
const Trail & LiteralTrail() const
void SetNumVariables(int num_variables)
void AddPropagator(SatPropagator *propagator)
void SetParameters(const SatParameters ¶meters)
BooleanVariable ReferenceVarWithSameReason(BooleanVariable var) const
std::vector< Literal > * MutableConflict()
int64_t NumberOfEnqueues() const
void SetDecisionLevel(int level)
Changes the decision level used by the next Enqueue().
int AssignmentType(BooleanVariable var) const
void EnqueueSearchDecision(Literal true_literal)
Specific Enqueue() version for the search decision.
void Untrail(int target_trail_index)
absl::Span< const Literal > Reason(BooleanVariable var, int64_t conflict_id=-1) const
void EnqueueWithUnitReason(Literal true_literal)
Specific Enqueue() version for a fixed variable.
int CurrentDecisionLevel() const
const AssignmentInfo & Info(BooleanVariable var) const
void RegisterPropagator(SatPropagator *propagator)
SatClause * FailingSatClause() const
absl::Span< const Literal > FailingClause() const
Returns the last conflict.
void Resize(int num_variables)
const VariablesAssignment & Assignment() const
void AddToConflict(MutableUpperBoundedLinearConstraint *conflict)
BooleanVariable FirstVariableWithSameReason(BooleanVariable var)
void Clear()
Clears the cache. Call this before each conflict analysis.
void Resize(int num_variables)
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
bool LiteralIsAssigned(Literal literal) const
Literal GetTrueLiteralForAssignedVariable(BooleanVariable var) const
bool LiteralIsFalse(Literal literal) const
int NumberOfVariables() const
void AssignFromTrueLiteral(Literal literal)
void UnassignLiteral(Literal literal)
void Resize(int num_variables)
bool LiteralIsTrue(Literal literal) const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
std::string SatStatusString(SatSolver::Status status)
Returns a string representation of a SatSolver::Status.
Coefficient ComputeNegatedCanonicalRhs(Coefficient lower_bound, Coefficient bound_shift, Coefficient max_value)
bool BooleanLinearExpressionIsCanonical(absl::Span< const LiteralWithCoeff > cst)
Returns true iff the Boolean linear expression is in canonical form.
Coefficient ComputeCanonicalRhs(Coefficient upper_bound, Coefficient bound_shift, Coefficient max_value)
const int kUnsatTrailIndex
A constant used by the EnqueueDecision*() API.
int MoveOneUnprocessedLiteralLast(const absl::btree_set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
bool ComputeBooleanLinearExpressionCanonicalForm(std::vector< LiteralWithCoeff > *cst, Coefficient *bound_shift, Coefficient *max_value)
int64_t MemoryUsageProcess()
In SWIG mode, we don't want anything besides these top-level includes.
std::string ProtobufShortDebugString(const P &message)
std::string MemoryUsage()
Returns the current thread's total memory usage in an human-readable string.
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)
Information about a variable assignment.
int32_t trail_index
The index of this assignment in the trail.
static constexpr int kSearchDecision
A binary clause. This is used by BinaryClauseManager.
Represents a term in a pseudo-Boolean formula.
int64_t minimization_num_true
int64_t num_subsumed_clauses
int64_t minimization_num_decisions
int64_t minimization_num_clauses
TryToMinimizeClause() stats.
int64_t num_minimizations
Minimization stats.
int64_t minimization_num_removed_literals
int64_t minimization_num_subsumed
int64_t num_literals_removed
int64_t minimization_num_reused
int64_t num_literals_learned
Clause learning /deletion stats.
int64_t num_learned_pb_literals
PB constraints.
#define SOLVER_LOG(logger,...)