181ad6265SDimitry Andric //===- WatchedLiteralsSolver.cpp --------------------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file defines a SAT solver implementation that can be used by dataflow 1081ad6265SDimitry Andric // analyses. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include <cassert> 1581ad6265SDimitry Andric #include <cstdint> 1681ad6265SDimitry Andric #include <iterator> 1781ad6265SDimitry Andric #include <queue> 1881ad6265SDimitry Andric #include <vector> 1981ad6265SDimitry Andric 20*06c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Formula.h" 2181ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Solver.h" 2281ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h" 23*06c3fb27SDimitry Andric #include "llvm/ADT/ArrayRef.h" 2481ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h" 2581ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h" 2681ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric namespace clang { 2981ad6265SDimitry Andric namespace dataflow { 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric // `WatchedLiteralsSolver` is an implementation of Algorithm D from Knuth's 3281ad6265SDimitry Andric // The Art of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is 3381ad6265SDimitry Andric // based on the backtracking DPLL algorithm [1], keeps references to a single 3481ad6265SDimitry Andric // "watched" literal per clause, and uses a set of "active" variables to perform 3581ad6265SDimitry Andric // unit propagation. 3681ad6265SDimitry Andric // 3781ad6265SDimitry Andric // The solver expects that its input is a boolean formula in conjunctive normal 3881ad6265SDimitry Andric // form that consists of clauses of at least one literal. A literal is either a 3981ad6265SDimitry Andric // boolean variable or its negation. Below we define types, data structures, and 4081ad6265SDimitry Andric // utilities that are used to represent boolean formulas in conjunctive normal 4181ad6265SDimitry Andric // form. 4281ad6265SDimitry Andric // 4381ad6265SDimitry Andric // [1] https://en.wikipedia.org/wiki/DPLL_algorithm 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric /// Boolean variables are represented as positive integers. 4681ad6265SDimitry Andric using Variable = uint32_t; 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric /// A null boolean variable is used as a placeholder in various data structures 4981ad6265SDimitry Andric /// and algorithms. 5081ad6265SDimitry Andric static constexpr Variable NullVar = 0; 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric /// Literals are represented as positive integers. Specifically, for a boolean 5381ad6265SDimitry Andric /// variable `V` that is represented as the positive integer `I`, the positive 5481ad6265SDimitry Andric /// literal `V` is represented as the integer `2*I` and the negative literal 5581ad6265SDimitry Andric /// `!V` is represented as the integer `2*I+1`. 5681ad6265SDimitry Andric using Literal = uint32_t; 5781ad6265SDimitry Andric 5881ad6265SDimitry Andric /// A null literal is used as a placeholder in various data structures and 5981ad6265SDimitry Andric /// algorithms. 6081ad6265SDimitry Andric static constexpr Literal NullLit = 0; 6181ad6265SDimitry Andric 6281ad6265SDimitry Andric /// Returns the positive literal `V`. 6381ad6265SDimitry Andric static constexpr Literal posLit(Variable V) { return 2 * V; } 6481ad6265SDimitry Andric 6581ad6265SDimitry Andric /// Returns the negative literal `!V`. 6681ad6265SDimitry Andric static constexpr Literal negLit(Variable V) { return 2 * V + 1; } 6781ad6265SDimitry Andric 6881ad6265SDimitry Andric /// Returns the negated literal `!L`. 6981ad6265SDimitry Andric static constexpr Literal notLit(Literal L) { return L ^ 1; } 7081ad6265SDimitry Andric 7181ad6265SDimitry Andric /// Returns the variable of `L`. 7281ad6265SDimitry Andric static constexpr Variable var(Literal L) { return L >> 1; } 7381ad6265SDimitry Andric 7481ad6265SDimitry Andric /// Clause identifiers are represented as positive integers. 7581ad6265SDimitry Andric using ClauseID = uint32_t; 7681ad6265SDimitry Andric 7781ad6265SDimitry Andric /// A null clause identifier is used as a placeholder in various data structures 7881ad6265SDimitry Andric /// and algorithms. 7981ad6265SDimitry Andric static constexpr ClauseID NullClause = 0; 8081ad6265SDimitry Andric 8181ad6265SDimitry Andric /// A boolean formula in conjunctive normal form. 82*06c3fb27SDimitry Andric struct CNFFormula { 8381ad6265SDimitry Andric /// `LargestVar` is equal to the largest positive integer that represents a 8481ad6265SDimitry Andric /// variable in the formula. 8581ad6265SDimitry Andric const Variable LargestVar; 8681ad6265SDimitry Andric 8781ad6265SDimitry Andric /// Literals of all clauses in the formula. 8881ad6265SDimitry Andric /// 8981ad6265SDimitry Andric /// The element at index 0 stands for the literal in the null clause. It is 9081ad6265SDimitry Andric /// set to 0 and isn't used. Literals of clauses in the formula start from the 9181ad6265SDimitry Andric /// element at index 1. 9281ad6265SDimitry Andric /// 9381ad6265SDimitry Andric /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of 9481ad6265SDimitry Andric /// `Clauses` will be `[0, L1, L2, L2, L3, L4]`. 9581ad6265SDimitry Andric std::vector<Literal> Clauses; 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric /// Start indices of clauses of the formula in `Clauses`. 9881ad6265SDimitry Andric /// 9981ad6265SDimitry Andric /// The element at index 0 stands for the start index of the null clause. It 10081ad6265SDimitry Andric /// is set to 0 and isn't used. Start indices of clauses in the formula start 10181ad6265SDimitry Andric /// from the element at index 1. 10281ad6265SDimitry Andric /// 10381ad6265SDimitry Andric /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of 10481ad6265SDimitry Andric /// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first 10581ad6265SDimitry Andric /// clause always start at index 1. The start index for the literals of the 10681ad6265SDimitry Andric /// second clause depends on the size of the first clause and so on. 10781ad6265SDimitry Andric std::vector<size_t> ClauseStarts; 10881ad6265SDimitry Andric 10981ad6265SDimitry Andric /// Maps literals (indices of the vector) to clause identifiers (elements of 11081ad6265SDimitry Andric /// the vector) that watch the respective literals. 11181ad6265SDimitry Andric /// 11281ad6265SDimitry Andric /// For a given clause, its watched literal is always its first literal in 11381ad6265SDimitry Andric /// `Clauses`. This invariant is maintained when watched literals change. 11481ad6265SDimitry Andric std::vector<ClauseID> WatchedHead; 11581ad6265SDimitry Andric 11681ad6265SDimitry Andric /// Maps clause identifiers (elements of the vector) to identifiers of other 11781ad6265SDimitry Andric /// clauses that watch the same literals, forming a set of linked lists. 11881ad6265SDimitry Andric /// 11981ad6265SDimitry Andric /// The element at index 0 stands for the identifier of the clause that 12081ad6265SDimitry Andric /// follows the null clause. It is set to 0 and isn't used. Identifiers of 12181ad6265SDimitry Andric /// clauses in the formula start from the element at index 1. 12281ad6265SDimitry Andric std::vector<ClauseID> NextWatched; 12381ad6265SDimitry Andric 124*06c3fb27SDimitry Andric /// Stores the variable identifier and Atom for atomic booleans in the 125*06c3fb27SDimitry Andric /// formula. 126*06c3fb27SDimitry Andric llvm::DenseMap<Variable, Atom> Atomics; 127753f127fSDimitry Andric 128*06c3fb27SDimitry Andric explicit CNFFormula(Variable LargestVar, 129*06c3fb27SDimitry Andric llvm::DenseMap<Variable, Atom> Atomics) 130753f127fSDimitry Andric : LargestVar(LargestVar), Atomics(std::move(Atomics)) { 13181ad6265SDimitry Andric Clauses.push_back(0); 13281ad6265SDimitry Andric ClauseStarts.push_back(0); 13381ad6265SDimitry Andric NextWatched.push_back(0); 13481ad6265SDimitry Andric const size_t NumLiterals = 2 * LargestVar + 1; 13581ad6265SDimitry Andric WatchedHead.resize(NumLiterals + 1, 0); 13681ad6265SDimitry Andric } 13781ad6265SDimitry Andric 13881ad6265SDimitry Andric /// Adds the `L1 v L2 v L3` clause to the formula. If `L2` or `L3` are 13981ad6265SDimitry Andric /// `NullLit` they are respectively omitted from the clause. 14081ad6265SDimitry Andric /// 14181ad6265SDimitry Andric /// Requirements: 14281ad6265SDimitry Andric /// 14381ad6265SDimitry Andric /// `L1` must not be `NullLit`. 14481ad6265SDimitry Andric /// 14581ad6265SDimitry Andric /// All literals in the input that are not `NullLit` must be distinct. 14681ad6265SDimitry Andric void addClause(Literal L1, Literal L2 = NullLit, Literal L3 = NullLit) { 147*06c3fb27SDimitry Andric // The literals are guaranteed to be distinct from properties of Formula 148*06c3fb27SDimitry Andric // and the construction in `buildCNF`. 14981ad6265SDimitry Andric assert(L1 != NullLit && L1 != L2 && L1 != L3 && 15081ad6265SDimitry Andric (L2 != L3 || L2 == NullLit)); 15181ad6265SDimitry Andric 15281ad6265SDimitry Andric const ClauseID C = ClauseStarts.size(); 15381ad6265SDimitry Andric const size_t S = Clauses.size(); 15481ad6265SDimitry Andric ClauseStarts.push_back(S); 15581ad6265SDimitry Andric 15681ad6265SDimitry Andric Clauses.push_back(L1); 15781ad6265SDimitry Andric if (L2 != NullLit) 15881ad6265SDimitry Andric Clauses.push_back(L2); 15981ad6265SDimitry Andric if (L3 != NullLit) 16081ad6265SDimitry Andric Clauses.push_back(L3); 16181ad6265SDimitry Andric 16281ad6265SDimitry Andric // Designate the first literal as the "watched" literal of the clause. 16381ad6265SDimitry Andric NextWatched.push_back(WatchedHead[L1]); 16481ad6265SDimitry Andric WatchedHead[L1] = C; 16581ad6265SDimitry Andric } 16681ad6265SDimitry Andric 16781ad6265SDimitry Andric /// Returns the number of literals in clause `C`. 16881ad6265SDimitry Andric size_t clauseSize(ClauseID C) const { 16981ad6265SDimitry Andric return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C] 17081ad6265SDimitry Andric : ClauseStarts[C + 1] - ClauseStarts[C]; 17181ad6265SDimitry Andric } 17281ad6265SDimitry Andric 17381ad6265SDimitry Andric /// Returns the literals of clause `C`. 17481ad6265SDimitry Andric llvm::ArrayRef<Literal> clauseLiterals(ClauseID C) const { 17581ad6265SDimitry Andric return llvm::ArrayRef<Literal>(&Clauses[ClauseStarts[C]], clauseSize(C)); 17681ad6265SDimitry Andric } 17781ad6265SDimitry Andric }; 17881ad6265SDimitry Andric 17981ad6265SDimitry Andric /// Converts the conjunction of `Vals` into a formula in conjunctive normal 18081ad6265SDimitry Andric /// form where each clause has at least one and at most three literals. 181*06c3fb27SDimitry Andric CNFFormula buildCNF(const llvm::ArrayRef<const Formula *> &Vals) { 18281ad6265SDimitry Andric // The general strategy of the algorithm implemented below is to map each 18381ad6265SDimitry Andric // of the sub-values in `Vals` to a unique variable and use these variables in 18481ad6265SDimitry Andric // the resulting CNF expression to avoid exponential blow up. The number of 18581ad6265SDimitry Andric // literals in the resulting formula is guaranteed to be linear in the number 186*06c3fb27SDimitry Andric // of sub-formulas in `Vals`. 18781ad6265SDimitry Andric 188*06c3fb27SDimitry Andric // Map each sub-formula in `Vals` to a unique variable. 189*06c3fb27SDimitry Andric llvm::DenseMap<const Formula *, Variable> SubValsToVar; 190*06c3fb27SDimitry Andric // Store variable identifiers and Atom of atomic booleans. 191*06c3fb27SDimitry Andric llvm::DenseMap<Variable, Atom> Atomics; 19281ad6265SDimitry Andric Variable NextVar = 1; 19381ad6265SDimitry Andric { 194*06c3fb27SDimitry Andric std::queue<const Formula *> UnprocessedSubVals; 195*06c3fb27SDimitry Andric for (const Formula *Val : Vals) 19681ad6265SDimitry Andric UnprocessedSubVals.push(Val); 19781ad6265SDimitry Andric while (!UnprocessedSubVals.empty()) { 198753f127fSDimitry Andric Variable Var = NextVar; 199*06c3fb27SDimitry Andric const Formula *Val = UnprocessedSubVals.front(); 20081ad6265SDimitry Andric UnprocessedSubVals.pop(); 20181ad6265SDimitry Andric 202753f127fSDimitry Andric if (!SubValsToVar.try_emplace(Val, Var).second) 20381ad6265SDimitry Andric continue; 20481ad6265SDimitry Andric ++NextVar; 20581ad6265SDimitry Andric 206*06c3fb27SDimitry Andric for (const Formula *F : Val->operands()) 207*06c3fb27SDimitry Andric UnprocessedSubVals.push(F); 208*06c3fb27SDimitry Andric if (Val->kind() == Formula::AtomRef) 209*06c3fb27SDimitry Andric Atomics[Var] = Val->getAtom(); 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric } 21281ad6265SDimitry Andric 213*06c3fb27SDimitry Andric auto GetVar = [&SubValsToVar](const Formula *Val) { 21481ad6265SDimitry Andric auto ValIt = SubValsToVar.find(Val); 21581ad6265SDimitry Andric assert(ValIt != SubValsToVar.end()); 21681ad6265SDimitry Andric return ValIt->second; 21781ad6265SDimitry Andric }; 21881ad6265SDimitry Andric 219*06c3fb27SDimitry Andric CNFFormula CNF(NextVar - 1, std::move(Atomics)); 22081ad6265SDimitry Andric std::vector<bool> ProcessedSubVals(NextVar, false); 22181ad6265SDimitry Andric 222*06c3fb27SDimitry Andric // Add a conjunct for each variable that represents a top-level formula in 223*06c3fb27SDimitry Andric // `Vals`. 224*06c3fb27SDimitry Andric for (const Formula *Val : Vals) 225*06c3fb27SDimitry Andric CNF.addClause(posLit(GetVar(Val))); 22681ad6265SDimitry Andric 22781ad6265SDimitry Andric // Add conjuncts that represent the mapping between newly-created variables 228*06c3fb27SDimitry Andric // and their corresponding sub-formulas. 229*06c3fb27SDimitry Andric std::queue<const Formula *> UnprocessedSubVals; 230*06c3fb27SDimitry Andric for (const Formula *Val : Vals) 23181ad6265SDimitry Andric UnprocessedSubVals.push(Val); 23281ad6265SDimitry Andric while (!UnprocessedSubVals.empty()) { 233*06c3fb27SDimitry Andric const Formula *Val = UnprocessedSubVals.front(); 23481ad6265SDimitry Andric UnprocessedSubVals.pop(); 23581ad6265SDimitry Andric const Variable Var = GetVar(Val); 23681ad6265SDimitry Andric 23781ad6265SDimitry Andric if (ProcessedSubVals[Var]) 23881ad6265SDimitry Andric continue; 23981ad6265SDimitry Andric ProcessedSubVals[Var] = true; 24081ad6265SDimitry Andric 241*06c3fb27SDimitry Andric switch (Val->kind()) { 242*06c3fb27SDimitry Andric case Formula::AtomRef: 243*06c3fb27SDimitry Andric break; 244*06c3fb27SDimitry Andric case Formula::And: { 245*06c3fb27SDimitry Andric const Variable LHS = GetVar(Val->operands()[0]); 246*06c3fb27SDimitry Andric const Variable RHS = GetVar(Val->operands()[1]); 24781ad6265SDimitry Andric 248*06c3fb27SDimitry Andric if (LHS == RHS) { 249972a253aSDimitry Andric // `X <=> (A ^ A)` is equivalent to `(!X v A) ^ (X v !A)` which is 250972a253aSDimitry Andric // already in conjunctive normal form. Below we add each of the 251972a253aSDimitry Andric // conjuncts of the latter expression to the result. 252*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), posLit(LHS)); 253*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), negLit(LHS)); 254972a253aSDimitry Andric } else { 25581ad6265SDimitry Andric // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)` 25681ad6265SDimitry Andric // which is already in conjunctive normal form. Below we add each of the 25781ad6265SDimitry Andric // conjuncts of the latter expression to the result. 258*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), posLit(LHS)); 259*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), posLit(RHS)); 260*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), negLit(LHS), negLit(RHS)); 261972a253aSDimitry Andric } 262*06c3fb27SDimitry Andric break; 263*06c3fb27SDimitry Andric } 264*06c3fb27SDimitry Andric case Formula::Or: { 265*06c3fb27SDimitry Andric const Variable LHS = GetVar(Val->operands()[0]); 266*06c3fb27SDimitry Andric const Variable RHS = GetVar(Val->operands()[1]); 26781ad6265SDimitry Andric 268*06c3fb27SDimitry Andric if (LHS == RHS) { 269972a253aSDimitry Andric // `X <=> (A v A)` is equivalent to `(!X v A) ^ (X v !A)` which is 270972a253aSDimitry Andric // already in conjunctive normal form. Below we add each of the 271972a253aSDimitry Andric // conjuncts of the latter expression to the result. 272*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), posLit(LHS)); 273*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), negLit(LHS)); 274972a253aSDimitry Andric } else { 275*06c3fb27SDimitry Andric // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v 276*06c3fb27SDimitry Andric // !B)` which is already in conjunctive normal form. Below we add each 277*06c3fb27SDimitry Andric // of the conjuncts of the latter expression to the result. 278*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), posLit(LHS), posLit(RHS)); 279*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), negLit(LHS)); 280*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), negLit(RHS)); 281972a253aSDimitry Andric } 282*06c3fb27SDimitry Andric break; 283*06c3fb27SDimitry Andric } 284*06c3fb27SDimitry Andric case Formula::Not: { 285*06c3fb27SDimitry Andric const Variable Operand = GetVar(Val->operands()[0]); 28681ad6265SDimitry Andric 287*06c3fb27SDimitry Andric // `X <=> !Y` is equivalent to `(!X v !Y) ^ (X v Y)` which is 288*06c3fb27SDimitry Andric // already in conjunctive normal form. Below we add each of the 289*06c3fb27SDimitry Andric // conjuncts of the latter expression to the result. 290*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), negLit(Operand)); 291*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), posLit(Operand)); 292*06c3fb27SDimitry Andric break; 293*06c3fb27SDimitry Andric } 294*06c3fb27SDimitry Andric case Formula::Implies: { 295*06c3fb27SDimitry Andric const Variable LHS = GetVar(Val->operands()[0]); 296*06c3fb27SDimitry Andric const Variable RHS = GetVar(Val->operands()[1]); 297972a253aSDimitry Andric 298972a253aSDimitry Andric // `X <=> (A => B)` is equivalent to 299972a253aSDimitry Andric // `(X v A) ^ (X v !B) ^ (!X v !A v B)` which is already in 300*06c3fb27SDimitry Andric // conjunctive normal form. Below we add each of the conjuncts of 301*06c3fb27SDimitry Andric // the latter expression to the result. 302*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), posLit(LHS)); 303*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), negLit(RHS)); 304*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), negLit(LHS), posLit(RHS)); 305*06c3fb27SDimitry Andric break; 306*06c3fb27SDimitry Andric } 307*06c3fb27SDimitry Andric case Formula::Equal: { 308*06c3fb27SDimitry Andric const Variable LHS = GetVar(Val->operands()[0]); 309*06c3fb27SDimitry Andric const Variable RHS = GetVar(Val->operands()[1]); 310972a253aSDimitry Andric 311*06c3fb27SDimitry Andric if (LHS == RHS) { 312972a253aSDimitry Andric // `X <=> (A <=> A)` is equvalent to `X` which is already in 313972a253aSDimitry Andric // conjunctive normal form. Below we add each of the conjuncts of the 314972a253aSDimitry Andric // latter expression to the result. 315*06c3fb27SDimitry Andric CNF.addClause(posLit(Var)); 316972a253aSDimitry Andric 317972a253aSDimitry Andric // No need to visit the sub-values of `Val`. 318*06c3fb27SDimitry Andric continue; 319*06c3fb27SDimitry Andric } 320972a253aSDimitry Andric // `X <=> (A <=> B)` is equivalent to 321*06c3fb27SDimitry Andric // `(X v A v B) ^ (X v !A v !B) ^ (!X v A v !B) ^ (!X v !A v B)` which 322*06c3fb27SDimitry Andric // is already in conjunctive normal form. Below we add each of the 323*06c3fb27SDimitry Andric // conjuncts of the latter expression to the result. 324*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), posLit(LHS), posLit(RHS)); 325*06c3fb27SDimitry Andric CNF.addClause(posLit(Var), negLit(LHS), negLit(RHS)); 326*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), posLit(LHS), negLit(RHS)); 327*06c3fb27SDimitry Andric CNF.addClause(negLit(Var), negLit(LHS), posLit(RHS)); 328*06c3fb27SDimitry Andric break; 329972a253aSDimitry Andric } 33081ad6265SDimitry Andric } 331*06c3fb27SDimitry Andric for (const Formula *Child : Val->operands()) 332*06c3fb27SDimitry Andric UnprocessedSubVals.push(Child); 33381ad6265SDimitry Andric } 33481ad6265SDimitry Andric 335*06c3fb27SDimitry Andric return CNF; 33681ad6265SDimitry Andric } 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric class WatchedLiteralsSolverImpl { 33981ad6265SDimitry Andric /// A boolean formula in conjunctive normal form that the solver will attempt 34081ad6265SDimitry Andric /// to prove satisfiable. The formula will be modified in the process. 341*06c3fb27SDimitry Andric CNFFormula CNF; 34281ad6265SDimitry Andric 34381ad6265SDimitry Andric /// The search for a satisfying assignment of the variables in `Formula` will 34481ad6265SDimitry Andric /// proceed in levels, starting from 1 and going up to `Formula.LargestVar` 34581ad6265SDimitry Andric /// (inclusive). The current level is stored in `Level`. At each level the 34681ad6265SDimitry Andric /// solver will assign a value to an unassigned variable. If this leads to a 34781ad6265SDimitry Andric /// consistent partial assignment, `Level` will be incremented. Otherwise, if 34881ad6265SDimitry Andric /// it results in a conflict, the solver will backtrack by decrementing 34981ad6265SDimitry Andric /// `Level` until it reaches the most recent level where a decision was made. 35081ad6265SDimitry Andric size_t Level = 0; 35181ad6265SDimitry Andric 35281ad6265SDimitry Andric /// Maps levels (indices of the vector) to variables (elements of the vector) 35381ad6265SDimitry Andric /// that are assigned values at the respective levels. 35481ad6265SDimitry Andric /// 35581ad6265SDimitry Andric /// The element at index 0 isn't used. Variables start from the element at 35681ad6265SDimitry Andric /// index 1. 35781ad6265SDimitry Andric std::vector<Variable> LevelVars; 35881ad6265SDimitry Andric 35981ad6265SDimitry Andric /// State of the solver at a particular level. 36081ad6265SDimitry Andric enum class State : uint8_t { 36181ad6265SDimitry Andric /// Indicates that the solver made a decision. 36281ad6265SDimitry Andric Decision = 0, 36381ad6265SDimitry Andric 36481ad6265SDimitry Andric /// Indicates that the solver made a forced move. 36581ad6265SDimitry Andric Forced = 1, 36681ad6265SDimitry Andric }; 36781ad6265SDimitry Andric 36881ad6265SDimitry Andric /// State of the solver at a particular level. It keeps track of previous 36981ad6265SDimitry Andric /// decisions that the solver can refer to when backtracking. 37081ad6265SDimitry Andric /// 37181ad6265SDimitry Andric /// The element at index 0 isn't used. States start from the element at index 37281ad6265SDimitry Andric /// 1. 37381ad6265SDimitry Andric std::vector<State> LevelStates; 37481ad6265SDimitry Andric 37581ad6265SDimitry Andric enum class Assignment : int8_t { 37681ad6265SDimitry Andric Unassigned = -1, 37781ad6265SDimitry Andric AssignedFalse = 0, 37881ad6265SDimitry Andric AssignedTrue = 1 37981ad6265SDimitry Andric }; 38081ad6265SDimitry Andric 38181ad6265SDimitry Andric /// Maps variables (indices of the vector) to their assignments (elements of 38281ad6265SDimitry Andric /// the vector). 38381ad6265SDimitry Andric /// 38481ad6265SDimitry Andric /// The element at index 0 isn't used. Variable assignments start from the 38581ad6265SDimitry Andric /// element at index 1. 38681ad6265SDimitry Andric std::vector<Assignment> VarAssignments; 38781ad6265SDimitry Andric 38881ad6265SDimitry Andric /// A set of unassigned variables that appear in watched literals in 38981ad6265SDimitry Andric /// `Formula`. The vector is guaranteed to contain unique elements. 39081ad6265SDimitry Andric std::vector<Variable> ActiveVars; 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric public: 393*06c3fb27SDimitry Andric explicit WatchedLiteralsSolverImpl( 394*06c3fb27SDimitry Andric const llvm::ArrayRef<const Formula *> &Vals) 395*06c3fb27SDimitry Andric : CNF(buildCNF(Vals)), LevelVars(CNF.LargestVar + 1), 396*06c3fb27SDimitry Andric LevelStates(CNF.LargestVar + 1) { 39781ad6265SDimitry Andric assert(!Vals.empty()); 39881ad6265SDimitry Andric 39981ad6265SDimitry Andric // Initialize the state at the root level to a decision so that in 40081ad6265SDimitry Andric // `reverseForcedMoves` we don't have to check that `Level >= 0` on each 40181ad6265SDimitry Andric // iteration. 40281ad6265SDimitry Andric LevelStates[0] = State::Decision; 40381ad6265SDimitry Andric 40481ad6265SDimitry Andric // Initialize all variables as unassigned. 405*06c3fb27SDimitry Andric VarAssignments.resize(CNF.LargestVar + 1, Assignment::Unassigned); 40681ad6265SDimitry Andric 40781ad6265SDimitry Andric // Initialize the active variables. 408*06c3fb27SDimitry Andric for (Variable Var = CNF.LargestVar; Var != NullVar; --Var) { 40981ad6265SDimitry Andric if (isWatched(posLit(Var)) || isWatched(negLit(Var))) 41081ad6265SDimitry Andric ActiveVars.push_back(Var); 41181ad6265SDimitry Andric } 41281ad6265SDimitry Andric } 41381ad6265SDimitry Andric 414*06c3fb27SDimitry Andric // Returns the `Result` and the number of iterations "remaining" from 415*06c3fb27SDimitry Andric // `MaxIterations` (that is, `MaxIterations` - iterations in this call). 416*06c3fb27SDimitry Andric std::pair<Solver::Result, std::int64_t> solve(std::int64_t MaxIterations) && { 41781ad6265SDimitry Andric size_t I = 0; 41881ad6265SDimitry Andric while (I < ActiveVars.size()) { 419*06c3fb27SDimitry Andric if (MaxIterations == 0) 420*06c3fb27SDimitry Andric return std::make_pair(Solver::Result::TimedOut(), 0); 421*06c3fb27SDimitry Andric --MaxIterations; 422*06c3fb27SDimitry Andric 42381ad6265SDimitry Andric // Assert that the following invariants hold: 42481ad6265SDimitry Andric // 1. All active variables are unassigned. 42581ad6265SDimitry Andric // 2. All active variables form watched literals. 42681ad6265SDimitry Andric // 3. Unassigned variables that form watched literals are active. 42781ad6265SDimitry Andric // FIXME: Consider replacing these with test cases that fail if the any 42881ad6265SDimitry Andric // of the invariants is broken. That might not be easy due to the 429*06c3fb27SDimitry Andric // transformations performed by `buildCNF`. 43081ad6265SDimitry Andric assert(activeVarsAreUnassigned()); 43181ad6265SDimitry Andric assert(activeVarsFormWatchedLiterals()); 43281ad6265SDimitry Andric assert(unassignedVarsFormingWatchedLiteralsAreActive()); 43381ad6265SDimitry Andric 43481ad6265SDimitry Andric const Variable ActiveVar = ActiveVars[I]; 43581ad6265SDimitry Andric 43681ad6265SDimitry Andric // Look for unit clauses that contain the active variable. 43781ad6265SDimitry Andric const bool unitPosLit = watchedByUnitClause(posLit(ActiveVar)); 43881ad6265SDimitry Andric const bool unitNegLit = watchedByUnitClause(negLit(ActiveVar)); 43981ad6265SDimitry Andric if (unitPosLit && unitNegLit) { 44081ad6265SDimitry Andric // We found a conflict! 44181ad6265SDimitry Andric 44281ad6265SDimitry Andric // Backtrack and rewind the `Level` until the most recent non-forced 44381ad6265SDimitry Andric // assignment. 44481ad6265SDimitry Andric reverseForcedMoves(); 44581ad6265SDimitry Andric 44681ad6265SDimitry Andric // If the root level is reached, then all possible assignments lead to 44781ad6265SDimitry Andric // a conflict. 44881ad6265SDimitry Andric if (Level == 0) 449*06c3fb27SDimitry Andric return std::make_pair(Solver::Result::Unsatisfiable(), MaxIterations); 45081ad6265SDimitry Andric 45181ad6265SDimitry Andric // Otherwise, take the other branch at the most recent level where a 45281ad6265SDimitry Andric // decision was made. 45381ad6265SDimitry Andric LevelStates[Level] = State::Forced; 45481ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 45581ad6265SDimitry Andric VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue 45681ad6265SDimitry Andric ? Assignment::AssignedFalse 45781ad6265SDimitry Andric : Assignment::AssignedTrue; 45881ad6265SDimitry Andric 45981ad6265SDimitry Andric updateWatchedLiterals(); 46081ad6265SDimitry Andric } else if (unitPosLit || unitNegLit) { 46181ad6265SDimitry Andric // We found a unit clause! The value of its unassigned variable is 46281ad6265SDimitry Andric // forced. 46381ad6265SDimitry Andric ++Level; 46481ad6265SDimitry Andric 46581ad6265SDimitry Andric LevelVars[Level] = ActiveVar; 46681ad6265SDimitry Andric LevelStates[Level] = State::Forced; 46781ad6265SDimitry Andric VarAssignments[ActiveVar] = 46881ad6265SDimitry Andric unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse; 46981ad6265SDimitry Andric 47081ad6265SDimitry Andric // Remove the variable that was just assigned from the set of active 47181ad6265SDimitry Andric // variables. 47281ad6265SDimitry Andric if (I + 1 < ActiveVars.size()) { 47381ad6265SDimitry Andric // Replace the variable that was just assigned with the last active 47481ad6265SDimitry Andric // variable for efficient removal. 47581ad6265SDimitry Andric ActiveVars[I] = ActiveVars.back(); 47681ad6265SDimitry Andric } else { 47781ad6265SDimitry Andric // This was the last active variable. Repeat the process from the 47881ad6265SDimitry Andric // beginning. 47981ad6265SDimitry Andric I = 0; 48081ad6265SDimitry Andric } 48181ad6265SDimitry Andric ActiveVars.pop_back(); 48281ad6265SDimitry Andric 48381ad6265SDimitry Andric updateWatchedLiterals(); 48481ad6265SDimitry Andric } else if (I + 1 == ActiveVars.size()) { 48581ad6265SDimitry Andric // There are no remaining unit clauses in the formula! Make a decision 48681ad6265SDimitry Andric // for one of the active variables at the current level. 48781ad6265SDimitry Andric ++Level; 48881ad6265SDimitry Andric 48981ad6265SDimitry Andric LevelVars[Level] = ActiveVar; 49081ad6265SDimitry Andric LevelStates[Level] = State::Decision; 49181ad6265SDimitry Andric VarAssignments[ActiveVar] = decideAssignment(ActiveVar); 49281ad6265SDimitry Andric 49381ad6265SDimitry Andric // Remove the variable that was just assigned from the set of active 49481ad6265SDimitry Andric // variables. 49581ad6265SDimitry Andric ActiveVars.pop_back(); 49681ad6265SDimitry Andric 49781ad6265SDimitry Andric updateWatchedLiterals(); 49881ad6265SDimitry Andric 49981ad6265SDimitry Andric // This was the last active variable. Repeat the process from the 50081ad6265SDimitry Andric // beginning. 50181ad6265SDimitry Andric I = 0; 50281ad6265SDimitry Andric } else { 50381ad6265SDimitry Andric ++I; 50481ad6265SDimitry Andric } 50581ad6265SDimitry Andric } 506*06c3fb27SDimitry Andric return std::make_pair(Solver::Result::Satisfiable(buildSolution()), MaxIterations); 50781ad6265SDimitry Andric } 50881ad6265SDimitry Andric 50981ad6265SDimitry Andric private: 510*06c3fb27SDimitry Andric /// Returns a satisfying truth assignment to the atoms in the boolean formula. 511*06c3fb27SDimitry Andric llvm::DenseMap<Atom, Solver::Result::Assignment> buildSolution() { 512*06c3fb27SDimitry Andric llvm::DenseMap<Atom, Solver::Result::Assignment> Solution; 513*06c3fb27SDimitry Andric for (auto &Atomic : CNF.Atomics) { 514753f127fSDimitry Andric // A variable may have a definite true/false assignment, or it may be 515753f127fSDimitry Andric // unassigned indicating its truth value does not affect the result of 516753f127fSDimitry Andric // the formula. Unassigned variables are assigned to true as a default. 517753f127fSDimitry Andric Solution[Atomic.second] = 518753f127fSDimitry Andric VarAssignments[Atomic.first] == Assignment::AssignedFalse 519753f127fSDimitry Andric ? Solver::Result::Assignment::AssignedFalse 520753f127fSDimitry Andric : Solver::Result::Assignment::AssignedTrue; 521753f127fSDimitry Andric } 522753f127fSDimitry Andric return Solution; 523753f127fSDimitry Andric } 524753f127fSDimitry Andric 525753f127fSDimitry Andric /// Reverses forced moves until the most recent level where a decision was 526753f127fSDimitry Andric /// made on the assignment of a variable. 52781ad6265SDimitry Andric void reverseForcedMoves() { 52881ad6265SDimitry Andric for (; LevelStates[Level] == State::Forced; --Level) { 52981ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 53081ad6265SDimitry Andric 53181ad6265SDimitry Andric VarAssignments[Var] = Assignment::Unassigned; 53281ad6265SDimitry Andric 53381ad6265SDimitry Andric // If the variable that we pass through is watched then we add it to the 53481ad6265SDimitry Andric // active variables. 53581ad6265SDimitry Andric if (isWatched(posLit(Var)) || isWatched(negLit(Var))) 53681ad6265SDimitry Andric ActiveVars.push_back(Var); 53781ad6265SDimitry Andric } 53881ad6265SDimitry Andric } 53981ad6265SDimitry Andric 540753f127fSDimitry Andric /// Updates watched literals that are affected by a variable assignment. 54181ad6265SDimitry Andric void updateWatchedLiterals() { 54281ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 54381ad6265SDimitry Andric 54481ad6265SDimitry Andric // Update the watched literals of clauses that currently watch the literal 54581ad6265SDimitry Andric // that falsifies `Var`. 54681ad6265SDimitry Andric const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue 54781ad6265SDimitry Andric ? negLit(Var) 54881ad6265SDimitry Andric : posLit(Var); 549*06c3fb27SDimitry Andric ClauseID FalseLitWatcher = CNF.WatchedHead[FalseLit]; 550*06c3fb27SDimitry Andric CNF.WatchedHead[FalseLit] = NullClause; 55181ad6265SDimitry Andric while (FalseLitWatcher != NullClause) { 552*06c3fb27SDimitry Andric const ClauseID NextFalseLitWatcher = CNF.NextWatched[FalseLitWatcher]; 55381ad6265SDimitry Andric 55481ad6265SDimitry Andric // Pick the first non-false literal as the new watched literal. 555*06c3fb27SDimitry Andric const size_t FalseLitWatcherStart = CNF.ClauseStarts[FalseLitWatcher]; 55681ad6265SDimitry Andric size_t NewWatchedLitIdx = FalseLitWatcherStart + 1; 557*06c3fb27SDimitry Andric while (isCurrentlyFalse(CNF.Clauses[NewWatchedLitIdx])) 55881ad6265SDimitry Andric ++NewWatchedLitIdx; 559*06c3fb27SDimitry Andric const Literal NewWatchedLit = CNF.Clauses[NewWatchedLitIdx]; 56081ad6265SDimitry Andric const Variable NewWatchedLitVar = var(NewWatchedLit); 56181ad6265SDimitry Andric 56281ad6265SDimitry Andric // Swap the old watched literal for the new one in `FalseLitWatcher` to 56381ad6265SDimitry Andric // maintain the invariant that the watched literal is at the beginning of 56481ad6265SDimitry Andric // the clause. 565*06c3fb27SDimitry Andric CNF.Clauses[NewWatchedLitIdx] = FalseLit; 566*06c3fb27SDimitry Andric CNF.Clauses[FalseLitWatcherStart] = NewWatchedLit; 56781ad6265SDimitry Andric 56881ad6265SDimitry Andric // If the new watched literal isn't watched by any other clause and its 56981ad6265SDimitry Andric // variable isn't assigned we need to add it to the active variables. 57081ad6265SDimitry Andric if (!isWatched(NewWatchedLit) && !isWatched(notLit(NewWatchedLit)) && 57181ad6265SDimitry Andric VarAssignments[NewWatchedLitVar] == Assignment::Unassigned) 57281ad6265SDimitry Andric ActiveVars.push_back(NewWatchedLitVar); 57381ad6265SDimitry Andric 574*06c3fb27SDimitry Andric CNF.NextWatched[FalseLitWatcher] = CNF.WatchedHead[NewWatchedLit]; 575*06c3fb27SDimitry Andric CNF.WatchedHead[NewWatchedLit] = FalseLitWatcher; 57681ad6265SDimitry Andric 57781ad6265SDimitry Andric // Go to the next clause that watches `FalseLit`. 57881ad6265SDimitry Andric FalseLitWatcher = NextFalseLitWatcher; 57981ad6265SDimitry Andric } 58081ad6265SDimitry Andric } 58181ad6265SDimitry Andric 58281ad6265SDimitry Andric /// Returns true if and only if one of the clauses that watch `Lit` is a unit 58381ad6265SDimitry Andric /// clause. 58481ad6265SDimitry Andric bool watchedByUnitClause(Literal Lit) const { 585*06c3fb27SDimitry Andric for (ClauseID LitWatcher = CNF.WatchedHead[Lit]; LitWatcher != NullClause; 586*06c3fb27SDimitry Andric LitWatcher = CNF.NextWatched[LitWatcher]) { 587*06c3fb27SDimitry Andric llvm::ArrayRef<Literal> Clause = CNF.clauseLiterals(LitWatcher); 58881ad6265SDimitry Andric 58981ad6265SDimitry Andric // Assert the invariant that the watched literal is always the first one 59081ad6265SDimitry Andric // in the clause. 59181ad6265SDimitry Andric // FIXME: Consider replacing this with a test case that fails if the 59281ad6265SDimitry Andric // invariant is broken by `updateWatchedLiterals`. That might not be easy 593*06c3fb27SDimitry Andric // due to the transformations performed by `buildCNF`. 59481ad6265SDimitry Andric assert(Clause.front() == Lit); 59581ad6265SDimitry Andric 59681ad6265SDimitry Andric if (isUnit(Clause)) 59781ad6265SDimitry Andric return true; 59881ad6265SDimitry Andric } 59981ad6265SDimitry Andric return false; 60081ad6265SDimitry Andric } 60181ad6265SDimitry Andric 60281ad6265SDimitry Andric /// Returns true if and only if `Clause` is a unit clause. 60381ad6265SDimitry Andric bool isUnit(llvm::ArrayRef<Literal> Clause) const { 60481ad6265SDimitry Andric return llvm::all_of(Clause.drop_front(), 60581ad6265SDimitry Andric [this](Literal L) { return isCurrentlyFalse(L); }); 60681ad6265SDimitry Andric } 60781ad6265SDimitry Andric 60881ad6265SDimitry Andric /// Returns true if and only if `Lit` evaluates to `false` in the current 60981ad6265SDimitry Andric /// partial assignment. 61081ad6265SDimitry Andric bool isCurrentlyFalse(Literal Lit) const { 61181ad6265SDimitry Andric return static_cast<int8_t>(VarAssignments[var(Lit)]) == 61281ad6265SDimitry Andric static_cast<int8_t>(Lit & 1); 61381ad6265SDimitry Andric } 61481ad6265SDimitry Andric 61581ad6265SDimitry Andric /// Returns true if and only if `Lit` is watched by a clause in `Formula`. 61681ad6265SDimitry Andric bool isWatched(Literal Lit) const { 617*06c3fb27SDimitry Andric return CNF.WatchedHead[Lit] != NullClause; 61881ad6265SDimitry Andric } 61981ad6265SDimitry Andric 62081ad6265SDimitry Andric /// Returns an assignment for an unassigned variable. 62181ad6265SDimitry Andric Assignment decideAssignment(Variable Var) const { 62281ad6265SDimitry Andric return !isWatched(posLit(Var)) || isWatched(negLit(Var)) 62381ad6265SDimitry Andric ? Assignment::AssignedFalse 62481ad6265SDimitry Andric : Assignment::AssignedTrue; 62581ad6265SDimitry Andric } 62681ad6265SDimitry Andric 62781ad6265SDimitry Andric /// Returns a set of all watched literals. 62881ad6265SDimitry Andric llvm::DenseSet<Literal> watchedLiterals() const { 62981ad6265SDimitry Andric llvm::DenseSet<Literal> WatchedLiterals; 630*06c3fb27SDimitry Andric for (Literal Lit = 2; Lit < CNF.WatchedHead.size(); Lit++) { 631*06c3fb27SDimitry Andric if (CNF.WatchedHead[Lit] == NullClause) 63281ad6265SDimitry Andric continue; 63381ad6265SDimitry Andric WatchedLiterals.insert(Lit); 63481ad6265SDimitry Andric } 63581ad6265SDimitry Andric return WatchedLiterals; 63681ad6265SDimitry Andric } 63781ad6265SDimitry Andric 63881ad6265SDimitry Andric /// Returns true if and only if all active variables are unassigned. 63981ad6265SDimitry Andric bool activeVarsAreUnassigned() const { 64081ad6265SDimitry Andric return llvm::all_of(ActiveVars, [this](Variable Var) { 64181ad6265SDimitry Andric return VarAssignments[Var] == Assignment::Unassigned; 64281ad6265SDimitry Andric }); 64381ad6265SDimitry Andric } 64481ad6265SDimitry Andric 64581ad6265SDimitry Andric /// Returns true if and only if all active variables form watched literals. 64681ad6265SDimitry Andric bool activeVarsFormWatchedLiterals() const { 64781ad6265SDimitry Andric const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals(); 64881ad6265SDimitry Andric return llvm::all_of(ActiveVars, [&WatchedLiterals](Variable Var) { 64981ad6265SDimitry Andric return WatchedLiterals.contains(posLit(Var)) || 65081ad6265SDimitry Andric WatchedLiterals.contains(negLit(Var)); 65181ad6265SDimitry Andric }); 65281ad6265SDimitry Andric } 65381ad6265SDimitry Andric 65481ad6265SDimitry Andric /// Returns true if and only if all unassigned variables that are forming 65581ad6265SDimitry Andric /// watched literals are active. 65681ad6265SDimitry Andric bool unassignedVarsFormingWatchedLiteralsAreActive() const { 65781ad6265SDimitry Andric const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(), 65881ad6265SDimitry Andric ActiveVars.end()); 65981ad6265SDimitry Andric for (Literal Lit : watchedLiterals()) { 66081ad6265SDimitry Andric const Variable Var = var(Lit); 66181ad6265SDimitry Andric if (VarAssignments[Var] != Assignment::Unassigned) 66281ad6265SDimitry Andric continue; 66381ad6265SDimitry Andric if (ActiveVarsSet.contains(Var)) 66481ad6265SDimitry Andric continue; 66581ad6265SDimitry Andric return false; 66681ad6265SDimitry Andric } 66781ad6265SDimitry Andric return true; 66881ad6265SDimitry Andric } 66981ad6265SDimitry Andric }; 67081ad6265SDimitry Andric 671*06c3fb27SDimitry Andric Solver::Result 672*06c3fb27SDimitry Andric WatchedLiteralsSolver::solve(llvm::ArrayRef<const Formula *> Vals) { 673*06c3fb27SDimitry Andric if (Vals.empty()) 674*06c3fb27SDimitry Andric return Solver::Result::Satisfiable({{}}); 675*06c3fb27SDimitry Andric auto [Res, Iterations] = 676*06c3fb27SDimitry Andric WatchedLiteralsSolverImpl(Vals).solve(MaxIterations); 677*06c3fb27SDimitry Andric MaxIterations = Iterations; 678*06c3fb27SDimitry Andric return Res; 67981ad6265SDimitry Andric } 68081ad6265SDimitry Andric 68181ad6265SDimitry Andric } // namespace dataflow 68281ad6265SDimitry Andric } // namespace clang 683