1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, Dejan Jovanovic |
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 |
|
* The PropEngine (propositional engine). |
14 |
|
* |
15 |
|
* Main interface point between cvc5's SMT infrastructure and the SAT solver. |
16 |
|
*/ |
17 |
|
|
18 |
|
#include "cvc5_private.h" |
19 |
|
|
20 |
|
#ifndef CVC5__PROP_ENGINE_H |
21 |
|
#define CVC5__PROP_ENGINE_H |
22 |
|
|
23 |
|
#include "context/cdlist.h" |
24 |
|
#include "expr/node.h" |
25 |
|
#include "proof/trust_node.h" |
26 |
|
#include "prop/skolem_def_manager.h" |
27 |
|
#include "theory/output_channel.h" |
28 |
|
#include "theory/skolem_lemma.h" |
29 |
|
#include "util/result.h" |
30 |
|
|
31 |
|
namespace cvc5 { |
32 |
|
|
33 |
|
class Env; |
34 |
|
class ResourceManager; |
35 |
|
class ProofNodeManager; |
36 |
|
class TheoryEngine; |
37 |
|
|
38 |
|
namespace decision { |
39 |
|
class DecisionEngine; |
40 |
|
} |
41 |
|
|
42 |
|
namespace prop { |
43 |
|
|
44 |
|
class CnfStream; |
45 |
|
class CDCLTSatSolverInterface; |
46 |
|
class ProofCnfStream; |
47 |
|
class PropPfManager; |
48 |
|
class TheoryProxy; |
49 |
|
|
50 |
|
/** |
51 |
|
* PropEngine is the abstraction of a Sat Solver, providing methods for |
52 |
|
* solving the SAT problem and conversion to CNF (via the CnfStream). |
53 |
|
*/ |
54 |
|
class PropEngine |
55 |
|
{ |
56 |
|
public: |
57 |
|
/** |
58 |
|
* Create a PropEngine with a particular decision and theory engine. |
59 |
|
*/ |
60 |
|
PropEngine(TheoryEngine* te, Env& env); |
61 |
|
|
62 |
|
/** |
63 |
|
* Destructor. |
64 |
|
*/ |
65 |
|
~PropEngine(); |
66 |
|
|
67 |
|
/** |
68 |
|
* Finish initialize. Call this after construction just before we are |
69 |
|
* ready to use this class. Should be called after TheoryEngine::finishInit. |
70 |
|
* This method converts and asserts true and false into the CNF stream. |
71 |
|
*/ |
72 |
|
void finishInit(); |
73 |
|
|
74 |
|
/** |
75 |
|
* This is called by SolverEngine, at shutdown time, just before |
76 |
|
* destruction. It is important because there are destruction |
77 |
|
* ordering issues between some parts of the system (notably between |
78 |
|
* PropEngine and Theory). For now, there's nothing to do here in |
79 |
|
* the PropEngine. |
80 |
|
*/ |
81 |
15266 |
void shutdown() {} |
82 |
|
|
83 |
|
/** |
84 |
|
* Preprocess the given node. Return the REWRITE trust node corresponding to |
85 |
|
* rewriting node. New lemmas and skolems are added to ppLemmas and |
86 |
|
* ppSkolems respectively. |
87 |
|
* |
88 |
|
* @param node The assertion to preprocess, |
89 |
|
* @param ppLemmas The lemmas to add to the set of assertions, which tracks |
90 |
|
* their corresponding skolems, |
91 |
|
* @return The (REWRITE) trust node corresponding to rewritten node via |
92 |
|
* preprocessing. |
93 |
|
*/ |
94 |
|
TrustNode preprocess(TNode node, std::vector<theory::SkolemLemma>& ppLemmas); |
95 |
|
/** |
96 |
|
* Remove term ITEs (and more generally, term formulas) from the given node. |
97 |
|
* Return the REWRITE trust node corresponding to rewriting node. New lemmas |
98 |
|
* and skolems are added to ppLemmas and ppSkolems respectively. This can |
99 |
|
* be seen a subset of the above preprocess method, which also does theory |
100 |
|
* preprocessing and rewriting. |
101 |
|
* |
102 |
|
* @param node The assertion to preprocess, |
103 |
|
* @param ppLemmas The lemmas to add to the set of assertions, which tracks |
104 |
|
* their corresponding skolems. |
105 |
|
* @return The (REWRITE) trust node corresponding to rewritten node via |
106 |
|
* preprocessing. |
107 |
|
*/ |
108 |
|
TrustNode removeItes(TNode node, std::vector<theory::SkolemLemma>& ppLemmas); |
109 |
|
|
110 |
|
/** |
111 |
|
* Converts the given formulas to CNF and assert the CNF to the SAT solver. |
112 |
|
* These formulas are asserted permanently for the current context. |
113 |
|
* Information about which assertions correspond to skolem definitions is |
114 |
|
* contained in skolemMap. |
115 |
|
* |
116 |
|
* @param assertions the formulas to assert |
117 |
|
* @param skolemMap a map which says which skolem (if any) each assertion |
118 |
|
* corresponds to. For example, if (ite C (= k a) (= k b)) is the i^th |
119 |
|
* assertion, then skolemMap may contain the entry { i -> k }. |
120 |
|
*/ |
121 |
|
void assertInputFormulas(const std::vector<Node>& assertions, |
122 |
|
std::unordered_map<size_t, Node>& skolemMap); |
123 |
|
|
124 |
|
/** |
125 |
|
* Converts the given formula to CNF and assert the CNF to the SAT solver. |
126 |
|
* The formula can be removed by the SAT solver after backtracking lower |
127 |
|
* than the (SAT and SMT) level at which it was asserted. |
128 |
|
* |
129 |
|
* @param trn the trust node storing the formula to assert |
130 |
|
* @param p the properties of the lemma |
131 |
|
*/ |
132 |
|
void assertLemma(TrustNode tlemma, theory::LemmaProperty p); |
133 |
|
|
134 |
|
/** |
135 |
|
* If ever n is decided upon, it must be in the given phase. This |
136 |
|
* occurs *globally*, i.e., even if the literal is untranslated by |
137 |
|
* user pop and retranslated, it keeps this phase. The associated |
138 |
|
* variable will _always_ be phase-locked. |
139 |
|
* |
140 |
|
* @param n the node in question; must have an associated SAT literal |
141 |
|
* @param phase the phase to use |
142 |
|
*/ |
143 |
|
void requirePhase(TNode n, bool phase); |
144 |
|
|
145 |
|
/** |
146 |
|
* Return whether the given literal is a SAT decision. Either phase |
147 |
|
* is permitted; that is, if "lit" is a SAT decision, this function |
148 |
|
* returns true for both lit and the negation of lit. |
149 |
|
*/ |
150 |
|
bool isDecision(Node lit) const; |
151 |
|
|
152 |
|
/** |
153 |
|
* Return SAT context level at which `lit` was decided on. |
154 |
|
* |
155 |
|
* @param lit: The node in question, must have an associated SAT literal. |
156 |
|
* @return Decision level of the SAT variable of `lit` (phase is disregarded), |
157 |
|
* or -1 if `lit` has not been assigned yet. |
158 |
|
*/ |
159 |
|
int32_t getDecisionLevel(Node lit) const; |
160 |
|
|
161 |
|
/** |
162 |
|
* Return the user-context level when `lit` was introduced.. |
163 |
|
* |
164 |
|
* @return User-context level or -1 if not yet introduced. |
165 |
|
*/ |
166 |
|
int32_t getIntroLevel(Node lit) const; |
167 |
|
|
168 |
|
/** |
169 |
|
* Checks the current context for satisfiability. |
170 |
|
* |
171 |
|
*/ |
172 |
|
Result checkSat(); |
173 |
|
|
174 |
|
/** |
175 |
|
* Get the value of a boolean variable. |
176 |
|
* |
177 |
|
* @return mkConst<true>, mkConst<false>, or Node::null() if |
178 |
|
* unassigned. |
179 |
|
*/ |
180 |
|
Node getValue(TNode node) const; |
181 |
|
|
182 |
|
/** |
183 |
|
* Return true if node has an associated SAT literal. |
184 |
|
*/ |
185 |
|
bool isSatLiteral(TNode node) const; |
186 |
|
|
187 |
|
/** |
188 |
|
* Check if the node has a value and return it if yes. |
189 |
|
*/ |
190 |
|
bool hasValue(TNode node, bool& value) const; |
191 |
|
|
192 |
|
/** |
193 |
|
* Returns the Boolean variables known to the SAT solver. |
194 |
|
*/ |
195 |
|
void getBooleanVariables(std::vector<TNode>& outputVariables) const; |
196 |
|
|
197 |
|
/** |
198 |
|
* Ensure that the given node will have a designated SAT literal |
199 |
|
* that is definitionally equal to it. Note that theory preprocessing is |
200 |
|
* applied to n. The node returned by this method can be subsequently queried |
201 |
|
* via getSatValue(). |
202 |
|
*/ |
203 |
|
Node ensureLiteral(TNode n); |
204 |
|
/** |
205 |
|
* This returns the theory-preprocessed form of term n. This rewrites and |
206 |
|
* preprocesses n, which notice may involve adding clauses to the SAT solver |
207 |
|
* if preprocessing n involves introducing new skolems. |
208 |
|
*/ |
209 |
|
Node getPreprocessedTerm(TNode n); |
210 |
|
/** |
211 |
|
* Same as above, but also compute the skolems in n and in the lemmas |
212 |
|
* corresponding to their definition. |
213 |
|
* |
214 |
|
* Note this will include skolems that occur in the definition lemma |
215 |
|
* for all skolems in sks. This is run until a fixed point is reached. |
216 |
|
* For example, if k1 has definition (ite A (= k1 k2) (= k1 x)) where k2 is |
217 |
|
* another skolem introduced by term formula removal, then calling this |
218 |
|
* method on (P k1) will include both k1 and k2 in sks, and their definitions |
219 |
|
* in skAsserts. |
220 |
|
* |
221 |
|
* Notice that this method is not frequently used. It is used for algorithms |
222 |
|
* that explicitly care about knowing which skolems occur in the preprocessed |
223 |
|
* form of a term, recursively. |
224 |
|
*/ |
225 |
|
Node getPreprocessedTerm(TNode n, |
226 |
|
std::vector<Node>& skAsserts, |
227 |
|
std::vector<Node>& sks); |
228 |
|
|
229 |
|
/** |
230 |
|
* Push the context level. |
231 |
|
*/ |
232 |
|
void push(); |
233 |
|
|
234 |
|
/** |
235 |
|
* Pop the context level. |
236 |
|
*/ |
237 |
|
void pop(); |
238 |
|
|
239 |
|
/* |
240 |
|
* Reset the decisions in the DPLL(T) SAT solver at the current assertion |
241 |
|
* level. |
242 |
|
*/ |
243 |
|
void resetTrail(); |
244 |
|
|
245 |
|
/** |
246 |
|
* Get the assertion level of the SAT solver. |
247 |
|
*/ |
248 |
|
unsigned getAssertionLevel() const; |
249 |
|
|
250 |
|
/** |
251 |
|
* Return true if we are currently searching (either in this or |
252 |
|
* another thread). |
253 |
|
*/ |
254 |
|
bool isRunning() const; |
255 |
|
|
256 |
|
/** |
257 |
|
* Interrupt a running solver (cause a timeout). |
258 |
|
* |
259 |
|
* Can potentially throw a ModalException. |
260 |
|
*/ |
261 |
|
void interrupt(); |
262 |
|
|
263 |
|
/** |
264 |
|
* Informs the ResourceManager that a resource has been spent. If out of |
265 |
|
* resources, can throw an UnsafeInterruptException exception. |
266 |
|
*/ |
267 |
|
void spendResource(Resource r); |
268 |
|
|
269 |
|
/** |
270 |
|
* For debugging. Return true if "expl" is a well-formed |
271 |
|
* explanation for "node," meaning: |
272 |
|
* |
273 |
|
* 1. expl is either a SAT literal or an AND of SAT literals |
274 |
|
* currently assigned true; |
275 |
|
* 2. node is assigned true; |
276 |
|
* 3. node does not appear in expl; and |
277 |
|
* 4. node was assigned after all of the literals in expl |
278 |
|
*/ |
279 |
|
bool properExplanation(TNode node, TNode expl) const; |
280 |
|
|
281 |
|
/** Retrieve this modules proof CNF stream. */ |
282 |
|
ProofCnfStream* getProofCnfStream(); |
283 |
|
|
284 |
|
/** Checks that the proof is closed w.r.t. asserted formulas to this engine as |
285 |
|
* well as to the given assertions. */ |
286 |
|
void checkProof(const context::CDList<Node>& assertions); |
287 |
|
|
288 |
|
/** |
289 |
|
* Return the prop engine proof. This should be called only when proofs are |
290 |
|
* enabled. Returns a proof of false whose free assumptions are the |
291 |
|
* preprocessed assertions. |
292 |
|
*/ |
293 |
|
std::shared_ptr<ProofNode> getProof(); |
294 |
|
|
295 |
|
/** Is proof enabled? */ |
296 |
|
bool isProofEnabled() const; |
297 |
|
|
298 |
|
/** Retrieve unsat core from SAT solver for assumption-based unsat cores. */ |
299 |
|
void getUnsatCore(std::vector<Node>& core); |
300 |
|
|
301 |
|
/** Return the prop engine proof for assumption-based unsat cores. */ |
302 |
|
std::shared_ptr<ProofNode> getRefutation(); |
303 |
|
|
304 |
|
private: |
305 |
|
/** Dump out the satisfying assignment (after SAT result) */ |
306 |
|
void printSatisfyingAssignment(); |
307 |
|
|
308 |
|
/** |
309 |
|
* Converts the given formula to CNF and asserts the CNF to the SAT solver. |
310 |
|
* The formula can be removed by the SAT solver after backtracking lower |
311 |
|
* than the (SAT and SMT) level at which it was asserted. |
312 |
|
* |
313 |
|
* @param trn the trust node storing the formula to assert |
314 |
|
* @param removable whether this lemma can be quietly removed based |
315 |
|
* on an activity heuristic |
316 |
|
*/ |
317 |
|
void assertTrustedLemmaInternal(TrustNode trn, bool removable); |
318 |
|
/** |
319 |
|
* Assert node as a formula to the CNF stream |
320 |
|
* @param node The formula to assert |
321 |
|
* @param negated Whether to assert the negation of node |
322 |
|
* @param removable Whether the formula is removable |
323 |
|
* @param input Whether the formula came from the input |
324 |
|
* @param pg Pointer to a proof generator that can provide a proof of node |
325 |
|
* (or its negation if negated is true). |
326 |
|
*/ |
327 |
|
void assertInternal(TNode node, |
328 |
|
bool negated, |
329 |
|
bool removable, |
330 |
|
bool input, |
331 |
|
ProofGenerator* pg = nullptr); |
332 |
|
/** |
333 |
|
* Assert lemmas internal, where trn is a trust node corresponding to a |
334 |
|
* formula to assert to the CNF stream, ppLemmas are the skolem definitions |
335 |
|
* obtained from preprocessing it, and removable is whether the lemma is |
336 |
|
* removable. |
337 |
|
*/ |
338 |
|
void assertLemmasInternal(TrustNode trn, |
339 |
|
const std::vector<theory::SkolemLemma>& ppLemmas, |
340 |
|
bool removable); |
341 |
|
|
342 |
|
/** |
343 |
|
* Indicates that the SAT solver is currently solving something and we should |
344 |
|
* not mess with it's internal state. |
345 |
|
*/ |
346 |
|
bool d_inCheckSat; |
347 |
|
|
348 |
|
/** The theory engine we will be using */ |
349 |
|
TheoryEngine* d_theoryEngine; |
350 |
|
|
351 |
|
/** Reference to the environment */ |
352 |
|
Env& d_env; |
353 |
|
|
354 |
|
/** The decision engine we will be using */ |
355 |
|
std::unique_ptr<decision::DecisionEngine> d_decisionEngine; |
356 |
|
|
357 |
|
/** The skolem definition manager */ |
358 |
|
std::unique_ptr<SkolemDefManager> d_skdm; |
359 |
|
|
360 |
|
/** SAT solver's proxy back to theories; kept around for dtor cleanup */ |
361 |
|
TheoryProxy* d_theoryProxy; |
362 |
|
|
363 |
|
/** The SAT solver proxy */ |
364 |
|
CDCLTSatSolverInterface* d_satSolver; |
365 |
|
|
366 |
|
/** List of all of the assertions that need to be made */ |
367 |
|
std::vector<Node> d_assertionList; |
368 |
|
|
369 |
|
/** The CNF converter in use */ |
370 |
|
CnfStream* d_cnfStream; |
371 |
|
/** Proof-producing CNF converter */ |
372 |
|
std::unique_ptr<ProofCnfStream> d_pfCnfStream; |
373 |
|
|
374 |
|
/** The proof manager for prop engine */ |
375 |
|
std::unique_ptr<PropPfManager> d_ppm; |
376 |
|
|
377 |
|
/** Whether we were just interrupted (or not) */ |
378 |
|
bool d_interrupted; |
379 |
|
|
380 |
|
/** |
381 |
|
* Stores assumptions added via assertInternal() if assumption-based unsat |
382 |
|
* cores are enabled. |
383 |
|
*/ |
384 |
|
context::CDList<Node> d_assumptions; |
385 |
|
}; |
386 |
|
|
387 |
|
} // namespace prop |
388 |
|
} // namespace cvc5 |
389 |
|
|
390 |
|
#endif /* CVC5__PROP_ENGINE_H */ |