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