Skip to content

Commit f43b60b

Browse files
committed
[CP-SAT] work on lrat; better expansion of variables only appearing in encoding constraints
1 parent e0a20e4 commit f43b60b

37 files changed

+715
-841
lines changed

ortools/sat/BUILD.bazel

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ cc_library(
328328
visibility = ["//visibility:public"],
329329
deps = [
330330
":cp_model_cc_proto",
331-
":drat_proof_handler",
332331
":sat_base",
333332
"//ortools/base:base_export",
334333
"//ortools/base:file",
@@ -372,6 +371,7 @@ cc_library(
372371
deps = [
373372
":cp_model_cc_proto",
374373
":cp_model_utils",
374+
":drat_checker",
375375
":integer_base",
376376
":model",
377377
":sat_base",
@@ -701,6 +701,7 @@ cc_library(
701701
":linear_programming_constraint",
702702
":linear_relaxation",
703703
":lp_utils",
704+
":lrat_proof_handler",
704705
":max_hs",
705706
":model",
706707
":optimization",
@@ -817,7 +818,6 @@ cc_library(
817818
":cuts",
818819
":diffn_util",
819820
":drat_checker",
820-
":drat_proof_handler",
821821
":feasibility_jump",
822822
":feasibility_pump",
823823
":implied_bounds",
@@ -908,7 +908,6 @@ cc_test(
908908
":cp_model_test_utils",
909909
":cp_model_utils",
910910
":drat_checker",
911-
":drat_proof_handler",
912911
":lp_utils",
913912
":model",
914913
":sat_base",
@@ -1154,6 +1153,7 @@ cc_library(
11541153
"//ortools/algorithms:sparse_permutation",
11551154
"//ortools/util:sorted_interval_list",
11561155
"@abseil-cpp//absl/algorithm:container",
1156+
"@abseil-cpp//absl/container:btree",
11571157
"@abseil-cpp//absl/container:flat_hash_map",
11581158
"@abseil-cpp//absl/container:flat_hash_set",
11591159
"@abseil-cpp//absl/container:inlined_vector",
@@ -1470,7 +1470,6 @@ cc_library(
14701470
hdrs = ["sat_solver.h"],
14711471
deps = [
14721472
":clause",
1473-
":drat_proof_handler",
14741473
":enforcement",
14751474
":lrat_proof_handler",
14761475
":model",
@@ -1594,7 +1593,6 @@ cc_library(
15941593
hdrs = ["sat_inprocessing.h"],
15951594
deps = [
15961595
":clause",
1597-
":drat_checker",
15981596
":linear_programming_constraint",
15991597
":lrat_proof_handler",
16001598
":model",
@@ -1688,7 +1686,6 @@ cc_library(
16881686
hdrs = ["clause.h"],
16891687
deps = [
16901688
":container",
1691-
":drat_proof_handler",
16921689
":inclusion",
16931690
":lrat_proof_handler",
16941691
":model",
@@ -1742,7 +1739,6 @@ cc_library(
17421739
srcs = ["simplification.cc"],
17431740
hdrs = ["simplification.h"],
17441741
deps = [
1745-
":drat_proof_handler",
17461742
":sat_base",
17471743
":sat_parameters_cc_proto",
17481744
":sat_solver",
@@ -4197,23 +4193,6 @@ cc_test(
41974193
],
41984194
)
41994195

4200-
cc_library(
4201-
name = "drat_proof_handler",
4202-
srcs = ["drat_proof_handler.cc"],
4203-
hdrs = ["drat_proof_handler.h"],
4204-
deps = [
4205-
":drat_checker",
4206-
":drat_writer",
4207-
":sat_base",
4208-
"//ortools/base",
4209-
"//ortools/base:file",
4210-
"//ortools/base:strong_vector",
4211-
"//ortools/util:strong_integers",
4212-
"@abseil-cpp//absl/log:check",
4213-
"@abseil-cpp//absl/types:span",
4214-
],
4215-
)
4216-
42174196
cc_library(
42184197
name = "drat_checker",
42194198
srcs = ["drat_checker.cc"],
@@ -4287,9 +4266,12 @@ cc_library(
42874266
srcs = ["lrat_proof_handler.cc"],
42884267
hdrs = ["lrat_proof_handler.h"],
42894268
deps = [
4269+
":drat_checker",
4270+
":drat_writer",
42904271
":lrat_checker",
42914272
":model",
42924273
":sat_base",
4274+
"//ortools/base:file",
42934275
"@abseil-cpp//absl/log",
42944276
"@abseil-cpp//absl/log:check",
42954277
"@abseil-cpp//absl/strings",

ortools/sat/boolean_problem.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,8 +844,7 @@ void ProbeAndSimplifyProblem(SatPostsolver* postsolver,
844844
}
845845

846846
util_intops::StrongVector<LiteralIndex, LiteralIndex> equiv_map;
847-
ProbeAndFindEquivalentLiteral(&solver, postsolver,
848-
/*drat_proof_handler=*/nullptr, &equiv_map);
847+
ProbeAndFindEquivalentLiteral(&solver, postsolver, &equiv_map);
849848

850849
// We can abort if no information is learned.
851850
if (equiv_map.empty() && solver.LiteralTrail().Index() == 0) break;

ortools/sat/clause.cc

Lines changed: 21 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#include "ortools/base/timer.h"
4141
#include "ortools/graph/strongly_connected_components.h"
4242
#include "ortools/sat/container.h"
43-
#include "ortools/sat/drat_proof_handler.h"
4443
#include "ortools/sat/inclusion.h"
4544
#include "ortools/sat/lrat_proof_handler.h"
4645
#include "ortools/sat/model.h"
@@ -398,20 +397,15 @@ void ClauseManager::Attach(SatClause* clause, Trail* trail) {
398397

399398
void ClauseManager::InternalDetach(SatClause* clause,
400399
DeletionSourceForStat source) {
401-
const size_t size = clause->size();
402-
403400
// Double-deletion.
404401
// TODO(user): change that to a check?
405-
if (size == 0) return;
402+
if (clause->size() == 0) return;
406403

407404
--num_watched_clauses_;
408-
if (drat_proof_handler_ != nullptr && size > 2) {
409-
drat_proof_handler_->DeleteClause({clause->begin(), size});
410-
}
411405
if (lrat_proof_handler_ != nullptr) {
412406
const auto it = clause_id_.find(clause);
413407
if (it != clause_id_.end()) {
414-
lrat_proof_handler_->DeleteClauses({it->second});
408+
lrat_proof_handler_->DeleteClause(it->second, clause->AsSpan());
415409
clause_id_.erase(it);
416410
}
417411
}
@@ -460,9 +454,6 @@ void ClauseManager::AttachAllClauses() {
460454
bool ClauseManager::InprocessingAddUnitClause(ClauseId unit_clause_id,
461455
Literal true_literal) {
462456
DCHECK_EQ(trail_->CurrentDecisionLevel(), 0);
463-
if (drat_proof_handler_ != nullptr) {
464-
drat_proof_handler_->AddClause({true_literal});
465-
}
466457
if (trail_->Assignment().LiteralIsTrue(true_literal)) return true;
467458

468459
trail_->EnqueueWithUnitReason(unit_clause_id, true_literal);
@@ -475,9 +466,6 @@ bool ClauseManager::InprocessingAddUnitClause(ClauseId unit_clause_id,
475466
bool ClauseManager::InprocessingFixLiteral(
476467
Literal true_literal, absl::Span<const ClauseId> clause_ids) {
477468
DCHECK_EQ(trail_->CurrentDecisionLevel(), 0);
478-
if (drat_proof_handler_ != nullptr) {
479-
drat_proof_handler_->AddClause({true_literal});
480-
}
481469
if (trail_->Assignment().LiteralIsTrue(true_literal)) return true;
482470

483471
ClauseId clause_id = kNoClauseId;
@@ -530,10 +518,12 @@ bool ClauseManager::InprocessingRewriteClause(
530518
return true;
531519
}
532520

533-
if (drat_proof_handler_ != nullptr) {
534-
// We must write the new clause before we delete the old one.
535-
drat_proof_handler_->AddClause(new_clause);
536-
drat_proof_handler_->DeleteClause(clause->AsSpan());
521+
if (lrat_proof_handler_ != nullptr) {
522+
const auto it = clause_id_.find(clause);
523+
if (it != clause_id_.end()) {
524+
lrat_proof_handler_->DeleteClause(it->second, clause->AsSpan());
525+
}
526+
SetClauseId(clause, new_clause_id);
537527
}
538528

539529
if (all_clauses_are_attached_) {
@@ -543,25 +533,13 @@ bool ClauseManager::InprocessingRewriteClause(
543533
clause->Clear();
544534
for (const Literal l : {clause->FirstLiteral(), clause->SecondLiteral()}) {
545535
needs_cleaning_.Clear(l);
546-
// std::erase_if is C++20, not yet fully supported on OR-Tools.
547-
watchers_on_false_[l].erase(
548-
std::remove_if(watchers_on_false_[l].begin(),
549-
watchers_on_false_[l].end(),
550-
[](const Watcher& watcher) {
551-
return watcher.clause->IsRemoved();
552-
}),
553-
watchers_on_false_[l].end());
536+
OpenSourceEraseIf(watchers_on_false_[l], [](const Watcher& watcher) {
537+
return watcher.clause->IsRemoved();
538+
});
554539
}
555540
}
556541

557542
clause->Rewrite(new_clause);
558-
if (lrat_proof_handler_ != nullptr) {
559-
const auto it = clause_id_.find(clause);
560-
if (it != clause_id_.end()) {
561-
lrat_proof_handler_->DeleteClauses({it->second});
562-
}
563-
SetClauseId(clause, new_clause_id);
564-
}
565543

566544
// And we reattach it.
567545
if (all_clauses_are_attached_) {
@@ -601,12 +579,9 @@ void ClauseManager::CleanUpWatchers() {
601579
SCOPED_TIME_STAT(&stats_);
602580
for (const LiteralIndex index : needs_cleaning_.PositionsSetAtLeastOnce()) {
603581
if (!needs_cleaning_[index]) continue;
604-
// std::erase_if is C++20, not yet fully supported on OR-Tools.
605-
watchers_on_false_[index].erase(
606-
std::remove_if(
607-
watchers_on_false_[index].begin(), watchers_on_false_[index].end(),
608-
[](const Watcher& watcher) { return watcher.clause->IsRemoved(); }),
609-
watchers_on_false_[index].end());
582+
OpenSourceEraseIf(watchers_on_false_[index], [](const Watcher& watcher) {
583+
return watcher.clause->IsRemoved();
584+
});
610585
needs_cleaning_.Clear(index);
611586
}
612587
needs_cleaning_.NotifyAllClear();
@@ -789,24 +764,16 @@ bool BinaryImplicationGraph::HasNoDuplicates() {
789764
// use them here to maintains invariant? Explore this when we start cleaning our
790765
// clauses using equivalence during search. We can easily do it for every
791766
// conflict we learn instead of here.
792-
bool BinaryImplicationGraph::AddBinaryClauseInternal(ClauseId id, Literal a,
793-
Literal b,
794-
bool change_reason) {
767+
bool BinaryImplicationGraph::AddBinaryClauseInternal(
768+
ClauseId id, Literal a, Literal b, bool change_reason,
769+
bool delete_non_representative_id) {
795770
SCOPED_TIME_STAT(&stats_);
796771

797772
// Tricky: If this is the first clause, the propagator will be added and
798773
// assumed to be in a "propagated" state. This makes sure this is the case.
799774
if (no_constraint_ever_added_) propagation_trail_index_ = trail_->Index();
800775
no_constraint_ever_added_ = false;
801776

802-
if (drat_proof_handler_ != nullptr) {
803-
// TODO(user): Like this we will duplicate all binary clause from the
804-
// problem. However this leads to a simpler API (since we don't need to
805-
// special case the loading of the original clauses) and we mainly use drat
806-
// proof for testing anyway.
807-
drat_proof_handler_->AddClause({a, b});
808-
}
809-
810777
Literal rep_a = a;
811778
Literal rep_b = b;
812779
ClauseId rep_id = kNoClauseId;
@@ -839,8 +806,8 @@ bool BinaryImplicationGraph::AddBinaryClauseInternal(ClauseId id, Literal a,
839806
// Remember the non-canonical clause so we can delete it on restart.
840807
changed_reasons_on_trail_.emplace_back(std::minmax(a, b));
841808
AddClauseId(id, a, b);
842-
} else {
843-
lrat_proof_handler_->DeleteClauses({id});
809+
} else if (delete_non_representative_id) {
810+
lrat_proof_handler_->DeleteClause(id, {a, b});
844811
}
845812
}
846813
AddClauseId(rep_id, rep_a, rep_b);
@@ -939,9 +906,6 @@ bool BinaryImplicationGraph::FixLiteral(Literal true_literal,
939906
return false;
940907
}
941908

942-
if (drat_proof_handler_ != nullptr) {
943-
drat_proof_handler_->AddClause({true_literal});
944-
}
945909
ClauseId new_clause_id = kNoClauseId;
946910
if (lrat_proof_handler_ != nullptr) {
947911
new_clause_id = clause_id_generator_->GetNextId();
@@ -1515,7 +1479,6 @@ class LratEquivalenceHelper {
15151479
trail_(graph->trail_),
15161480
implications_and_amos_(graph->implications_and_amos_),
15171481
clause_id_generator_(graph->clause_id_generator_),
1518-
drat_proof_handler_(graph->drat_proof_handler_),
15191482
lrat_proof_handler_(graph->lrat_proof_handler_) {}
15201483

15211484
// Initializes the internal data structures to process the given component
@@ -1714,9 +1677,6 @@ class LratEquivalenceHelper {
17141677
void AddInferredClause(ClauseId new_clause_id,
17151678
absl::Span<const Literal> literals,
17161679
absl::Span<const ClauseId> clause_ids) {
1717-
if (drat_proof_handler_ != nullptr) {
1718-
drat_proof_handler_->AddClause(literals);
1719-
}
17201680
if (lrat_proof_handler_ != nullptr) {
17211681
lrat_proof_handler_->AddInferredClause(new_clause_id, literals,
17221682
clause_ids);
@@ -1728,7 +1688,6 @@ class LratEquivalenceHelper {
17281688
util_intops::StrongVector<LiteralIndex, LiteralsOrOffsets>&
17291689
implications_and_amos_;
17301690
ClauseIdGenerator* clause_id_generator_;
1731-
DratProofHandler* drat_proof_handler_;
17321691
LratProofHandler* lrat_proof_handler_;
17331692

17341693
// Temporary data structures used by the above methods:
@@ -1745,14 +1704,6 @@ class LratEquivalenceHelper {
17451704
std::vector<Literal> tmp_literals_;
17461705
};
17471706

1748-
void BinaryImplicationGraph::SetDratProofHandler(
1749-
DratProofHandler* drat_proof_handler) {
1750-
drat_proof_handler_ = drat_proof_handler;
1751-
if (lrat_helper_ == nullptr) {
1752-
lrat_helper_ = new LratEquivalenceHelper(this);
1753-
}
1754-
}
1755-
17561707
bool BinaryImplicationGraph::DetectEquivalences(bool log_info) {
17571708
// This was already called, and no new constraint where added. Note that new
17581709
// fixed variable cannot create new equivalence, only new binary clauses do.
@@ -1764,7 +1715,8 @@ bool BinaryImplicationGraph::DetectEquivalences(bool log_info) {
17641715
if (trail_->CurrentDecisionLevel() == 0) {
17651716
for (std::pair<Literal, Literal> clause : changed_reasons_on_trail_) {
17661717
auto it = clause_id_.find(clause);
1767-
lrat_proof_handler_->DeleteClauses({it->second});
1718+
lrat_proof_handler_->DeleteClause(it->second,
1719+
{clause.first, clause.second});
17681720
clause_id_.erase(it);
17691721
}
17701722
changed_reasons_on_trail_.clear();
@@ -3157,15 +3109,9 @@ void BinaryImplicationGraph::RemoveBooleanVariable(
31573109
// Notify the deletion to the proof checker and the postsolve.
31583110
// Note that we want var first in these clauses for the postsolve.
31593111
for (const Literal b : direct_implications_) {
3160-
if (drat_proof_handler_ != nullptr) {
3161-
drat_proof_handler_->DeleteClause({Literal(var, false), b});
3162-
}
31633112
postsolve_clauses->push_back({Literal(var, false), b});
31643113
}
31653114
for (const Literal a_negated : direct_implications_of_negated_literal_) {
3166-
if (drat_proof_handler_ != nullptr) {
3167-
drat_proof_handler_->DeleteClause({Literal(var, true), a_negated});
3168-
}
31693115
postsolve_clauses->push_back({Literal(var, true), a_negated});
31703116
}
31713117

0 commit comments

Comments
 (0)