1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Mathias Preiner, Andres Noetzli, Liana Hadarean |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Wrapper for CaDiCaL SAT Solver. |
14 |
|
* |
15 |
|
* Implementation of the CaDiCaL SAT solver for cvc5 (bit-vectors). |
16 |
|
*/ |
17 |
|
|
18 |
|
#include "prop/cadical.h" |
19 |
|
|
20 |
|
#ifdef CVC5_USE_CADICAL |
21 |
|
|
22 |
|
#include "base/check.h" |
23 |
|
#include "util/statistics_registry.h" |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
namespace prop { |
27 |
|
|
28 |
|
using CadicalLit = int; |
29 |
|
using CadicalVar = int; |
30 |
|
|
31 |
|
// helper functions |
32 |
|
namespace { |
33 |
|
|
34 |
12 |
SatValue toSatValue(int result) |
35 |
|
{ |
36 |
12 |
if (result == 10) return SAT_VALUE_TRUE; |
37 |
3 |
if (result == 20) return SAT_VALUE_FALSE; |
38 |
|
Assert(result == 0); |
39 |
|
return SAT_VALUE_UNKNOWN; |
40 |
|
} |
41 |
|
|
42 |
|
/* Note: CaDiCaL returns lit/-lit for true/false. Older versions returned 1/-1. |
43 |
|
*/ |
44 |
144 |
SatValue toSatValueLit(int value) |
45 |
|
{ |
46 |
144 |
if (value > 0) return SAT_VALUE_TRUE; |
47 |
33 |
Assert(value < 0); |
48 |
33 |
return SAT_VALUE_FALSE; |
49 |
|
} |
50 |
|
|
51 |
6705 |
CadicalLit toCadicalLit(const SatLiteral lit) |
52 |
|
{ |
53 |
6705 |
return lit.isNegated() ? -lit.getSatVariable() : lit.getSatVariable(); |
54 |
|
} |
55 |
|
|
56 |
6 |
CadicalVar toCadicalVar(SatVariable var) { return var; } |
57 |
|
|
58 |
|
} // namespace helper functions |
59 |
|
|
60 |
3 |
CadicalSolver::CadicalSolver(StatisticsRegistry& registry, |
61 |
3 |
const std::string& name) |
62 |
3 |
: d_solver(new CaDiCaL::Solver()), |
63 |
|
// Note: CaDiCaL variables start with index 1 rather than 0 since negated |
64 |
|
// literals are represented as the negation of the index. |
65 |
|
d_nextVarIdx(1), |
66 |
|
d_inSatMode(false), |
67 |
6 |
d_statistics(registry, name) |
68 |
|
{ |
69 |
3 |
} |
70 |
|
|
71 |
3 |
void CadicalSolver::init() |
72 |
|
{ |
73 |
3 |
d_true = newVar(); |
74 |
3 |
d_false = newVar(); |
75 |
|
|
76 |
3 |
d_solver->set("quiet", 1); // CaDiCaL is verbose by default |
77 |
3 |
d_solver->add(toCadicalVar(d_true)); |
78 |
3 |
d_solver->add(0); |
79 |
3 |
d_solver->add(-toCadicalVar(d_false)); |
80 |
3 |
d_solver->add(0); |
81 |
3 |
} |
82 |
|
|
83 |
6 |
CadicalSolver::~CadicalSolver() {} |
84 |
|
|
85 |
2550 |
ClauseId CadicalSolver::addClause(SatClause& clause, bool removable) |
86 |
|
{ |
87 |
9102 |
for (const SatLiteral& lit : clause) |
88 |
|
{ |
89 |
6552 |
d_solver->add(toCadicalLit(lit)); |
90 |
|
} |
91 |
2550 |
d_solver->add(0); |
92 |
2550 |
++d_statistics.d_numClauses; |
93 |
2550 |
return ClauseIdError; |
94 |
|
} |
95 |
|
|
96 |
|
ClauseId CadicalSolver::addXorClause(SatClause& clause, |
97 |
|
bool rhs, |
98 |
|
bool removable) |
99 |
|
{ |
100 |
|
Unreachable() << "CaDiCaL does not support adding XOR clauses."; |
101 |
|
} |
102 |
|
|
103 |
921 |
SatVariable CadicalSolver::newVar(bool isTheoryAtom, |
104 |
|
bool preRegister, |
105 |
|
bool canErase) |
106 |
|
{ |
107 |
921 |
++d_statistics.d_numVariables; |
108 |
921 |
return d_nextVarIdx++; |
109 |
|
} |
110 |
|
|
111 |
|
SatVariable CadicalSolver::trueVar() { return d_true; } |
112 |
|
|
113 |
|
SatVariable CadicalSolver::falseVar() { return d_false; } |
114 |
|
|
115 |
|
SatValue CadicalSolver::solve() |
116 |
|
{ |
117 |
|
TimerStat::CodeTimer codeTimer(d_statistics.d_solveTime); |
118 |
|
d_assumptions.clear(); |
119 |
|
SatValue res = toSatValue(d_solver->solve()); |
120 |
|
d_inSatMode = (res == SAT_VALUE_TRUE); |
121 |
|
++d_statistics.d_numSatCalls; |
122 |
|
return res; |
123 |
|
} |
124 |
|
|
125 |
|
SatValue CadicalSolver::solve(long unsigned int&) |
126 |
|
{ |
127 |
|
Unimplemented() << "Setting limits for CaDiCaL not supported yet"; |
128 |
|
}; |
129 |
|
|
130 |
12 |
SatValue CadicalSolver::solve(const std::vector<SatLiteral>& assumptions) |
131 |
|
{ |
132 |
24 |
TimerStat::CodeTimer codeTimer(d_statistics.d_solveTime); |
133 |
12 |
d_assumptions.clear(); |
134 |
21 |
for (const SatLiteral& lit : assumptions) |
135 |
|
{ |
136 |
9 |
d_solver->assume(toCadicalLit(lit)); |
137 |
9 |
d_assumptions.push_back(lit); |
138 |
|
} |
139 |
12 |
SatValue res = toSatValue(d_solver->solve()); |
140 |
12 |
d_inSatMode = (res == SAT_VALUE_TRUE); |
141 |
12 |
++d_statistics.d_numSatCalls; |
142 |
24 |
return res; |
143 |
|
} |
144 |
|
|
145 |
|
bool CadicalSolver::setPropagateOnly() |
146 |
|
{ |
147 |
|
d_solver->limit("decisions", 0); /* Gets reset after next solve() call. */ |
148 |
|
return true; |
149 |
|
} |
150 |
|
|
151 |
|
void CadicalSolver::getUnsatAssumptions(std::vector<SatLiteral>& assumptions) |
152 |
|
{ |
153 |
|
for (const SatLiteral& lit : d_assumptions) |
154 |
|
{ |
155 |
|
if (d_solver->failed(toCadicalLit(lit))) |
156 |
|
{ |
157 |
|
assumptions.push_back(lit); |
158 |
|
} |
159 |
|
} |
160 |
|
} |
161 |
|
|
162 |
|
void CadicalSolver::interrupt() { d_solver->terminate(); } |
163 |
|
|
164 |
144 |
SatValue CadicalSolver::value(SatLiteral l) |
165 |
|
{ |
166 |
144 |
Assert(d_inSatMode); |
167 |
144 |
return toSatValueLit(d_solver->val(toCadicalLit(l))); |
168 |
|
} |
169 |
|
|
170 |
|
SatValue CadicalSolver::modelValue(SatLiteral l) |
171 |
|
{ |
172 |
|
Assert(d_inSatMode); |
173 |
|
return value(l); |
174 |
|
} |
175 |
|
|
176 |
|
unsigned CadicalSolver::getAssertionLevel() const |
177 |
|
{ |
178 |
|
Unreachable() << "CaDiCaL does not support assertion levels."; |
179 |
|
} |
180 |
|
|
181 |
|
bool CadicalSolver::ok() const { return d_inSatMode; } |
182 |
|
|
183 |
3 |
CadicalSolver::Statistics::Statistics(StatisticsRegistry& registry, |
184 |
3 |
const std::string& prefix) |
185 |
6 |
: d_numSatCalls(registry.registerInt(prefix + "cadical::calls_to_solve", 0)), |
186 |
6 |
d_numVariables(registry.registerInt(prefix + "cadical::variables", 0)), |
187 |
6 |
d_numClauses(registry.registerInt(prefix + "cadical::clauses", 0)), |
188 |
12 |
d_solveTime(registry.registerTimer(prefix + "cadical::solve_time")) |
189 |
|
{ |
190 |
3 |
} |
191 |
|
|
192 |
|
} // namespace prop |
193 |
27735 |
} // namespace cvc5 |
194 |
|
|
195 |
|
#endif // CVC5_USE_CADICAL |