23#include "absl/container/btree_set.h"
24#include "absl/log/check.h"
25#include "absl/types/span.h"
36#include "ortools/sat/sat_parameters.pb.h"
46 : initial_num_variables_(num_variables), num_variables_(num_variables) {
47 reverse_mapping_.resize(num_variables);
48 for (BooleanVariable var(0); var < num_variables; ++var) {
49 reverse_mapping_[var] = var;
51 assignment_.Resize(num_variables);
55 DCHECK(!clause.empty());
56 DCHECK(std::find(clause.begin(), clause.end(), x) != clause.end());
57 associated_literal_.push_back(ApplyReverseMapping(x));
58 clauses_start_.push_back(clauses_literals_.size());
59 for (
const Literal& l : clause) {
60 clauses_literals_.push_back(ApplyReverseMapping(l));
65 const Literal l = ApplyReverseMapping(x);
66 assignment_.AssignFromTrueLiteral(l);
73 if (reverse_mapping_.size() < mapping.size()) {
75 while (reverse_mapping_.size() < mapping.size()) {
76 reverse_mapping_.push_back(BooleanVariable(num_variables_++));
78 assignment_.Resize(num_variables_);
80 for (BooleanVariable v(0); v < mapping.size(); ++v) {
81 const BooleanVariable image = mapping[v];
83 if (image >= new_mapping.size()) {
86 new_mapping[image] = reverse_mapping_[v];
90 std::swap(new_mapping, reverse_mapping_);
94 if (l.
Variable() >= reverse_mapping_.size()) {
96 while (l.
Variable() >= reverse_mapping_.size()) {
97 reverse_mapping_.
push_back(BooleanVariable(num_variables_++));
99 assignment_.
Resize(num_variables_);
110 for (BooleanVariable var(0); var <
assignment->NumberOfVariables(); ++var) {
112 assignment->AssignFromTrueLiteral(Literal(var,
true));
116 int previous_start = clauses_literals_.size();
117 for (
int i =
static_cast<int>(clauses_start_.size()) - 1;
i >= 0; --
i) {
118 bool set_associated_var =
true;
119 const int new_start = clauses_start_[
i];
120 for (
int j = new_start; j < previous_start; ++j) {
121 if (
assignment->LiteralIsTrue(clauses_literals_[j])) {
122 set_associated_var =
false;
126 previous_start = new_start;
127 if (set_associated_var) {
128 assignment->UnassignLiteral(associated_literal_[
i].Negated());
129 assignment->AssignFromTrueLiteral(associated_literal_[
i]);
140 for (BooleanVariable var(0); var < solver.
NumVariables(); ++var) {
149 const std::vector<bool>&
solution) {
150 for (BooleanVariable var(0); var <
solution.size(); ++var) {
151 DCHECK_LT(var, reverse_mapping_.size());
153 DCHECK(!assignment_.VariableIsAssigned(reverse_mapping_[var]));
154 assignment_.AssignFromTrueLiteral(
157 Postsolve(&assignment_);
158 std::vector<bool> postsolved_solution;
159 postsolved_solution.reserve(initial_num_variables_);
160 for (
int i = 0;
i < initial_num_variables_; ++
i) {
161 postsolved_solution.push_back(
162 assignment_.LiteralIsTrue(
Literal(BooleanVariable(
i),
true)));
164 return postsolved_solution;
170 DCHECK_GT(clause.size(), 0) <<
"Added an empty clause to the presolver";
172 clauses_.push_back(std::vector<Literal>(clause.begin(), clause.end()));
173 in_clause_to_process_.push_back(
true);
174 clause_to_process_.push_back(ci);
176 bool changed =
false;
177 std::vector<Literal>& clause_ref = clauses_.back();
178 if (!equiv_mapping_.empty()) {
179 for (
int i = 0;
i < clause_ref.size(); ++
i) {
180 const Literal old_literal = clause_ref[
i];
181 clause_ref[
i] =
Literal(equiv_mapping_[clause_ref[
i]]);
182 if (old_literal != clause_ref[
i]) changed =
true;
185 std::sort(clause_ref.begin(), clause_ref.end());
186 clause_ref.erase(std::unique(clause_ref.begin(), clause_ref.end()),
190 for (
int i = 1;
i < clause_ref.size(); ++
i) {
191 if (clause_ref[
i] == clause_ref[
i - 1].Negated()) {
193 ++num_trivial_clauses_;
194 clause_to_process_.pop_back();
196 in_clause_to_process_.pop_back();
202 signatures_.push_back(ComputeSignatureOfClauseVariables(ci));
203 DCHECK_EQ(signatures_.size(), clauses_.size());
205 if (drat_proof_handler_ !=
nullptr && changed) {
206 drat_proof_handler_->AddClause(clause_ref);
207 drat_proof_handler_->DeleteClause(clause);
210 const Literal max_literal = clause_ref.back();
211 const int required_size = std::max(max_literal.
Index().value(),
214 if (required_size > literal_to_clauses_.size()) {
215 literal_to_clauses_.resize(required_size);
216 literal_to_clause_sizes_.resize(required_size);
219 literal_to_clauses_[e].push_back(ci);
220 literal_to_clause_sizes_[e]++;
225 const int required_size = 2 * num_variables;
226 if (required_size > literal_to_clauses_.size()) {
227 literal_to_clauses_.resize(required_size);
228 literal_to_clause_sizes_.resize(required_size);
232void SatPresolver::AddClauseInternal(std::vector<Literal>* clause) {
233 if (drat_proof_handler_ !=
nullptr) drat_proof_handler_->
AddClause(*clause);
235 DCHECK(std::is_sorted(clause->begin(), clause->end()));
236 DCHECK_GT(clause->size(), 0) <<
"TODO(user): Unsat during presolve?";
238 clauses_.push_back(std::vector<Literal>());
239 clauses_.back().swap(*clause);
240 in_clause_to_process_.push_back(
true);
241 clause_to_process_.push_back(ci);
242 for (
const Literal e : clauses_.back()) {
244 literal_to_clause_sizes_[e]++;
245 UpdatePriorityQueue(e.Variable());
246 UpdateBvaPriorityQueue(e.Index());
249 signatures_.push_back(ComputeSignatureOfClauseVariables(ci));
250 DCHECK_EQ(signatures_.size(), clauses_.size());
256 BooleanVariable new_var(0);
257 for (BooleanVariable var(0); var <
NumVariables(); ++var) {
258 if (literal_to_clause_sizes_[
Literal(var,
true)] > 0 ||
259 literal_to_clause_sizes_[
Literal(var,
false)] > 0) {
273 var_pq_elements_.clear();
274 in_clause_to_process_.clear();
275 clause_to_process_.clear();
276 literal_to_clauses_.clear();
282 for (BooleanVariable index : mapping) {
286 std::vector<Literal> temp;
288 for (std::vector<Literal>& clause_ref : clauses_) {
299bool SatPresolver::ProcessAllClauses() {
300 int num_skipped_checks = 0;
301 const int kCheckFrequency = 1000;
305 std::stable_sort(clause_to_process_.begin(), clause_to_process_.end(),
307 return clauses_[c1].size() < clauses_[c2].size();
309 while (!clause_to_process_.empty()) {
311 in_clause_to_process_[ci] =
false;
312 clause_to_process_.pop_front();
314 if (++num_skipped_checks >= kCheckFrequency) {
315 if (num_inspected_signatures_ + num_inspected_literals_ > 1e9) {
316 VLOG(1) <<
"Aborting ProcessAllClauses() because work limit has been "
320 if (time_limit_ !=
nullptr && time_limit_->
LimitReached())
return true;
321 num_skipped_checks = 0;
338 if (logger_->LoggingIsEnabled()) {
339 int64_t num_removable = 0;
340 for (
const bool b : can_be_removed) {
341 if (
b) ++num_removable;
344 "[SAT presolve] num removable Booleans: ", num_removable,
" / ",
345 can_be_removed.size());
347 "[SAT presolve] num trivial clauses: ", num_trivial_clauses_);
353 if (!ProcessAllClauses())
return false;
354 if (logger_->LoggingIsEnabled()) DisplayStats(timer.
Get());
356 if (time_limit_ !=
nullptr && time_limit_->LimitReached())
return true;
357 if (num_inspected_signatures_ + num_inspected_literals_ > 1e9)
return true;
359 InitializePriorityQueue();
360 while (var_pq_.Size() > 0) {
361 const BooleanVariable var = var_pq_.Top()->variable;
363 if (!can_be_removed[var.value()])
continue;
365 if (!ProcessAllClauses())
return false;
367 if (time_limit_ !=
nullptr && time_limit_->LimitReached())
return true;
368 if (num_inspected_signatures_ + num_inspected_literals_ > 1e9)
return true;
370 if (logger_->LoggingIsEnabled()) DisplayStats(timer.
Get());
373 if (parameters_.presolve_use_bva()) {
375 if (logger_->LoggingIsEnabled()) DisplayStats(timer.
Get());
383 var_pq_elements_.clear();
384 InitializeBvaPriorityQueue();
385 while (bva_pq_.Size() > 0) {
386 const LiteralIndex lit = bva_pq_.Top()->literal;
389 if (time_limit_ !=
nullptr && time_limit_->LimitReached())
break;
394void SatPresolver::SimpleBva(LiteralIndex l) {
395 literal_to_p_size_.
resize(literal_to_clauses_.size(), 0);
396 DCHECK(std::all_of(literal_to_p_size_.begin(), literal_to_p_size_.end(),
397 [](
int v) { return v == 0; }));
402 m_cls_ = literal_to_clauses_[l];
405 for (
int loop = 0; loop < 100; ++loop) {
409 flattened_p_.clear();
411 const std::vector<Literal>& clause = clauses_[c];
412 if (clause.empty())
continue;
416 const LiteralIndex l_min =
417 FindLiteralWithShortestOccurrenceListExcluding(clause, Literal(l));
422 for (
const ClauseIndex d : literal_to_clauses_[l_min]) {
423 if (clause.size() != clauses_[d].size())
continue;
424 const LiteralIndex l_diff =
427 if (l_diff == Literal(l).NegatedIndex()) {
432 VLOG(1) <<
"self-subsumbtion";
435 flattened_p_.push_back({l_diff, c});
436 const int new_size = ++literal_to_p_size_[l_diff];
437 if (new_size > max_size) {
445 const int new_m_lit_size = m_lit_.size() + 1;
446 const int new_m_cls_size = max_size;
447 const int new_reduction =
448 new_m_lit_size * new_m_cls_size - new_m_cls_size - new_m_lit_size;
450 if (new_reduction <= reduction)
break;
451 DCHECK_NE(1, new_m_lit_size);
452 DCHECK_NE(1, new_m_cls_size);
458 reduction = new_reduction;
463 for (
const auto& entry : flattened_p_) {
464 literal_to_p_size_[entry.first] = 0;
465 if (entry.first == lmax) m_cls_.push_back(entry.second);
467 flattened_p_.clear();
471 for (
const auto& entry : flattened_p_) literal_to_p_size_[entry.first] = 0;
472 flattened_p_.clear();
477 if (reduction <= parameters_.presolve_bva_threshold())
return;
478 DCHECK_GT(m_lit_.size(), 1);
481 const int old_size = literal_to_clauses_.size();
482 const LiteralIndex x_true = LiteralIndex(old_size);
483 const LiteralIndex x_false = LiteralIndex(old_size + 1);
484 literal_to_clauses_.resize(old_size + 2);
485 literal_to_clause_sizes_.resize(old_size + 2);
486 bva_pq_elements_.resize(old_size + 2);
487 bva_pq_elements_[x_true.value()].literal = x_true;
488 bva_pq_elements_[x_false.value()].literal = x_false;
491 if (drat_proof_handler_ !=
nullptr) drat_proof_handler_->AddOneVariable();
492 for (
const LiteralIndex lit : m_lit_) {
493 tmp_new_clause_ = {Literal(lit), Literal(x_true)};
494 AddClauseInternal(&tmp_new_clause_);
497 tmp_new_clause_ = clauses_[ci];
498 DCHECK(!tmp_new_clause_.empty());
499 for (Literal& ref : tmp_new_clause_) {
500 if (ref.Index() == l) {
501 ref = Literal(x_false);
509 std::sort(tmp_new_clause_.begin(), tmp_new_clause_.end());
510 AddClauseInternal(&tmp_new_clause_);
520 const std::vector<Literal>& clause = clauses_[
c];
521 DCHECK(!clause.empty());
522 const LiteralIndex l_min =
523 FindLiteralWithShortestOccurrenceListExcluding(clause, Literal(l));
524 for (
const LiteralIndex lit : m_lit_) {
525 if (lit == l)
continue;
526 for (
const ClauseIndex d : literal_to_clauses_[l_min]) {
527 if (clause.size() != clauses_[d].size())
continue;
528 const LiteralIndex l_diff =
544 AddToBvaPriorityQueue(x_true);
545 AddToBvaPriorityQueue(x_false);
546 AddToBvaPriorityQueue(l);
549uint64_t SatPresolver::ComputeSignatureOfClauseVariables(ClauseIndex ci) {
550 uint64_t signature = 0;
551 for (
const Literal l : clauses_[ci]) {
552 signature |= (uint64_t{1} << (l.Variable().value() % 64));
554 DCHECK_EQ(signature == 0, clauses_[ci].empty());
561bool SatPresolver::ProcessClauseToSimplifyOthersUsingLiteral(
562 ClauseIndex clause_index,
Literal lit) {
563 const std::vector<Literal>& clause = clauses_[clause_index];
564 const uint64_t clause_signature = signatures_[clause_index];
565 LiteralIndex opposite_literal;
570 bool need_cleaning =
false;
571 num_inspected_signatures_ += literal_to_clauses_[lit].size();
572 for (
const ClauseIndex ci : literal_to_clauses_[lit]) {
573 const uint64_t ci_signature = signatures_[ci];
577 DCHECK_EQ(ci_signature, ComputeSignatureOfClauseVariables(ci));
578 if (ci_signature == 0) {
579 need_cleaning =
true;
586 if (ci != clause_index && (clause_signature & ~ci_signature) == 0 &&
588 &num_inspected_literals_)) {
590 need_cleaning =
true;
594 DCHECK_NE(opposite_literal, lit.Index());
595 if (clauses_[ci].empty())
return false;
596 if (drat_proof_handler_ !=
nullptr) {
598 drat_proof_handler_->AddClause(clauses_[ci]);
602 signatures_[ci] = ComputeSignatureOfClauseVariables(ci);
608 --literal_to_clause_sizes_[opposite_literal];
609 UpdatePriorityQueue(Literal(opposite_literal).Variable());
611 if (!in_clause_to_process_[ci]) {
612 in_clause_to_process_[ci] =
true;
613 clause_to_process_.push_back(ci);
621 auto& occurrence_list_ref = literal_to_clauses_[lit];
623 if (signatures_[ci] != 0) occurrence_list_ref[new_index++] = ci;
625 occurrence_list_ref.resize(new_index);
626 DCHECK_EQ(literal_to_clause_sizes_[lit], new_index);
636 const std::vector<Literal>& clause = clauses_[clause_index];
637 if (clause.empty())
return true;
638 DCHECK(std::is_sorted(clause.begin(), clause.end()));
640 LiteralIndex opposite_literal;
641 const Literal lit = FindLiteralWithShortestOccurrenceList(clause);
643 if (!ProcessClauseToSimplifyOthersUsingLiteral(clause_index, lit)) {
649 const LiteralIndex other_lit_index =
650 FindLiteralWithShortestOccurrenceListExcluding(clause, lit);
652 literal_to_clause_sizes_[other_lit_index] <
654 return ProcessClauseToSimplifyOthersUsingLiteral(clause_index,
659 bool something_removed =
false;
660 auto& occurrence_list_ref = literal_to_clauses_[lit.
NegatedIndex()];
661 const uint64_t clause_signature = signatures_[clause_index];
663 const uint64_t ci_signature = signatures_[ci];
664 DCHECK_EQ(ci_signature, ComputeSignatureOfClauseVariables(ci));
665 if (ci_signature == 0)
continue;
671 if ((clause_signature & ~ci_signature) == 0 &&
673 &num_inspected_literals_)) {
675 if (clauses_[ci].empty())
return false;
676 if (drat_proof_handler_ !=
nullptr) {
678 drat_proof_handler_->AddClause(clauses_[ci]);
682 signatures_[ci] = ComputeSignatureOfClauseVariables(ci);
684 if (!in_clause_to_process_[ci]) {
685 in_clause_to_process_[ci] =
true;
686 clause_to_process_.push_back(ci);
688 something_removed =
true;
691 occurrence_list_ref[new_index] = ci;
694 occurrence_list_ref.resize(new_index);
695 literal_to_clause_sizes_[lit.
NegatedIndex()] = new_index;
696 if (something_removed) {
703void SatPresolver::RemoveAndRegisterForPostsolveAllClauseContaining(
Literal x) {
705 if (!clauses_[
i].empty()) RemoveAndRegisterForPostsolve(
i, x);
708 literal_to_clause_sizes_[x] = 0;
712 const int s1 = literal_to_clause_sizes_[x];
713 const int s2 = literal_to_clause_sizes_[x.NegatedIndex()];
717 if (s1 == 0 && s2 == 0)
return false;
721 if (s1 > 1 && s2 > 1 && s1 * s2 > parameters_.presolve_bve_threshold()) {
727 const int clause_weight = parameters_.presolve_bve_clause_weight();
729 if (!clauses_[
i].empty()) {
730 threshold += clause_weight + clauses_[
i].size();
733 for (
ClauseIndex i : literal_to_clauses_[x.NegatedIndex()]) {
734 if (!clauses_[
i].empty()) {
735 threshold += clause_weight + clauses_[
i].size();
740 if (s1 < s2) x = x.Negated();
745 if (clauses_[
i].empty())
continue;
746 bool no_resolvant =
true;
747 for (
ClauseIndex j : literal_to_clauses_[x.NegatedIndex()]) {
748 if (clauses_[j].empty())
continue;
751 no_resolvant =
false;
752 size += clause_weight + rs;
755 if (size > threshold)
return false;
758 if (no_resolvant && parameters_.presolve_blocked_clause()) {
771 RemoveAndRegisterForPostsolve(
i, x);
778 std::vector<Literal> temp;
780 if (clauses_[
i].empty())
continue;
781 for (
ClauseIndex j : literal_to_clauses_[x.NegatedIndex()]) {
782 if (clauses_[j].empty())
continue;
784 AddClauseInternal(&temp);
793 RemoveAndRegisterForPostsolveAllClauseContaining(x);
794 RemoveAndRegisterForPostsolveAllClauseContaining(x.Negated());
801void SatPresolver::Remove(ClauseIndex ci) {
803 for (
Literal e : clauses_[ci]) {
804 literal_to_clause_sizes_[e]--;
805 UpdatePriorityQueue(e.Variable());
806 UpdateBvaPriorityQueue(
Literal(e.Variable(),
true).
Index());
807 UpdateBvaPriorityQueue(
Literal(e.Variable(),
false).
Index());
809 if (drat_proof_handler_ !=
nullptr) {
815void SatPresolver::RemoveAndRegisterForPostsolve(ClauseIndex ci,
Literal x) {
816 postsolver_->Add(x, clauses_[ci]);
820Literal SatPresolver::FindLiteralWithShortestOccurrenceList(
821 const std::vector<Literal>& clause) {
822 DCHECK(!clause.empty());
823 Literal result = clause.front();
824 int best_size = literal_to_clause_sizes_[result];
825 for (
const Literal l : clause) {
826 const int size = literal_to_clause_sizes_[l];
827 if (size < best_size) {
835LiteralIndex SatPresolver::FindLiteralWithShortestOccurrenceListExcluding(
836 const std::vector<Literal>& clause,
Literal to_exclude) {
837 DCHECK(!clause.empty());
839 int num_occurrences = std::numeric_limits<int>::max();
840 for (
const Literal l : clause) {
841 if (l == to_exclude)
continue;
842 if (literal_to_clause_sizes_[l] < num_occurrences) {
844 num_occurrences = literal_to_clause_sizes_[l];
850void SatPresolver::UpdatePriorityQueue(BooleanVariable var) {
851 if (var_pq_elements_.empty())
return;
852 PQElement* element = &var_pq_elements_[var];
853 element->weight = literal_to_clause_sizes_[Literal(var,
true)] +
854 literal_to_clause_sizes_[Literal(var,
false)];
855 if (var_pq_.Contains(element)) {
856 var_pq_.NoteChangedPriority(element);
858 var_pq_.Add(element);
862void SatPresolver::InitializePriorityQueue() {
864 var_pq_elements_.resize(num_vars);
865 for (BooleanVariable var(0); var < num_vars; ++var) {
866 PQElement* element = &var_pq_elements_[var];
867 element->variable = var;
868 element->weight = literal_to_clause_sizes_[Literal(var,
true)] +
869 literal_to_clause_sizes_[Literal(var,
false)];
870 var_pq_.Add(element);
874void SatPresolver::UpdateBvaPriorityQueue(LiteralIndex lit) {
875 if (bva_pq_elements_.empty())
return;
876 DCHECK_LT(lit, bva_pq_elements_.size());
877 BvaPqElement* element = &bva_pq_elements_[lit.value()];
878 element->weight = literal_to_clause_sizes_[lit];
879 if (bva_pq_.Contains(element)) {
880 bva_pq_.NoteChangedPriority(element);
884void SatPresolver::AddToBvaPriorityQueue(LiteralIndex lit) {
885 if (bva_pq_elements_.empty())
return;
886 DCHECK_LT(lit, bva_pq_elements_.size());
887 BvaPqElement* element = &bva_pq_elements_[lit.value()];
888 element->weight = literal_to_clause_sizes_[lit];
889 DCHECK(!bva_pq_.Contains(element));
890 if (element->weight > 2) bva_pq_.Add(element);
893void SatPresolver::InitializeBvaPriorityQueue() {
896 bva_pq_elements_.assign(num_literals, BvaPqElement());
897 for (LiteralIndex lit(0); lit < num_literals; ++lit) {
898 BvaPqElement* element = &bva_pq_elements_[lit.value()];
899 element->literal = lit;
900 element->weight = literal_to_clause_sizes_[lit];
904 if (element->weight > 2) bva_pq_.Add(element);
908void SatPresolver::DisplayStats(
double elapsed_seconds) {
909 int num_literals = 0;
911 int num_singleton_clauses = 0;
912 for (
const std::vector<Literal>& c : clauses_) {
914 if (
c.size() == 1) ++num_singleton_clauses;
916 num_literals +=
c.size();
919 int num_one_side = 0;
920 int num_simple_definition = 0;
922 for (BooleanVariable var(0); var <
NumVariables(); ++var) {
923 const int s1 = literal_to_clause_sizes_[Literal(var,
true)];
924 const int s2 = literal_to_clause_sizes_[Literal(var,
false)];
925 if (s1 == 0 && s2 == 0)
continue;
928 if (s1 == 0 || s2 == 0) {
930 }
else if (s1 == 1 || s2 == 1) {
931 num_simple_definition++;
934 SOLVER_LOG(logger_,
"[SAT presolve] [", elapsed_seconds,
"s]",
935 " clauses:", num_clauses,
" literals:", num_literals,
936 " vars:", num_vars,
" one_side_vars:", num_one_side,
937 " simple_definition:", num_simple_definition,
938 " singleton_clauses:", num_singleton_clauses);
942 LiteralIndex* opposite_literal,
943 int64_t* num_inspected_literals) {
944 if (
b->size() < a.size())
return false;
945 DCHECK(std::is_sorted(a.begin(), a.end()));
946 DCHECK(std::is_sorted(
b->begin(),
b->end()));
947 if (num_inspected_literals !=
nullptr) {
948 *num_inspected_literals += a.size();
949 *num_inspected_literals +=
b->size();
952 *opposite_literal = LiteralIndex(-1);
955 std::vector<Literal>::const_iterator ia = a.begin();
956 std::vector<Literal>::const_iterator ib =
b->begin();
957 std::vector<Literal>::const_iterator to_remove;
961 int size_diff =
b->size() - a.size();
962 while (ia != a.end() ) {
966 }
else if (*ia == ib->Negated()) {
968 if (num_diff > 1)
return false;
972 }
else if (*ia < *ib) {
979 if (--size_diff < 0)
return false;
983 *opposite_literal = to_remove->Index();
990 const std::vector<Literal>&
b,
Literal l) {
991 DCHECK_EQ(
b.size(), a.size());
992 DCHECK(std::is_sorted(a.begin(), a.end()));
993 DCHECK(std::is_sorted(
b.begin(),
b.end()));
995 std::vector<Literal>::const_iterator ia = a.begin();
996 std::vector<Literal>::const_iterator ib =
b.begin();
997 while (ia != a.end() && ib !=
b.end()) {
1001 }
else if (*ia < *ib) {
1010 result = (*ib).Index();
1016 if (ib !=
b.end()) {
1018 result = (*ib).Index();
1024 const std::vector<Literal>&
b,
1025 std::vector<Literal>* out) {
1026 DCHECK(std::is_sorted(a.begin(), a.end()));
1027 DCHECK(std::is_sorted(
b.begin(),
b.end()));
1030 std::vector<Literal>::const_iterator ia = a.begin();
1031 std::vector<Literal>::const_iterator ib =
b.begin();
1032 while ((ia != a.end()) && (ib !=
b.end())) {
1034 out->push_back(*ia);
1037 }
else if (*ia == ib->Negated()) {
1038 if (*ia != x)
return false;
1039 DCHECK_EQ(*ib, x.Negated());
1042 }
else if (*ia < *ib) {
1043 out->push_back(*ia);
1046 out->push_back(*ib);
1052 out->insert(out->end(), ia, a.end());
1053 out->insert(out->end(), ib,
b.end());
1059 const std::vector<Literal>&
b) {
1060 DCHECK(std::is_sorted(a.begin(), a.end()));
1061 DCHECK(std::is_sorted(
b.begin(),
b.end()));
1063 int size =
static_cast<int>(a.size() +
b.size()) - 2;
1064 std::vector<Literal>::const_iterator ia = a.begin();
1065 std::vector<Literal>::const_iterator ib =
b.begin();
1066 while ((ia != a.end()) && (ib !=
b.end())) {
1071 }
else if (*ia == ib->Negated()) {
1072 if (*ia != x)
return -1;
1073 DCHECK_EQ(*ib, x.Negated());
1076 }
else if (*ia < *ib) {
1097 deterministic_time_limit(solver->deterministic_time() +
1098 deterministic_time_limit) {}
1108 scratchpad_.clear();
1109 solver_->Backtrack(0);
1116 if (solver_->deterministic_time() > deterministic_time_limit) {
1121 if (!solver_->Assignment().LiteralIsAssigned(l)) {
1122 const int trail_index = solver_->LiteralTrail().Index();
1123 solver_->EnqueueDecisionAndBackjumpOnConflict(l);
1124 if (solver_->CurrentDecisionLevel() > 0) {
1126 for (
int i = trail_index + 1;
i < solver_->LiteralTrail().Index();
1128 scratchpad_.push_back(solver_->LiteralTrail()[
i].Index().value());
1136 mutable std::vector<int32_t> scratchpad_;
1138 const double deterministic_time_limit;
1154 solver->
parameters().presolve_probing_deterministic_time_limit(), solver);
1156 std::vector<std::vector<int32_t>> scc;
1169 for (
const std::vector<int32_t>& component : scc) {
1170 if (component.size() > 1) {
1171 if (mapping->empty()) mapping->
resize(size, LiteralIndex(-1));
1172 const Literal representative((LiteralIndex(component[0])));
1173 for (
int i = 1;
i < component.size(); ++
i) {
1174 const Literal l((LiteralIndex(component[
i])));
1186 representative.
Index().value()))),
1195 if (!mapping->empty()) {
1205 for (LiteralIndex
i(0);
i < size; ++
i) {
1213 if (drat_proof_handler !=
nullptr) {
1214 drat_proof_handler->
AddClause({true_lit});
1218 for (LiteralIndex
i(0);
i < size; ++
i) {
1220 (*mapping)[
i] = rep;
1227 if (drat_proof_handler !=
nullptr) {
1228 drat_proof_handler->
AddClause({true_lit});
1237 if (drat_proof_handler !=
nullptr) {
1238 drat_proof_handler->
AddClause({true_lit});
1241 }
else if (rep !=
i) {
1244 if (drat_proof_handler !=
nullptr) {
1251 if (logger !=
nullptr) {
1252 SOLVER_LOG(logger,
"[Pure SAT probing] fixed ", num_already_fixed_vars,
1254 " equiv ", num_equiv / 2,
" total ", solver->
NumVariables(),
1255 " wtime: ", timer.
Get());
1257 const bool log_info =
1258 solver->
parameters().log_search_progress() || VLOG_IS_ON(1);
1259 LOG_IF(INFO, log_info) <<
"Probing. fixed " << num_already_fixed_vars
1262 num_already_fixed_vars
1263 <<
" equiv " << num_equiv / 2 <<
" total "
1265 <<
" 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)
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,...)