24#include "absl/cleanup/cleanup.h"
25#include "absl/container/inlined_vector.h"
26#include "absl/log/check.h"
27#include "absl/random/distributions.h"
28#include "absl/types/span.h"
39#include "ortools/sat/sat_parameters.pb.h"
53 clauses.emplace_back(clause.begin(), clause.end());
54 for (
int i = 0;
i < clause.size(); ++
i) {
64#define RETURN_IF_FALSE(f) \
65 if (!(f)) return false;
72 double probing_time = 0.0;
73 const bool log_round_info = VLOG_IS_ON(1);
114 !implication_graph_->
IsDag()) {
120 !implication_graph_->
IsDag()) {
127 if (!params_.fill_tightened_domains_in_response()) {
128 blocked_clause_simplifier_->
DoOneRound(log_round_info);
137 const double saved_wtime = wall_timer.
Get();
138 const double time_left =
140 if (time_left <= 0)
break;
142 probing_options.
log_info = log_round_info;
147 probing_time += wall_timer.
Get() - saved_wtime;
150 !implication_graph_->
IsDag()) {
161 logger_,
"[Pure SAT presolve]",
" num_fixed: ", trail_->
Index(),
168 " non-probing time: ", (wall_timer.
Get() - probing_time));
177 const bool log_info = VLOG_IS_ON(1);
178 const bool log_round_info = VLOG_IS_ON(2);
182 double probing_time = 0.0;
186 if (first_inprocessing_call_) {
187 reference_dtime_ = start_dtime;
188 first_inprocessing_call_ =
false;
196 const double diff = start_dtime - reference_dtime_;
197 if (total_dtime_ > params_.inprocessing_dtime_ratio() * diff) {
206 std::vector<std::pair<LinearProgrammingConstraint*, bool>> saved_state;
208 saved_state.push_back({lp, lp->PropagationIsEnabled()});
209 lp->EnablePropagation(
false);
211 auto cleanup = absl::MakeCleanup([&saved_state]() {
212 for (
const auto [lp, old_value] : saved_state) {
213 lp->EnablePropagation(old_value);
230 if (params_.inprocessing_probing_dtime() > 0.0) {
231 const double saved_wtime = wall_timer.
Get();
233 probing_options.
log_info = log_round_info;
237 probing_time += wall_timer.
Get() - saved_wtime;
249 const auto old_counter = sat_solver_->
counters();
250 if (params_.inprocessing_minimization_dtime() > 0.0) {
252 params_.inprocessing_minimization_dtime()));
254 const int64_t mini_num_clause =
256 old_counter.minimization_num_clauses;
257 const int64_t mini_num_removed =
259 old_counter.minimization_num_removed_literals;
268 blocked_clause_simplifier_->
DoOneRound(log_round_info);
277 logger_,
"Inprocessing.",
" fixed:", trail_->
Index(),
282 " minimization:", mini_num_clause,
"|", mini_num_removed,
284 " wtime:", wall_timer.
Get(),
285 " np_wtime:", (wall_timer.
Get() - probing_time));
293#undef RETURN_IF_FALSE
296 const int64_t new_num_fixed_variables = trail_->
Index();
297 return last_num_fixed_variables_ < new_num_fixed_variables;
301 const int64_t new_num_redundant_literals =
303 return last_num_redundant_literals_ < new_num_redundant_literals;
318 if (!implication_graph_->
IsDag()) {
324 if (use_transitive_reduction) {
351 const int64_t new_num_redundant_literals =
353 const int64_t new_num_fixed_variables = trail_->
Index();
354 if (last_num_redundant_literals_ == new_num_redundant_literals &&
355 last_num_fixed_variables_ == new_num_fixed_variables) {
358 last_num_fixed_variables_ = new_num_fixed_variables;
359 last_num_redundant_literals_ = new_num_redundant_literals;
365 int64_t num_removed_literals = 0;
366 int64_t num_inspected_literals = 0;
370 std::vector<Literal> new_clause;
373 const int num_literals(sat_solver_->
NumVariables() * 2);
379 bool removed =
false;
380 bool need_rewrite =
false;
383 for (
const Literal l : clause->AsSpan()) {
390 num_removed_literals += clause->size();
400 num_inspected_literals += clause->size();
401 if (removed || !need_rewrite)
continue;
402 num_inspected_literals += clause->size();
406 for (
const Literal l : clause->AsSpan()) {
413 num_removed_literals += clause->size();
418 new_clause.push_back(r);
422 for (
const Literal l : new_clause) marked[l] =
false;
423 if (removed)
continue;
425 num_removed_literals += clause->size() - new_clause.size();
432 const double dtime =
static_cast<double>(num_inspected_literals) * 1e-8;
434 LOG_IF(INFO, log_info) <<
"Cleanup. num_removed_literals: "
435 << num_removed_literals <<
" dtime: " << dtime
436 <<
" wtime: " << wall_timer.
Get();
449 int64_t num_subsumed_clauses = 0;
450 int64_t num_removed_literals = 0;
451 int64_t num_inspected_signatures = 0;
452 int64_t num_inspected_literals = 0;
456 std::vector<Literal> new_clause;
468 std::vector<SatClause*> clauses =
471 clauses.begin(), clauses.end(),
475 const LiteralIndex num_literals(sat_solver_->
NumVariables() * 2);
481 one_watcher(num_literals.value());
484 std::vector<uint64_t> signatures(clauses.size());
486 std::vector<Literal> candidates_for_removal;
487 for (
int clause_index = 0; clause_index < clauses.size(); ++clause_index) {
488 SatClause* clause = clauses[clause_index];
494 if (num_inspected_literals + num_inspected_signatures > 1e9) {
509 uint64_t signature = 0;
512 marked.
Set(l.Index());
513 signature |= (uint64_t{1} << (l.Variable().
value() % 64));
519 bool removed =
false;
520 candidates_for_removal.clear();
521 const uint64_t mask = ~signature;
523 num_inspected_signatures += one_watcher[l].size();
524 for (
const int i : one_watcher[l]) {
525 if ((mask & signatures[
i]) != 0)
continue;
527 bool subsumed =
true;
528 bool stengthen =
true;
530 num_inspected_literals += clauses[
i]->size();
531 for (
const Literal o : clauses[
i]->AsSpan()) {
535 to_remove = o.NegatedIndex();
543 ++num_subsumed_clauses;
544 num_removed_literals += clause->
size();
551 candidates_for_removal.push_back(
Literal(to_remove));
556 if (removed)
continue;
560 num_inspected_signatures += one_watcher[l.NegatedIndex()].size();
561 for (
const int i : one_watcher[l.NegatedIndex()]) {
562 if ((mask & signatures[
i]) != 0)
continue;
564 bool stengthen =
true;
565 num_inspected_literals += clauses[
i]->size();
566 for (
const Literal o : clauses[
i]->AsSpan()) {
567 if (o == l.Negated())
continue;
574 candidates_for_removal.push_back(l);
585 if (!candidates_for_removal.empty()) {
588 if (l == candidates_for_removal[0])
continue;
589 new_clause.push_back(l);
591 CHECK_EQ(new_clause.size() + 1, clause->
size());
593 num_removed_literals += clause->
size() - new_clause.size();
597 if (clause->
size() == 0)
continue;
602 signature |= (uint64_t{1} << (l.Variable().
value() % 64));
620 int min_size = std::numeric_limits<int32_t>::max();
623 if (one_watcher[l].
size() < min_size) {
624 min_size = one_watcher[l].size();
625 min_literal = l.Index();
635 signatures[clause_index] = signature;
636 one_watcher[min_literal].
push_back(clause_index);
644 const double dtime =
static_cast<double>(num_inspected_signatures) * 1e-8 +
645 static_cast<double>(num_inspected_literals) * 5e-9;
647 LOG_IF(INFO, log_info) <<
"Subsume. num_removed_literals: "
648 << num_removed_literals
649 <<
" num_subsumed: " << num_subsumed_clauses
650 <<
" dtime: " << dtime
651 <<
" wtime: " << wall_timer.
Get();
660 num_subsumed_clauses_ = 0;
661 num_removed_literals_ = 0;
664 if (implication_graph_->
literal_size() == 0)
return true;
667 if (!stamps_are_already_computed_) {
676 stamps_are_already_computed_ =
false;
682 LOG_IF(INFO, log_info) <<
"Stamping. num_removed_literals: "
683 << num_removed_literals_
684 <<
" num_subsumed: " << num_subsumed_clauses_
685 <<
" num_fixed: " << num_fixed_ <<
" dtime: " << dtime_
686 <<
" wtime: " << wall_timer.
Get();
696 if (implication_graph_->
literal_size() == 0)
return true;
703 stamps_are_already_computed_ =
true;
707 LOG_IF(INFO, log_info) <<
"Prestamping." <<
" num_fixed: " << num_fixed_
708 <<
" dtime: " << dtime_
709 <<
" wtime: " << wall_timer.
Get();
715 CHECK(implication_graph_->
IsDag());
717 for (LiteralIndex
i(0);
i <
size; ++
i) {
730 for (
int num_tries = 0; num_tries < 10; ++num_tries) {
733 const LiteralIndex
index =
738 if (implication_graph_->
IsRedundant(candidate))
continue;
739 if (
i == candidate.
Index())
continue;
742 parents_[
i] = candidate.
Index();
753 for (LiteralIndex
i(0);
i <
size; ++
i) {
754 if (parents_[
i] ==
i)
continue;
755 sizes_[parents_[
i]]++;
760 starts_[LiteralIndex(0)] = 0;
761 for (LiteralIndex
i(1);
i <=
size; ++
i) {
762 starts_[
i] = starts_[
i - 1] + sizes_[
i - 1];
766 children_.resize(
size);
767 for (LiteralIndex
i(0);
i <
size; ++
i) {
768 if (parents_[
i] ==
i)
continue;
769 children_[starts_[parents_[
i]]++] =
i;
773 for (LiteralIndex
i(0);
i <
size; ++
i) {
774 starts_[
i] -= sizes_[
i];
778 CHECK_EQ(starts_[LiteralIndex(0)], 0);
779 for (LiteralIndex
i(1);
i <=
size; ++
i) {
780 CHECK_EQ(starts_[
i], starts_[
i - 1] + sizes_[
i - 1]);
789 for (LiteralIndex
i(0);
i <
size; ++
i) {
790 if (parents_[
i] !=
i)
continue;
792 const LiteralIndex tree_root =
i;
793 dfs_stack_.push_back(
i);
794 while (!dfs_stack_.empty()) {
795 const LiteralIndex top = dfs_stack_.back();
797 dfs_stack_.pop_back();
798 last_stamps_[top] =
stamp++;
801 first_stamps_[top] =
stamp++;
806 if (marked_[
Literal(top).NegatedIndex()] &&
807 first_stamps_[
Literal(top).NegatedIndex()] >=
808 first_stamps_[tree_root]) {
811 LiteralIndex lca = top;
812 while (first_stamps_[lca] > first_stamp) {
821 const int end = starts_[top + 1];
822 for (
int j = starts_[top]; j <
end; ++j) {
823 DCHECK_NE(top, children_[j]);
824 DCHECK(!marked_[children_[j]]);
825 dfs_stack_.push_back(children_[j]);
839 bool operator<(
const Entry& o)
const {
return start < o.start; }
841 std::vector<int> to_remove;
842 std::vector<Literal> new_clause;
843 std::vector<Entry> entries;
847 const auto span = clause->AsSpan();
848 if (span.empty())
continue;
857 for (
int i = 0;
i < span.size(); ++
i) {
864 {
i,
false, first_stamps_[span[
i]], last_stamps_[span[
i]]});
865 entries.push_back({
i,
true, first_stamps_[span[
i].NegatedIndex()],
866 last_stamps_[span[
i].NegatedIndex()]});
868 if (clause->IsRemoved())
continue;
871 if (!entries.empty()) {
872 const double n =
static_cast<double>(entries.size());
873 dtime_ += 1.5e-8 * n * std::log(n);
874 std::sort(entries.begin(), entries.end());
880 for (
const Entry& e : entries) {
881 if (e.end < top_entry.end) {
883 const Literal lhs = top_entry.is_negated ? span[top_entry.i].Negated()
885 const Literal rhs = e.is_negated ? span[e.i].
Negated() : span[e.i];
888 if (top_entry.is_negated != e.is_negated) {
890 if (top_entry.i == e.i) {
892 if (top_entry.is_negated) {
901 span[top_entry.i].Negated())) {
904 to_remove.push_back(top_entry.i);
913 if (top_entry.is_negated) {
914 num_subsumed_clauses_++;
919 CHECK_NE(top_entry.i, e.i);
920 if (top_entry.is_negated) {
922 to_remove.push_back(e.i);
931 to_remove.push_back(top_entry.i);
939 if (clause->IsRemoved())
continue;
942 if (!to_remove.empty() || entries.size() < span.size()) {
945 int to_remove_index = 0;
946 for (
int i = 0;
i < span.size(); ++
i) {
947 if (to_remove_index < to_remove.size() &&
948 i == to_remove[to_remove_index]) {
957 new_clause.push_back(span[
i]);
959 num_removed_literals_ += span.size() - new_clause.size();
973 num_blocked_clauses_ = 0;
974 num_inspected_literals_ = 0;
976 InitializeForNewRound();
978 while (!time_limit_->
LimitReached() && !queue_.empty()) {
979 const Literal l = queue_.front();
980 in_queue_[l] =
false;
985 if (num_inspected_literals_ <= 1e9) ProcessLiteral(l);
989 literal_to_clauses_.clear();
991 dtime_ += 1e-8 * num_inspected_literals_;
993 log_info |= VLOG_IS_ON(1);
994 LOG_IF(INFO, log_info) <<
"Blocked clause. num_blocked_clauses: "
995 << num_blocked_clauses_ <<
" dtime: " << dtime_
996 <<
" wtime: " << wall_timer.
Get();
999void BlockedClauseSimplifier::InitializeForNewRound() {
1007 clauses_.push_back(c);
1009 const int num_literals = clause_manager_->
literal_size();
1013 in_queue_.
assign(num_literals,
true);
1014 for (LiteralIndex l(0); l < num_literals; ++l) {
1015 queue_.push_back(Literal(l));
1018 marked_.
resize(num_literals);
1020 std::all_of(marked_.begin(), marked_.end(), [](
bool b) { return !b; }));
1024 literal_to_clauses_.clear();
1025 literal_to_clauses_.
resize(num_literals);
1026 for (ClauseIndex
i(0);
i < clauses_.size(); ++
i) {
1027 for (
const Literal l : clauses_[
i]->AsSpan()) {
1030 num_inspected_literals_ += clauses_[
i]->size();
1034void BlockedClauseSimplifier::ProcessLiteral(Literal current_literal) {
1036 if (implication_graph_->
IsRemoved(current_literal))
return;
1051 const std::vector<Literal>& implications =
1053 for (
const Literal l : implications) {
1054 if (l == current_literal)
continue;
1062 std::vector<ClauseIndex> clauses_to_process;
1063 for (
const ClauseIndex
i : literal_to_clauses_[current_literal]) {
1064 if (clauses_[
i]->IsRemoved())
continue;
1070 if (num_binary > 0) {
1071 if (clauses_[
i]->
size() <= num_binary)
continue;
1072 int num_with_negation_marked = 0;
1073 for (
const Literal l : clauses_[
i]->AsSpan()) {
1074 if (l == current_literal)
continue;
1075 if (marked_[l.NegatedIndex()]) {
1076 ++num_with_negation_marked;
1079 num_inspected_literals_ += clauses_[
i]->size();
1080 if (num_with_negation_marked < num_binary)
continue;
1082 clauses_to_process.push_back(
i);
1086 for (
const Literal l : implications) {
1098 for (
const ClauseIndex
i : clauses_to_process) {
1099 const auto c = clauses_[
i]->AsSpan();
1100 if (ClauseIsBlocked(current_literal, c)) {
1107 for (
const Literal l : c) {
1108 if (!in_queue_[l.NegatedIndex()]) {
1109 in_queue_[l.NegatedIndex()] =
true;
1110 queue_.push_back(l.Negated());
1118 ++num_blocked_clauses_;
1125bool BlockedClauseSimplifier::ClauseIsBlocked(
1126 Literal current_literal, absl::Span<const Literal> clause) {
1127 bool is_blocked =
true;
1128 for (
const Literal l : clause) marked_[l] =
true;
1132 for (
const ClauseIndex
i :
1133 literal_to_clauses_[current_literal.NegatedIndex()]) {
1134 if (clauses_[
i]->IsRemoved())
continue;
1135 bool some_marked =
false;
1136 for (
const Literal l : clauses_[
i]->AsSpan()) {
1138 ++num_inspected_literals_;
1140 if (l == current_literal.Negated())
continue;
1141 if (marked_[l.NegatedIndex()]) {
1152 for (
const Literal l : clause) marked_[l] =
false;
1161 num_inspected_literals_ = 0;
1162 num_eliminated_variables_ = 0;
1163 num_literals_diff_ = 0;
1164 num_clauses_diff_ = 0;
1165 num_simplifications_ = 0;
1166 num_blocked_clauses_ = 0;
1177 clauses_.push_back(c);
1179 const int num_literals = clause_manager_->
literal_size();
1180 const int num_variables = num_literals / 2;
1182 literal_to_clauses_.clear();
1183 literal_to_clauses_.
resize(num_literals);
1184 literal_to_num_clauses_.
assign(num_literals, 0);
1185 for (ClauseIndex
i(0);
i < clauses_.size(); ++
i) {
1186 for (
const Literal l : clauses_[
i]->AsSpan()) {
1188 literal_to_num_clauses_[l]++;
1190 num_inspected_literals_ += clauses_[
i]->size();
1193 const int saved_trail_index = trail_->
Index();
1194 propagation_index_ = trail_->
Index();
1196 need_to_be_updated_.clear();
1197 in_need_to_be_updated_.
resize(num_variables);
1198 queue_.
Reserve(num_variables);
1199 for (BooleanVariable v(0); v < num_variables; ++v) {
1201 UpdatePriorityQueue(v);
1204 marked_.
resize(num_literals);
1206 std::all_of(marked_.begin(), marked_.end(), [](
bool b) { return !b; }));
1212 const BooleanVariable top = queue_.
Top().var;
1220 bool is_unsat =
false;
1221 if (!Propagate())
return false;
1223 if (!Propagate())
return false;
1225 if (is_unsat)
return false;
1227 if (!CrossProduct(top))
return false;
1229 for (
const BooleanVariable v : need_to_be_updated_) {
1230 in_need_to_be_updated_[v] =
false;
1233 if (v != top) UpdatePriorityQueue(v);
1235 in_need_to_be_updated_.clear();
1236 need_to_be_updated_.clear();
1239 if (!Propagate())
return false;
1245 bool remove =
false;
1246 for (
const Literal l : c->AsSpan()) {
1256 literal_to_clauses_.clear();
1257 literal_to_num_clauses_.clear();
1259 dtime_ += 1e-8 * num_inspected_literals_;
1261 log_info |= VLOG_IS_ON(1);
1262 LOG_IF(INFO, log_info) <<
"BVE." <<
" num_fixed: "
1263 << trail_->
Index() - saved_trail_index
1264 <<
" num_simplified_literals: " << num_simplifications_
1265 <<
" num_blocked_clauses_: " << num_blocked_clauses_
1266 <<
" num_eliminations: " << num_eliminated_variables_
1267 <<
" num_literals_diff: " << num_literals_diff_
1268 <<
" num_clause_diff: " << num_clauses_diff_
1269 <<
" dtime: " << dtime_
1270 <<
" wtime: " << wall_timer.
Get();
1274bool BoundedVariableElimination::RemoveLiteralFromClause(
1276 num_literals_diff_ -= sat_clause->
size();
1280 literal_to_num_clauses_[l]--;
1284 num_clauses_diff_--;
1288 resolvant_.push_back(l);
1294 --num_clauses_diff_;
1295 for (
const Literal l : resolvant_) literal_to_num_clauses_[l]--;
1297 num_literals_diff_ += sat_clause->
size();
1302bool BoundedVariableElimination::Propagate() {
1303 for (; propagation_index_ < trail_->
Index(); ++propagation_index_) {
1305 if (!implication_graph_->
Propagate(trail_))
return false;
1307 const Literal l = (*trail_)[propagation_index_];
1308 for (
const ClauseIndex
index : literal_to_clauses_[l]) {
1309 if (clauses_[
index]->IsRemoved())
continue;
1310 num_clauses_diff_--;
1311 num_literals_diff_ -= clauses_[
index]->size();
1314 literal_to_clauses_[l].clear();
1315 for (
const ClauseIndex
index : literal_to_clauses_[l.NegatedIndex()]) {
1316 if (clauses_[
index]->IsRemoved())
continue;
1317 if (!RemoveLiteralFromClause(l.Negated(), clauses_[
index]))
return false;
1319 literal_to_clauses_[l.NegatedIndex()].clear();
1326int BoundedVariableElimination::NumClausesContaining(Literal l) {
1327 return literal_to_num_clauses_[l] +
1332void BoundedVariableElimination::UpdatePriorityQueue(BooleanVariable
var) {
1334 if (implication_graph_->
IsRemoved(Literal(
var,
true)))
return;
1336 const int priority = -NumClausesContaining(Literal(
var,
true)) -
1337 NumClausesContaining(Literal(
var,
false));
1341 queue_.
Add({
var, priority});
1345void BoundedVariableElimination::DeleteClause(SatClause* sat_clause) {
1346 const auto clause = sat_clause->AsSpan();
1348 num_clauses_diff_--;
1349 num_literals_diff_ -= clause.size();
1352 for (
const Literal l : clause) {
1353 literal_to_num_clauses_[l]--;
1354 if (!in_need_to_be_updated_[l.Variable()]) {
1355 in_need_to_be_updated_[l.Variable()] =
true;
1356 need_to_be_updated_.push_back(l.Variable());
1364void BoundedVariableElimination::DeleteAllClausesContaining(Literal
literal) {
1365 for (
const ClauseIndex
i : literal_to_clauses_[
literal]) {
1366 const auto clause = clauses_[
i]->AsSpan();
1367 if (clause.empty())
continue;
1369 DeleteClause(clauses_[
i]);
1371 literal_to_clauses_[
literal].clear();
1374void BoundedVariableElimination::AddClause(absl::Span<const Literal> clause) {
1376 if (pt ==
nullptr)
return;
1378 num_clauses_diff_++;
1379 num_literals_diff_ += clause.size();
1381 const ClauseIndex
index(clauses_.size());
1382 clauses_.push_back(pt);
1383 for (
const Literal l : clause) {
1384 literal_to_num_clauses_[l]++;
1386 if (!in_need_to_be_updated_[l.Variable()]) {
1387 in_need_to_be_updated_[l.Variable()] =
true;
1388 need_to_be_updated_.push_back(l.Variable());
1393template <
bool score_only,
bool with_binary_only>
1394bool BoundedVariableElimination::ResolveAllClauseContaining(Literal
lit) {
1395 const int clause_weight = parameters_.presolve_bve_clause_weight();
1397 const std::vector<Literal>& implications =
1399 auto& clause_containing_lit = literal_to_clauses_[
lit];
1400 for (
int i = 0;
i < clause_containing_lit.size(); ++
i) {
1401 const ClauseIndex clause_index = clause_containing_lit[
i];
1402 const auto clause = clauses_[clause_index]->AsSpan();
1403 if (clause.empty())
continue;
1405 if (!score_only) resolvant_.clear();
1406 for (
const Literal l : clause) {
1407 if (!score_only && l !=
lit) resolvant_.push_back(l);
1410 DCHECK(marked_[
lit]);
1411 num_inspected_literals_ += clause.size() + implications.size();
1415 bool clause_can_be_simplified =
false;
1416 const int64_t saved_score = new_score_;
1419 for (
const Literal l : implications) {
1421 if (marked_[l.NegatedIndex()])
continue;
1423 clause_can_be_simplified =
true;
1427 new_score_ += clause_weight + clause.size();
1429 resolvant_.push_back(l);
1430 AddClause(resolvant_);
1431 resolvant_.pop_back();
1437 if (!with_binary_only && !clause_can_be_simplified) {
1438 auto& clause_containing_not_lit = literal_to_clauses_[
lit.NegatedIndex()];
1439 for (
int j = 0; j < clause_containing_not_lit.size(); ++j) {
1440 if (score_only && new_score_ > score_threshold_)
break;
1441 const ClauseIndex other_index = clause_containing_not_lit[j];
1442 const auto other = clauses_[other_index]->AsSpan();
1443 if (other.empty())
continue;
1444 bool trivial =
false;
1446 for (
const Literal l : other) {
1448 ++num_inspected_literals_;
1449 if (l ==
lit.Negated())
continue;
1450 if (marked_[l.NegatedIndex()]) {
1456 if (!score_only) resolvant_.push_back(l);
1460 if (!score_only) resolvant_.resize(resolvant_.size() - extra_size);
1466 if (score_only && clause.size() + extra_size <= other.size()) {
1472 if (
false) DCHECK_EQ(clause.size() + extra_size, other.size());
1473 ++num_simplifications_;
1477 score_threshold_ -= clause_weight + other.size();
1479 if (extra_size == 0) {
1483 DeleteClause(clauses_[other_index]);
1485 if (!RemoveLiteralFromClause(
lit.Negated(),
1486 clauses_[other_index])) {
1489 std::swap(clause_containing_not_lit[j],
1490 clause_containing_not_lit.back());
1491 clause_containing_not_lit.pop_back();
1497 if (extra_size == 0) {
1498 clause_can_be_simplified =
true;
1503 if (clause.size() - 1 + extra_size > 100) {
1504 new_score_ = score_threshold_ + 1;
1508 new_score_ += clause_weight + clause.size() - 1 + extra_size;
1510 AddClause(resolvant_);
1511 resolvant_.resize(resolvant_.size() - extra_size);
1518 for (
const Literal l : clause) marked_[l] =
false;
1521 if (clause_can_be_simplified) {
1522 ++num_simplifications_;
1525 new_score_ = saved_score;
1526 score_threshold_ -= clause_weight + clause.size();
1528 if (!RemoveLiteralFromClause(
lit, clauses_[clause_index]))
return false;
1529 std::swap(clause_containing_lit[
i], clause_containing_lit.back());
1530 clause_containing_lit.pop_back();
1534 if (score_only && new_score_ > score_threshold_)
return true;
1546 if (score_only && !with_binary_only && !clause_can_be_simplified &&
1547 new_score_ == saved_score) {
1548 ++num_blocked_clauses_;
1549 score_threshold_ -= clause_weight + clause.size();
1551 DeleteClause(clauses_[clause_index]);
1557bool BoundedVariableElimination::CrossProduct(BooleanVariable
var) {
1560 const Literal
lit(
var,
true);
1561 const Literal not_lit(
var,
false);
1564 const int s1 = NumClausesContaining(
lit);
1565 const int s2 = NumClausesContaining(not_lit);
1566 if (s1 == 0 && s2 == 0)
return true;
1567 if (s1 > 0 && s2 == 0) {
1568 num_eliminated_variables_++;
1570 DeleteAllClausesContaining(
lit);
1573 if (s1 == 0 && s2 > 0) {
1574 num_eliminated_variables_++;
1576 DeleteAllClausesContaining(not_lit);
1582 if (s1 > 1 && s2 > 1 && s1 * s2 > parameters_.presolve_bve_threshold()) {
1595 const int clause_weight = parameters_.presolve_bve_clause_weight();
1599 (clause_weight + 2);
1600 for (
const ClauseIndex
i : literal_to_clauses_[
lit]) {
1601 const auto c = clauses_[
i]->AsSpan();
1602 if (!
c.empty()) score += clause_weight +
c.size();
1604 for (
const ClauseIndex
i : literal_to_clauses_[not_lit]) {
1605 const auto c = clauses_[
i]->AsSpan();
1606 if (!
c.empty()) score += clause_weight +
c.size();
1617 score_threshold_ = score;
1619 (clause_weight + 2);
1620 if (new_score_ > score_threshold_)
return true;
1621 if (!ResolveAllClauseContaining<
true,
1625 if (new_score_ > score_threshold_)
return true;
1626 if (!ResolveAllClauseContaining<
true,
1630 if (new_score_ > score_threshold_)
return true;
1633 if (new_score_ > 0) {
1634 if (!ResolveAllClauseContaining<
false,
1638 if (!ResolveAllClauseContaining<
false,
1644 ++num_eliminated_variables_;
1646 DeleteAllClausesContaining(
lit);
1647 DeleteAllClausesContaining(not_lit);
void Start()
When Start() is called multiple times, only the most recent is used.
void Add(Element element)
void ChangePriority(Element element)
bool Contains(int index) const
Returns true if the element with given index is currently in the queue.
void Set(IntegerType index)
void AdvanceDeterministicTime(double deterministic_duration)
double GetElapsedDeterministicTime() const
bool ComputeTransitiveReduction(bool log_info=false)
Literal RepresentativeOf(Literal l) const
int64_t num_redundant_literals() const
int64_t num_implications() const
bool Propagate(Trail *trail) final
SatPropagator interface.
void RemoveDuplicates()
Clean up implications list that might have duplicates.
void CleanupAllRemovedAndFixedVariables()
int64_t NumImplicationOnVariableRemoval(BooleanVariable var)
int DirectImplicationsEstimatedSize(Literal literal) const
void RemoveFixedVariables()
void RemoveBooleanVariable(BooleanVariable var, std::deque< std::vector< Literal > > *postsolve_clauses)
For all possible a => var => b, add a => b.
bool IsRedundant(Literal l) const
bool DetectEquivalences(bool log_info=false)
const std::vector< Literal > & DirectImplications(Literal literal)
void RemoveAllRedundantVariables(std::deque< std::vector< Literal > > *postsolve_clauses)
int64_t literal_size() const
bool FindFailedLiteralAroundVar(BooleanVariable var, bool *is_unsat)
LiteralIndex RandomImpliedLiteral(Literal lhs)
bool IsRemoved(Literal l) const
void DoOneRound(bool log_info)
bool DoOneRound(bool log_info)
SatClause * InprocessingAddClause(absl::Span< const Literal > new_clause)
void InprocessingRemoveClause(SatClause *clause)
These must only be called between [Detach/Attach]AllClauses() calls.
bool IsRemovable(SatClause *const clause) const
void DeleteRemovedClauses()
int64_t literal_size() const
The number of different literals (always twice the number of variables).
int64_t num_watched_clauses() const
Number of clauses currently watched.
const std::vector< SatClause * > & AllClausesInCreationOrder() const
ABSL_MUST_USE_RESULT bool InprocessingFixLiteral(Literal true_literal)
This one do not need the clause to be detached.
ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(SatClause *clause, absl::Span< const Literal > new_clause)
bool SubsumeAndStrenghtenRound(bool log_info)
bool DetectEquivalencesAndStamp(bool use_transitive_reduction, bool log_info)
bool MoreFixedVariableToClean() const
bool RemoveFixedAndEquivalentVariables(bool log_info)
bool MoreRedundantVariableToClean() const
bool PresolveLoop(SatPresolveOptions options)
bool LevelZeroPropagate()
LiteralIndex NegatedIndex() const
LiteralIndex Index() const
absl::Span< const Literal > AsSpan() const
Returns a Span<> representation of the clause.
int size() const
Number of literals in the clause.
void MaybeEnablePhaseSaving(bool save_phase)
bool MinimizeByPropagation(double dtime)
ABSL_MUST_USE_RESULT bool Propagate()
void AdvanceDeterministicTime(TimeLimit *limit)
int CurrentDecisionLevel() const
Counters counters() const
bool ComputeStampsForNextRound(bool log_info)
bool ImplicationIsInTree(Literal a, Literal b) const
void SampleTreeAndFillParent()
Visible for testing.
bool DoOneRound(bool log_info)
bool VariableIsAssigned(BooleanVariable var) const
Returns true iff the given variable is assigned.
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsFalse(Literal literal) const
bool LiteralIsTrue(Literal literal) const
void assign(size_type n, const value_type &val)
void push_back(const value_type &val)
void resize(size_type new_size)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
const LiteralIndex kNoLiteralIndex(-1)
bool FailedLiteralProbingRound(ProbingOptions options, Model *model)
In SWIG mode, we don't want anything besides these top-level includes.
#define RETURN_IF_FALSE(f)
std::optional< int64_t > end
std::deque< std::vector< Literal > > clauses
void AddClauseWithSpecialLiteral(Literal literal, absl::Span< const Literal > clause)
double deterministic_limit
bool log_info
We assume this is also true if –v 1 is activated.
bool extract_binary_clauses
double deterministic_time_limit
The time budget to spend.
bool use_transitive_reduction
bool extract_binary_clauses_in_probing
See ProbingOptions in probing.h.
int64_t minimization_num_clauses
TryToMinimizeClause() stats.
int64_t minimization_num_removed_literals
#define SOLVER_LOG(logger,...)