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