Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
drat_checker.cc
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <stddef.h>
17
18#include <algorithm>
19#include <cstdint>
20#include <cstdlib>
21#include <fstream> // NOLINT
22#include <limits>
23#include <string>
24#include <vector>
25
26#include "absl/container/flat_hash_set.h"
27#include "absl/log/check.h"
28#include "absl/strings/numbers.h"
29#include "absl/strings/str_split.h"
30#include "absl/strings/string_view.h"
31#include "absl/time/clock.h"
32#include "absl/types/span.h"
33#include "ortools/base/hash.h"
39
40namespace operations_research {
41namespace sat {
42
43DratChecker::Clause::Clause(size_t first_literal_index, int num_literals)
44 : first_literal_index(first_literal_index), num_literals(num_literals) {}
45
46std::size_t DratChecker::ClauseHash::operator()(
47 const ClauseIndex clause_index) const {
48 size_t hash = 0;
49 for (Literal literal : checker->Literals(checker->clauses_[clause_index])) {
50 hash = util_hash::Hash(literal.Index().value(), hash);
51 }
52 return hash;
53}
54
55bool DratChecker::ClauseEquiv::operator()(
56 const ClauseIndex clause_index1, const ClauseIndex clause_index2) const {
57 return checker->Literals(checker->clauses_[clause_index1]) ==
58 checker->Literals(checker->clauses_[clause_index2]);
59}
60
62 : first_inferred_clause_index_(kNoClauseIndex),
63 clause_set_(0, ClauseHash(this), ClauseEquiv(this)),
64 num_variables_(0) {}
65
66bool DratChecker::Clause::IsDeleted(ClauseIndex clause_index) const {
67 return deleted_index <= clause_index;
68}
69
70void DratChecker::AddProblemClause(absl::Span<const Literal> clause) {
71 DCHECK_EQ(first_inferred_clause_index_, kNoClauseIndex);
72 const ClauseIndex clause_index = MaybeAddClause(clause);
73 if (clause_index == kNoClauseIndex) return;
74
75 const auto it = clause_set_.find(clause_index);
76 if (it != clause_set_.end()) {
77 clauses_[*it].num_copies += 1;
78 RemoveLastClause();
79 } else {
80 clause_set_.insert(clause_index);
81 }
82}
83
84void DratChecker::AddInferredClause(absl::Span<const Literal> clause) {
85 const ClauseIndex inferred_clause_index = MaybeAddClause(clause);
86 CHECK_NE(inferred_clause_index, kNoClauseIndex);
87 if (first_inferred_clause_index_ == kNoClauseIndex) {
88 first_inferred_clause_index_ = inferred_clause_index;
89 }
90
91 const auto it = clause_set_.find(inferred_clause_index);
92 if (it != clause_set_.end()) {
93 clauses_[*it].num_copies += 1;
94 if (*it >= first_inferred_clause_index_ && !clause.empty()) {
95 CHECK_EQ(clauses_[*it].rat_literal_index, clause[0].Index());
96 }
97 RemoveLastClause();
98 } else {
99 clauses_[inferred_clause_index].rat_literal_index =
100 clause.empty() ? kNoLiteralIndex : clause[0].Index();
101 clause_set_.insert(inferred_clause_index);
102 }
103}
104
105ClauseIndex DratChecker::MaybeAddClause(absl::Span<const Literal> clause) {
106 const size_t first_literal_index = literals_.size();
107 literals_.insert(literals_.end(), clause.begin(), clause.end());
108 // Sort the input clause in strictly increasing order (by sorting and then
109 // removing the duplicate literals).
110 std::sort(literals_.begin() + first_literal_index, literals_.end());
111 literals_.erase(
112 std::unique(literals_.begin() + first_literal_index, literals_.end()),
113 literals_.end());
114
115 for (size_t i = first_literal_index + 1; i < literals_.size(); ++i) {
116 if (literals_[i] == literals_[i - 1].Negated()) {
117 literals_.resize(first_literal_index);
118 return kNoClauseIndex;
119 }
120 }
121 clauses_.push_back(
122 Clause(first_literal_index, literals_.size() - first_literal_index));
123 if (!clause.empty()) {
124 num_variables_ =
125 std::max(num_variables_, literals_.back().Variable().value() + 1);
126 }
127 return ClauseIndex(clauses_.size() - 1);
128}
129
130void DratChecker::DeleteClause(absl::Span<const Literal> clause) {
131 // Temporarily add 'clause' to find if it has been previously added.
132 const ClauseIndex clause_index = MaybeAddClause(clause);
133 if (clause_index == kNoClauseIndex) return;
134 const auto it = clause_set_.find(clause_index);
135 if (it != clause_set_.end()) {
136 Clause& existing_clause = clauses_[*it];
137 existing_clause.num_copies -= 1;
138 if (existing_clause.num_copies == 0) {
139 DCHECK(existing_clause.deleted_index == std::numeric_limits<int>::max());
140 existing_clause.deleted_index = clauses_.size() - 1;
141 if (clauses_.back().num_literals >= 2) {
142 clauses_[ClauseIndex(clauses_.size() - 2)].deleted_clauses.push_back(
143 *it);
144 }
145 clause_set_.erase(it);
146 }
147 } else {
148 LOG(WARNING) << "Couldn't find deleted clause";
149 }
150 // Delete 'clause' and its literals.
151 RemoveLastClause();
152}
153
154void DratChecker::RemoveLastClause() {
155 literals_.resize(clauses_.back().first_literal_index);
156 clauses_.pop_back();
157}
158
159// See Algorithm of Fig. 8 in 'Trimming while Checking Clausal Proofs'.
160DratChecker::Status DratChecker::Check(double max_time_in_seconds) {
161 // First check that the last inferred clause is empty (this implies there
162 // should be at least one inferred clause), and mark it as needed for the
163 // proof.
164 if (clauses_.empty() || first_inferred_clause_index_ == kNoClauseIndex ||
165 clauses_.back().num_literals != 0) {
166 return Status::INVALID;
167 }
168 clauses_.back().is_needed_for_proof = true;
169
170 // Checks the inferred clauses in reversed order. The advantage of this order
171 // is that when checking a clause, one can mark all the clauses that are used
172 // to check it. In turn, only these marked clauses need to be checked (and so
173 // on recursively). By contrast, a forward iteration needs to check all the
174 // clauses.
175 const int64_t start_time_nanos = absl::GetCurrentTimeNanos();
176 TimeLimit time_limit(max_time_in_seconds);
177 Init();
178 for (ClauseIndex i(clauses_.size() - 1); i >= first_inferred_clause_index_;
179 --i) {
180 if (time_limit.LimitReached()) {
181 return Status::UNKNOWN;
182 }
183 const Clause& clause = clauses_[i];
184 // Start watching the literals of the clauses that were deleted just after
185 // this one, and which are now no longer deleted.
186 for (const ClauseIndex j : clause.deleted_clauses) {
187 WatchClause(j);
188 }
189 if (!clause.is_needed_for_proof) {
190 continue;
191 }
192 // 'clause' must have either the Reverse Unit Propagation (RUP) property:
193 if (HasRupProperty(i, Literals(clause))) {
194 continue;
195 }
196 // or the Reverse Asymmetric Tautology (RAT) property. This property is
197 // defined by the fact that all clauses which contain the negation of
198 // the RAT literal of 'clause', after resolution with 'clause', must have
199 // the RUP property.
200 // Note from 'DRAT-trim: Efficient Checking and Trimming Using Expressive
201 // Clausal Proofs': "[in order] to access to all clauses containing the
202 // negation of the resolution literal, one could build a literal-to-clause
203 // lookup table of the original formula and update it after each lemma
204 // addition and deletion step. However, these updates can be expensive and
205 // the lookup table potentially doubles the memory usage of the tool.
206 // Since most lemmas emitted by state-of-the-art SAT solvers can be
207 // validated using the RUP check, such a lookup table has been omitted."
208 if (clause.rat_literal_index == kNoLiteralIndex) return Status::INVALID;
209 ++num_rat_checks_;
210 std::vector<Literal> resolvent;
211 for (ClauseIndex j(0); j < i; ++j) {
212 if (!clauses_[j].IsDeleted(i) &&
213 ContainsLiteral(Literals(clauses_[j]),
214 Literal(clause.rat_literal_index).Negated())) {
215 // Check that the resolvent has the RUP property.
216 if (!Resolve(Literals(clause), Literals(clauses_[j]),
217 Literal(clause.rat_literal_index), &tmp_assignment_,
218 &resolvent) ||
219 !HasRupProperty(i, resolvent)) {
220 return Status::INVALID;
221 }
222 }
223 }
224 }
225 LogStatistics(absl::GetCurrentTimeNanos() - start_time_nanos);
226 return Status::VALID;
227}
228
229std::vector<std::vector<Literal>> DratChecker::GetUnsatSubProblem() const {
230 return GetClausesNeededForProof(ClauseIndex(0), first_inferred_clause_index_);
231}
232
233std::vector<std::vector<Literal>> DratChecker::GetOptimizedProof() const {
234 return GetClausesNeededForProof(first_inferred_clause_index_,
235 ClauseIndex(clauses_.size()));
236}
237
238std::vector<std::vector<Literal>> DratChecker::GetClausesNeededForProof(
239 ClauseIndex begin, ClauseIndex end) const {
240 std::vector<std::vector<Literal>> result;
241 for (ClauseIndex i = begin; i < end; ++i) {
242 const Clause& clause = clauses_[i];
243 if (clause.is_needed_for_proof) {
244 const absl::Span<const Literal>& literals = Literals(clause);
245 result.emplace_back(literals.begin(), literals.end());
246 if (clause.rat_literal_index != kNoLiteralIndex) {
247 const size_t rat_literal_clause_index =
248 std::find(literals.begin(), literals.end(),
249 Literal(clause.rat_literal_index)) -
250 literals.begin();
251 std::swap(result.back()[0], result.back()[rat_literal_clause_index]);
252 }
253 }
254 }
255 return result;
256}
257
258absl::Span<const Literal> DratChecker::Literals(const Clause& clause) const {
259 return absl::Span<const Literal>(
260 literals_.data() + clause.first_literal_index, clause.num_literals);
261}
262
263void DratChecker::Init() {
264 assigned_.clear();
265 assignment_.Resize(num_variables_);
266 assignment_source_.resize(num_variables_, kNoClauseIndex);
267 high_priority_literals_to_assign_.clear();
268 low_priority_literals_to_assign_.clear();
269 watched_literals_.clear();
270 watched_literals_.resize(2 * num_variables_);
271 single_literal_clauses_.clear();
272 unit_stack_.clear();
273 tmp_assignment_.Resize(num_variables_);
274 num_rat_checks_ = 0;
275
276 for (ClauseIndex clause_index(0); clause_index < clauses_.size();
277 ++clause_index) {
278 Clause& clause = clauses_[clause_index];
279 if (clause.num_literals >= 2) {
280 // Don't watch the literals of the deleted clauses right away, instead
281 // watch them when these clauses become 'undeleted' in backward checking.
282 if (clause.deleted_index == std::numeric_limits<int>::max()) {
283 WatchClause(clause_index);
284 }
285 } else if (clause.num_literals == 1) {
286 single_literal_clauses_.push_back(clause_index);
287 }
288 }
289}
290
291void DratChecker::WatchClause(ClauseIndex clause_index) {
292 const Literal* clause_literals =
293 literals_.data() + clauses_[clause_index].first_literal_index;
294 watched_literals_[clause_literals[0].Index()].push_back(clause_index);
295 watched_literals_[clause_literals[1].Index()].push_back(clause_index);
296}
297
298bool DratChecker::HasRupProperty(ClauseIndex num_clauses,
299 absl::Span<const Literal> clause) {
300 ClauseIndex conflict = kNoClauseIndex;
301 for (const Literal literal : clause) {
302 conflict =
303 AssignAndPropagate(num_clauses, literal.Negated(), kNoClauseIndex);
304 if (conflict != kNoClauseIndex) {
305 break;
306 }
307 }
308
309 for (const ClauseIndex clause_index : single_literal_clauses_) {
310 const Clause& clause = clauses_[clause_index];
311 // TODO(user): consider ignoring the deletion of single literal clauses
312 // as done in drat-trim.
313 if (clause_index < num_clauses && !clause.IsDeleted(num_clauses)) {
314 if (clause.is_needed_for_proof) {
315 high_priority_literals_to_assign_.push_back(
316 {literals_[clause.first_literal_index], clause_index});
317 } else {
318 low_priority_literals_to_assign_.push_back(
319 {literals_[clause.first_literal_index], clause_index});
320 }
321 }
322 }
323
324 while (!(high_priority_literals_to_assign_.empty() &&
325 low_priority_literals_to_assign_.empty()) &&
326 conflict == kNoClauseIndex) {
327 std::vector<LiteralToAssign>& stack =
328 high_priority_literals_to_assign_.empty()
329 ? low_priority_literals_to_assign_
330 : high_priority_literals_to_assign_;
331 const LiteralToAssign literal_to_assign = stack.back();
332 stack.pop_back();
333 if (assignment_.LiteralIsAssigned(literal_to_assign.literal)) {
334 // If the literal to assign to true is already assigned to false, we found
335 // a conflict, with the source clause of this previous assignment.
336 if (assignment_.LiteralIsFalse(literal_to_assign.literal)) {
337 conflict = literal_to_assign.source_clause_index;
338 break;
339 } else {
340 continue;
341 }
342 }
343 DCHECK(literal_to_assign.source_clause_index != kNoClauseIndex);
344 unit_stack_.push_back(literal_to_assign.source_clause_index);
345 conflict = AssignAndPropagate(num_clauses, literal_to_assign.literal,
346 literal_to_assign.source_clause_index);
347 }
348 if (conflict != kNoClauseIndex) {
349 MarkAsNeededForProof(&clauses_[conflict]);
350 }
351
352 for (const Literal literal : assigned_) {
353 assignment_.UnassignLiteral(literal);
354 }
355 assigned_.clear();
356 high_priority_literals_to_assign_.clear();
357 low_priority_literals_to_assign_.clear();
358 unit_stack_.clear();
359
360 return conflict != kNoClauseIndex;
361}
362
363ClauseIndex DratChecker::AssignAndPropagate(ClauseIndex num_clauses,
364 Literal literal,
365 ClauseIndex source_clause_index) {
366 assigned_.push_back(literal);
367 assignment_.AssignFromTrueLiteral(literal);
368 assignment_source_[literal.Variable()] = source_clause_index;
369
370 const Literal false_literal = literal.Negated();
371 std::vector<ClauseIndex>& watched = watched_literals_[false_literal.Index()];
372 int new_watched_size = 0;
373 ClauseIndex conflict_index = kNoClauseIndex;
374 for (const ClauseIndex clause_index : watched) {
375 if (clause_index >= num_clauses) {
376 // Stop watching the literals of clauses which cannot possibly be
377 // necessary to check the rest of the proof.
378 continue;
379 }
380 Clause& clause = clauses_[clause_index];
381 DCHECK(!clause.IsDeleted(num_clauses));
382 if (conflict_index != kNoClauseIndex) {
383 watched[new_watched_size++] = clause_index;
384 continue;
385 }
386
387 Literal* clause_literals = literals_.data() + clause.first_literal_index;
388 const Literal other_watched_literal(LiteralIndex(
389 clause_literals[0].Index().value() ^
390 clause_literals[1].Index().value() ^ false_literal.Index().value()));
391 if (assignment_.LiteralIsTrue(other_watched_literal)) {
392 watched[new_watched_size++] = clause_index;
393 continue;
394 }
395
396 bool new_watched_literal_found = false;
397 for (int i = 2; i < clause.num_literals; ++i) {
398 if (!assignment_.LiteralIsFalse(clause_literals[i])) {
399 clause_literals[0] = other_watched_literal;
400 clause_literals[1] = clause_literals[i];
401 clause_literals[i] = false_literal;
402 watched_literals_[clause_literals[1].Index()].push_back(clause_index);
403 new_watched_literal_found = true;
404 break;
405 }
406 }
407
408 if (!new_watched_literal_found) {
409 if (assignment_.LiteralIsFalse(other_watched_literal)) {
410 // 'clause' is falsified with 'assignment_', we found a conflict.
411 // TODO(user): test moving the rest of the vector here and
412 // returning right away.
413 conflict_index = clause_index;
414 } else {
415 DCHECK(!assignment_.LiteralIsAssigned(other_watched_literal));
416 // 'clause' is unit, push its unit literal on
417 // 'literals_to_assign_high_priority' or
418 // 'literals_to_assign_low_priority' to assign it to true and propagate
419 // it in a later call to AssignAndPropagate().
420 if (clause.is_needed_for_proof) {
421 high_priority_literals_to_assign_.push_back(
422 {other_watched_literal, clause_index});
423 } else {
424 low_priority_literals_to_assign_.push_back(
425 {other_watched_literal, clause_index});
426 }
427 }
428 watched[new_watched_size++] = clause_index;
429 }
430 }
431 watched.resize(new_watched_size);
432 return conflict_index;
433}
434
435void DratChecker::MarkAsNeededForProof(Clause* clause) {
436 const auto mark_clause_and_sources = [&](Clause* clause) {
437 clause->is_needed_for_proof = true;
438 for (const Literal literal : Literals(*clause)) {
439 const ClauseIndex source_clause_index =
440 assignment_source_[literal.Variable()];
441 if (source_clause_index != kNoClauseIndex) {
442 clauses_[source_clause_index].tmp_is_needed_for_proof_step = true;
443 }
444 }
445 };
446 mark_clause_and_sources(clause);
447 for (int i = unit_stack_.size() - 1; i >= 0; --i) {
448 Clause& unit_clause = clauses_[unit_stack_[i]];
449 if (unit_clause.tmp_is_needed_for_proof_step) {
450 mark_clause_and_sources(&unit_clause);
451 // We can clean this flag here without risking missing clauses needed for
452 // the proof, because the clauses needed for a clause C are always lower
453 // than C in the stack.
454 unit_clause.tmp_is_needed_for_proof_step = false;
455 }
456 }
457}
458
459void DratChecker::LogStatistics(int64_t duration_nanos) const {
460 int problem_clauses_needed_for_proof = 0;
461 int inferred_clauses_needed_for_proof = 0;
462 for (ClauseIndex i(0); i < clauses_.size(); ++i) {
463 if (clauses_[i].is_needed_for_proof) {
464 if (i < first_inferred_clause_index_) {
465 ++problem_clauses_needed_for_proof;
466 } else {
467 ++inferred_clauses_needed_for_proof;
468 }
469 }
470 }
471 VLOG(1) << problem_clauses_needed_for_proof
472 << " problem clauses needed for proof, out of "
473 << first_inferred_clause_index_;
474 VLOG(1) << inferred_clauses_needed_for_proof
475 << " inferred clauses needed for proof, out of "
476 << clauses_.size() - first_inferred_clause_index_;
477 VLOG(1) << num_rat_checks_ << " RAT inferred clauses";
478 VLOG(1) << "verification time: " << 1e-9 * duration_nanos << " s";
479}
480
481bool ContainsLiteral(absl::Span<const Literal> clause, Literal literal) {
482 return std::find(clause.begin(), clause.end(), literal) != clause.end();
483}
484
485bool Resolve(absl::Span<const Literal> clause,
486 absl::Span<const Literal> other_clause,
487 Literal complementary_literal, VariablesAssignment* assignment,
488 std::vector<Literal>* resolvent) {
489 DCHECK(ContainsLiteral(clause, complementary_literal));
490 DCHECK(ContainsLiteral(other_clause, complementary_literal.Negated()));
491 resolvent->clear();
492
493 for (const Literal literal : clause) {
494 if (literal != complementary_literal) {
495 // Temporary assignment used to do the checks below in linear time.
496 assignment->AssignFromTrueLiteral(literal);
497 resolvent->push_back(literal);
498 }
499 }
500
501 bool result = true;
502 for (const Literal other_literal : other_clause) {
503 if (other_literal != complementary_literal.Negated()) {
504 if (assignment->LiteralIsFalse(other_literal)) {
505 result = false;
506 break;
507 } else if (!assignment->LiteralIsAssigned(other_literal)) {
508 resolvent->push_back(other_literal);
509 }
510 }
511 }
512
513 // Revert the temporary assignment done above.
514 for (const Literal literal : clause) {
515 if (literal != complementary_literal) {
516 assignment->UnassignLiteral(literal);
517 }
518 }
519 return result;
520}
521
522bool AddProblemClauses(const std::string& file_path,
523 DratChecker* drat_checker) {
524 int line_number = 0;
525 int num_variables = 0;
526 int num_clauses = 0;
527 std::vector<Literal> literals;
528 std::ifstream file(file_path);
529 std::string line;
530 bool result = true;
531 while (std::getline(file, line)) {
532 line_number++;
533 std::vector<absl::string_view> words =
534 absl::StrSplit(line, absl::ByAnyChar(" \t"), absl::SkipWhitespace());
535 if (words.empty() || words[0] == "c") {
536 // Ignore empty and comment lines.
537 continue;
538 }
539 if (words[0] == "p") {
540 if (num_clauses > 0 || words.size() != 4 || words[1] != "cnf" ||
541 !absl::SimpleAtoi(words[2], &num_variables) || num_variables <= 0 ||
542 !absl::SimpleAtoi(words[3], &num_clauses) || num_clauses <= 0) {
543 LOG(ERROR) << "Invalid content '" << line << "' at line " << line_number
544 << " of " << file_path;
545 result = false;
546 break;
547 }
548 continue;
549 }
550 literals.clear();
551 for (int i = 0; i < words.size(); ++i) {
552 int signed_value;
553 if (!absl::SimpleAtoi(words[i], &signed_value) ||
554 std::abs(signed_value) > num_variables ||
555 (signed_value == 0 && i != words.size() - 1)) {
556 LOG(ERROR) << "Invalid content '" << line << "' at line " << line_number
557 << " of " << file_path;
558 result = false;
559 break;
560 }
561 if (signed_value != 0) {
562 literals.push_back(Literal(signed_value));
563 }
564 }
565 drat_checker->AddProblemClause(literals);
566 }
567 file.close();
568 return result;
569}
570
571bool AddInferredAndDeletedClauses(const std::string& file_path,
572 DratChecker* drat_checker) {
573 int line_number = 0;
574 bool ends_with_empty_clause = false;
575 std::vector<Literal> literals;
576 std::ifstream file(file_path);
577 std::string line;
578 bool result = true;
579 while (std::getline(file, line)) {
580 line_number++;
581 std::vector<absl::string_view> words =
582 absl::StrSplit(line, absl::ByAnyChar(" \t"), absl::SkipWhitespace());
583 bool delete_clause = !words.empty() && words[0] == "d";
584 literals.clear();
585 for (int i = (delete_clause ? 1 : 0); i < words.size(); ++i) {
586 int signed_value;
587 if (!absl::SimpleAtoi(words[i], &signed_value) ||
588 (signed_value == 0 && i != words.size() - 1)) {
589 LOG(ERROR) << "Invalid content '" << line << "' at line " << line_number
590 << " of " << file_path;
591 result = false;
592 break;
593 }
594 if (signed_value != 0) {
595 literals.push_back(Literal(signed_value));
596 }
597 }
598 if (delete_clause) {
599 drat_checker->DeleteClause(literals);
600 ends_with_empty_clause = false;
601 } else {
602 drat_checker->AddInferredClause(literals);
603 ends_with_empty_clause = literals.empty();
604 }
605 }
606 if (!ends_with_empty_clause) {
607 drat_checker->AddInferredClause({});
608 }
609 file.close();
610 return result;
611}
612
613bool PrintClauses(const std::string& file_path, SatFormat format,
614 absl::Span<const std::vector<Literal>> clauses,
615 int num_variables) {
616 std::ofstream output_stream(file_path, std::ofstream::out);
617 if (format == DIMACS) {
618 output_stream << "p cnf " << num_variables << " " << clauses.size() << "\n";
619 }
620 for (const auto& clause : clauses) {
621 for (Literal literal : clause) {
622 output_stream << literal.SignedValue() << " ";
623 }
624 output_stream << "0\n";
625 }
626 output_stream.close();
627 return output_stream.good();
628}
629
630} // namespace sat
631} // namespace operations_research
void AddProblemClause(absl::Span< const Literal > clause)
std::vector< std::vector< Literal > > GetUnsatSubProblem() const
Status Check(double max_time_in_seconds)
std::vector< std::vector< Literal > > GetOptimizedProof() const
void AddInferredClause(absl::Span< const Literal > clause)
void DeleteClause(absl::Span< const Literal > clause)
bool LiteralIsAssigned(Literal literal) const
Definition sat_base.h:209
bool LiteralIsFalse(Literal literal) const
Definition sat_base.h:203
void push_back(const value_type &val)
Definition file.cc:327
bool AddProblemClauses(const std::string &file_path, DratChecker *drat_checker)
const LiteralIndex kNoLiteralIndex(-1)
bool Resolve(absl::Span< const Literal > clause, absl::Span< const Literal > other_clause, Literal complementary_literal, VariablesAssignment *assignment, std::vector< Literal > *resolvent)
bool PrintClauses(const std::string &file_path, SatFormat format, absl::Span< const std::vector< Literal > > clauses, int num_variables)
std::vector< Literal > Literals(absl::Span< const int > input)
Definition sat_base.h:164
bool ContainsLiteral(absl::Span< const Literal > clause, Literal literal)
bool AddInferredAndDeletedClauses(const std::string &file_path, DratChecker *drat_checker)
const ClauseIndex kNoClauseIndex(-1)
OR-Tools root namespace.
ClosedInterval::Iterator end(ClosedInterval interval)
ClosedInterval::Iterator begin(ClosedInterval interval)
uint64_t Hash(uint64_t num, uint64_t c)
Definition hash.h:73