Skip to content

Commit a34ae3e

Browse files
committed
[CP-SAT] more work on encodings, lrat
1 parent 9335950 commit a34ae3e

15 files changed

+609
-143
lines changed

ortools/sat/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,7 @@ cc_library(
12091209
"//ortools/util:saturated_arithmetic",
12101210
"//ortools/util:sorted_interval_list",
12111211
"@abseil-cpp//absl/algorithm:container",
1212+
"@abseil-cpp//absl/base:log_severity",
12121213
"@abseil-cpp//absl/container:btree",
12131214
"@abseil-cpp//absl/container:flat_hash_set",
12141215
"@abseil-cpp//absl/log",
@@ -1559,6 +1560,7 @@ cc_library(
15591560
"//ortools/util:sorted_interval_list",
15601561
"//ortools/util:strong_integers",
15611562
"//ortools/util:time_limit",
1563+
"@abseil-cpp//absl/cleanup",
15621564
"@abseil-cpp//absl/container:btree",
15631565
"@abseil-cpp//absl/container:flat_hash_map",
15641566
"@abseil-cpp//absl/container:inlined_vector",

ortools/sat/clause.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ class ClauseManager : public SatPropagator {
262262
absl::flat_hash_map<SatClause*, ClauseInfo>* mutable_clauses_info() {
263263
return &clauses_info_;
264264
}
265+
int LbdOrZeroIfNotRemovable(SatClause* const clause) const {
266+
auto it = clauses_info_.find(clause);
267+
if (it == clauses_info_.end()) return 0;
268+
return it->second.lbd;
269+
}
265270

266271
// Total number of clauses inspected during calls to Propagate().
267272
int64_t num_inspected_clauses() const { return num_inspected_clauses_; }

ortools/sat/cp_model_postsolve.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ void PostsolveExactlyOne(const ConstraintProto& ct,
9797
// There must be one.
9898
void SetEnforcementLiteralToFalse(const ConstraintProto& ct,
9999
std::vector<Domain>* domains) {
100-
CHECK(!ct.enforcement_literal().empty());
100+
CHECK(!ct.enforcement_literal().empty()) << ProtobufShortDebugString(ct);
101101
bool has_free_enforcement_literal = false;
102102
for (const int enf : ct.enforcement_literal()) {
103103
if ((*domains)[PositiveRef(enf)].IsFixed()) continue;

ortools/sat/cp_model_presolve.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4504,6 +4504,7 @@ bool CpModelPresolver::PropagateDomainsInLinear(int ct_index,
45044504
// actual changes.
45054505
if (is_in_objective &&
45064506
!context_->SubstituteVariableInObjective(var, var_coeff, *ct)) {
4507+
if (context_->ModelIsUnsat()) return false;
45074508
continue;
45084509
}
45094510

@@ -13170,13 +13171,12 @@ void CpModelPresolver::ProcessVariableOnlyUsedInEncoding(int var) {
1317013171
return;
1317113172
}
1317213173

13173-
int new_exo_to_presolve_index = -1;
13174-
TryToReplaceVariableByItsEncoding(var, new_exo_to_presolve_index, context_,
13175-
solution_crush_);
13176-
if (new_exo_to_presolve_index != -1) {
13177-
if (PresolveExactlyOne(context_->working_model->mutable_constraints(
13178-
new_exo_to_presolve_index))) {
13179-
context_->UpdateConstraintVariableUsage(new_exo_to_presolve_index);
13174+
// Presolve newly created constraints.
13175+
const int old_size = context_->working_model->constraints_size();
13176+
TryToReplaceVariableByItsEncoding(var, context_, solution_crush_);
13177+
for (int c = old_size; c < context_->working_model->constraints_size(); ++c) {
13178+
if (PresolveOneConstraint(c)) {
13179+
context_->UpdateConstraintVariableUsage(c);
1318013180
}
1318113181
}
1318213182
}

ortools/sat/cp_model_presolve_test.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8158,6 +8158,7 @@ TEST(PresolveCpModelTest, SolveDiophantine) {
81588158
// Should solve in < .01 second. Note that deterministic time is not
81598159
// completely accurate.
81608160
params.set_max_deterministic_time(.001);
8161+
params.set_num_workers(1);
81618162
const CpSolverResponse response_with =
81628163
SolveWithParameters(model_proto, params);
81638164

ortools/sat/integer_search.cc

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,9 +1366,9 @@ bool IntegerSearchHelper::BeforeTakingDecision() {
13661366
DCHECK(sat_solver_->PropagationIsDone());
13671367

13681368
// If we pushed root level deductions, we go back to level zero and call
1369-
// Propagate() to incorporate them. Note that the propagation is not strcily
1369+
// Propagate() to incorporate them. Note that the propagation is not strictly
13701370
// needed, but it is nicer to be at fixed point when we call the level zero
1371-
// callabacks.
1371+
// callbacks.
13721372
if (integer_trail_->HasPendingRootLevelDeduction()) {
13731373
sat_solver_->Backtrack(0);
13741374
if (!sat_solver_->Propagate()) {
@@ -1843,7 +1843,8 @@ SatSolver::Status ContinuousProber::Probe() {
18431843
tmp_dnf_.push_back({literal});
18441844
}
18451845
++num_at_least_one_probed_;
1846-
if (!prober_->ProbeDnf("at_least_one", tmp_dnf_)) {
1846+
if (!prober_->ProbeDnf("at_least_one", tmp_dnf_,
1847+
Prober::DnfType::kAtLeastOne, clause)) {
18471848
return SatSolver::INFEASIBLE;
18481849
}
18491850

@@ -1866,7 +1867,8 @@ SatSolver::Status ContinuousProber::Probe() {
18661867
}
18671868
tmp_dnf_.push_back(tmp_literals_);
18681869
++num_at_most_one_probed_;
1869-
if (!prober_->ProbeDnf("at_most_one", tmp_dnf_)) {
1870+
if (!prober_->ProbeDnf("at_most_one", tmp_dnf_,
1871+
Prober::DnfType::kAtLeastOneOrZero)) {
18701872
return SatSolver::INFEASIBLE;
18711873
}
18721874

@@ -1887,12 +1889,12 @@ SatSolver::Status ContinuousProber::Probe() {
18871889
for (; current_bv2_ < bool_vars_.size(); ++current_bv2_) {
18881890
const BooleanVariable& bv2 = bool_vars_[current_bv2_];
18891891
if (assignment.VariableIsAssigned(bv2)) continue;
1890-
if (!prober_->ProbeDnf(
1891-
"pair_of_bool_vars",
1892-
{{Literal(bv1, true), Literal(bv2, true)},
1893-
{Literal(bv1, true), Literal(bv2, false)},
1894-
{Literal(bv1, false), Literal(bv2, true)},
1895-
{Literal(bv1, false), Literal(bv2, false)}})) {
1892+
if (!prober_->ProbeDnf("pair_of_bool_vars",
1893+
{{Literal(bv1, false), Literal(bv2, false)},
1894+
{Literal(bv1, false), Literal(bv2, true)},
1895+
{Literal(bv1, true), Literal(bv2, false)},
1896+
{Literal(bv1, true), Literal(bv2, true)}},
1897+
Prober::DnfType::kAtLeastOneCombination)) {
18961898
return SatSolver::INFEASIBLE;
18971899
}
18981900
RETURN_IF_NOT_FEASIBLE(PeriodicSyncAndCheck());
@@ -1910,12 +1912,12 @@ SatSolver::Status ContinuousProber::Probe() {
19101912
if (assignment.VariableIsAssigned(bv2) || bv1 == bv2) {
19111913
continue;
19121914
}
1913-
if (!prober_->ProbeDnf(
1914-
"rnd_pair_of_bool_vars",
1915-
{{Literal(bv1, true), Literal(bv2, true)},
1916-
{Literal(bv1, true), Literal(bv2, false)},
1917-
{Literal(bv1, false), Literal(bv2, true)},
1918-
{Literal(bv1, false), Literal(bv2, false)}})) {
1915+
if (!prober_->ProbeDnf("rnd_pair_of_bool_vars",
1916+
{{Literal(bv1, false), Literal(bv2, false)},
1917+
{Literal(bv1, false), Literal(bv2, true)},
1918+
{Literal(bv1, true), Literal(bv2, false)},
1919+
{Literal(bv1, true), Literal(bv2, true)}},
1920+
Prober::DnfType::kAtLeastOneCombination)) {
19191921
return SatSolver::INFEASIBLE;
19201922
}
19211923

@@ -1948,12 +1950,13 @@ SatSolver::Status ContinuousProber::Probe() {
19481950
}
19491951
tmp_dnf_.clear();
19501952
for (int i = 0; i < 8; ++i) {
1951-
tmp_dnf_.push_back({Literal(bv1, (i & 1) > 0),
1953+
tmp_dnf_.push_back({Literal(bv1, (i & 4) > 0),
19521954
Literal(bv2, (i & 2) > 0),
1953-
Literal(bv3, (i & 4) > 0)});
1955+
Literal(bv3, (i & 1) > 0)});
19541956
}
19551957

1956-
if (!prober_->ProbeDnf("rnd_triplet_of_bool_vars", tmp_dnf_)) {
1958+
if (!prober_->ProbeDnf("rnd_triplet_of_bool_vars", tmp_dnf_,
1959+
Prober::DnfType::kAtLeastOneCombination)) {
19571960
return SatSolver::INFEASIBLE;
19581961
}
19591962

ortools/sat/lrat_proof_handler.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,32 @@ bool LratProofHandler::AddAssumedClause(ClauseId id,
146146
return true;
147147
}
148148

149+
void LratProofHandler::PinClause(ClauseId id,
150+
absl::Span<const Literal> clause) {
151+
DCHECK_NE(id, kNoClauseId);
152+
DCHECK_EQ(pinned_clause_id_, kNoClauseId);
153+
pinned_clause_id_ = id;
154+
if (drat_checker_ != nullptr || drat_writer_ != nullptr) {
155+
pinned_clause_.assign(clause.begin(), clause.end());
156+
}
157+
delete_pinned_clause_ = false;
158+
}
159+
160+
void LratProofHandler::UnpinClause(ClauseId id) {
161+
DCHECK_NE(id, kNoClauseId);
162+
DCHECK_EQ(pinned_clause_id_, id);
163+
pinned_clause_id_ = kNoClauseId;
164+
if (delete_pinned_clause_) {
165+
DeleteClause(id, pinned_clause_);
166+
}
167+
}
168+
149169
void LratProofHandler::DeleteClause(ClauseId id,
150170
absl::Span<const Literal> clause) {
171+
if (pinned_clause_id_ == id) {
172+
delete_pinned_clause_ = true;
173+
return;
174+
}
151175
VLOG(1) << "DeleteClause: id=" << id
152176
<< " literals=" << absl::StrJoin(clause, ",");
153177
if (drat_checker_ != nullptr) {

ortools/sat/lrat_proof_handler.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ class LratProofHandler {
6363
// checks are enabled and the ID is already used by another clause).
6464
bool AddAssumedClause(ClauseId id, absl::Span<const Literal> clause);
6565

66+
// Prevents the given clause from being deleted, until UnpinClause() is called
67+
// with the same ID. At most one clause can be pinned at any time.
68+
void PinClause(ClauseId id, absl::Span<const Literal> clause);
69+
70+
// Unpins the clause with the given ID, and deletes it if a call to
71+
// DeleteClause() for this clause was made since it was pinned.
72+
void UnpinClause(ClauseId id);
73+
6674
// Deletes a problem or inferred clause. The clause literals are only needed
6775
// when checking DRAT.
6876
void DeleteClause(ClauseId id, absl::Span<const Literal> clause);
@@ -92,7 +100,11 @@ class LratProofHandler {
92100

93101
bool all_problem_clauses_loaded_ = false;
94102
int64_t num_assumed_clauses_ = 0;
95-
bool debug_crash_on_error_;
103+
bool debug_crash_on_error_ = false;
104+
105+
ClauseId pinned_clause_id_ = kNoClauseId;
106+
std::vector<Literal> pinned_clause_;
107+
bool delete_pinned_clause_ = false;
96108

97109
// Only used when checking DRAT, because the DRAT checker does not support
98110
// interleaving problem and inferred clauses.

0 commit comments

Comments
 (0)