21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/DenseSet.h"
24#include "llvm/ADT/STLExtras.h"
32class WatchedLiteralsSolverImpl {
35 llvm::DenseMap<Variable, Atom> Atomics;
46 std::vector<ClauseID> WatchedHead;
54 std::vector<ClauseID> NextWatched;
70 std::vector<Variable> LevelVars;
86 std::vector<State> LevelStates;
88 enum class Assignment :
int8_t {
99 std::vector<Assignment> VarAssignments;
103 std::vector<Variable> ActiveVars;
106 explicit WatchedLiteralsSolverImpl(
107 const llvm::ArrayRef<const Formula *> &Vals)
110 : Atomics(), CNF(
buildCNF(Vals, Atomics)),
111 LevelVars(CNF.largestVar() + 1), LevelStates(CNF.largestVar() + 1) {
112 assert(!Vals.empty());
115 if (CNF.knownContradictory())
119 NextWatched.push_back(0);
120 const size_t NumLiterals = 2 * CNF.largestVar() + 1;
121 WatchedHead.resize(NumLiterals + 1, 0);
124 Literal FirstLit = CNF.clauseLiterals(
C).front();
125 NextWatched.push_back(WatchedHead[FirstLit]);
126 WatchedHead[FirstLit] =
C;
132 LevelStates[0] = State::Decision;
135 VarAssignments.resize(CNF.largestVar() + 1, Assignment::Unassigned);
140 ActiveVars.push_back(Var);
146 std::pair<Solver::Result, std::int64_t> solve(std::int64_t MaxIterations) && {
147 if (CNF.knownContradictory()) {
153 while (I < ActiveVars.size()) {
154 if (MaxIterations == 0)
165#ifdef EXPENSIVE_CHECKS
166 assert(activeVarsAreUnassigned());
167 assert(activeVarsFormWatchedLiterals());
168 assert(unassignedVarsFormingWatchedLiteralsAreActive());
171 const Variable ActiveVar = ActiveVars[I];
174 const bool unitPosLit = watchedByUnitClause(
posLit(ActiveVar));
175 const bool unitNegLit = watchedByUnitClause(
negLit(ActiveVar));
176 if (unitPosLit && unitNegLit) {
181 reverseForcedMoves();
190 LevelStates[Level] = State::Forced;
191 const Variable Var = LevelVars[Level];
192 VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue
193 ? Assignment::AssignedFalse
194 : Assignment::AssignedTrue;
196 updateWatchedLiterals();
197 }
else if (unitPosLit || unitNegLit) {
202 LevelVars[Level] = ActiveVar;
203 LevelStates[Level] = State::Forced;
204 VarAssignments[ActiveVar] =
205 unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse;
209 if (I + 1 < ActiveVars.size()) {
212 ActiveVars[I] = ActiveVars.back();
218 ActiveVars.pop_back();
220 updateWatchedLiterals();
221 }
else if (I + 1 == ActiveVars.size()) {
226 LevelVars[Level] = ActiveVar;
227 LevelStates[Level] = State::Decision;
228 VarAssignments[ActiveVar] = decideAssignment(ActiveVar);
232 ActiveVars.pop_back();
234 updateWatchedLiterals();
249 llvm::DenseMap<Atom, Solver::Result::Assignment> buildSolution() {
250 llvm::DenseMap<Atom, Solver::Result::Assignment> Solution;
251 for (
auto &
Atomic : Atomics) {
256 VarAssignments[
Atomic.first] == Assignment::AssignedFalse
265 void reverseForcedMoves() {
266 for (; LevelStates[Level] == State::Forced; --Level) {
267 const Variable Var = LevelVars[Level];
269 VarAssignments[Var] = Assignment::Unassigned;
274 ActiveVars.push_back(Var);
279 void updateWatchedLiterals() {
280 const Variable Var = LevelVars[Level];
284 const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue
287 ClauseID FalseLitWatcher = WatchedHead[FalseLit];
290 const ClauseID NextFalseLitWatcher = NextWatched[FalseLitWatcher];
294 CNF.startOfClause(FalseLitWatcher);
296 while (isCurrentlyFalse(*NewWatchedLitIter))
298 const Literal NewWatchedLit = *NewWatchedLitIter;
299 const Variable NewWatchedLitVar =
var(NewWatchedLit);
304 *NewWatchedLitIter = FalseLit;
305 *FalseLitWatcherStart = NewWatchedLit;
309 if (!isWatched(NewWatchedLit) && !isWatched(
notLit(NewWatchedLit)) &&
310 VarAssignments[NewWatchedLitVar] == Assignment::Unassigned)
311 ActiveVars.push_back(NewWatchedLitVar);
313 NextWatched[FalseLitWatcher] = WatchedHead[NewWatchedLit];
314 WatchedHead[NewWatchedLit] = FalseLitWatcher;
317 FalseLitWatcher = NextFalseLitWatcher;
323 bool watchedByUnitClause(
Literal Lit)
const {
325 LitWatcher = NextWatched[LitWatcher]) {
326 llvm::ArrayRef<Literal> Clause = CNF.clauseLiterals(LitWatcher);
333 assert(Clause.front() == Lit);
342 bool isUnit(llvm::ArrayRef<Literal> Clause)
const {
343 return llvm::all_of(Clause.drop_front(),
344 [
this](
Literal L) { return isCurrentlyFalse(L); });
349 bool isCurrentlyFalse(
Literal Lit)
const {
350 return static_cast<int8_t>(VarAssignments[
var(Lit)]) ==
351 static_cast<int8_t>(Lit & 1);
358 Assignment decideAssignment(
Variable Var)
const {
359 return !isWatched(
posLit(Var)) || isWatched(
negLit(Var))
360 ? Assignment::AssignedFalse
361 : Assignment::AssignedTrue;
365 llvm::DenseSet<Literal> watchedLiterals()
const {
366 llvm::DenseSet<Literal> WatchedLiterals;
367 for (
Literal Lit = 2; Lit < WatchedHead.size(); Lit++) {
370 WatchedLiterals.insert(Lit);
372 return WatchedLiterals;
376 bool activeVarsAreUnassigned()
const {
377 return llvm::all_of(ActiveVars, [
this](
Variable Var) {
378 return VarAssignments[Var] == Assignment::Unassigned;
383 bool activeVarsFormWatchedLiterals()
const {
384 const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals();
385 return llvm::all_of(ActiveVars, [&WatchedLiterals](
Variable Var) {
386 return WatchedLiterals.contains(
posLit(Var)) ||
387 WatchedLiterals.contains(
negLit(Var));
393 bool unassignedVarsFormingWatchedLiteralsAreActive()
const {
394 const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(),
396 for (
Literal Lit : watchedLiterals()) {
398 if (VarAssignments[Var] != Assignment::Unassigned)
400 if (ActiveVarsSet.contains(Var))
414 auto [Res, Iterations] = WatchedLiteralsSolverImpl(Vals).solve(MaxIterations);
415 MaxIterations = Iterations;
Result solve(llvm::ArrayRef< const Formula * > Vals) override
Checks if the conjunction of Vals is satisfiable and returns the corresponding result.
Dataflow Directional Tag Classes.
uint32_t ClauseID
Clause identifiers are represented as positive integers.
constexpr Literal posLit(Variable V)
Returns the positive literal V.
constexpr Variable NullVar
A null boolean variable is used as a placeholder in various data structures and algorithms.
uint32_t Literal
Literals are represented as positive integers.
uint32_t Variable
Boolean variables are represented as positive integers.
CNFFormula buildCNF(const llvm::ArrayRef< const Formula * > &Formulas, llvm::DenseMap< Variable, Atom > &Atomics)
Converts the conjunction of Vals into a formula in conjunctive normal form where each clause has at l...
constexpr ClauseID NullClause
A null clause identifier is used as a placeholder in various data structures and algorithms.
constexpr Variable var(Literal L)
Returns the variable of L.
constexpr Literal negLit(Variable V)
Returns the negative literal !V.
constexpr Literal notLit(Literal L)
Returns the negated literal !L.
The JSON file list parser is used to communicate input to InstallAPI.
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 uint8_t
static Result TimedOut()
Constructs a result indicating that satisfiability checking on the queried boolean formula was not co...
static Result Unsatisfiable()
Constructs a result indicating that the queried boolean formula is unsatisfiable.
@ Satisfiable
Indicates that there exists a satisfying assignment for a boolean formula.