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 
14 // This file contains the solver internal representation of the clauses and the
15 // classes used for their propagation.
16 
17 #ifndef OR_TOOLS_SAT_CLAUSE_H_
18 #define OR_TOOLS_SAT_CLAUSE_H_
19 
20 #include <cstdint>
21 #include <deque>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "absl/container/flat_hash_map.h"
27 #include "absl/container/flat_hash_set.h"
28 #include "absl/container/inlined_vector.h"
29 #include "absl/random/bit_gen_ref.h"
30 #include "absl/types/span.h"
31 #include "ortools/base/hash.h"
32 #include "ortools/base/int_type.h"
33 #include "ortools/base/integral_types.h"
34 #include "ortools/base/macros.h"
35 #include "ortools/base/strong_vector.h"
36 #include "ortools/sat/drat_proof_handler.h"
37 #include "ortools/sat/model.h"
38 #include "ortools/sat/sat_base.h"
39 #include "ortools/sat/sat_parameters.pb.h"
40 #include "ortools/sat/util.h"
41 #include "ortools/util/bitset.h"
42 #include "ortools/util/stats.h"
43 #include "ortools/util/time_limit.h"
44 
45 namespace operations_research {
46 namespace sat {
47 
48 // This is how the SatSolver stores a clause. A clause is just a disjunction of
49 // literals. In many places, we just use vector<literal> to encode one. But in
50 // the critical propagation code, we use this class to remove one memory
51 // indirection.
52 class SatClause {
53  public:
54   // Creates a sat clause. There must be at least 2 literals. Smaller clause are
55   // treated separatly and never constructed. In practice, we do use
56   // BinaryImplicationGraph for the clause of size 2, so this is mainly used for
57   // size at least 3.
58   static SatClause* Create(absl::Span<const Literal> literals);
59 
60   // Non-sized delete because this is a tail-padded class.
delete(void * p)61   void operator delete(void* p) {
62     ::operator delete(p);  // non-sized delete
63   }
64 
65   // Number of literals in the clause.
size()66   int size() const { return size_; }
empty()67   int empty() const { return size_ == 0; }
68 
69   // Allows for range based iteration: for (Literal literal : clause) {}.
begin()70   const Literal* const begin() const { return &(literals_[0]); }
end()71   const Literal* const end() const { return &(literals_[size_]); }
72 
73   // Returns the first and second literals. These are always the watched
74   // literals if the clause is attached in the LiteralWatchers.
FirstLiteral()75   Literal FirstLiteral() const { return literals_[0]; }
SecondLiteral()76   Literal SecondLiteral() const { return literals_[1]; }
77 
78   // Returns the literal that was propagated to true. This only works for a
79   // clause that just propagated this literal. Otherwise, this will just returns
80   // a literal of the clause.
PropagatedLiteral()81   Literal PropagatedLiteral() const { return literals_[0]; }
82 
83   // Returns the reason for the last unit propagation of this clause. The
84   // preconditions are the same as for PropagatedLiteral(). Note that we don't
85   // need to include the propagated literal.
PropagationReason()86   absl::Span<const Literal> PropagationReason() const {
87     return absl::Span<const Literal>(&(literals_[1]), size_ - 1);
88   }
89 
90   // Returns a Span<> representation of the clause.
AsSpan()91   absl::Span<const Literal> AsSpan() const {
92     return absl::Span<const Literal>(&(literals_[0]), size_);
93   }
94 
95   // Removes literals that are fixed. This should only be called at level 0
96   // where a literal is fixed iff it is assigned. Aborts and returns true if
97   // they are not all false.
98   //
99   // Note that the removed literal can still be accessed in the portion [size,
100   // old_size) of literals().
101   bool RemoveFixedLiteralsAndTestIfTrue(const VariablesAssignment& assignment);
102 
103   // Returns true if the clause is satisfied for the given assignment. Note that
104   // the assignment may be partial, so false does not mean that the clause can't
105   // be satisfied by completing the assignment.
106   bool IsSatisfied(const VariablesAssignment& assignment) const;
107 
108   // Returns true if the clause is attached to a LiteralWatchers.
IsAttached()109   bool IsAttached() const { return size_ > 0; }
110 
111   std::string DebugString() const;
112 
113  private:
114   // LiteralWatchers needs to permute the order of literals in the clause and
115   // call Clear()/Rewrite.
116   friend class LiteralWatchers;
117 
literals()118   Literal* literals() { return &(literals_[0]); }
119 
120   // Marks the clause so that the next call to CleanUpWatchers() can identify it
121   // and actually detach it. We use size_ = 0 for this since the clause will
122   // never be used afterwards.
Clear()123   void Clear() { size_ = 0; }
124 
125   // Rewrites a clause with another shorter one. Note that the clause shouldn't
126   // be attached when this is called.
Rewrite(absl::Span<const Literal> new_clause)127   void Rewrite(absl::Span<const Literal> new_clause) {
128     size_ = 0;
129     for (const Literal l : new_clause) literals_[size_++] = l;
130   }
131 
132   int32_t size_;
133 
134   // This class store the literals inline, and literals_ mark the starts of the
135   // variable length portion.
136   Literal literals_[0];
137 
138   DISALLOW_COPY_AND_ASSIGN(SatClause);
139 };
140 
141 // Clause information used for the clause database management. Note that only
142 // the clauses that can be removed have an info. The problem clauses and
143 // the learned one that we wants to keep forever do not have one.
144 struct ClauseInfo {
145   double activity = 0.0;
146   int32_t lbd = 0;
147   bool protected_during_next_cleanup = false;
148 };
149 
150 class BinaryImplicationGraph;
151 
152 // Stores the 2-watched literals data structure.  See
153 // http://www.cs.berkeley.edu/~necula/autded/lecture24-sat.pdf for
154 // detail.
155 //
156 // This class is also responsible for owning the clause memory and all related
157 // information.
158 //
159 // TODO(user): Rename ClauseManager. This does more than just watching the
160 // clauses and is the place where all the clauses are stored.
161 class LiteralWatchers : public SatPropagator {
162  public:
163   explicit LiteralWatchers(Model* model);
164   ~LiteralWatchers() override;
165 
166   // Must be called before adding clauses refering to such variables.
167   void Resize(int num_variables);
168 
169   // SatPropagator API.
170   bool Propagate(Trail* trail) final;
171   absl::Span<const Literal> Reason(const Trail& trail,
172                                    int trail_index) const final;
173 
174   // Returns the reason of the variable at given trail_index. This only works
175   // for variable propagated by this class and is almost the same as Reason()
176   // with a different return format.
177   SatClause* ReasonClause(int trail_index) const;
178 
179   // Adds a new clause and perform initial propagation for this clause only.
180   bool AddClause(absl::Span<const Literal> literals, Trail* trail);
181   bool AddClause(absl::Span<const Literal> literals);
182 
183   // Same as AddClause() for a removable clause. This is only called on learned
184   // conflict, so this should never have all its literal at false (CHECKED).
185   SatClause* AddRemovableClause(const std::vector<Literal>& literals,
186                                 Trail* trail);
187 
188   // Lazily detach the given clause. The deletion will actually occur when
189   // CleanUpWatchers() is called. The later needs to be called before any other
190   // function in this class can be called. This is DCHECKed.
191   //
192   // Note that we remove the clause from clauses_info_ right away.
193   void LazyDetach(SatClause* clause);
194   void CleanUpWatchers();
195 
196   // Detaches the given clause right away.
197   //
198   // TODO(user): It might be better to have a "slower" mode in
199   // PropagateOnFalse() that deal with detached clauses in the watcher list and
200   // is activated until the next CleanUpWatchers() calls.
201   void Detach(SatClause* clause);
202 
203   // Attaches the given clause. The first two literal of the clause must
204   // be unassigned and the clause must not be already attached.
205   void Attach(SatClause* clause, Trail* trail);
206 
207   // Reclaims the memory of the lazily removed clauses (their size was set to
208   // zero) and remove them from AllClausesInCreationOrder() this work in
209   // O(num_clauses()).
210   void DeleteRemovedClauses();
num_clauses()211   int64_t num_clauses() const { return clauses_.size(); }
AllClausesInCreationOrder()212   const std::vector<SatClause*>& AllClausesInCreationOrder() const {
213     return clauses_;
214   }
215 
216   // True if removing this clause will not change the set of feasible solution.
217   // This is the case for clauses that were learned during search. Note however
218   // that some learned clause are kept forever (heuristics) and do not appear
219   // here.
IsRemovable(SatClause * const clause)220   bool IsRemovable(SatClause* const clause) const {
221     return clauses_info_.contains(clause);
222   }
num_removable_clauses()223   int64_t num_removable_clauses() const { return clauses_info_.size(); }
mutable_clauses_info()224   absl::flat_hash_map<SatClause*, ClauseInfo>* mutable_clauses_info() {
225     return &clauses_info_;
226   }
227 
228   // Total number of clauses inspected during calls to PropagateOnFalse().
num_inspected_clauses()229   int64_t num_inspected_clauses() const { return num_inspected_clauses_; }
num_inspected_clause_literals()230   int64_t num_inspected_clause_literals() const {
231     return num_inspected_clause_literals_;
232   }
233 
234   // The number of different literals (always twice the number of variables).
literal_size()235   int64_t literal_size() const { return needs_cleaning_.size().value(); }
236 
237   // Number of clauses currently watched.
num_watched_clauses()238   int64_t num_watched_clauses() const { return num_watched_clauses_; }
239 
SetDratProofHandler(DratProofHandler * drat_proof_handler)240   void SetDratProofHandler(DratProofHandler* drat_proof_handler) {
241     drat_proof_handler_ = drat_proof_handler;
242   }
243 
244   // Really basic algorithm to return a clause to try to minimize. We simply
245   // loop over the clause that we keep forever, in creation order. This starts
246   // by the problem clauses and then the learned one that we keep forever.
NextClauseToMinimize()247   SatClause* NextClauseToMinimize() {
248     for (; to_minimize_index_ < clauses_.size(); ++to_minimize_index_) {
249       if (!clauses_[to_minimize_index_]->IsAttached()) continue;
250       if (!IsRemovable(clauses_[to_minimize_index_])) {
251         return clauses_[to_minimize_index_++];
252       }
253     }
254     return nullptr;
255   }
256 
257   // Restart the scan in NextClauseToMinimize() from the first problem clause.
ResetToMinimizeIndex()258   void ResetToMinimizeIndex() { to_minimize_index_ = 0; }
259 
260   // During an inprocessing phase, it is easier to detach all clause first,
261   // then simplify and then reattach them. Note however that during these
262   // two calls, it is not possible to use the solver unit-progation.
263   //
264   // Important: When reattach is called, we assume that none of their literal
265   // are fixed, so we don't do any special checks.
266   //
267   // These functions can be called multiple-time and do the right things. This
268   // way before doing something, you can call the corresponding function and be
269   // sure to be in a good state. I.e. always AttachAllClauses() before
270   // propagation and DetachAllClauses() before going to do an inprocessing pass
271   // that might transform them.
272   void DetachAllClauses();
273   void AttachAllClauses();
274 
275   // These must only be called between [Detach/Attach]AllClauses() calls.
276   void InprocessingRemoveClause(SatClause* clause);
277   ABSL_MUST_USE_RESULT bool InprocessingFixLiteral(Literal true_literal);
278   ABSL_MUST_USE_RESULT bool InprocessingRewriteClause(
279       SatClause* clause, absl::Span<const Literal> new_clause);
280 
281   // This can return nullptr if new_clause was of size one or two as these are
282   // treated differently. Note that none of the variable should be fixed in the
283   // given new clause.
284   SatClause* InprocessingAddClause(absl::Span<const Literal> new_clause);
285 
286   // Contains, for each literal, the list of clauses that need to be inspected
287   // when the corresponding literal becomes false.
288   struct Watcher {
WatcherWatcher289     Watcher() {}
290     Watcher(SatClause* c, Literal b, int i = 2)
blocking_literalWatcher291         : blocking_literal(b), start_index(i), clause(c) {}
292 
293     // Optimization. A literal from the clause that sometimes allow to not even
294     // look at the clause memory when true.
295     Literal blocking_literal;
296 
297     // Optimization. An index in the clause. Instead of looking for another
298     // literal to watch from the start, we will start from here instead, and
299     // loop around if needed. This allows to avoid bad quadratric corner cases
300     // and lead to an "optimal" complexity. See "Optimal Implementation of
301     // Watched Literals and more General Techniques", Ian P. Gent.
302     //
303     // Note that ideally, this should be part of a SatClause, so it can be
304     // shared across watchers. However, since we have 32 bits for "free" here
305     // because of the struct alignment, we store it here instead.
306     int32_t start_index;
307 
308     SatClause* clause;
309   };
310 
311   // This is exposed since some inprocessing code can heuristically exploit the
312   // currently watched literal and blocking literal to do some simplification.
WatcherListOnFalse(Literal false_literal)313   const std::vector<Watcher>& WatcherListOnFalse(Literal false_literal) const {
314     return watchers_on_false_[false_literal.Index()];
315   }
316 
317  private:
318   // Attaches the given clause. This eventually propagates a literal which is
319   // enqueued on the trail. Returns false if a contradiction was encountered.
320   bool AttachAndPropagate(SatClause* clause, Trail* trail);
321 
322   // Launches all propagation when the given literal becomes false.
323   // Returns false if a contradiction was encountered.
324   bool PropagateOnFalse(Literal false_literal, Trail* trail);
325 
326   // Attaches the given clause to the event: the given literal becomes false.
327   // The blocking_literal can be any literal from the clause, it is used to
328   // speed up PropagateOnFalse() by skipping the clause if it is true.
329   void AttachOnFalse(Literal literal, Literal blocking_literal,
330                      SatClause* clause);
331 
332   // Common code between LazyDetach() and Detach().
333   void InternalDetach(SatClause* clause);
334 
335   absl::StrongVector<LiteralIndex, std::vector<Watcher>> watchers_on_false_;
336 
337   // SatClause reasons by trail_index.
338   std::vector<SatClause*> reasons_;
339 
340   // Indicates if the corresponding watchers_on_false_ list need to be
341   // cleaned. The boolean is_clean_ is just used in DCHECKs.
342   SparseBitset<LiteralIndex> needs_cleaning_;
343   bool is_clean_ = true;
344 
345   BinaryImplicationGraph* implication_graph_;
346   Trail* trail_;
347 
348   int64_t num_inspected_clauses_;
349   int64_t num_inspected_clause_literals_;
350   int64_t num_watched_clauses_;
351   mutable StatsGroup stats_;
352 
353   // For DetachAllClauses()/AttachAllClauses().
354   bool all_clauses_are_attached_ = true;
355 
356   // All the clauses currently in memory. This vector has ownership of the
357   // pointers. We currently do not use std::unique_ptr<SatClause> because it
358   // can't be used with some STL algorithms like std::partition.
359   //
360   // Note that the unit clauses are not kept here and if the parameter
361   // treat_binary_clauses_separately is true, the binary clause are not kept
362   // here either.
363   std::vector<SatClause*> clauses_;
364 
365   int to_minimize_index_ = 0;
366 
367   // Only contains removable clause.
368   absl::flat_hash_map<SatClause*, ClauseInfo> clauses_info_;
369 
370   DratProofHandler* drat_proof_handler_ = nullptr;
371 
372   DISALLOW_COPY_AND_ASSIGN(LiteralWatchers);
373 };
374 
375 // A binary clause. This is used by BinaryClauseManager.
376 struct BinaryClause {
BinaryClauseBinaryClause377   BinaryClause(Literal _a, Literal _b) : a(_a), b(_b) {}
378   bool operator==(BinaryClause o) const { return a == o.a && b == o.b; }
379   bool operator!=(BinaryClause o) const { return a != o.a || b != o.b; }
380   Literal a;
381   Literal b;
382 };
383 
384 // A simple class to manage a set of binary clauses.
385 class BinaryClauseManager {
386  public:
BinaryClauseManager()387   BinaryClauseManager() {}
NumClauses()388   int NumClauses() const { return set_.size(); }
389 
390   // Adds a new binary clause to the manager and returns true if it wasn't
391   // already present.
Add(BinaryClause c)392   bool Add(BinaryClause c) {
393     std::pair<int, int> p(c.a.SignedValue(), c.b.SignedValue());
394     if (p.first > p.second) std::swap(p.first, p.second);
395     if (set_.find(p) == set_.end()) {
396       set_.insert(p);
397       newly_added_.push_back(c);
398       return true;
399     }
400     return false;
401   }
402 
403   // Returns the newly added BinaryClause since the last ClearNewlyAdded() call.
newly_added()404   const std::vector<BinaryClause>& newly_added() const { return newly_added_; }
ClearNewlyAdded()405   void ClearNewlyAdded() { newly_added_.clear(); }
406 
407  private:
408   absl::flat_hash_set<std::pair<int, int>> set_;
409   std::vector<BinaryClause> newly_added_;
410   DISALLOW_COPY_AND_ASSIGN(BinaryClauseManager);
411 };
412 
413 // Special class to store and propagate clauses of size 2 (i.e. implication).
414 // Such clauses are never deleted. Together, they represent the 2-SAT part of
415 // the problem. Note that 2-SAT satisfiability is a polynomial problem, but
416 // W2SAT (weighted 2-SAT) is NP-complete.
417 //
418 // TODO(user): Most of the note below are done, but we currently only applies
419 // the reduction before the solve. We should consider doing more in-processing.
420 // The code could probably still be improved too.
421 //
422 // Note(user): All the variables in a strongly connected component are
423 // equivalent and can be thus merged as one. This is relatively cheap to compute
424 // from time to time (linear complexity). We will also get contradiction (a <=>
425 // not a) this way. This is done by DetectEquivalences().
426 //
427 // Note(user): An implication (a => not a) implies that a is false. I am not
428 // sure it is worth detecting that because if the solver assign a to true, it
429 // will learn that right away. I don't think we can do it faster.
430 //
431 // Note(user): The implication graph can be pruned. This is called the
432 // transitive reduction of a graph. For instance If a => {b,c} and b => {c},
433 // then there is no need to store a => {c}. The transitive reduction is unique
434 // on an acyclic graph. Computing it will allow for a faster propagation and
435 // memory reduction. It is however not cheap. Maybe simple lazy heuristics to
436 // remove redundant arcs are better. Note that all the learned clauses we add
437 // will never be redundant (but they could introduce cycles). This is done
438 // by ComputeTransitiveReduction().
439 //
440 // Note(user): This class natively support at most one constraints. This is
441 // a way to reduced significantly the memory and size of some 2-SAT instances.
442 // However, it is not fully exploited for pure SAT problems. See
443 // TransformIntoMaxCliques().
444 //
445 // Note(user): Add a preprocessor to remove duplicates in the implication lists.
446 // Note that all the learned clauses we add will never create duplicates.
447 //
448 // References for most of the above and more:
449 // - Brafman RI, "A simplifier for propositional formulas with many binary
450 //   clauses", IEEE Trans Syst Man Cybern B Cybern. 2004 Feb;34(1):52-9.
451 //   http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.28.4911
452 // - Marijn J. H. Heule, Matti Järvisalo, Armin Biere, "Efficient CNF
453 //   Simplification Based on Binary Implication Graphs", Theory and Applications
454 //   of Satisfiability Testing - SAT 2011, Lecture Notes in Computer Science
455 //   Volume 6695, 2011, pp 201-215
456 //   http://www.cs.helsinki.fi/u/mjarvisa/papers/heule-jarvisalo-biere.sat11.pdf
457 class BinaryImplicationGraph : public SatPropagator {
458  public:
BinaryImplicationGraph(Model * model)459   explicit BinaryImplicationGraph(Model* model)
460       : SatPropagator("BinaryImplicationGraph"),
461         stats_("BinaryImplicationGraph"),
462         time_limit_(model->GetOrCreate<TimeLimit>()),
463         random_(model->GetOrCreate<ModelRandomGenerator>()),
464         trail_(model->GetOrCreate<Trail>()) {
465     trail_->RegisterPropagator(this);
466   }
467 
~BinaryImplicationGraph()468   ~BinaryImplicationGraph() override {
469     IF_STATS_ENABLED({
470       LOG(INFO) << stats_.StatString();
471       LOG(INFO) << "num_redundant_implications " << num_redundant_implications_;
472     });
473   }
474 
475   // SatPropagator interface.
476   bool Propagate(Trail* trail) final;
477   absl::Span<const Literal> Reason(const Trail& trail,
478                                    int trail_index) const final;
479 
480   // Resizes the data structure.
481   void Resize(int num_variables);
482 
483   // Returns true if there is no constraints in this class.
IsEmpty()484   bool IsEmpty() { return num_implications_ == 0 && at_most_ones_.empty(); }
485 
486   // Adds the binary clause (a OR b), which is the same as (not a => b).
487   // Note that it is also equivalent to (not b => a).
488   void AddBinaryClause(Literal a, Literal b);
AddImplication(Literal a,Literal b)489   void AddImplication(Literal a, Literal b) {
490     return AddBinaryClause(a.Negated(), b);
491   }
492 
493   // Same as AddBinaryClause() but enqueues a possible unit propagation. Note
494   // that if the binary clause propagates, it must do so at the last level, this
495   // is DCHECKed.
496   //
497   // Return false and do nothing if both a and b are currently false.
498   bool AddBinaryClauseDuringSearch(Literal a, Literal b);
499 
500   // An at most one constraint of size n is a compact way to encode n * (n - 1)
501   // implications. This must only be called at level zero.
502   //
503   // Returns false if this creates a conflict. Currently this can only happens
504   // if there is duplicate literal already assigned to true in this constraint.
505   ABSL_MUST_USE_RESULT bool AddAtMostOne(absl::Span<const Literal> at_most_one);
506 
507   // Uses the binary implication graph to minimize the given conflict by
508   // removing literals that implies others. The idea is that if a and b are two
509   // literals from the given conflict and a => b (which is the same as not(b) =>
510   // not(a)) then a is redundant and can be removed.
511   //
512   // Note that removing as many literals as possible is too time consuming, so
513   // we use different heuristics/algorithms to do this minimization.
514   // See the binary_minimization_algorithm SAT parameter and the .cc for more
515   // details about the different algorithms.
516   void MinimizeConflictWithReachability(std::vector<Literal>* c);
517   void MinimizeConflictExperimental(const Trail& trail,
518                                     std::vector<Literal>* c);
519   void MinimizeConflictFirst(const Trail& trail, std::vector<Literal>* c,
520                              SparseBitset<BooleanVariable>* marked);
521   void MinimizeConflictFirstWithTransitiveReduction(
522       const Trail& trail, std::vector<Literal>* c,
523       SparseBitset<BooleanVariable>* marked, absl::BitGenRef random);
524 
525   // This must only be called at decision level 0 after all the possible
526   // propagations. It:
527   // - Removes the variable at true from the implications lists.
528   // - Frees the propagation list of the assigned literals.
529   void RemoveFixedVariables();
530 
531   // Returns false if the model is unsat, otherwise detects equivalent variable
532   // (with respect to the implications only) and reorganize the propagation
533   // lists accordingly.
534   //
535   // TODO(user): Completely get rid of such literal instead? it might not be
536   // reasonable code-wise to remap our literals in all of our constraints
537   // though.
538   bool DetectEquivalences(bool log_info = false);
539 
540   // Returns true if DetectEquivalences() has been called and no new binary
541   // clauses have been added since then. When this is true then there is no
542   // cycle in the binary implication graph (modulo the redundant literals that
543   // form a cycle with their representative).
IsDag()544   bool IsDag() const { return is_dag_; }
545 
546   // One must call DetectEquivalences() first, this is CHECKed.
547   // Returns a list so that if x => y, then x is after y.
ReverseTopologicalOrder()548   const std::vector<LiteralIndex>& ReverseTopologicalOrder() const {
549     CHECK(is_dag_);
550     return reverse_topological_order_;
551   }
552 
553   // Returns the list of literal "directly" implied by l. Beware that this can
554   // easily change behind your back if you modify the solver state.
Implications(Literal l)555   const absl::InlinedVector<Literal, 6>& Implications(Literal l) const {
556     return implications_[l.Index()];
557   }
558 
559   // Returns the representative of the equivalence class of l (or l itself if it
560   // is on its own). Note that DetectEquivalences() should have been called to
561   // get any non-trival results.
RepresentativeOf(Literal l)562   Literal RepresentativeOf(Literal l) const {
563     if (l.Index() >= representative_of_.size()) return l;
564     if (representative_of_[l.Index()] == kNoLiteralIndex) return l;
565     return Literal(representative_of_[l.Index()]);
566   }
567 
568   // Prunes the implication graph by calling first DetectEquivalences() to
569   // remove cycle and then by computing the transitive reduction of the
570   // remaining DAG.
571   //
572   // Note that this can be slow (num_literals graph traversals), so we abort
573   // early if we start doing too much work.
574   //
575   // Returns false if the model is detected to be UNSAT (this needs to call
576   // DetectEquivalences() if not already done).
577   bool ComputeTransitiveReduction(bool log_info = false);
578 
579   // Another way of representing an implication graph is a list of maximal "at
580   // most one" constraints, each forming a max-clique in the incompatibility
581   // graph. This representation is useful for having a good linear relaxation.
582   //
583   // This function will transform each of the given constraint into a maximal
584   // one in the underlying implication graph. Constraints that are redundant
585   // after other have been expanded (i.e. included into) will be cleared.
586   //
587   // Returns false if the model is detected to be UNSAT (this needs to call
588   // DetectEquivalences() if not already done).
589   bool TransformIntoMaxCliques(std::vector<std::vector<Literal>>* at_most_ones,
590                                int64_t max_num_explored_nodes = 1e8);
591 
592   // LP clique cut heuristic. Returns a set of "at most one" constraints on the
593   // given literals or their negation that are violated by the current LP
594   // solution. Note that this assumes that
595   //   lp_value(lit) = 1 - lp_value(lit.Negated()).
596   //
597   // The literal and lp_values vector are in one to one correspondence. We will
598   // only generate clique with these literals or their negation.
599   //
600   // TODO(user): Refine the heuristic and unit test!
601   const std::vector<std::vector<Literal>>& GenerateAtMostOnesWithLargeWeight(
602       const std::vector<Literal>& literals,
603       const std::vector<double>& lp_values);
604 
605   // Number of literal propagated by this class (including conflicts).
num_propagations()606   int64_t num_propagations() const { return num_propagations_; }
607 
608   // Number of literals inspected by this class during propagation.
num_inspections()609   int64_t num_inspections() const { return num_inspections_; }
610 
611   // MinimizeClause() stats.
num_minimization()612   int64_t num_minimization() const { return num_minimization_; }
num_literals_removed()613   int64_t num_literals_removed() const { return num_literals_removed_; }
614 
615   // Returns true if this literal is fixed or is equivalent to another literal.
616   // This means that it can just be ignored in most situation.
617   //
618   // Note that the set (and thus number) of redundant literal can only grow over
619   // time. This is because we always use the lowest index as representative of
620   // an equivalent class, so a redundant literal will stay that way.
IsRedundant(Literal l)621   bool IsRedundant(Literal l) const { return is_redundant_[l.Index()]; }
num_redundant_literals()622   int64_t num_redundant_literals() const {
623     CHECK_EQ(num_redundant_literals_ % 2, 0);
624     return num_redundant_literals_;
625   }
626 
627   // Number of implications removed by transitive reduction.
num_redundant_implications()628   int64_t num_redundant_implications() const {
629     return num_redundant_implications_;
630   }
631 
632   // Returns the number of current implications. Note that a => b and not(b) =>
633   // not(a) are counted separately since they appear separately in our
634   // propagation lists. The number of size 2 clauses that represent the same
635   // thing is half this number.
num_implications()636   int64_t num_implications() const { return num_implications_; }
literal_size()637   int64_t literal_size() const { return implications_.size(); }
638 
639   // Extract all the binary clauses managed by this class. The Output type must
640   // support an AddBinaryClause(Literal a, Literal b) function.
641   //
642   // Important: This currently does NOT include at most one constraints.
643   //
644   // TODO(user): When extracting to cp_model.proto we could be more efficient
645   // by extracting bool_and constraint with many lhs terms.
646   template <typename Output>
ExtractAllBinaryClauses(Output * out)647   void ExtractAllBinaryClauses(Output* out) const {
648     // TODO(user): Ideally we should just never have duplicate clauses in this
649     // class. But it seems we do in some corner cases, so lets not output them
650     // twice.
651     absl::flat_hash_set<std::pair<LiteralIndex, LiteralIndex>>
652         duplicate_detection;
653     for (LiteralIndex i(0); i < implications_.size(); ++i) {
654       const Literal a = Literal(i).Negated();
655       for (const Literal b : implications_[i]) {
656         // Note(user): We almost always have both a => b and not(b) => not(a) in
657         // our implications_ database. Except if ComputeTransitiveReduction()
658         // was aborted early, but in this case, if only one is present, the
659         // other could be removed, so we shouldn't need to output it.
660         if (a < b &&
661             duplicate_detection.insert({a.Index(), b.Index()}).second) {
662           out->AddBinaryClause(a, b);
663         }
664       }
665     }
666   }
667 
SetDratProofHandler(DratProofHandler * drat_proof_handler)668   void SetDratProofHandler(DratProofHandler* drat_proof_handler) {
669     drat_proof_handler_ = drat_proof_handler;
670   }
671 
672   // Changes the reason of the variable at trail index to a binary reason.
673   // Note that the implication "new_reason => trail_[trail_index]" should be
674   // part of the implication graph.
ChangeReason(int trail_index,Literal new_reason)675   void ChangeReason(int trail_index, Literal new_reason) {
676     CHECK(trail_->Assignment().LiteralIsTrue(new_reason));
677     reasons_[trail_index] = new_reason.Negated();
678     trail_->ChangeReason(trail_index, propagator_id_);
679   }
680 
681   // The literals that are "directly" implied when literal is set to true. This
682   // is not a full "reachability". It includes at most ones propagation. The set
683   // of all direct implications is enough to describe the implications graph
684   // completely.
685   //
686   // When doing blocked clause elimination of bounded variable elimination, one
687   // only need to consider this list and not the full reachability.
688   const std::vector<Literal>& DirectImplications(Literal literal);
689 
690   // A proxy for DirectImplications().size(), However we currently do not
691   // maintain it perfectly. It is exact each time DirectImplications() is
692   // called, and we update it in some situation but we don't deal with fixed
693   // variables, at_most ones and duplicates implications for now.
DirectImplicationsEstimatedSize(Literal literal)694   int DirectImplicationsEstimatedSize(Literal literal) const {
695     return estimated_sizes_[literal.Index()];
696   }
697 
698   // Variable elimination by replacing everything of the form a => var => b by a
699   // => b. We ignore any a => a so the number of new implications is not always
700   // just the product of the two direct implication list of var and not(var).
701   // However, if a => var => a, then a and var are equivalent, so this case will
702   // be removed if one run DetectEquivalences() before this. Similarly, if a =>
703   // var => not(a) then a must be false and this is detected and dealt with by
704   // FindFailedLiteralAroundVar().
705   bool FindFailedLiteralAroundVar(BooleanVariable var, bool* is_unsat);
706   int64_t NumImplicationOnVariableRemoval(BooleanVariable var);
707   void RemoveBooleanVariable(
708       BooleanVariable var, std::deque<std::vector<Literal>>* postsolve_clauses);
IsRemoved(Literal l)709   bool IsRemoved(Literal l) const { return is_removed_[l.Index()]; }
710 
711   // TODO(user): consider at most ones.
712   void CleanupAllRemovedVariables();
713 
714  private:
715   // Simple wrapper to not forget to output newly fixed variable to the DRAT
716   // proof if needed. This will propagate rigth away the implications.
717   bool FixLiteral(Literal true_literal);
718 
719   // Propagates all the direct implications of the given literal becoming true.
720   // Returns false if a conflict was encountered, in which case
721   // trail->SetFailingClause() will be called with the correct size 2 clause.
722   // This calls trail->Enqueue() on the newly assigned literals.
723   bool PropagateOnTrue(Literal true_literal, Trail* trail);
724 
725   // Remove any literal whose negation is marked (except the first one).
726   void RemoveRedundantLiterals(std::vector<Literal>* conflict);
727 
728   // Fill is_marked_ with all the descendant of root.
729   // Note that this also use dfs_stack_.
730   void MarkDescendants(Literal root);
731 
732   // Expands greedily the given at most one until we get a maximum clique in
733   // the underlying incompatibility graph. Note that there is no guarantee that
734   // if this is called with any sub-clique of the result we will get the same
735   // maximal clique.
736   std::vector<Literal> ExpandAtMostOne(
737       const absl::Span<const Literal> at_most_one,
738       int64_t max_num_explored_nodes);
739 
740   // Same as ExpandAtMostOne() but try to maximize the weight in the clique.
741   std::vector<Literal> ExpandAtMostOneWithWeight(
742       const absl::Span<const Literal> at_most_one,
743       const absl::StrongVector<LiteralIndex, bool>& can_be_included,
744       const absl::StrongVector<LiteralIndex, double>& expanded_lp_values);
745 
746   // Process all at most one constraints starting at or after base_index in
747   // at_most_one_buffer_. This replace literal by their representative, remove
748   // fixed literals and deal with duplicates. Return false iff the model is
749   // UNSAT.
750   bool CleanUpAndAddAtMostOnes(const int base_index);
751 
752   mutable StatsGroup stats_;
753   TimeLimit* time_limit_;
754   ModelRandomGenerator* random_;
755   Trail* trail_;
756   DratProofHandler* drat_proof_handler_ = nullptr;
757 
758   // Binary reasons by trail_index. We need a deque because we kept pointers to
759   // elements of this array and this can dynamically change size.
760   std::deque<Literal> reasons_;
761 
762   // This is indexed by the Index() of a literal. Each list stores the
763   // literals that are implied if the index literal becomes true.
764   //
765   // Using InlinedVector helps quite a bit because on many problems, a literal
766   // only implies a few others. Note that on a 64 bits computer we get exactly
767   // 6 inlined int32_t elements without extra space, and the size of the inlined
768   // vector is 4 times 64 bits.
769   //
770   // TODO(user): We could be even more efficient since a size of int32_t is
771   // enough for us and we could store in common the inlined/not-inlined size.
772   absl::StrongVector<LiteralIndex, absl::InlinedVector<Literal, 6>>
773       implications_;
774   int64_t num_implications_ = 0;
775 
776   // Internal representation of at_most_one constraints. Each entry point to the
777   // start of a constraint in the buffer. Constraints are terminated by
778   // kNoLiteral. When LiteralIndex is true, then all entry in the at most one
779   // constraint must be false except the one referring to LiteralIndex.
780   //
781   // TODO(user): We could be more cache efficient by combining this with
782   // implications_ in some way. Do some propagation speed benchmark.
783   absl::StrongVector<LiteralIndex, absl::InlinedVector<int32_t, 6>>
784       at_most_ones_;
785   std::vector<Literal> at_most_one_buffer_;
786 
787   // Used by GenerateAtMostOnesWithLargeWeight().
788   std::vector<std::vector<Literal>> tmp_cuts_;
789 
790   // Some stats.
791   int64_t num_propagations_ = 0;
792   int64_t num_inspections_ = 0;
793   int64_t num_minimization_ = 0;
794   int64_t num_literals_removed_ = 0;
795   int64_t num_redundant_implications_ = 0;
796   int64_t num_redundant_literals_ = 0;
797 
798   // Bitset used by MinimizeClause().
799   // TODO(user): use the same one as the one used in the classic minimization
800   // because they are already initialized. Moreover they contains more
801   // information.
802   SparseBitset<LiteralIndex> is_marked_;
803   SparseBitset<LiteralIndex> is_simplified_;
804 
805   // Temporary stack used by MinimizeClauseWithReachability().
806   std::vector<Literal> dfs_stack_;
807 
808   // Used to limit the work done by ComputeTransitiveReduction() and
809   // TransformIntoMaxCliques().
810   int64_t work_done_in_mark_descendants_ = 0;
811 
812   // Filled by DetectEquivalences().
813   bool is_dag_ = false;
814   std::vector<LiteralIndex> reverse_topological_order_;
815   absl::StrongVector<LiteralIndex, bool> is_redundant_;
816   absl::StrongVector<LiteralIndex, LiteralIndex> representative_of_;
817 
818   // For in-processing and removing variables.
819   std::vector<Literal> direct_implications_;
820   std::vector<Literal> direct_implications_of_negated_literal_;
821   absl::StrongVector<LiteralIndex, bool> in_direct_implications_;
822   absl::StrongVector<LiteralIndex, bool> is_removed_;
823   absl::StrongVector<LiteralIndex, int> estimated_sizes_;
824 
825   // For RemoveFixedVariables().
826   int num_processed_fixed_variables_ = 0;
827 
828   DISALLOW_COPY_AND_ASSIGN(BinaryImplicationGraph);
829 };
830 
831 }  // namespace sat
832 }  // namespace operations_research
833 
834 #endif  // OR_TOOLS_SAT_CLAUSE_H_
835