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