Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
clause.h
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
14// This file contains the solver internal representation of the clauses and the
15// classes used for their propagation.
16
17#ifndef ORTOOLS_SAT_CLAUSE_H_
18#define ORTOOLS_SAT_CLAUSE_H_
19
20#include <cstdint>
21#include <deque>
22#include <functional>
23#include <optional>
24#include <string>
25#include <utility>
26#include <vector>
27
28#include "absl/base/attributes.h"
29#include "absl/container/flat_hash_map.h"
30#include "absl/container/flat_hash_set.h"
31#include "absl/functional/any_invocable.h"
32#include "absl/functional/function_ref.h"
33#include "absl/log/check.h"
34#include "absl/types/span.h"
39#include "ortools/sat/model.h"
42#include "ortools/sat/util.h"
43#include "ortools/util/bitset.h"
44#include "ortools/util/stats.h"
47
48namespace operations_research {
49namespace sat {
50
51// This is how the SatSolver stores a clause. A clause is just a disjunction of
52// literals. In many places, we just use vector<literal> to encode one. But in
53// the critical propagation code, we use this class to remove one memory
54// indirection.
55class SatClause {
56 public:
57 // Creates a sat clause. There must be at least 2 literals.
58 // Clause with one literal fix variable directly and are never constructed.
59 // Note that in practice, we use BinaryImplicationGraph for the clause of size
60 // 2, so this is used for size at least 3.
61 static SatClause* Create(absl::Span<const Literal> literals);
62
63 // Non-sized delete because this is a tail-padded class.
64 void operator delete(void* p) {
65 ::operator delete(p); // non-sized delete
66 }
67
68 // Number of literals in the clause.
69 int size() const { return size_; }
70 bool empty() const { return size_ == 0; }
71
72 // We re-use the size to lazily remove clause and notify that they need to be
73 // deleted. It is why this is not called empty() to emphasis that fact. Note
74 // that we never create an initially empty clause, so there is no confusion
75 // with an infeasible model with an empty clause inside.
76 int IsRemoved() const { return size_ == 0; }
77
78 // Allows for range based iteration: for (Literal literal : clause) {}.
79 const Literal* begin() const { return &(literals_[0]); }
80 const Literal* end() const { return &(literals_[size_]); }
81
82 // Returns the first and second literals. These are always the watched
83 // literals if the clause is attached in the LiteralWatchers.
84 Literal FirstLiteral() const { return literals_[0]; }
85 Literal SecondLiteral() const { return literals_[1]; }
86
87 // Returns the literal that was propagated to true. This only works for a
88 // clause that just propagated this literal. Otherwise, this will just returns
89 // a literal of the clause.
90 Literal PropagatedLiteral() const { return literals_[0]; }
91
92 // Returns the reason for the last unit propagation of this clause. The
93 // preconditions are the same as for PropagatedLiteral(). Note that we don't
94 // need to include the propagated literal.
95 absl::Span<const Literal> PropagationReason() const {
96 return absl::Span<const Literal>(&(literals_[1]), size_ - 1);
97 }
98
99 // Returns a Span<> representation of the clause.
100 absl::Span<const Literal> AsSpan() const {
101 return absl::Span<const Literal>(&(literals_[0]), size_);
102 }
103
104 // Returns true if the clause is satisfied for the given assignment. Note that
105 // the assignment may be partial, so false does not mean that the clause can't
106 // be satisfied by completing the assignment.
107 bool IsSatisfied(const VariablesAssignment& assignment) const;
108
109 std::string DebugString() const;
110
111 private:
112 // The manager needs to permute the order of literals in the clause and
113 // call Clear()/Rewrite.
114 friend class ClauseManager;
115
116 Literal* literals() { return &(literals_[0]); }
117
118 // Marks the clause so that the next call to CleanUpWatchers() can identify it
119 // and actually remove it. We use size_ = 0 for this since the clause will
120 // never be used afterwards.
121 void Clear() { size_ = 0; }
122
123 // Removes literals that are fixed. This should only be called at level 0
124 // where a literal is fixed iff it is assigned. Aborts and returns true if
125 // they are not all false.
126 //
127 // Note that the removed literal can still be accessed in the portion [size,
128 // old_size) of literals().
129 bool RemoveFixedLiteralsAndTestIfTrue(const VariablesAssignment& assignment);
130
131 // Rewrites a clause with another shorter one. Note that the clause shouldn't
132 // be attached when this is called.
133 void Rewrite(absl::Span<const Literal> new_clause) {
134 size_ = 0;
135 for (const Literal l : new_clause) literals_[size_++] = l;
136 }
137
138 int32_t size_;
139
140 // This class store the literals inline, and literals_ mark the starts of the
141 // variable length portion.
142 Literal literals_[0];
143};
144
145// Clause information used for the clause database management. Note that only
146// the clauses that can be removed have an info. The problem clauses and
147// the learned one that we wants to keep forever do not have one.
149 double activity = 0.0;
150 int32_t lbd = 0;
152};
153
155
156// Used for tracking the source of LazyDelete() for each clauses.
173
174// Stores the 2-watched literals data structure. See
175// http://www.cs.berkeley.edu/~necula/autded/lecture24-sat.pdf for
176// detail.
177//
178// This class is also responsible for owning the clause memory and all related
179// information.
181 public:
182 explicit ClauseManager(Model* model);
183
184 // This type is neither copyable nor movable.
185 ClauseManager(const ClauseManager&) = delete;
187
188 ~ClauseManager() override;
189
190 // Must be called before adding clauses referring to such variables.
191 void Resize(int num_variables);
192
193 // SatPropagator API.
194 bool Propagate(Trail* trail) final;
195 absl::Span<const Literal> Reason(const Trail& trail, int trail_index,
196 int64_t conflict_id) const final;
197 void Reimply(Trail* trail, int old_trail_index) final;
198
199 // Returns the reason of the variable at given trail_index. This only works
200 // for variable propagated by this class and is almost the same as Reason()
201 // with a different return format.
202 SatClause* ReasonClause(int trail_index) const;
203
204 // Returns the clause that fixed `var`, or nullptr if `var` is not fixed, or
205 // was not fixed by a clause.
206 SatClause* ReasonClauseOrNull(BooleanVariable var) const;
207
208 // Returns true iff the clause is the reason for an assigned variable.
209 bool ClauseIsUsedAsReason(SatClause* clause) const;
210
211 // Adds a new clause and perform initial propagation for this clause only.
212 bool AddClause(ClauseId id, absl::Span<const Literal> literals, Trail* trail,
213 int lbd);
214 bool AddClause(absl::Span<const Literal> literals);
215
216 // Same as AddClause() for a removable clause. This is only called on learned
217 // conflict, so this should never have all its literal at false (CHECKED).
218 SatClause* AddRemovableClause(ClauseId id, absl::Span<const Literal> literals,
219 Trail* trail, int lbd);
220
221 // Returns the number of deletion for each DeletionSourceForStat type.
222 absl::Span<const int64_t> DeletionCounters() const {
223 return deletion_counters_;
224 }
225
226 // Lazily detach the given clause. Watchers are removed during propagation or
227 // when CleanUpWatchers() is called, and the clause will be deleted by
228 // DeleteRemovedClauses().
229 //
230 // Note that we remove the clause from clauses_info_ right away.
231 // Callers must not reattach `clause` after calling this method.
232 void LazyDelete(SatClause* clause, DeletionSourceForStat source);
233
234 // Removes all watchers for any clauses that have been lazily detached.
235 void CleanUpWatchers();
236
237 // Attaches the given clause. The first two literal of the clause must
238 // be unassigned and the clause must not be already attached.
239 void Attach(SatClause* clause, Trail* trail);
240
241 // Reclaims the memory of the lazily removed clauses (their size was set to
242 // zero) and remove them from AllClausesInCreationOrder() this work in
243 // O(num_clauses()).
245 int64_t num_clauses() const { return clauses_.size(); }
246 const std::vector<SatClause*>& AllClausesInCreationOrder() const {
247 return clauses_;
248 }
249
250 // True if removing this clause will not change the set of feasible solution.
251 // This is the case for clauses that were learned during search. Note however
252 // that some learned clause are kept forever (heuristics) and do not appear
253 // here.
254 bool IsRemovable(SatClause* const clause) const {
255 return clauses_info_.contains(clause);
256 }
257 int64_t num_removable_clauses() const { return clauses_info_.size(); }
258 absl::flat_hash_map<SatClause*, ClauseInfo>* mutable_clauses_info() {
259 return &clauses_info_;
260 }
261 int LbdOrZeroIfNotRemovable(SatClause* const clause) const {
262 auto it = clauses_info_.find(clause);
263 if (it == clauses_info_.end()) return 0;
264 return it->second.lbd;
265 }
266 void KeepClauseForever(SatClause* const clause) {
267 clauses_info_.erase(clause);
268 }
269 void RescaleClauseActivities(double scaling_factor) {
270 for (auto& entry : clauses_info_) {
271 entry.second.activity *= scaling_factor;
272 }
273 }
274
275 // If the new lbd is better than the stored one, update it.
276 // And return the result of IsRemovable() (this save one hash lookup).
277 void ChangeLbdIfBetter(SatClause* clause, int new_lbd);
278
279 // Total number of clauses inspected during calls to Propagate().
280 int64_t num_inspected_clauses() const { return num_inspected_clauses_; }
282 return num_inspected_clause_literals_;
283 }
284
285 // The number of different literals (always twice the number of variables).
286 int64_t literal_size() const { return needs_cleaning_.size().value(); }
287
288 // Number of clauses currently watched.
289 int64_t num_watched_clauses() const { return num_watched_clauses_; }
290
291 // Number of time an existing clause lbd was reduced (due to inprocessing or
292 // recomputation of lbd in different branches).
293 int64_t num_lbd_promotions() const { return num_lbd_promotions_; }
294
295 ClauseId GetClauseId(const SatClause* clause) const {
296 const auto it = clause_id_.find(clause);
297 return it != clause_id_.end() ? it->second : kNoClauseId;
298 }
299
300 void SetClauseId(const SatClause* clause, ClauseId id) {
301 clause_id_[clause] = id;
302 }
303
304 // Methods implementing pseudo-iterators over the clause database that are
305 // stable across cleanups. They all return nullptr if there are no more
306 // clauses.
307
308 // Returns the next clause to minimize that has never been minimized before.
309 // Note that we only minimize clauses kept forever.
311
312 // Returns the next clause to minimize, this iterator will be reset to the
313 // start so the clauses will be returned in round-robin order.
314 // Note that we only minimize clauses kept forever.
316
317 // Returns the next clause to probe in round-robin order.
319
320 // This is used for the "eager" subsumption. Each time we learn a conflict, we
321 // see if one of the last learned clause can be subsumed with it or not.
322 absl::Span<SatClause*> LastNClauses(int n) {
323 if (n > clauses_.size()) n = clauses_.size();
324 return absl::MakeSpan(clauses_).subspan(clauses_.size() - n);
325 }
326
327 // Restart the scans.
328 void ResetToProbeIndex() { to_probe_index_ = 0; }
329 int64_t NumToMinimizeIndexResets() const {
330 return num_to_minimize_index_resets_;
331 }
332
333 // Ensures that NextNewClauseToMinimize() returns only learned clauses.
334 // This is a noop after the first call.
336 if (to_first_minimize_index_ > 0) return;
337 to_first_minimize_index_ = clauses_.size();
338 }
339
340 // During an inprocessing phase, it is easier to detach all clause first,
341 // then simplify and then reattach them. Note however that during these
342 // two calls, it is not possible to use the solver unit-progation.
343 //
344 // Important: When reattach is called, we assume that none of their literal
345 // are fixed, so we don't do any special checks.
346 //
347 // These functions can be called multiple-time and do the right things. This
348 // way before doing something, you can call the corresponding function and be
349 // sure to be in a good state. I.e. always AttachAllClauses() before
350 // propagation and DetachAllClauses() before going to do an inprocessing pass
351 // that might transform them.
352 void DetachAllClauses();
353 void AttachAllClauses();
354
355 // Replaces a clause with a subset of the literals.
356 // This may be called while clauses are attached, but the first two literals
357 // in new_clause must be valid watchers.
358 // This does *not* propagate the clause.
359 ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(
360 SatClause* clause, absl::Span<const Literal> new_clause,
361 absl::Span<const ClauseId> clause_ids = {});
362
363 bool RemoveFixedLiteralsAndTestIfTrue(SatClause* clause);
364
365 // Fix a literal either with an existing LRAT `unit_clause_id`, or with a new
366 // inferred unit clause, using `clause_ids` as proof.
367 // This do NOT need to be between [Detach/Attach]AllClauses() calls.
368 ABSL_MUST_USE_RESULT bool InprocessingAddUnitClause(ClauseId unit_clause_id,
369 Literal true_literal);
370 ABSL_MUST_USE_RESULT bool InprocessingFixLiteral(
371 Literal true_literal, absl::Span<const ClauseId> clause_ids = {});
372
373 // This can return nullptr if new_clause was of size one or two as these are
374 // treated differently. Note that none of the variable should be fixed in the
375 // given new clause.
376 SatClause* InprocessingAddClause(absl::Span<const Literal> new_clause);
377
378 // Contains, for each literal, the list of clauses that need to be inspected
379 // when the corresponding literal becomes false.
380 struct Watcher {
381 Watcher() = default;
384
385 // Optimization. A literal from the clause that sometimes allow to not even
386 // look at the clause memory when true.
388
389 // Optimization. An index in the clause. Instead of looking for another
390 // literal to watch from the start, we will start from here instead, and
391 // loop around if needed. This allows to avoid bad quadratic corner cases
392 // and lead to an "optimal" complexity. See "Optimal Implementation of
393 // Watched Literals and more General Techniques", Ian P. Gent.
394 //
395 // Note that ideally, this should be part of a SatClause, so it can be
396 // shared across watchers. However, since we have 32 bits for "free" here
397 // because of the struct alignment, we store it here instead.
398 int32_t start_index;
399
401 };
402
403 // This is exposed since some inprocessing code can heuristically exploit the
404 // currently watched literal and blocking literal to do some simplification.
405 const std::vector<Watcher>& WatcherListOnFalse(Literal false_literal) const {
406 return watchers_on_false_[false_literal];
407 }
408
410 absl::AnyInvocable<void(int lbd, ClauseId id, absl::Span<const Literal>)>
411 add_clause_callback) {
412 add_clause_callback_ = std::move(add_clause_callback);
413 }
414
415 // Removes the add clause callback and returns it. This can be used to
416 // temporarily disable the callback.
417 absl::AnyInvocable<void(int lbd, ClauseId id, absl::Span<const Literal>)>
419 return std::move(add_clause_callback_);
420 }
421
422 // Returns the ID of the unit, binary, or general clause that is the reason
423 // for the given literal, or kNoClauseId if there is none.
424 ClauseId ReasonClauseId(Literal literal) const;
425
426 // Appends to `clause_ids` the IDs of the clauses which, by unit propagation
427 // from some decisions, are sufficient to ensure that all literals in
428 // `literals` are fixed to their current value.
429 //
430 // If `decision` is not `kNoLiteralIndex`, also appends the IDs of the clauses
431 // proving that `decision` implies all the literals in `literals`. In this
432 // case, `decision` must either be the last decision on the trail, or must
433 // directly imply it. Furthermore, each decision must directly imply the
434 // previous one on the trail.
435 //
436 // This method expands the reasons of each literal recursively until a
437 // decision, or a literal implied by the decision at its decision level, or a
438 // literal for which `root_literals` returns a value other than kNoClauseId,
439 // is found. The latter criteria avoid a quadratic complexity when
440 // implications of the form "decision(s) => literal" are added for each newly
441 // propagated literal after taking a decision (provided these implications are
442 // added to the binary implication graph or to the `root_literals` function
443 // right away, in trail index order).
444 //
445 // `root_literals` must take a decision level and a trail index as parameter
446 // (the level is the assignment level of this trail index). It must return the
447 // ID of the clause stating that the literal at this index is fixed by
448 // previous decision(s), if the reason expansion should be stopped here
449 // (otherwise it should return kNoClauseId).
451 absl::Span<const Literal> literals, std::vector<ClauseId>* clause_ids,
452 LiteralIndex decision = kNoLiteralIndex,
453 std::optional<absl::FunctionRef<ClauseId(int, int)>> root_literals = {});
454
455 private:
456 // Attaches the given clause. This eventually propagates a literal which is
457 // enqueued on the trail. Returns false if a contradiction was encountered.
458 bool AttachAndPropagate(SatClause* clause, Trail* trail);
459
460 // Attaches the given clause to the event: the given literal becomes false.
461 // The blocking_literal can be any literal from the clause, it is used to
462 // speed up Propagate() by skipping the clause if it is true.
463 void AttachOnFalse(Literal literal, Literal blocking_literal,
464 SatClause* clause);
465
466 // Common code between LazyDelete() and Detach().
467 void InternalDetach(SatClause* clause, DeletionSourceForStat source);
468
469 ClauseIdGenerator* clause_id_generator_;
470
472 watchers_on_false_;
473
474 // SatClause reasons by trail_index.
475 std::vector<SatClause*> reasons_;
476
477 // Indicates if the corresponding watchers_on_false_ list need to be
478 // cleaned. The boolean is_clean_ is just used in DCHECKs.
479 SparseBitset<LiteralIndex> needs_cleaning_;
480 bool is_clean_ = true;
481
482 const SatParameters& parameters_;
483 const VariablesAssignment& assignment_;
484 BinaryImplicationGraph* implication_graph_;
485 Trail* trail_;
486
487 // For statistic reporting.
488 std::vector<int64_t> deletion_counters_;
489 int64_t num_inspected_clauses_ = 0;
490 int64_t num_inspected_clause_literals_ = 0;
491 int64_t num_watched_clauses_ = 0;
492 int64_t num_lbd_promotions_ = 0;
493 mutable StatsGroup stats_;
494
495 // For DetachAllClauses()/AttachAllClauses().
496 bool all_clauses_are_attached_ = true;
497
498 // All the clauses currently in memory. This vector has ownership of the
499 // pointers. We currently do not use std::unique_ptr<SatClause> because it
500 // can't be used with some STL algorithms like std::partition.
501 //
502 // Note that the unit clauses and binary clause are not kept here.
503 std::vector<SatClause*> clauses_;
504
505 // TODO(user): If more indices are needed, switch to a generic API.
506 int to_minimize_index_ = 0;
507
508 int num_to_minimize_index_resets_ = 0;
509 int to_first_minimize_index_ = 0;
510 int to_probe_index_ = 0;
511
512 absl::flat_hash_map<const SatClause*, ClauseId> clause_id_;
513 // Only contains removable clause.
514 absl::flat_hash_map<SatClause*, ClauseInfo> clauses_info_;
515
516 LratProofHandler* lrat_proof_handler_ = nullptr;
517
518 // Temporary member used when adding LRAT inferred clauses.
519 std::vector<ClauseId> clause_ids_scratchpad_;
520
521 absl::AnyInvocable<void(int lbd, ClauseId id, absl::Span<const Literal>)>
522 add_clause_callback_ = nullptr;
523
525 std::vector<int> marked_trail_indices_heap_;
526 std::vector<ClauseId> tmp_clause_ids_for_append_clauses_fixing_;
527};
528
529// A binary clause. This is used by BinaryClauseManager.
531 BinaryClause(Literal _a, Literal _b) : id(-1), a(_a), b(_b) {}
532 bool operator==(BinaryClause o) const { return a == o.a && b == o.b; }
533 bool operator!=(BinaryClause o) const { return a != o.a || b != o.b; }
534 ClauseId id;
537};
538
539// A simple class to manage a set of binary clauses.
541 public:
543
544 // This type is neither copyable nor movable.
547
548 int NumClauses() const { return set_.size(); }
549
550 // Adds a new binary clause to the manager and returns true if it wasn't
551 // already present.
553 std::pair<int, int> p(c.a.SignedValue(), c.b.SignedValue());
554 if (p.first > p.second) std::swap(p.first, p.second);
555 if (set_.find(p) == set_.end()) {
556 set_.insert(p);
557 newly_added_.push_back(c);
558 return true;
559 }
560 return false;
561 }
562
563 // Returns the newly added BinaryClause since the last ClearNewlyAdded() call.
564 const std::vector<BinaryClause>& newly_added() const { return newly_added_; }
565 void ClearNewlyAdded() { newly_added_.clear(); }
566
567 private:
568 absl::flat_hash_set<std::pair<int, int>> set_;
569 std::vector<BinaryClause> newly_added_;
570};
571
572// Internal BinaryImplicationGraph helper for LRAT in DetectEquivalences().
573class LratEquivalenceHelper;
574
575// Special class to store and propagate clauses of size 2 (i.e. implication).
576// Such clauses are never deleted. Together, they represent the 2-SAT part of
577// the problem. Note that 2-SAT satisfiability is a polynomial problem, but
578// W2SAT (weighted 2-SAT) is NP-complete.
579//
580// TODO(user): Most of the note below are done, but we currently only applies
581// the reduction before the solve. We should consider doing more in-processing.
582// The code could probably still be improved too.
583//
584// Note(user): All the variables in a strongly connected component are
585// equivalent and can be thus merged as one. This is relatively cheap to compute
586// from time to time (linear complexity). We will also get contradiction (a <=>
587// not a) this way. This is done by DetectEquivalences().
588//
589// Note(user): An implication (a => not a) implies that a is false. I am not
590// sure it is worth detecting that because if the solver assign a to true, it
591// will learn that right away. I don't think we can do it faster.
592//
593// Note(user): The implication graph can be pruned. This is called the
594// transitive reduction of a graph. For instance If a => {b,c} and b => {c},
595// then there is no need to store a => {c}. The transitive reduction is unique
596// on an acyclic graph. Computing it will allow for a faster propagation and
597// memory reduction. It is however not cheap. Maybe simple lazy heuristics to
598// remove redundant arcs are better. Note that all the learned clauses we add
599// will never be redundant (but they could introduce cycles). This is done
600// by ComputeTransitiveReduction().
601//
602// Note(user): This class natively support at most one constraints. This is
603// a way to reduced significantly the memory and size of some 2-SAT instances.
604// However, it is not fully exploited for pure SAT problems. See
605// TransformIntoMaxCliques().
606//
607// Note(user): Add a preprocessor to remove duplicates in the implication lists.
608// Note that all the learned clauses we add will never create duplicates.
609//
610// References for most of the above and more:
611// - Brafman RI, "A simplifier for propositional formulas with many binary
612// clauses", IEEE Trans Syst Man Cybern B Cybern. 2004 Feb;34(1):52-9.
613// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.28.4911
614// - Marijn J. H. Heule, Matti Järvisalo, Armin Biere, "Efficient CNF
615// Simplification Based on Binary Implication Graphs", Theory and Applications
616// of Satisfiability Testing - SAT 2011, Lecture Notes in Computer Science
617// Volume 6695, 2011, pp 201-215
618// http://www.cs.helsinki.fi/u/mjarvisa/papers/heule-jarvisalo-biere.sat11.pdf
620 public:
621 explicit BinaryImplicationGraph(Model* model);
622
623 // This type is neither copyable nor movable.
626
627 ~BinaryImplicationGraph() override;
628
629 // SatPropagator interface.
630 bool Propagate(Trail* trail) final;
631 absl::Span<const Literal> Reason(const Trail& trail, int trail_index,
632 int64_t conflict_id) const final;
633 void Reimply(Trail* trail, int old_trail_index) final;
634
635 // Resizes the data structure.
636 void Resize(int num_variables);
637
638 // Returns the "size" of this class, that is 2 * num_boolean_variables as
639 // updated by the larger Resize() call.
640 int64_t literal_size() const { return implications_and_amos_.size(); }
641
642 // Returns true if no constraints where ever added to this class.
643 bool IsEmpty() const final { return no_constraint_ever_added_; }
644
645 // Adds the binary clause (a OR b), which is the same as (not a => b).
646 // Note that it is also equivalent to (not b => a). More precisely, adds the
647 // binary clause (rep(a) OR rep(b)), where rep(l) is the representative of l.
648 // If they are different from a and b, a new inferred LRAT clause is also
649 // added (if an LRAT proof handler is set), with a new clause ID (and the old
650 // LRAT `id` clause is deleted, unless `delete_non_representative_id` is
651 // false).
652 //
653 // Preconditions:
654 // - If we are at root node, then none of the literal should be assigned.
655 // This is Checked and is there to track inefficiency as we do not need a
656 // clause in this case.
657 // - If we are at a positive decision level, we will propagate something if
658 // we can. However, if both literal are false, we will just return false
659 // and do nothing. In all other case, we will return true.
660 bool AddBinaryClause(ClauseId id, Literal a, Literal b,
661 bool delete_non_representative_id = true) {
662 return AddBinaryClauseInternal(id, a, b, /*change_reason=*/false,
663 delete_non_representative_id);
664 }
666 return AddBinaryClause(kNoClauseId, a, b);
667 }
669 return AddBinaryClause(a.Negated(), b);
670 }
671
672 ClauseId GetClauseId(Literal a, Literal b) const {
673 if (a.Variable() > b.Variable()) std::swap(a, b);
674 const auto it = clause_id_.find(std::make_pair(a, b));
675 return it != clause_id_.end() ? it->second : kNoClauseId;
676 }
677
678 // When set, the callback will be called on ALL newly added binary clauses.
679 //
680 // The EnableSharing() function can be used to disable sharing temporarily for
681 // the clauses that are imported from the Shared repository already.
682 //
683 // TODO(user): this is meant to share clause between workers, hopefully the
684 // contention will not be too high. Double check and maybe add a batch version
685 // were we keep new implication and add them in batches.
686 void EnableSharing(bool enable) { enable_sharing_ = enable; }
687 void SetAdditionCallback(std::function<void(Literal, Literal)> f) {
688 add_binary_callback_ = f;
689 }
690 // An at most one constraint of size n is a compact way to encode n * (n - 1)
691 // implications. This must only be called at level zero.
692 //
693 // Returns false if this creates a conflict. Currently this can only happens
694 // if there is duplicate literal already assigned to true in this constraint.
695 //
696 // TODO(user): Our algorithm could generalize easily to at_most_ones + a list
697 // of literals that will be false if one of the literal in the amo is at one.
698 // It is a way to merge common list of implications.
699 //
700 // If the final AMO size is smaller than at_most_one_expansion_size
701 // parameters, we fully expand it.
702 ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span<const Literal> at_most_one);
703
704 // Uses the binary implication graph to minimize the given conflict by
705 // removing literals that implies others. The idea is that if a and b are two
706 // literals from the given conflict and a => b (which is the same as not(b) =>
707 // not(a)) then a is redundant and can be removed. If an LRAT proof handler is
708 // set, fills the LRAT proof for these implications in `clause_ids`.
709 //
710 // Note that removing as many literals as possible is too time consuming, so
711 // we use different heuristics/algorithms to do this minimization.
712 // See the binary_minimization_algorithm SAT parameter and the .cc for more
713 // details about the different algorithms.
714 void MinimizeConflictFirst(const Trail& trail, std::vector<Literal>* c,
716 std::vector<ClauseId>* clause_ids,
717 bool also_use_decisions);
718
719 // Appends the IDs of the unit and binary clauses that imply the given
720 // literals to `clause_ids`. Either `MinimizeConflictFirst` or
721 // `ClearImpliedLiterals` must have been called just before, and the given
722 // literals must be the reason of a literal in the conflict. Does nothing for
723 // literals that have already been processed by a previous call to this
724 // method.
725 void AppendImplicationChains(absl::Span<const Literal> literals,
726 std::vector<ClauseId>* clause_ids);
727
728 // This must only be called at decision level 0 after all the possible
729 // propagations. It:
730 // - Removes the variable at true from the implications lists.
731 // - Frees the propagation list of the assigned literals.
733
734 // Returns false if the model is unsat, otherwise detects equivalent variable
735 // (with respect to the implications only) and reorganize the propagation
736 // lists accordingly.
737 //
738 // TODO(user): Completely get rid of such literal instead? it might not be
739 // reasonable code-wise to remap our literals in all of our constraints
740 // though.
741 bool DetectEquivalences(bool log_info = false);
742
743 // Returns true if DetectEquivalences() has been called and no new binary
744 // clauses have been added since then. When this is true then there is no
745 // cycle in the binary implication graph (modulo the redundant literals that
746 // form a cycle with their representative).
747 bool IsDag() const { return is_dag_; }
748
749 // One must call DetectEquivalences() first, this is CHECKed.
750 // Returns a list so that if x => y, then x is after y.
751 const std::vector<LiteralIndex>& ReverseTopologicalOrder() const {
752 CHECK(is_dag_);
753 return reverse_topological_order_;
754 }
755
756 // Returns the list of literal "directly" implied by l. Beware that this can
757 // easily change behind your back if you modify the solver state.
758 absl::Span<const Literal> Implications(Literal l) const {
759 return implications_and_amos_[l].literals();
760 }
761
762 // Returns the representative of the equivalence class of l (or l itself if it
763 // is on its own). Note that DetectEquivalences() should have been called to
764 // get any non-trivial results.
766 if (l.Index() >= representative_of_.size()) return l;
767 if (representative_of_[l] == kNoLiteralIndex) return l;
768 return Literal(representative_of_[l]);
769 }
770
771 // Prunes the implication graph by calling first DetectEquivalences() to
772 // remove cycle and then by computing the transitive reduction of the
773 // remaining DAG.
774 //
775 // Note that this can be slow (num_literals graph traversals), so we abort
776 // early if we start doing too much work.
777 //
778 // Returns false if the model is detected to be UNSAT (this needs to call
779 // DetectEquivalences() if not already done).
780 bool ComputeTransitiveReduction(bool log_info = false);
781
782 // Another way of representing an implication graph is a list of maximal "at
783 // most one" constraints, each forming a max-clique in the incompatibility
784 // graph. This representation is useful for having a good linear relaxation.
785 //
786 // This function will transform each of the given constraint into a maximal
787 // one in the underlying implication graph. Constraints that are redundant
788 // after other have been expanded (i.e. included into) will be cleared.
789 // Note that the order of constraints will be conserved.
790 //
791 // Returns false if the model is detected to be UNSAT (this needs to call
792 // DetectEquivalences() if not already done).
793 bool TransformIntoMaxCliques(std::vector<std::vector<Literal>>* at_most_ones,
794 int64_t max_num_explored_nodes = 1e8);
795
796 // This is similar to TransformIntoMaxCliques() but we are just looking into
797 // reducing the number of constraints. If two initial clique A and B can be
798 // merged into A U B, we do it. We do not extends clique further.
799 //
800 // This approach should minimize the number of overall literals. It should
801 // be also enough for presolve. We can extend clique even more later for
802 // faster propagation or better linear relaxation.
803 //
804 // Note that we can do that relatively efficiently, if the candidate for
805 // extension of a clique A contains clique B, then we can just extend.
806 // Moreover this is a symmetric relation. And if we look at the graph of
807 // possible extension (A <-> B if A U B is a valid clique), then we can
808 // find maximum clique in this graph which might be relatively small.
809 //
810 // TODO(user): Switch to a dtime limit.
811 bool MergeAtMostOnes(absl::Span<std::vector<Literal>> at_most_ones,
812 int64_t max_num_explored_nodes = 1e8,
813 double* dtime = nullptr);
814
815 // LP clique cut heuristic. Returns a set of "at most one" constraints on the
816 // given literals or their negation that are violated by the current LP
817 // solution. Note that this assumes that
818 // lp_value(lit) = 1 - lp_value(lit.Negated()).
819 //
820 // The literal and lp_values vector are in one to one correspondence. We will
821 // only generate clique with these literals or their negation.
822 //
823 // TODO(user): Refine the heuristic and unit test!
824 const std::vector<std::vector<Literal>>& GenerateAtMostOnesWithLargeWeight(
825 absl::Span<const Literal> literals, absl::Span<const double> lp_values,
826 absl::Span<const double> reduced_costs);
827
828 // Heuristically identify "at most one" between the given literals, swap
829 // them around and return these amo as span inside the literals vector.
830 //
831 // TODO(user): Add a limit to make sure this do not take too much time.
832 std::vector<absl::Span<const Literal>> HeuristicAmoPartition(
833 std::vector<Literal>* literals);
834
835 // Number of literal propagated by this class (including conflicts).
836 int64_t num_propagations() const { return num_propagations_; }
837
838 // Number of literals inspected by this class during propagation.
839 int64_t num_inspections() const { return num_inspections_; }
840
841 // MinimizeClause() stats.
842 int64_t num_minimization() const { return num_minimization_; }
843 int64_t num_literals_removed() const { return num_literals_removed_; }
844
845 // Returns true if this literal is fixed or is equivalent to another literal.
846 // This means that it can just be ignored in most situation.
847 //
848 // Note that the set (and thus number) of redundant literal can only grow over
849 // time. This is because we always use the lowest index as representative of
850 // an equivalent class, so a redundant literal will stay that way.
851 bool IsRedundant(Literal l) const { return is_redundant_[l]; }
852 int64_t num_redundant_literals() const {
853 CHECK_EQ(num_redundant_literals_ % 2, 0);
854 return num_redundant_literals_;
855 }
856
857 // Contrary to "num_redundant_literals_" this does not count equivalences for
858 // fixed variables or variables that where deleted.
859 int64_t num_current_equivalences() const {
860 CHECK_EQ(num_current_equivalences_ % 2, 0);
861 return num_current_equivalences_;
862 }
863
864 // Number of implications removed by transitive reduction.
866 return num_redundant_implications_;
867 }
868
869 // Returns the number of current implications. Note that a => b and not(b)
870 // => not(a) are counted separately since they appear separately in our
871 // propagation lists. The number of size 2 clauses that represent the same
872 // thing is half this number. This should only be used in logs.
874 int64_t result = 0;
875 for (const auto& list : implications_and_amos_) {
876 result += list.num_literals();
877 }
878 return result;
879 }
880
881 // Extract all the binary clauses managed by this class. The Output type must
882 // support an AddBinaryClause(Literal a, Literal b) function.
883 //
884 // Important: This currently does NOT include at most one constraints.
885 //
886 // TODO(user): When extracting to cp_model.proto we could be more efficient
887 // by extracting bool_and constraint with many lhs terms.
888 template <typename Output>
889 void ExtractAllBinaryClauses(Output* out) const {
890 // TODO(user): Ideally we should just never have duplicate clauses in this
891 // class. But it seems we do in some corner cases, so lets not output them
892 // twice.
893 absl::flat_hash_set<std::pair<LiteralIndex, LiteralIndex>>
894 duplicate_detection;
895 for (LiteralIndex i(0); i < implications_and_amos_.size(); ++i) {
896 const Literal a = Literal(i).Negated();
897 for (const Literal b : implications_and_amos_[i].literals()) {
898 // Note(user): We almost always have both a => b and not(b) => not(a) in
899 // our implications_ database. Except if ComputeTransitiveReduction()
900 // was aborted early, but in this case, if only one is present, the
901 // other could be removed, so we shouldn't need to output it.
902 if (a < b && duplicate_detection.insert({a, b}).second) {
903 out->AddBinaryClause(a, b);
904 }
905 }
906 }
907 }
908
909 // Adds a binary clause and changes the reason of `a` as if it were propagated
910 // by this new clause.
911 // This allows inprocessing to shrink clauses to binary without backtracking
912 // to the root.
914 return AddBinaryClauseInternal(id, a, b, /*change_reason=*/true);
915 }
916
917 // The literals that are "directly" implied when literal is set to true. This
918 // is not a full "reachability". It includes at most ones propagation. The set
919 // of all direct implications is enough to describe the implications graph
920 // completely.
921 //
922 // When doing blocked clause elimination of bounded variable elimination, one
923 // only need to consider this list and not the full reachability.
924 const std::vector<Literal>& DirectImplications(Literal literal);
925
926 // Returns a random literal in DirectImplications(lhs). Note that this is
927 // biased if lhs appear in some most one, but it is constant time, which is a
928 // lot faster than computing DirectImplications() and then sampling from it.
929 LiteralIndex RandomImpliedLiteral(Literal lhs);
930
931 // A proxy for DirectImplications().size(), However we currently do not
932 // maintain it perfectly. It is exact each time DirectImplications() is
933 // called, and we update it in some situation but we don't deal with fixed
934 // variables, at_most ones and duplicates implications for now.
936 return estimated_sizes_[literal];
937 }
938
939 // Variable elimination by replacing everything of the form a => var => b by
940 // a => b. We ignore any a => a so the number of new implications is not
941 // always just the product of the two direct implication list of var and
942 // not(var). However, if a => var => a, then a and var are equivalent, so this
943 // case will be removed if one run DetectEquivalences() before this.
944 // Similarly, if a => var => not(a) then a must be false and this is detected
945 // and dealt with by FindFailedLiteralAroundVar().
946 bool FindFailedLiteralAroundVar(BooleanVariable var, bool* is_unsat);
947 int64_t NumImplicationOnVariableRemoval(BooleanVariable var);
949 BooleanVariable var, std::deque<std::vector<Literal>>* postsolve_clauses);
950 bool IsRemoved(Literal l) const { return is_removed_[l]; }
952 std::deque<std::vector<Literal>>* postsolve_clauses);
954
955 // ExpandAtMostOneWithWeight() will increase this, so a client can put a limit
956 // on this possibly expansive operation.
957 void ResetWorkDone() { work_done_in_mark_descendants_ = 0; }
958 int64_t WorkDone() const { return work_done_in_mark_descendants_; }
959
960 // Returns all the literals that are implied directly or indirectly by `root`.
961 // The result must be used before the next call to this function.
962 // It is also possible to use LiteralIsImplied() to find in O(1) if one
963 // literal is in the list.
964 absl::Span<const Literal> GetAllImpliedLiterals(Literal root);
965 bool LiteralIsImplied(Literal l) const { return is_marked_[l]; }
967
968 // Same as ExpandAtMostOne() but try to maximize the weight in the clique.
969 template <bool use_weight = true>
970 std::vector<Literal> ExpandAtMostOneWithWeight(
971 absl::Span<const Literal> at_most_one,
974 expanded_lp_values);
975
976 // Restarts the at_most_one iterator.
977 void ResetAtMostOneIterator() { at_most_one_iterator_ = 0; }
978
979 // Returns the next at_most_one, or a span of size 0 when finished.
980 absl::Span<const Literal> NextAtMostOne();
981
982 // Cleans up implications lists that might have duplicates.
983 // This only touches lists that changed, so it is okay to call proactively.
984 //
985 // If we have l => x and not(x), this will also set l to false which might
986 // casacade to an INFEASIBLE status in which case we will return false.
988
989 // For DCHECK() to debug inefficiency.
990 bool HasNoDuplicates();
991
992 // Returns an at most one "index" for all the at_most_ones containing this
993 // literal. Warning: the indices are not necessarily super dense. This can be
994 // used to detect that two literals are in the same AMO (i.e. if they share
995 // the same index).
996 absl::Span<const int> AtMostOneIndices(Literal lit) const {
997 return implications_and_amos_[lit].offsets();
998 }
999
1000 // Simple wrapper to not forget to output newly fixed variable to the DRAT
1001 // or LRAT proof (with clause_ids as proof) if needed. This will propagate
1002 // right away the implications.
1003 bool FixLiteral(Literal true_literal,
1004 absl::Span<const ClauseId> clause_ids = {});
1005
1006 private:
1008
1009 bool AddBinaryClauseInternal(ClauseId id, Literal a, Literal b,
1010 bool change_reason = false,
1011 bool delete_non_representative_id = true);
1012
1013 // Marks implications_[a] for cleanup in RemoveDuplicatesAndFixedVariables().
1014 void NotifyPossibleDuplicate(Literal a);
1015
1016 // Sorts, removes duplicates and detects l => x and not(x).
1017 // This only looks at the "direct" implications.
1018 // Returns false on UNSAT.
1019 ABSL_MUST_USE_RESULT bool CleanUpImplicationList(Literal a);
1020
1021 void AddClauseId(ClauseId id, Literal a, Literal b) {
1022 if (a.Variable() > b.Variable()) std::swap(a, b);
1023 clause_id_[{a, b}] = id;
1024 }
1025
1026 // Removes any literal whose negation is marked (except the first one). If
1027 // `fill_clause_ids` is true, fills the LRAT proof for this change in
1028 // `clause_ids` (this requires an LRAT proof handler to be set, and
1029 // `implied_by_` to be up to date).
1030 template <bool fill_clause_ids = false>
1031 void RemoveRedundantLiterals(std::vector<Literal>* conflict,
1032 std::vector<ClauseId>* clause_ids = nullptr);
1033
1034 // Appends the IDs of the binary clauses that imply the given literal to
1035 // `clause_ids`.
1036 void AppendImplicationChain(Literal literal,
1037 std::vector<ClauseId>* clause_ids);
1038
1039 // Fills is_marked_ with all the descendant of root, and returns them. If
1040 // `fill_implied_by` is true, also stores the parent of each marked literal in
1041 // the implied_by_ array. Note that this also uses bfs_stack_.
1042 template <bool fill_implied_by = false>
1043 absl::Span<const Literal> MarkDescendants(Literal root);
1044
1045 // Expands greedily the given at most one until we get a maximum clique in
1046 // the underlying incompatibility graph. Note that there is no guarantee that
1047 // if this is called with any sub-clique of the result we will get the same
1048 // maximal clique.
1049 std::vector<Literal> ExpandAtMostOne(absl::Span<const Literal> at_most_one,
1050 int64_t max_num_explored_nodes);
1051
1052 // Used by TransformIntoMaxCliques() and MergeAtMostOnes().
1053 std::vector<std::pair<int, int>> FilterAndSortAtMostOnes(
1054 absl::Span<std::vector<Literal>> at_most_ones);
1055
1056 // Process all at most one constraints starting at or after base_index in
1057 // at_most_one_buffer_. This replace literal by their representative, remove
1058 // fixed literals and deal with duplicates. Return false iff the model is
1059 // UNSAT.
1060 //
1061 // If the final AMO size is smaller than the at_most_one_expansion_size
1062 // parameters, we fully expand it.
1063 ABSL_MUST_USE_RESULT bool CleanUpAndAddAtMostOnes(int base_index);
1064
1065 // To be used in DCHECKs().
1066 bool InvariantsAreOk();
1067
1068 // Return the at most one encoded at the given start.
1069 // Important: this is only valid until a new at_most one is added.
1070 absl::Span<const Literal> AtMostOne(int start) const;
1071
1072 mutable StatsGroup stats_;
1073 TimeLimit* time_limit_;
1074 ModelRandomGenerator* random_;
1075 Trail* trail_;
1076 ClauseIdGenerator* clause_id_generator_;
1077 LratProofHandler* lrat_proof_handler_ = nullptr;
1078 LratEquivalenceHelper* lrat_helper_ = nullptr;
1079
1080 // When problems do not have any implications or at_most_ones this allows to
1081 // reduce the number of work we do here. This will be set to true the first
1082 // time something is added.
1083 bool no_constraint_ever_added_ = true;
1084
1085 // Binary reasons by trail_index. We need a deque because we kept pointers to
1086 // elements of this array and this can dynamically change size.
1087 std::deque<Literal> reasons_;
1088
1089 // The binary clause IDs. Each key is sorted by variable index.
1090 absl::flat_hash_map<std::pair<Literal, Literal>, ClauseId> clause_id_;
1091 // Stores a list of clauses added to clause_id_ that are only needed due to
1092 // ChangeReason calls. Once we backtrack past the first literal in the clause
1093 std::vector<std::pair<Literal, Literal>> changed_reasons_on_trail_;
1094
1095 // This is indexed by the Index() of a literal. Each entry stores two lists:
1096 // - A list of literals that are implied if the index literal becomes true.
1097 // - A set of offsets that point to the starts of AMO constraints in
1098 // at_most_one_buffer_. When LiteralIndex is true, then all entry in the at
1099 // most one constraint must be false except the one referring to
1100 // LiteralIndex.
1102 implications_and_amos_;
1103
1104 // Used by RemoveDuplicatesAndFixedVariables() and NotifyPossibleDuplicate().
1106 std::vector<Literal> to_clean_;
1107
1108 std::vector<Literal> at_most_one_buffer_;
1109 const int at_most_one_max_expansion_size_;
1110 int at_most_one_iterator_ = 0;
1111
1112 // Invariant: implies_something_[l] should be true iff
1113 // implications_and_amos_[l] might be non-empty.
1114 //
1115 // For problems with a large number of variables and sparse implications_ or
1116 // at_most_ones_ entries, checking this is way faster during
1117 // MarkDescendants(). See for instance proteindesign122trx11p8.pb.gz.
1118 Bitset64<LiteralIndex> implies_something_;
1119
1120 // Used by GenerateAtMostOnesWithLargeWeight().
1121 std::vector<std::vector<Literal>> tmp_cuts_;
1122
1123 // Some stats.
1124 int64_t num_propagations_ = 0;
1125 int64_t num_inspections_ = 0;
1126 int64_t num_minimization_ = 0;
1127 int64_t num_literals_removed_ = 0;
1128 int64_t num_redundant_implications_ = 0;
1129 int64_t num_redundant_literals_ = 0;
1130 int64_t num_current_equivalences_ = 0;
1131
1132 // Bitset used by MinimizeClause().
1133 //
1134 // TODO(user): use the same one as the one used in the classic minimization
1135 // because they are already initialized. Moreover they contains more
1136 // information?
1137 SparseBitset<LiteralIndex> is_marked_;
1138 SparseBitset<LiteralIndex> tmp_bitset_;
1139 SparseBitset<LiteralIndex> is_simplified_;
1140 std::vector<Literal> tmp_to_keep_;
1141
1142 // Used by AppendImplicationChains() to avoid processing a unit clause several
1143 // times.
1144 SparseBitset<LiteralIndex> processed_unit_clauses_;
1145
1146 // For each literal l marked by MarkDescendants(), the literal that directly
1147 // implies l. The root literal is implied by itself. Contains garbage for
1148 // literals which are not marked.
1150
1151 // Temporary stack used by MinimizeClauseWithReachability().
1152 std::vector<Literal> dfs_stack_;
1153
1154 // Used to limit the work done by ComputeTransitiveReduction() and
1155 // TransformIntoMaxCliques().
1156 int64_t work_done_in_mark_descendants_ = 0;
1157 std::vector<Literal> bfs_stack_;
1158
1159 // For clique cuts.
1162
1163 // Used by ComputeTransitiveReduction() in case we abort early to maintain
1164 // the invariant checked by InvariantsAreOk(). Some of our algo
1165 // relies on this to be always true.
1166 std::vector<std::pair<Literal, Literal>> tmp_removed_;
1167
1168 // Filled by DetectEquivalences().
1169 bool is_dag_ = false;
1170 std::vector<LiteralIndex> reverse_topological_order_;
1171 Bitset64<LiteralIndex> is_redundant_;
1173
1174 // For in-processing and removing variables.
1175 std::vector<Literal> direct_implications_;
1176 std::vector<Literal> direct_implications_of_negated_literal_;
1177 util_intops::StrongVector<LiteralIndex, bool> in_direct_implications_;
1180
1181 // For RemoveFixedVariables().
1182 int num_processed_fixed_variables_ = 0;
1183
1184 bool enable_sharing_ = true;
1185 std::function<void(Literal, Literal)> add_binary_callback_ = nullptr;
1186};
1187
1188extern template std::vector<Literal>
1190 const absl::Span<const Literal> at_most_one,
1191 const util_intops::StrongVector<LiteralIndex, bool>& can_be_included,
1192 const util_intops::StrongVector<LiteralIndex, double>& expanded_lp_values);
1193
1194extern template std::vector<Literal>
1196 const absl::Span<const Literal> at_most_one,
1197 const util_intops::StrongVector<LiteralIndex, bool>& can_be_included,
1198 const util_intops::StrongVector<LiteralIndex, double>& expanded_lp_values);
1199
1200} // namespace sat
1201} // namespace operations_research
1202
1203#endif // ORTOOLS_SAT_CLAUSE_H_
const std::vector< BinaryClause > & newly_added() const
Definition clause.h:564
BinaryClauseManager(const BinaryClauseManager &)=delete
BinaryClauseManager & operator=(const BinaryClauseManager &)=delete
void AppendImplicationChains(absl::Span< const Literal > literals, std::vector< ClauseId > *clause_ids)
Definition clause.cc:1487
bool ComputeTransitiveReduction(bool log_info=false)
Definition clause.cc:2214
Literal RepresentativeOf(Literal l) const
Definition clause.h:765
absl::Span< const int > AtMostOneIndices(Literal lit) const
Definition clause.h:996
const std::vector< std::vector< Literal > > & GenerateAtMostOnesWithLargeWeight(absl::Span< const Literal > literals, absl::Span< const double > lp_values, absl::Span< const double > reduced_costs)
Definition clause.cc:2835
void Reimply(Trail *trail, int old_trail_index) final
Definition clause.cc:1382
void ExtractAllBinaryClauses(Output *out) const
Definition clause.h:889
BinaryImplicationGraph(const BinaryImplicationGraph &)=delete
std::vector< Literal > ExpandAtMostOneWithWeight(absl::Span< const Literal > at_most_one, const util_intops::StrongVector< LiteralIndex, bool > &can_be_included, const util_intops::StrongVector< LiteralIndex, double > &expanded_lp_values)
Definition clause.cc:2754
bool TransformIntoMaxCliques(std::vector< std::vector< Literal > > *at_most_ones, int64_t max_num_explored_nodes=1e8)
Definition clause.cc:2500
absl::Span< const Literal > Implications(Literal l) const
Definition clause.h:758
absl::Span< const Literal > GetAllImpliedLiterals(Literal root)
Definition clause.cc:3108
int64_t NumImplicationOnVariableRemoval(BooleanVariable var)
Definition clause.cc:3312
bool AddBinaryClause(ClauseId id, Literal a, Literal b, bool delete_non_representative_id=true)
Definition clause.h:660
bool AddBinaryClause(Literal a, Literal b)
Definition clause.h:665
int DirectImplicationsEstimatedSize(Literal literal) const
Definition clause.h:935
absl::Span< const Literal > NextAtMostOne()
Definition clause.cc:3552
bool FixLiteral(Literal true_literal, absl::Span< const ClauseId > clause_ids={})
Definition clause.cc:1100
bool AddBinaryClauseAndChangeReason(ClauseId id, Literal a, Literal b)
Definition clause.h:913
bool AddImplication(Literal a, Literal b)
Definition clause.h:668
void RemoveBooleanVariable(BooleanVariable var, std::deque< std::vector< Literal > > *postsolve_clauses)
Definition clause.cc:3332
void MinimizeConflictFirst(const Trail &trail, std::vector< Literal > *c, SparseBitset< BooleanVariable > *marked, std::vector< ClauseId > *clause_ids, bool also_use_decisions)
Definition clause.cc:1397
bool DetectEquivalences(bool log_info=false)
Definition clause.cc:1950
void SetAdditionCallback(std::function< void(Literal, Literal)> f)
Definition clause.h:687
const std::vector< Literal > & DirectImplications(Literal literal)
Definition clause.cc:3218
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
Definition clause.cc:1377
bool MergeAtMostOnes(absl::Span< std::vector< Literal > > at_most_ones, int64_t max_num_explored_nodes=1e8, double *dtime=nullptr)
Definition clause.cc:2604
void RemoveAllRedundantVariables(std::deque< std::vector< Literal > > *postsolve_clauses)
Definition clause.cc:3378
const std::vector< LiteralIndex > & ReverseTopologicalOrder() const
Definition clause.h:751
bool FindFailedLiteralAroundVar(BooleanVariable var, bool *is_unsat)
Definition clause.cc:3287
BinaryImplicationGraph & operator=(const BinaryImplicationGraph &)=delete
LiteralIndex RandomImpliedLiteral(Literal lhs)
Definition clause.cc:3261
ClauseId GetClauseId(Literal a, Literal b) const
Definition clause.h:672
ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span< const Literal > at_most_one)
Definition clause.cc:1075
std::vector< absl::Span< const Literal > > HeuristicAmoPartition(std::vector< Literal > *literals)
Definition clause.cc:3037
SatClause * InprocessingAddClause(absl::Span< const Literal > new_clause)
Definition clause.cc:605
bool AddClause(ClauseId id, absl::Span< const Literal > literals, Trail *trail, int lbd)
Definition clause.cc:322
ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(SatClause *clause, absl::Span< const Literal > new_clause, absl::Span< const ClauseId > clause_ids={})
Definition clause.cc:527
absl::Span< SatClause * > LastNClauses(int n)
Definition clause.h:322
absl::Span< const int64_t > DeletionCounters() const
Definition clause.h:222
void LazyDelete(SatClause *clause, DeletionSourceForStat source)
Definition clause.cc:436
bool IsRemovable(SatClause *const clause) const
Definition clause.h:254
bool RemoveFixedLiteralsAndTestIfTrue(SatClause *clause)
Definition clause.cc:514
ABSL_MUST_USE_RESULT bool InprocessingFixLiteral(Literal true_literal, absl::Span< const ClauseId > clause_ids={})
Definition clause.cc:493
absl::Span< const Literal > Reason(const Trail &trail, int trail_index, int64_t conflict_id) const final
Definition clause.cc:277
ClauseManager(const ClauseManager &)=delete
ABSL_MUST_USE_RESULT bool InprocessingAddUnitClause(ClauseId unit_clause_id, Literal true_literal)
Definition clause.cc:473
SatClause * AddRemovableClause(ClauseId id, absl::Span< const Literal > literals, Trail *trail, int lbd)
Definition clause.cc:333
int64_t num_inspected_clause_literals() const
Definition clause.h:281
void SetAddClauseCallback(absl::AnyInvocable< void(int lbd, ClauseId id, absl::Span< const Literal >)> add_clause_callback)
Definition clause.h:409
void ChangeLbdIfBetter(SatClause *clause, int new_lbd)
Definition clause.cc:498
ClauseId ReasonClauseId(Literal literal) const
Definition clause.cc:732
void Reimply(Trail *trail, int old_trail_index) final
Definition clause.cc:283
int LbdOrZeroIfNotRemovable(SatClause *const clause) const
Definition clause.h:261
SatClause * ReasonClauseOrNull(BooleanVariable var) const
Definition clause.cc:299
SatClause * ReasonClause(int trail_index) const
Definition clause.cc:295
absl::flat_hash_map< SatClause *, ClauseInfo > * mutable_clauses_info()
Definition clause.h:258
const std::vector< SatClause * > & AllClausesInCreationOrder() const
Definition clause.h:246
void Resize(int num_variables)
Definition clause.cc:127
ClauseManager & operator=(const ClauseManager &)=delete
void Attach(SatClause *clause, Trail *trail)
Definition clause.cc:407
void SetClauseId(const SatClause *clause, ClauseId id)
Definition clause.h:300
absl::AnyInvocable< void(int lbd, ClauseId id, absl::Span< const Literal >)> TakeAddClauseCallback()
Definition clause.h:418
void AppendClauseIdsFixing(absl::Span< const Literal > literals, std::vector< ClauseId > *clause_ids, LiteralIndex decision=kNoLiteralIndex, std::optional< absl::FunctionRef< ClauseId(int, int)> > root_literals={})
Definition clause.cc:756
const std::vector< Watcher > & WatcherListOnFalse(Literal false_literal) const
Definition clause.h:405
ClauseId GetClauseId(const SatClause *clause) const
Definition clause.h:295
void KeepClauseForever(SatClause *const clause)
Definition clause.h:266
bool ClauseIsUsedAsReason(SatClause *clause) const
Definition clause.cc:312
void RescaleClauseActivities(double scaling_factor)
Definition clause.h:269
bool Propagate(Trail *trail) final
Definition clause.cc:142
LiteralIndex Index() const
Definition sat_base.h:92
BooleanVariable Variable() const
Definition sat_base.h:88
const Literal * end() const
Definition clause.h:80
static SatClause * Create(absl::Span< const Literal > literals)
Definition clause.cc:3590
absl::Span< const Literal > AsSpan() const
Definition clause.h:100
const Literal * begin() const
Definition clause.h:79
absl::Span< const Literal > PropagationReason() const
Definition clause.h:95
bool IsSatisfied(const VariablesAssignment &assignment) const
Definition clause.cc:3627
Literal PropagatedLiteral() const
Definition clause.h:90
std::string DebugString() const
Definition clause.cc:3634
SatPropagator(const std::string &name)
Definition sat_base.h:786
const LiteralIndex kNoLiteralIndex(-1)
constexpr ClauseId kNoClauseId(0)
OR-Tools root namespace.
bool operator!=(BinaryClause o) const
Definition clause.h:533
BinaryClause(Literal _a, Literal _b)
Definition clause.h:531
bool operator==(BinaryClause o) const
Definition clause.h:532
Watcher(SatClause *c, Literal b, int i=2)
Definition clause.h:382