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;
73 enum class State : uint8_t {
86 std::vector<State> LevelStates;
99 std::vector<Assignment> VarAssignments;
103 std::vector<Variable> ActiveVars;
106 explicit WatchedLiteralsSolverImpl(
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 assert(activeVarsAreUnassigned());
166 assert(activeVarsFormWatchedLiterals());
167 assert(unassignedVarsFormingWatchedLiteralsAreActive());
169 const Variable ActiveVar = ActiveVars[I];
172 const bool unitPosLit = watchedByUnitClause(
posLit(ActiveVar));
173 const bool unitNegLit = watchedByUnitClause(
negLit(ActiveVar));
174 if (unitPosLit && unitNegLit) {
179 reverseForcedMoves();
188 LevelStates[
Level] = State::Forced;
190 VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue
191 ? Assignment::AssignedFalse
192 : Assignment::AssignedTrue;
194 updateWatchedLiterals();
195 }
else if (unitPosLit || unitNegLit) {
200 LevelVars[
Level] = ActiveVar;
201 LevelStates[
Level] = State::Forced;
202 VarAssignments[ActiveVar] =
203 unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse;
207 if (I + 1 < ActiveVars.size()) {
210 ActiveVars[I] = ActiveVars.back();
216 ActiveVars.pop_back();
218 updateWatchedLiterals();
219 }
else if (I + 1 == ActiveVars.size()) {
224 LevelVars[
Level] = ActiveVar;
225 LevelStates[
Level] = State::Decision;
226 VarAssignments[ActiveVar] = decideAssignment(ActiveVar);
230 ActiveVars.pop_back();
232 updateWatchedLiterals();
247 llvm::DenseMap<Atom, Solver::Result::Assignment> buildSolution() {
248 llvm::DenseMap<Atom, Solver::Result::Assignment> Solution;
249 for (
auto &
Atomic : Atomics) {
254 VarAssignments[
Atomic.first] == Assignment::AssignedFalse
263 void reverseForcedMoves() {
264 for (; LevelStates[
Level] == State::Forced; --
Level) {
267 VarAssignments[Var] = Assignment::Unassigned;
272 ActiveVars.push_back(Var);
277 void updateWatchedLiterals() {
282 const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue
285 ClauseID FalseLitWatcher = WatchedHead[FalseLit];
288 const ClauseID NextFalseLitWatcher = NextWatched[FalseLitWatcher];
291 const CNFFormula::Iterator FalseLitWatcherStart =
292 CNF.startOfClause(FalseLitWatcher);
293 CNFFormula::Iterator NewWatchedLitIter = FalseLitWatcherStart.next();
294 while (isCurrentlyFalse(*NewWatchedLitIter))
296 const Literal NewWatchedLit = *NewWatchedLitIter;
297 const Variable NewWatchedLitVar =
var(NewWatchedLit);
302 *NewWatchedLitIter = FalseLit;
303 *FalseLitWatcherStart = NewWatchedLit;
307 if (!isWatched(NewWatchedLit) && !isWatched(
notLit(NewWatchedLit)) &&
308 VarAssignments[NewWatchedLitVar] == Assignment::Unassigned)
309 ActiveVars.push_back(NewWatchedLitVar);
311 NextWatched[FalseLitWatcher] = WatchedHead[NewWatchedLit];
312 WatchedHead[NewWatchedLit] = FalseLitWatcher;
315 FalseLitWatcher = NextFalseLitWatcher;
321 bool watchedByUnitClause(
Literal Lit)
const {
323 LitWatcher = NextWatched[LitWatcher]) {
331 assert(Clause.front() == Lit);
341 return llvm::all_of(Clause.drop_front(),
342 [
this](
Literal L) { return isCurrentlyFalse(L); });
347 bool isCurrentlyFalse(
Literal Lit)
const {
348 return static_cast<int8_t
>(VarAssignments[
var(Lit)]) ==
349 static_cast<int8_t
>(Lit & 1);
357 return !isWatched(
posLit(Var)) || isWatched(
negLit(Var))
358 ? Assignment::AssignedFalse
359 : Assignment::AssignedTrue;
363 llvm::DenseSet<Literal> watchedLiterals()
const {
364 llvm::DenseSet<Literal> WatchedLiterals;
365 for (
Literal Lit = 2; Lit < WatchedHead.size(); Lit++) {
368 WatchedLiterals.insert(Lit);
370 return WatchedLiterals;
374 bool activeVarsAreUnassigned()
const {
375 return llvm::all_of(ActiveVars, [
this](
Variable Var) {
376 return VarAssignments[Var] == Assignment::Unassigned;
381 bool activeVarsFormWatchedLiterals()
const {
382 const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals();
383 return llvm::all_of(ActiveVars, [&WatchedLiterals](
Variable Var) {
384 return WatchedLiterals.contains(
posLit(Var)) ||
385 WatchedLiterals.contains(
negLit(Var));
391 bool unassignedVarsFormingWatchedLiteralsAreActive()
const {
392 const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(),
394 for (
Literal Lit : watchedLiterals()) {
396 if (VarAssignments[Var] != Assignment::Unassigned)
398 if (ActiveVarsSet.contains(Var))
412 auto [Res, Iterations] = WatchedLiteralsSolverImpl(Vals).solve(MaxIterations);
413 MaxIterations = Iterations;
Result solve(llvm::ArrayRef< const Formula * > Vals) override
Checks if the conjunction of Vals is satisfiable and returns the corresponding result.
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.
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.
uint32_t Literal
Literals are represented as positive integers.
uint32_t Variable
Boolean variables are represented as positive integers.
constexpr Literal notLit(Literal L)
Returns the negated literal !L.
The JSON file list parser is used to communicate input to InstallAPI.
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.