23#include "absl/container/btree_set.h"
24#include "absl/log/check.h"
25#include "absl/log/log.h"
26#include "absl/log/vlog_is_on.h"
27#include "absl/types/span.h"
48 : initial_num_variables_(num_variables), num_variables_(num_variables) {
49 reverse_mapping_.resize(num_variables);
50 for (BooleanVariable var(0); var < num_variables; ++var) {
51 reverse_mapping_[var] = var;
53 assignment_.Resize(num_variables);
57 DCHECK(!clause.empty());
58 DCHECK(std::find(clause.begin(), clause.end(), x) != clause.end());
59 associated_literal_.push_back(ApplyReverseMapping(x));
60 clauses_start_.push_back(clauses_literals_.size());
61 for (
const Literal& l : clause) {
62 clauses_literals_.push_back(ApplyReverseMapping(l));
67 const Literal l = ApplyReverseMapping(x);
68 assignment_.AssignFromTrueLiteral(l);
75 if (reverse_mapping_.size() < mapping.size()) {
77 while (reverse_mapping_.size() < mapping.size()) {
78 reverse_mapping_.push_back(BooleanVariable(num_variables_++));
80 assignment_.Resize(num_variables_);
82 for (BooleanVariable v(0); v < mapping.size(); ++v) {
83 const BooleanVariable image = mapping[v];
85 if (image >= new_mapping.size()) {
88 new_mapping[image] = reverse_mapping_[v];
92 std::swap(new_mapping, reverse_mapping_);
96 if (l.
Variable() >= reverse_mapping_.size()) {
98 while (l.
Variable() >= reverse_mapping_.size()) {
99 reverse_mapping_.
push_back(BooleanVariable(num_variables_++));
101 assignment_.
Resize(num_variables_);
112 for (BooleanVariable var(0); var <
assignment->NumberOfVariables(); ++var) {
114 assignment->AssignFromTrueLiteral(Literal(var,
true));
118 int previous_start = clauses_literals_.size();
119 for (
int i =
static_cast<int>(clauses_start_.size()) - 1;
i >= 0; --
i) {
120 bool set_associated_var =
true;
121 const int new_start = clauses_start_[
i];
122 for (
int j = new_start; j < previous_start; ++j) {
123 if (
assignment->LiteralIsTrue(clauses_literals_[j])) {
124 set_associated_var =
false;
128 previous_start = new_start;
129 if (set_associated_var) {
130 assignment->UnassignLiteral(associated_literal_[
i].Negated());
131 assignment->AssignFromTrueLiteral(associated_literal_[
i]);
142 for (BooleanVariable var(0); var < solver.
NumVariables(); ++var) {
151 const std::vector<bool>&
solution) {
152 for (BooleanVariable var(0); var <
solution.size(); ++var) {
153 DCHECK_LT(var, reverse_mapping_.size());
155 DCHECK(!assignment_.VariableIsAssigned(reverse_mapping_[var]));
156 assignment_.AssignFromTrueLiteral(
159 Postsolve(&assignment_);
160 std::vector<bool> postsolved_solution;
161 postsolved_solution.reserve(initial_num_variables_);
162 for (
int i = 0;
i < initial_num_variables_; ++
i) {
163 postsolved_solution.push_back(
164 assignment_.LiteralIsTrue(
Literal(BooleanVariable(
i),
true)));
166 return postsolved_solution;
172 DCHECK_GT(clause.size(), 0) <<
"Added an empty clause to the presolver";
174 clauses_.push_back(std::vector<Literal>(clause.begin(), clause.end()));
175 in_clause_to_process_.push_back(
true);
176 clause_to_process_.push_back(ci);
178 bool changed =
false;
179 std::vector<Literal>& clause_ref = clauses_.back();
180 if (!equiv_mapping_.empty()) {
181 for (
int i = 0;
i < clause_ref.size(); ++
i) {
182 const Literal old_literal = clause_ref[
i];
183 clause_ref[
i] =
Literal(equiv_mapping_[clause_ref[
i]]);
184 if (old_literal != clause_ref[
i]) changed =
true;
187 std::sort(clause_ref.begin(), clause_ref.end());
188 clause_ref.erase(std::unique(clause_ref.begin(), clause_ref.end()),
192 for (
int i = 1;
i < clause_ref.size(); ++
i) {
193 if (clause_ref[
i] == clause_ref[
i - 1].Negated()) {
195 ++num_trivial_clauses_;
196 clause_to_process_.pop_back();
198 in_clause_to_process_.pop_back();
204 signatures_.push_back(ComputeSignatureOfClauseVariables(ci));
205 DCHECK_EQ(signatures_.size(), clauses_.size());
207 if (drat_proof_handler_ !=
nullptr && changed) {
208 drat_proof_handler_->AddClause(clause_ref);
209 drat_proof_handler_->DeleteClause(clause);
212 const Literal max_literal = clause_ref.back();
213 const int required_size = std::max(max_literal.
Index().value(),
216 if (required_size > literal_to_clauses_.size()) {
217 literal_to_clauses_.resize(required_size);
218 literal_to_clause_sizes_.resize(required_size);
221 literal_to_clauses_[e].push_back(ci);
222 literal_to_clause_sizes_[e]++;
227 const int required_size = 2 * num_variables;
228 if (required_size > literal_to_clauses_.size()) {
229 literal_to_clauses_.resize(required_size);
230 literal_to_clause_sizes_.resize(required_size);
234void SatPresolver::RebuildLiteralToClauses() {
235 const int size = literal_to_clauses_.size();
236 literal_to_clauses_.clear();
237 literal_to_clauses_.
resize(size);
238 for (
ClauseIndex ci(0); ci < clauses_.size(); ++ci) {
239 for (
const Literal lit : clauses_[ci]) {
243 num_deleted_literals_since_last_cleanup_ = 0;
246void SatPresolver::AddClauseInternal(std::vector<Literal>* clause) {
247 if (drat_proof_handler_ !=
nullptr) drat_proof_handler_->AddClause(*clause);
249 DCHECK(std::is_sorted(clause->begin(), clause->end()));
250 DCHECK_GT(clause->size(), 0) <<
"TODO(user): Unsat during presolve?";
252 clauses_.push_back(std::vector<Literal>());
253 clauses_.back().swap(*clause);
254 in_clause_to_process_.push_back(
true);
255 clause_to_process_.push_back(ci);
256 for (
const Literal e : clauses_.back()) {
257 literal_to_clauses_[e].push_back(ci);
258 literal_to_clause_sizes_[e]++;
259 UpdatePriorityQueue(e.Variable());
260 UpdateBvaPriorityQueue(e.Index());
263 signatures_.push_back(ComputeSignatureOfClauseVariables(ci));
264 DCHECK_EQ(signatures_.size(), clauses_.size());
267util_intops::StrongVector<BooleanVariable, BooleanVariable>
270 BooleanVariable new_var(0);
271 for (BooleanVariable var(0); var <
NumVariables(); ++var) {
272 if (literal_to_clause_sizes_[
Literal(var,
true)] > 0 ||
273 literal_to_clause_sizes_[
Literal(var,
false)] > 0) {
287 var_pq_elements_.clear();
288 in_clause_to_process_.clear();
289 clause_to_process_.clear();
290 literal_to_clauses_.clear();
296 for (BooleanVariable index : mapping) {
300 std::vector<Literal> temp;
302 for (std::vector<Literal>& clause_ref : clauses_) {
313bool SatPresolver::ProcessAllClauses() {
314 int num_skipped_checks = 0;
315 const int kCheckFrequency = 1000;
319 std::stable_sort(clause_to_process_.begin(), clause_to_process_.end(),
321 return clauses_[c1].size() < clauses_[c2].size();
323 while (!clause_to_process_.empty()) {
325 in_clause_to_process_[ci] =
false;
326 clause_to_process_.pop_front();
328 if (++num_skipped_checks >= kCheckFrequency) {
329 if (num_inspected_signatures_ + num_inspected_literals_ > 1e9) {
330 VLOG(1) <<
"Aborting ProcessAllClauses() because work limit has been "
334 if (time_limit_ !=
nullptr && time_limit_->
LimitReached())
return true;
335 num_skipped_checks = 0;
352 if (logger_->LoggingIsEnabled()) {
353 int64_t num_removable = 0;
354 for (
const bool b : can_be_removed) {
355 if (
b) ++num_removable;
358 "[SAT presolve] num removable Booleans: ", num_removable,
" / ",
359 can_be_removed.size());
361 "[SAT presolve] num trivial clauses: ", num_trivial_clauses_);
367 if (!ProcessAllClauses())
return false;
368 if (logger_->LoggingIsEnabled()) DisplayStats(timer.
Get());
370 if (time_limit_ !=
nullptr && time_limit_->LimitReached())
return true;
371 if (num_inspected_signatures_ + num_inspected_literals_ > 1e9)
return true;
373 InitializePriorityQueue();
374 while (var_pq_.Size() > 0) {
375 const BooleanVariable var = var_pq_.Top()->variable;
377 if (!can_be_removed[var.value()])
continue;
379 if (!ProcessAllClauses())
return false;
381 if (num_deleted_literals_since_last_cleanup_ > 1e7) {
382 RebuildLiteralToClauses();
385 if (time_limit_ !=
nullptr && time_limit_->LimitReached())
return true;
386 if (num_inspected_signatures_ + num_inspected_literals_ > 1e9)
return true;
388 if (logger_->LoggingIsEnabled()) DisplayStats(timer.
Get());
391 if (parameters_.presolve_use_bva()) {
393 if (logger_->LoggingIsEnabled()) DisplayStats(timer.
Get());
401 var_pq_elements_.clear();
402 InitializeBvaPriorityQueue();
403 while (bva_pq_.Size() > 0) {
404 const LiteralIndex lit = bva_pq_.Top()->literal;
407 if (time_limit_ !=
nullptr && time_limit_->LimitReached())
break;
412void SatPresolver::SimpleBva(LiteralIndex l) {
413 literal_to_p_size_.
resize(literal_to_clauses_.size(), 0);
414 DCHECK(std::all_of(literal_to_p_size_.begin(), literal_to_p_size_.end(),
415 [](
int v) { return v == 0; }));
420 m_cls_ = literal_to_clauses_[l];
423 for (
int loop = 0; loop < 100; ++loop) {
427 flattened_p_.clear();
429 const std::vector<Literal>& clause = clauses_[c];
430 if (clause.empty())
continue;
434 const LiteralIndex l_min =
435 FindLiteralWithShortestOccurrenceListExcluding(clause, Literal(l));
440 for (
const ClauseIndex d : literal_to_clauses_[l_min]) {
441 if (clause.size() != clauses_[d].size())
continue;
442 const LiteralIndex l_diff =
445 if (l_diff == Literal(l).NegatedIndex()) {
450 VLOG(1) <<
"self-subsumbtion";
453 flattened_p_.push_back({l_diff, c});
454 const int new_size = ++literal_to_p_size_[l_diff];
455 if (new_size > max_size) {
463 const int new_m_lit_size = m_lit_.size() + 1;
464 const int new_m_cls_size = max_size;
465 const int new_reduction =
466 new_m_lit_size * new_m_cls_size - new_m_cls_size - new_m_lit_size;
468 if (new_reduction <= reduction)
break;
469 DCHECK_NE(1, new_m_lit_size);
470 DCHECK_NE(1, new_m_cls_size);
476 reduction = new_reduction;
481 for (
const auto& entry : flattened_p_) {
482 literal_to_p_size_[entry.first] = 0;
483 if (entry.first == lmax) m_cls_.push_back(entry.second);
485 flattened_p_.clear();
489 for (
const auto& entry : flattened_p_) literal_to_p_size_[entry.first] = 0;
490 flattened_p_.clear();
495 if (reduction <= parameters_.presolve_bva_threshold())
return;
496 DCHECK_GT(m_lit_.size(), 1);
499 const int old_size = literal_to_clauses_.size();
500 const LiteralIndex x_true = LiteralIndex(old_size);
501 const LiteralIndex x_false = LiteralIndex(old_size + 1);
502 literal_to_clauses_.resize(old_size + 2);
503 literal_to_clause_sizes_.resize(old_size + 2);
504 bva_pq_elements_.resize(old_size + 2);
505 bva_pq_elements_[x_true.value()].literal = x_true;
506 bva_pq_elements_[x_false.value()].literal = x_false;
509 if (drat_proof_handler_ !=
nullptr) drat_proof_handler_->AddOneVariable();
510 for (
const LiteralIndex lit : m_lit_) {
511 tmp_new_clause_ = {Literal(lit), Literal(x_true)};
512 AddClauseInternal(&tmp_new_clause_);
515 tmp_new_clause_ = clauses_[ci];
516 DCHECK(!tmp_new_clause_.empty());
517 for (Literal& ref : tmp_new_clause_) {
518 if (ref.Index() == l) {
519 ref = Literal(x_false);
527 std::sort(tmp_new_clause_.begin(), tmp_new_clause_.end());
528 AddClauseInternal(&tmp_new_clause_);
538 const std::vector<Literal>& clause = clauses_[
c];
539 DCHECK(!clause.empty());
540 const LiteralIndex l_min =
541 FindLiteralWithShortestOccurrenceListExcluding(clause, Literal(l));
542 for (
const LiteralIndex lit : m_lit_) {
543 if (lit == l)
continue;
544 for (
const ClauseIndex d : literal_to_clauses_[l_min]) {
545 if (clause.size() != clauses_[d].size())
continue;
546 const LiteralIndex l_diff =
562 AddToBvaPriorityQueue(x_true);
563 AddToBvaPriorityQueue(x_false);
564 AddToBvaPriorityQueue(l);
567uint64_t SatPresolver::ComputeSignatureOfClauseVariables(ClauseIndex ci) {
568 uint64_t signature = 0;
569 for (
const Literal l : clauses_[ci]) {
570 signature |= (uint64_t{1} << (l.Variable().value() % 64));
572 DCHECK_EQ(signature == 0, clauses_[ci].empty());
579bool SatPresolver::ProcessClauseToSimplifyOthersUsingLiteral(
580 ClauseIndex clause_index,
Literal lit) {
581 const std::vector<Literal>& clause = clauses_[clause_index];
582 const uint64_t clause_signature = signatures_[clause_index];
583 LiteralIndex opposite_literal;
588 bool need_cleaning =
false;
589 num_inspected_signatures_ += literal_to_clauses_[lit].size();
590 for (
const ClauseIndex ci : literal_to_clauses_[lit]) {
591 const uint64_t ci_signature = signatures_[ci];
595 DCHECK_EQ(ci_signature, ComputeSignatureOfClauseVariables(ci));
596 if (ci_signature == 0) {
597 need_cleaning =
true;
604 if (ci != clause_index && (clause_signature & ~ci_signature) == 0 &&
606 &num_inspected_literals_)) {
608 need_cleaning =
true;
612 DCHECK_NE(opposite_literal, lit.Index());
613 if (clauses_[ci].empty())
return false;
614 if (drat_proof_handler_ !=
nullptr) {
616 drat_proof_handler_->AddClause(clauses_[ci]);
620 signatures_[ci] = ComputeSignatureOfClauseVariables(ci);
626 --literal_to_clause_sizes_[opposite_literal];
627 UpdatePriorityQueue(Literal(opposite_literal).Variable());
629 if (!in_clause_to_process_[ci]) {
630 in_clause_to_process_[ci] =
true;
631 clause_to_process_.push_back(ci);
639 auto& occurrence_list_ref = literal_to_clauses_[lit];
641 if (signatures_[ci] != 0) occurrence_list_ref[new_index++] = ci;
643 occurrence_list_ref.resize(new_index);
644 DCHECK_EQ(literal_to_clause_sizes_[lit], new_index);
654 const std::vector<Literal>& clause = clauses_[clause_index];
655 if (clause.empty())
return true;
656 DCHECK(std::is_sorted(clause.begin(), clause.end()));
658 LiteralIndex opposite_literal;
659 const Literal lit = FindLiteralWithShortestOccurrenceList(clause);
661 if (!ProcessClauseToSimplifyOthersUsingLiteral(clause_index, lit)) {
667 const LiteralIndex other_lit_index =
668 FindLiteralWithShortestOccurrenceListExcluding(clause, lit);
670 literal_to_clause_sizes_[other_lit_index] <
672 return ProcessClauseToSimplifyOthersUsingLiteral(clause_index,
677 bool something_removed =
false;
678 auto& occurrence_list_ref = literal_to_clauses_[lit.
NegatedIndex()];
679 const uint64_t clause_signature = signatures_[clause_index];
681 const uint64_t ci_signature = signatures_[ci];
682 DCHECK_EQ(ci_signature, ComputeSignatureOfClauseVariables(ci));
683 if (ci_signature == 0)
continue;
689 if ((clause_signature & ~ci_signature) == 0 &&
691 &num_inspected_literals_)) {
693 if (clauses_[ci].empty())
return false;
694 if (drat_proof_handler_ !=
nullptr) {
696 drat_proof_handler_->AddClause(clauses_[ci]);
700 signatures_[ci] = ComputeSignatureOfClauseVariables(ci);
702 if (!in_clause_to_process_[ci]) {
703 in_clause_to_process_[ci] =
true;
704 clause_to_process_.push_back(ci);
706 something_removed =
true;
709 occurrence_list_ref[new_index] = ci;
712 occurrence_list_ref.resize(new_index);
713 literal_to_clause_sizes_[lit.
NegatedIndex()] = new_index;
714 if (something_removed) {
721void SatPresolver::RemoveAllClauseContaining(
Literal x,
722 bool register_for_postsolve) {
723 if (register_for_postsolve) {
725 if (!clauses_[
i].empty()) {
726 RemoveAndRegisterForPostsolve(
i, x);
731 if (!clauses_[
i].empty()) Remove(
i);
735 literal_to_clause_sizes_[
x] = 0;
739 const int s1 = literal_to_clause_sizes_[x];
740 const int s2 = literal_to_clause_sizes_[x.NegatedIndex()];
744 if (s1 == 0 && s2 == 0)
return false;
748 if (s1 > 1 && s2 > 1 && s1 * s2 > parameters_.presolve_bve_threshold()) {
754 int64_t sum_for_x = 0;
755 int64_t sum_for_not_x = 0;
756 const int clause_weight = parameters_.presolve_bve_clause_weight();
758 if (!clauses_[
i].empty()) {
760 sum_for_x += clauses_[
i].size();
763 for (
ClauseIndex i : literal_to_clauses_[x.NegatedIndex()]) {
764 if (!clauses_[
i].empty()) {
766 sum_for_not_x += clauses_[
i].size();
769 const int64_t threshold =
770 clause_weight * num_clauses + sum_for_x + sum_for_not_x;
773 if (s1 < s2) x = x.Negated();
778 if (clauses_[
i].empty())
continue;
779 bool no_resolvant =
true;
780 for (
ClauseIndex j : literal_to_clauses_[x.NegatedIndex()]) {
781 if (clauses_[j].empty())
continue;
784 no_resolvant =
false;
785 size += clause_weight + rs;
788 if (size > threshold)
return false;
791 if (no_resolvant && parameters_.presolve_blocked_clause()) {
804 RemoveAndRegisterForPostsolve(
i, x);
811 std::vector<Literal> temp;
813 if (clauses_[
i].empty())
continue;
814 for (
ClauseIndex j : literal_to_clauses_[x.NegatedIndex()]) {
815 if (clauses_[j].empty())
continue;
817 AddClauseInternal(&temp);
826 bool push_x_for_postsolve =
true;
827 bool push_not_x_for_postsolve =
true;
828 if (parameters_.filter_sat_postsolve_clauses()) {
829 if (sum_for_x <= sum_for_not_x) {
830 push_not_x_for_postsolve =
false;
832 push_x_for_postsolve =
false;
835 RemoveAllClauseContaining(x, push_x_for_postsolve);
836 RemoveAllClauseContaining(x.Negated(), push_not_x_for_postsolve);
843void SatPresolver::Remove(ClauseIndex ci) {
844 num_deleted_literals_since_last_cleanup_ += clauses_[ci].size();
846 for (
const Literal e : clauses_[ci]) {
847 literal_to_clause_sizes_[e]--;
848 UpdatePriorityQueue(e.Variable());
849 UpdateBvaPriorityQueue(
Literal(e.Variable(),
true).
Index());
850 UpdateBvaPriorityQueue(
Literal(e.Variable(),
false).
Index());
852 if (drat_proof_handler_ !=
nullptr) {
858void SatPresolver::RemoveAndRegisterForPostsolve(ClauseIndex ci,
Literal x) {
859 postsolver_->Add(x, clauses_[ci]);
863Literal SatPresolver::FindLiteralWithShortestOccurrenceList(
864 absl::Span<const Literal> clause) {
865 DCHECK(!clause.empty());
866 Literal result = clause.front();
867 int best_size = literal_to_clause_sizes_[result];
868 for (
const Literal l : clause) {
869 const int size = literal_to_clause_sizes_[l];
870 if (size < best_size) {
878LiteralIndex SatPresolver::FindLiteralWithShortestOccurrenceListExcluding(
879 const std::vector<Literal>& clause,
Literal to_exclude) {
880 DCHECK(!clause.empty());
882 int num_occurrences = std::numeric_limits<int>::max();
883 for (
const Literal l : clause) {
884 if (l == to_exclude)
continue;
885 if (literal_to_clause_sizes_[l] < num_occurrences) {
887 num_occurrences = literal_to_clause_sizes_[l];
893void SatPresolver::UpdatePriorityQueue(BooleanVariable var) {
894 if (var_pq_elements_.empty())
return;
895 PQElement* element = &var_pq_elements_[var];
896 element->weight = literal_to_clause_sizes_[Literal(var,
true)] +
897 literal_to_clause_sizes_[Literal(var,
false)];
898 if (var_pq_.Contains(element)) {
899 var_pq_.NoteChangedPriority(element);
901 var_pq_.Add(element);
905void SatPresolver::InitializePriorityQueue() {
907 var_pq_elements_.resize(num_vars);
908 for (BooleanVariable var(0); var < num_vars; ++var) {
909 PQElement* element = &var_pq_elements_[var];
910 element->variable = var;
911 element->weight = literal_to_clause_sizes_[Literal(var,
true)] +
912 literal_to_clause_sizes_[Literal(var,
false)];
913 var_pq_.Add(element);
917void SatPresolver::UpdateBvaPriorityQueue(LiteralIndex lit) {
918 if (bva_pq_elements_.empty())
return;
919 DCHECK_LT(lit, bva_pq_elements_.size());
920 BvaPqElement* element = &bva_pq_elements_[lit.value()];
921 element->weight = literal_to_clause_sizes_[lit];
922 if (bva_pq_.Contains(element)) {
923 bva_pq_.NoteChangedPriority(element);
927void SatPresolver::AddToBvaPriorityQueue(LiteralIndex lit) {
928 if (bva_pq_elements_.empty())
return;
929 DCHECK_LT(lit, bva_pq_elements_.size());
930 BvaPqElement* element = &bva_pq_elements_[lit.value()];
931 element->weight = literal_to_clause_sizes_[lit];
932 DCHECK(!bva_pq_.Contains(element));
933 if (element->weight > 2) bva_pq_.Add(element);
936void SatPresolver::InitializeBvaPriorityQueue() {
939 bva_pq_elements_.assign(num_literals, BvaPqElement());
940 for (LiteralIndex lit(0); lit < num_literals; ++lit) {
941 BvaPqElement* element = &bva_pq_elements_[lit.value()];
942 element->literal = lit;
943 element->weight = literal_to_clause_sizes_[lit];
947 if (element->weight > 2) bva_pq_.Add(element);
951void SatPresolver::DisplayStats(
double elapsed_seconds) {
952 int num_literals = 0;
954 int num_singleton_clauses = 0;
955 for (
const std::vector<Literal>& c : clauses_) {
957 if (
c.size() == 1) ++num_singleton_clauses;
959 num_literals +=
c.size();
962 int num_one_side = 0;
963 int num_simple_definition = 0;
965 for (BooleanVariable var(0); var <
NumVariables(); ++var) {
966 const int s1 = literal_to_clause_sizes_[Literal(var,
true)];
967 const int s2 = literal_to_clause_sizes_[Literal(var,
false)];
968 if (s1 == 0 && s2 == 0)
continue;
971 if (s1 == 0 || s2 == 0) {
973 }
else if (s1 == 1 || s2 == 1) {
974 num_simple_definition++;
977 SOLVER_LOG(logger_,
"[SAT presolve] [", elapsed_seconds,
"s]",
978 " clauses:", num_clauses,
" literals:", num_literals,
979 " vars:", num_vars,
" one_side_vars:", num_one_side,
980 " simple_definition:", num_simple_definition,
981 " singleton_clauses:", num_singleton_clauses);
985 LiteralIndex* opposite_literal,
986 int64_t* num_inspected_literals) {
987 if (
b->size() < a.size())
return false;
988 DCHECK(std::is_sorted(a.begin(), a.end()));
989 DCHECK(std::is_sorted(
b->begin(),
b->end()));
990 if (num_inspected_literals !=
nullptr) {
991 *num_inspected_literals += a.size();
992 *num_inspected_literals +=
b->size();
995 *opposite_literal = LiteralIndex(-1);
998 std::vector<Literal>::const_iterator ia = a.begin();
999 std::vector<Literal>::const_iterator ib =
b->begin();
1000 std::vector<Literal>::const_iterator to_remove;
1004 int size_diff =
b->size() - a.size();
1005 while (ia != a.end() ) {
1009 }
else if (*ia == ib->Negated()) {
1011 if (num_diff > 1)
return false;
1015 }
else if (*ia < *ib) {
1022 if (--size_diff < 0)
return false;
1025 if (num_diff == 1) {
1026 *opposite_literal = to_remove->Index();
1027 b->erase(to_remove);
1033 const std::vector<Literal>&
b,
Literal l) {
1034 DCHECK_EQ(
b.size(), a.size());
1035 DCHECK(std::is_sorted(a.begin(), a.end()));
1036 DCHECK(std::is_sorted(
b.begin(),
b.end()));
1038 std::vector<Literal>::const_iterator ia = a.begin();
1039 std::vector<Literal>::const_iterator ib =
b.begin();
1040 while (ia != a.end() && ib !=
b.end()) {
1044 }
else if (*ia < *ib) {
1053 result = (*ib).Index();
1059 if (ib !=
b.end()) {
1061 result = (*ib).Index();
1067 const std::vector<Literal>&
b,
1068 std::vector<Literal>* out) {
1069 DCHECK(std::is_sorted(a.begin(), a.end()));
1070 DCHECK(std::is_sorted(
b.begin(),
b.end()));
1073 std::vector<Literal>::const_iterator ia = a.begin();
1074 std::vector<Literal>::const_iterator ib =
b.begin();
1075 while ((ia != a.end()) && (ib !=
b.end())) {
1077 out->push_back(*ia);
1080 }
else if (*ia == ib->Negated()) {
1081 if (*ia != x)
return false;
1082 DCHECK_EQ(*ib, x.Negated());
1085 }
else if (*ia < *ib) {
1086 out->push_back(*ia);
1089 out->push_back(*ib);
1095 out->insert(out->end(), ia, a.end());
1096 out->insert(out->end(), ib,
b.end());
1102 const std::vector<Literal>&
b) {
1103 DCHECK(std::is_sorted(a.begin(), a.end()));
1104 DCHECK(std::is_sorted(
b.begin(),
b.end()));
1106 int size =
static_cast<int>(a.size() +
b.size()) - 2;
1107 std::vector<Literal>::const_iterator ia = a.begin();
1108 std::vector<Literal>::const_iterator ib =
b.begin();
1109 while ((ia != a.end()) && (ib !=
b.end())) {
1114 }
else if (*ia == ib->Negated()) {
1115 if (*ia != x)
return -1;
1116 DCHECK_EQ(*ib, x.Negated());
1119 }
else if (*ia < *ib) {
1140 deterministic_time_limit(solver->deterministic_time() +
1141 deterministic_time_limit) {}
1151 scratchpad_.clear();
1152 solver_->Backtrack(0);
1159 if (solver_->deterministic_time() > deterministic_time_limit) {
1164 if (!solver_->Assignment().LiteralIsAssigned(l)) {
1165 const int trail_index = solver_->LiteralTrail().Index();
1166 solver_->EnqueueDecisionAndBackjumpOnConflict(l);
1167 if (solver_->CurrentDecisionLevel() > 0) {
1169 for (
int i = trail_index + 1;
i < solver_->LiteralTrail().Index();
1171 scratchpad_.push_back(solver_->LiteralTrail()[
i].Index().value());
1179 mutable std::vector<int32_t> scratchpad_;
1181 const double deterministic_time_limit;
1199 std::vector<std::vector<int32_t>> scc;
1212 for (
const std::vector<int32_t>& component : scc) {
1213 if (component.size() > 1) {
1214 if (mapping->empty()) mapping->
resize(size, LiteralIndex(-1));
1215 const Literal representative((LiteralIndex(component[0])));
1216 for (
int i = 1;
i < component.size(); ++
i) {
1217 const Literal l((LiteralIndex(component[
i])));
1229 representative.
Index().value()))),
1238 if (!mapping->empty()) {
1248 for (LiteralIndex
i(0);
i < size; ++
i) {
1256 if (drat_proof_handler !=
nullptr) {
1257 drat_proof_handler->
AddClause({true_lit});
1261 for (LiteralIndex
i(0);
i < size; ++
i) {
1263 (*mapping)[
i] = rep;
1270 if (drat_proof_handler !=
nullptr) {
1271 drat_proof_handler->
AddClause({true_lit});
1280 if (drat_proof_handler !=
nullptr) {
1281 drat_proof_handler->
AddClause({true_lit});
1284 }
else if (rep !=
i) {
1287 if (drat_proof_handler !=
nullptr) {
1294 if (logger !=
nullptr) {
1295 SOLVER_LOG(logger,
"[Pure SAT probing] fixed ", num_already_fixed_vars,
1297 " equiv ", num_equiv / 2,
" total ", solver->
NumVariables(),
1298 " wtime: ", timer.
Get());
1300 const bool log_info =
1302 LOG_IF(INFO, log_info) <<
"Probing. fixed " << num_already_fixed_vars
1305 num_already_fixed_vars
1306 <<
" equiv " << num_equiv / 2 <<
" total "
1308 <<
" wtime: " << timer.
Get();
void Start()
When Start() is called multiple times, only the most recent is used.
int MergePartsOf(int node1, int node2)
int GetRootAndCompressPath(int node)
void AddClause(absl::Span< const Literal > clause)
void DeleteClause(absl::Span< const Literal > clause)
LiteralIndex NegatedIndex() const
LiteralIndex Index() const
BooleanVariable Variable() const
PropagationGraph & operator=(const PropagationGraph &)=delete
const std::vector< int32_t > & operator[](int32_t index) const
PropagationGraph(const PropagationGraph &)=delete
This type is neither copyable nor movable.
PropagationGraph(double deterministic_time_limit, SatSolver *solver)
bool log_search_progress() const
double presolve_probing_deterministic_time_limit() const
const VariablesAssignment & assignment()
std::vector< bool > PostsolveSolution(const std::vector< bool > &solution)
void ApplyMapping(const util_intops::StrongVector< BooleanVariable, BooleanVariable > &mapping)
SatPostsolver(int num_variables)
void Add(Literal x, absl::Span< const Literal > clause)
std::vector< bool > ExtractAndPostsolveSolution(const SatSolver &solver)
void FixVariable(Literal x)
void AddBinaryClause(Literal a, Literal b)
bool CrossProduct(Literal x)
void SetNumVariables(int num_variables)
Adds new clause to the SatPresolver.
bool ProcessClauseToSimplifyOthers(ClauseIndex clause_index)
util_intops::StrongVector< BooleanVariable, BooleanVariable > VariableMapping() const
void AddClause(absl::Span< const Literal > clause)
void LoadProblemIntoSatSolver(SatSolver *solver)
void PresolveWithBva()
Visible for testing. Just applies the BVA step of the presolve.
bool AddProblemClause(absl::Span< const Literal > literals)
void Backtrack(int target_level)
const SatParameters & parameters() const
ABSL_MUST_USE_RESULT bool AddUnitClause(Literal true_literal)
const VariablesAssignment & Assignment() const
const Trail & LiteralTrail() const
void SetNumVariables(int num_variables)
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
bool LiteralIsAssigned(Literal literal) const
void Resize(int num_variables)
bool LiteralIsTrue(Literal literal) const
void push_back(const value_type &val)
void resize(size_type new_size)
void STLEraseAllFromSequence(T *v, const E &e)
void STLClearObject(T *obj)
const LiteralIndex kNoLiteralIndex(-1)
LiteralIndex DifferAtGivenLiteral(const std::vector< Literal > &a, const std::vector< Literal > &b, Literal l)
void ProbeAndFindEquivalentLiteral(SatSolver *solver, SatPostsolver *postsolver, DratProofHandler *drat_proof_handler, util_intops::StrongVector< LiteralIndex, LiteralIndex > *mapping, SolverLogger *logger)
int ComputeResolvantSize(Literal x, const std::vector< Literal > &a, const std::vector< Literal > &b)
bool SimplifyClause(const std::vector< Literal > &a, std::vector< Literal > *b, LiteralIndex *opposite_literal, int64_t *num_inspected_literals)
bool ComputeResolvant(Literal x, const std::vector< Literal > &a, const std::vector< Literal > &b, std::vector< Literal > *out)
const BooleanVariable kNoBooleanVariable(-1)
In SWIG mode, we don't want anything besides these top-level includes.
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
void FindStronglyConnectedComponents(NodeIndex num_nodes, const Graph &graph, SccOutput *components)
Simple wrapper function for most usage.
#define SOLVER_LOG(logger,...)