1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Dejan Jovanovic, Haniel Barbosa, Tim King |
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 |
|
* This class transforms a sequence of formulas into clauses. |
14 |
|
* |
15 |
|
* This class takes a sequence of formulas. |
16 |
|
* It outputs a stream of clauses that is propositionally |
17 |
|
* equi-satisfiable with the conjunction of the formulas. |
18 |
|
* This stream is maintained in an online fashion. |
19 |
|
* |
20 |
|
* Unlike other parts of the system it is aware of the PropEngine's |
21 |
|
* internals such as the representation and translation of [??? -Chris] |
22 |
|
*/ |
23 |
|
|
24 |
|
#include "cvc5_private.h" |
25 |
|
|
26 |
|
#ifndef CVC5__PROP__CNF_STREAM_H |
27 |
|
#define CVC5__PROP__CNF_STREAM_H |
28 |
|
|
29 |
|
#include "context/cdhashset.h" |
30 |
|
#include "context/cdinsert_hashmap.h" |
31 |
|
#include "context/cdlist.h" |
32 |
|
#include "expr/node.h" |
33 |
|
#include "prop/proof_cnf_stream.h" |
34 |
|
#include "prop/registrar.h" |
35 |
|
#include "prop/sat_solver_types.h" |
36 |
|
|
37 |
|
namespace cvc5 { |
38 |
|
|
39 |
|
class Env; |
40 |
|
|
41 |
|
namespace prop { |
42 |
|
|
43 |
|
class ProofCnfStream; |
44 |
|
class PropEngine; |
45 |
|
class SatSolver; |
46 |
|
|
47 |
|
/** A policy for how literals for formulas are handled in cnf_stream */ |
48 |
|
enum class FormulaLitPolicy : uint32_t |
49 |
|
{ |
50 |
|
// literals for formulas are notified |
51 |
|
TRACK_AND_NOTIFY, |
52 |
|
// literals for formulas are added to node map |
53 |
|
TRACK, |
54 |
|
// literals for formulas are kept internal (default) |
55 |
|
INTERNAL, |
56 |
|
}; |
57 |
|
|
58 |
|
/** |
59 |
|
* Implements the following recursive algorithm |
60 |
|
* http://people.inf.ethz.ch/daniekro/classes/251-0247-00/f2007/readings/Tseitin70.pdf |
61 |
|
* in a single pass. |
62 |
|
* |
63 |
|
* The general idea is to introduce a new literal that will be equivalent to |
64 |
|
* each subexpression in the constructed equi-satisfiable formula, then |
65 |
|
* substitute the new literal for the formula, and so on, recursively. |
66 |
|
*/ |
67 |
16154 |
class CnfStream { |
68 |
|
friend PropEngine; |
69 |
|
friend ProofCnfStream; |
70 |
|
|
71 |
|
public: |
72 |
|
/** Cache of what nodes have been registered to a literal. */ |
73 |
|
typedef context::CDInsertHashMap<SatLiteral, TNode, SatLiteralHashFunction> |
74 |
|
LiteralToNodeMap; |
75 |
|
|
76 |
|
/** Cache of what literals have been registered to a node. */ |
77 |
|
typedef context::CDInsertHashMap<Node, SatLiteral> NodeToLiteralMap; |
78 |
|
|
79 |
|
/** |
80 |
|
* Constructs a CnfStream that performs equisatisfiable CNF transformations |
81 |
|
* and sends the generated clauses and to the given SAT solver. This does not |
82 |
|
* take ownership of satSolver, registrar, or context. |
83 |
|
* |
84 |
|
* @param satSolver the sat solver to use. |
85 |
|
* @param registrar the entity that takes care of preregistration of Nodes. |
86 |
|
* @param context the context that the CNF should respect. |
87 |
|
* @param env Reference to the environment of the smt engine. Assertions |
88 |
|
* will not be dumped if env == nullptr. |
89 |
|
* @param rm the resource manager of the CNF stream |
90 |
|
* @param flpol policy for literals corresponding to formulas (those that are |
91 |
|
* not-theory literals). |
92 |
|
* @param name string identifier to distinguish between different instances |
93 |
|
* even for non-theory literals. |
94 |
|
*/ |
95 |
|
CnfStream(SatSolver* satSolver, |
96 |
|
Registrar* registrar, |
97 |
|
context::Context* context, |
98 |
|
Env* env, |
99 |
|
ResourceManager* rm, |
100 |
|
FormulaLitPolicy flpol = FormulaLitPolicy::INTERNAL, |
101 |
|
std::string name = ""); |
102 |
|
/** |
103 |
|
* Convert a given formula to CNF and assert it to the SAT solver. |
104 |
|
* |
105 |
|
* @param node node to convert and assert |
106 |
|
* @param removable whether the sat solver can choose to remove the clauses |
107 |
|
* @param negated whether we are asserting the node negated |
108 |
|
* @param input whether it is an input assertion (rather than a lemma). This |
109 |
|
* information is only relevant for unsat core tracking. |
110 |
|
*/ |
111 |
|
void convertAndAssert(TNode node, |
112 |
|
bool removable, |
113 |
|
bool negated, |
114 |
|
bool input = false); |
115 |
|
/** |
116 |
|
* Get the node that is represented by the given SatLiteral. |
117 |
|
* @param literal the literal from the sat solver |
118 |
|
* @return the actual node |
119 |
|
*/ |
120 |
|
TNode getNode(const SatLiteral& literal); |
121 |
|
|
122 |
|
/** |
123 |
|
* Returns true iff the node has an assigned literal (it might not be |
124 |
|
* translated). |
125 |
|
* @param node the node |
126 |
|
*/ |
127 |
|
bool hasLiteral(TNode node) const; |
128 |
|
|
129 |
|
/** |
130 |
|
* Ensure that the given node will have a designated SAT literal that is |
131 |
|
* definitionally equal to it. The result of this function is that the Node |
132 |
|
* can be queried via getSatValue(). Essentially, this is like a "convert-but- |
133 |
|
* don't-assert" version of convertAndAssert(). |
134 |
|
*/ |
135 |
|
void ensureLiteral(TNode n); |
136 |
|
|
137 |
|
/** |
138 |
|
* Returns the literal that represents the given node in the SAT CNF |
139 |
|
* representation. |
140 |
|
* @param node [Presumably there are some constraints on the kind of |
141 |
|
* node? E.g., it needs to be a boolean? -Chris] |
142 |
|
*/ |
143 |
|
SatLiteral getLiteral(TNode node); |
144 |
|
|
145 |
|
/** |
146 |
|
* Returns the Boolean variables from the input problem. |
147 |
|
*/ |
148 |
|
void getBooleanVariables(std::vector<TNode>& outputVariables) const; |
149 |
|
|
150 |
|
/** |
151 |
|
* For SAT/theory relevancy. Returns true if node is a "notify formula". |
152 |
|
* Returns true if node is formula that we are being notified about that |
153 |
|
* is not a theory atom. |
154 |
|
* |
155 |
|
* Note this is only ever true when the policy passed to this class is |
156 |
|
* FormulaLitPolicy::TRACK_AND_NOTIFY. |
157 |
|
*/ |
158 |
|
bool isNotifyFormula(TNode node) const; |
159 |
|
|
160 |
|
/** Retrieves map from nodes to literals. */ |
161 |
|
const CnfStream::NodeToLiteralMap& getTranslationCache() const; |
162 |
|
|
163 |
|
/** Retrieves map from literals to nodes. */ |
164 |
|
const CnfStream::LiteralToNodeMap& getNodeCache() const; |
165 |
|
|
166 |
|
protected: |
167 |
|
/** |
168 |
|
* Same as above, except that uses the saved d_removable flag. It calls the |
169 |
|
* dedicated converter for the possible formula kinds. |
170 |
|
*/ |
171 |
|
void convertAndAssert(TNode node, bool negated); |
172 |
|
/** Specific converters for each formula kind. */ |
173 |
|
void convertAndAssertAnd(TNode node, bool negated); |
174 |
|
void convertAndAssertOr(TNode node, bool negated); |
175 |
|
void convertAndAssertXor(TNode node, bool negated); |
176 |
|
void convertAndAssertIff(TNode node, bool negated); |
177 |
|
void convertAndAssertImplies(TNode node, bool negated); |
178 |
|
void convertAndAssertIte(TNode node, bool negated); |
179 |
|
|
180 |
|
/** |
181 |
|
* Transforms the node into CNF recursively and yields a literal |
182 |
|
* definitionally equal to it. |
183 |
|
* |
184 |
|
* This method also populates caches, kept in d_cnfStream, between formulas |
185 |
|
* and literals to avoid redundant work and to retrieve formulas from literals |
186 |
|
* and vice-versa. |
187 |
|
* |
188 |
|
* @param node the formula to transform |
189 |
|
* @param negated whether the literal is negated |
190 |
|
* @return the literal representing the root of the formula |
191 |
|
*/ |
192 |
|
SatLiteral toCNF(TNode node, bool negated = false); |
193 |
|
|
194 |
|
/** |
195 |
|
* Specific clausifiers that clausify a formula based on the given formula |
196 |
|
* kind and introduce a literal definitionally equal to it. |
197 |
|
*/ |
198 |
|
void handleXor(TNode node); |
199 |
|
void handleImplies(TNode node); |
200 |
|
void handleIff(TNode node); |
201 |
|
void handleIte(TNode node); |
202 |
|
void handleAnd(TNode node); |
203 |
|
void handleOr(TNode node); |
204 |
|
|
205 |
|
/** Stores the literal of the given node in d_literalToNodeMap. |
206 |
|
* |
207 |
|
* Note that n must already have a literal associated to it in |
208 |
|
* d_nodeToLiteralMap. |
209 |
|
*/ |
210 |
|
void ensureMappingForLiteral(TNode n); |
211 |
|
|
212 |
|
/** The SAT solver we will be using */ |
213 |
|
SatSolver* d_satSolver; |
214 |
|
|
215 |
|
/** Pointer to the env of the smt engine */ |
216 |
|
Env* d_env; |
217 |
|
|
218 |
|
/** Boolean variables that we translated */ |
219 |
|
context::CDList<TNode> d_booleanVariables; |
220 |
|
|
221 |
|
/** Formulas that we translated that we are notifying */ |
222 |
|
context::CDHashSet<Node> d_notifyFormulas; |
223 |
|
|
224 |
|
/** Map from nodes to literals */ |
225 |
|
NodeToLiteralMap d_nodeToLiteralMap; |
226 |
|
|
227 |
|
/** Map from literals to nodes */ |
228 |
|
LiteralToNodeMap d_literalToNodeMap; |
229 |
|
|
230 |
|
/** |
231 |
|
* True if the lit-to-Node map should be kept for all lits, not just |
232 |
|
* theory lits. This is true if e.g. replay logging is on, which |
233 |
|
* dumps the Nodes corresponding to decision literals. |
234 |
|
*/ |
235 |
|
const FormulaLitPolicy d_flitPolicy; |
236 |
|
|
237 |
|
/** The "registrar" for pre-registration of terms */ |
238 |
|
Registrar* d_registrar; |
239 |
|
|
240 |
|
/** The name of this CNF stream*/ |
241 |
|
std::string d_name; |
242 |
|
|
243 |
|
/** |
244 |
|
* Are we asserting a removable clause (true) or a permanent clause (false). |
245 |
|
* This is set at the beginning of convertAndAssert so that it doesn't |
246 |
|
* need to be passed on over the stack. Only pure clauses can be asserted |
247 |
|
* as removable. |
248 |
|
*/ |
249 |
|
bool d_removable; |
250 |
|
|
251 |
|
/** |
252 |
|
* Asserts the given clause to the sat solver. |
253 |
|
* @param node the node giving rise to this clause |
254 |
|
* @param clause the clause to assert |
255 |
|
* @return whether the clause was asserted in the SAT solver. |
256 |
|
*/ |
257 |
|
bool assertClause(TNode node, SatClause& clause); |
258 |
|
|
259 |
|
/** |
260 |
|
* Asserts the unit clause to the sat solver. |
261 |
|
* @param node the node giving rise to this clause |
262 |
|
* @param a the unit literal of the clause |
263 |
|
* @return whether the clause was asserted in the SAT solver. |
264 |
|
*/ |
265 |
|
bool assertClause(TNode node, SatLiteral a); |
266 |
|
|
267 |
|
/** |
268 |
|
* Asserts the binary clause to the sat solver. |
269 |
|
* @param node the node giving rise to this clause |
270 |
|
* @param a the first literal in the clause |
271 |
|
* @param b the second literal in the clause |
272 |
|
* @return whether the clause was asserted in the SAT solver. |
273 |
|
*/ |
274 |
|
bool assertClause(TNode node, SatLiteral a, SatLiteral b); |
275 |
|
|
276 |
|
/** |
277 |
|
* Asserts the ternary clause to the sat solver. |
278 |
|
* @param node the node giving rise to this clause |
279 |
|
* @param a the first literal in the clause |
280 |
|
* @param b the second literal in the clause |
281 |
|
* @param c the thirs literal in the clause |
282 |
|
* @return whether the clause was asserted in the SAT solver. |
283 |
|
*/ |
284 |
|
bool assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c); |
285 |
|
|
286 |
|
/** |
287 |
|
* Acquires a new variable from the SAT solver to represent the node |
288 |
|
* and inserts the necessary data it into the mapping tables. |
289 |
|
* @param node a formula |
290 |
|
* @param isTheoryAtom is this a theory atom that needs to be asserted to |
291 |
|
* theory. |
292 |
|
* @param preRegister whether to preregister the atom with the theory |
293 |
|
* @param canEliminate whether the sat solver can safely eliminate this |
294 |
|
* variable. |
295 |
|
* @return the literal corresponding to the formula |
296 |
|
*/ |
297 |
|
SatLiteral newLiteral(TNode node, bool isTheoryAtom = false, |
298 |
|
bool preRegister = false, bool canEliminate = true); |
299 |
|
|
300 |
|
/** |
301 |
|
* Constructs a new literal for an atom and returns it. Calls |
302 |
|
* newLiteral(). |
303 |
|
* |
304 |
|
* @param node the node to convert; there should be no boolean |
305 |
|
* structure in this expression. Assumed to not be in the |
306 |
|
* translation cache. |
307 |
|
*/ |
308 |
|
SatLiteral convertAtom(TNode node); |
309 |
|
|
310 |
|
/** Pointer to resource manager for associated SmtEngine */ |
311 |
|
ResourceManager* d_resourceManager; |
312 |
|
|
313 |
|
private: |
314 |
|
struct Statistics |
315 |
|
{ |
316 |
|
Statistics(const std::string& name); |
317 |
|
TimerStat d_cnfConversionTime; |
318 |
|
} d_stats; |
319 |
|
|
320 |
|
}; /* class CnfStream */ |
321 |
|
|
322 |
|
} // namespace prop |
323 |
|
} // namespace cvc5 |
324 |
|
|
325 |
|
#endif /* CVC5__PROP__CNF_STREAM_H */ |