1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Haniel Barbosa, Gereon Kremer |
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 proof manager for Minisat. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__SAT_PROOF_MANAGER_H |
19 |
|
#define CVC5__SAT_PROOF_MANAGER_H |
20 |
|
|
21 |
|
#include "context/cdhashset.h" |
22 |
|
#include "expr/node.h" |
23 |
|
#include "proof/buffered_proof_generator.h" |
24 |
|
#include "proof/lazy_proof_chain.h" |
25 |
|
#include "prop/minisat/core/SolverTypes.h" |
26 |
|
#include "prop/sat_solver_types.h" |
27 |
|
|
28 |
|
namespace Minisat { |
29 |
|
class Solver; |
30 |
|
} |
31 |
|
|
32 |
|
namespace cvc5 { |
33 |
|
|
34 |
|
class ProofNodeManager; |
35 |
|
|
36 |
|
namespace prop { |
37 |
|
|
38 |
|
class CnfStream; |
39 |
|
|
40 |
|
/** |
41 |
|
* This class is responsible for managing the proof production of the SAT |
42 |
|
* solver. It tracks resolutions produced during solving and stores them, |
43 |
|
* independently, with the connection of the resolutions only made when the |
44 |
|
* empty clause is produced and the refutation is complete. The expected |
45 |
|
* assumptions of the refutation are the clausified preprocessed assertions and |
46 |
|
* lemmas. |
47 |
|
* |
48 |
|
* These resolutions are stored in a LazyCDProofChain, a user-context-dependent |
49 |
|
* proof that takes lazy steps and can connect them when generating a proof for |
50 |
|
* a given fact. Its use in this proof manager is so that, assuming the |
51 |
|
* following lazy steps are saved in the LazyCDProofChain: |
52 |
|
* |
53 |
|
* --- S0: (l4, PG0) |
54 |
|
* --- S1: ((or l3 l4), PG1) |
55 |
|
* --- S2: ((or l1 ~l3), PG2) |
56 |
|
* --- S3: (false, PG3) |
57 |
|
* --- S4: (~l2, PG4) |
58 |
|
* --- S5: (~l3, PG5) |
59 |
|
* --- S6: (~l5, PG6) |
60 |
|
* |
61 |
|
* when requesting the proof of false, assuming that the proof generators have |
62 |
|
* the following expansions: |
63 |
|
* |
64 |
|
* --- PG0 -> (CHAIN_RES ((or l4 l1) ~l1)) |
65 |
|
* --- PG1 -> (CHAIN_RES ((or l3 l5 l6 l7) ~l5 (or ~l6 l7) (or l4 ~l7))) |
66 |
|
* --- PG2 -> (CHAIN_RES ((or l1 ~l3 l5) ~l5)) |
67 |
|
* --- PG3 -> (CHAIN_RES ((or l1 l2) ~l1 ~l2)) |
68 |
|
* --- PG4 -> (CHAIN_RES ((or l3 ~l2) ~l3)) |
69 |
|
* --- PG5 -> (CHAIN_RES ((or l1 ~l3) ~l1)) |
70 |
|
* --- PG6 -> (CHAIN_RES ((or l1 ~l5) ~l1)) |
71 |
|
* |
72 |
|
* will connect the independent resolutions and yield the following refutation |
73 |
|
* |
74 |
|
* (or l1 ~l5) ~l1 |
75 |
|
* ---------------- CHAIN_RES |
76 |
|
* (or l1 ~l3 l5) ~l5 |
77 |
|
* ---------------------- CHAIN_RES |
78 |
|
* (or l1 ~l3) ~l1 |
79 |
|
* ----------------------------- CHAIN_RES |
80 |
|
* (or l3 ~l2) ~l3 |
81 |
|
* -------------------- CHAIN_RES |
82 |
|
* (or l1 l2) ~l1 ~l2 |
83 |
|
* --------------------------- CHAIN_RES |
84 |
|
* false |
85 |
|
* |
86 |
|
* where note that the steps S0 and S1, for l4 and (or l3 l4), respectively, |
87 |
|
* were ignored, since they were not part of the chain starting with |
88 |
|
* false. Moreover there is no requirement that the steps are registered |
89 |
|
* chronologically in the LazyCDProofChain. The chain started on step S3 and |
90 |
|
* proceeded to steps S4, S5, S2, and finally S6. |
91 |
|
* |
92 |
|
* To track the reasoning of the SAT solver and produce the steps above this |
93 |
|
* class does three main things: |
94 |
|
* (1) Register the resolutions for learned clauses as they are learned. |
95 |
|
* (2) Register the resolutions for propagated literals when necessary. |
96 |
|
* (3) Register the *full* resolution proof for the empty clause. |
97 |
|
* |
98 |
|
* Case (1) covers the learned clauses during backjumping. The only information |
99 |
|
* saved is that, from clauses C1 to Cn, a given learned clause C is derived via |
100 |
|
* chain resolution (and possibly factoring, reordering and double negation |
101 |
|
* elimination in its literals), i.e., we do not recursively prove C1 to Cn at |
102 |
|
* this moment. |
103 |
|
* |
104 |
|
* Not explaining C1 to Cn eagerly is beneficial because: |
105 |
|
* - we might be wasting resources in fully explanaining it now, since C may not |
106 |
|
* be necessary for the derivation of the empty clause, and |
107 |
|
* - in explaining clauses lazily we might have shorter explanations, which has |
108 |
|
* been observed empirically to be often the case. |
109 |
|
* |
110 |
|
* The latter case is a result of the SAT solver possibly changing the |
111 |
|
* explanation of each of C, C1 to Cn, or the components of their |
112 |
|
* explanations. This is because the set of propagated literals that may be used |
113 |
|
* in these explanations can change in different SAT contexts, with the same |
114 |
|
* clause being derived several times, each from a different set of clauses. |
115 |
|
* |
116 |
|
* Therefore we only fully explain a clause when absolutely necessary, i.e., |
117 |
|
* when we are done (see case (3)) or when we'd not be able to do it afterwards |
118 |
|
* (see case (2)). In the example above, step S2 is generated from case (1), |
119 |
|
* with the shallow proof |
120 |
|
* |
121 |
|
* (or l1 ~l3 l5) ~l5 |
122 |
|
* ------------------------- CHAIN_RES |
123 |
|
* (or l1 ~l3) |
124 |
|
* |
125 |
|
* explaining the learned clause (or l1 ~l3). Its full proof would only be |
126 |
|
* produced if it were part of the final refutation, as it indeed is. Note that |
127 |
|
* in the example above the refutation proof contains the resolution proof of |
128 |
|
* ~l5. |
129 |
|
* |
130 |
|
* Case (2) covers: |
131 |
|
* (2.1) propagated literals explained by clauses being deleted |
132 |
|
* (2.2) propagated literals whose negation occurs in a learned clause, which |
133 |
|
* are then deleted for being redundant. |
134 |
|
* |
135 |
|
* Case (2.1) only happens for the so-called "locked clauses", which are clauses |
136 |
|
* C = l1 v ... v ln that propagate their first literal, l1. When a locked |
137 |
|
* clause C is deleted we save a chain resolution proof of l1 because we'd not |
138 |
|
* be able to retrieve C afterwards, since it is deleted. The proof is a chain |
139 |
|
* resolution step between C and ~l2, ..., ~ln, concluding l1. In the example |
140 |
|
* above, step S0 is generated from case (2.1), with the locked clause (or l4 |
141 |
|
* l1) being deleted and requiring the registration in the LazyCDPRoofChain of a |
142 |
|
* lazy step for |
143 |
|
* |
144 |
|
* (or l4 l1) ~l1 |
145 |
|
* ------------------------- CHAIN_RES |
146 |
|
* l4 |
147 |
|
* |
148 |
|
* Case (2.2) requires that, when a redundant literal (i.e., a literal whose |
149 |
|
* negation is propagated) is deleted from a learned clause, we add the |
150 |
|
* explanation of its negation to the chain resolution proof of the learned |
151 |
|
* clause. This justifies the deletion of the redundant literal. However, the |
152 |
|
* explanation for the propagated literal (the SAT solver maintains a map from |
153 |
|
* propagated literals to the clauses that propagate them in the current |
154 |
|
* context, i.e., their explanations, clauses in which all literals but the |
155 |
|
* propagated one have their negation propagated) may also contain literals that |
156 |
|
* were in the learned clause and were deleted for being redundant. Therefore |
157 |
|
* eliminating a redundant literal requires recursively explaining the |
158 |
|
* propagated literals in its explanation as long as they are, themselves, |
159 |
|
* redundant literals in the learned clause. |
160 |
|
* |
161 |
|
* In the above example step S1, concluding (or l3 l4), is generated from the |
162 |
|
* resolutions |
163 |
|
* |
164 |
|
* (or l3 l5 l6 l7) ~l5 |
165 |
|
* -------------------------- CHAIN_RES |
166 |
|
* (or l3 l6 l7) (or ~l6 l7) (or l4 ~l7) |
167 |
|
* ---------------------------------------------------------------- CHAIN_RES |
168 |
|
* (or l3 l4) |
169 |
|
* |
170 |
|
* as l6 and l7 are redundant, which leads to (or l3 l6 l7) being resolved with |
171 |
|
* l6's explanation, (or ~l6 l7). The literals in the explanation of l7 are |
172 |
|
* recursively explained if they are also redundant, which is the case for l7, |
173 |
|
* so its explanation is also added as premise for the resolution. Since l4 is |
174 |
|
* not redundant, it is not recursively explained. |
175 |
|
* |
176 |
|
* Note that the actual proof generated does not have the intermediary step |
177 |
|
* before removing redundant literals. It's all done in one fell swoop: |
178 |
|
* |
179 |
|
* (or l3 l5 l6 l7) ~l5 (or ~l6 l7) (or l4 ~l7) |
180 |
|
* --------------------------------------------------- CHAIN_RES |
181 |
|
* (or l3 l4) |
182 |
|
* |
183 |
|
* Finally, case (3) happens when the SAT solver derives the empty clause and |
184 |
|
* it's not possible to backjump. The empty clause is learned from a conflict |
185 |
|
* clause: a clause whose every literal has its negation propagated in the |
186 |
|
* current context. Thus the proof of the empty clause is generated, at first, |
187 |
|
* in the same way as case (1): a resolution chain betweeen the conflict clause |
188 |
|
* and its negated literals. However, since we are now done, we recursively |
189 |
|
* explain the propagated literals, starting from the negated literals from the |
190 |
|
* conflict clause and progressing to all propagated literals ocurring in a |
191 |
|
* given explanation. |
192 |
|
* |
193 |
|
* In the above example this happens as: step S3 |
194 |
|
* |
195 |
|
* (or l1 l2) ~l1 ~l2 |
196 |
|
* --------------------------- CHAIN_RES |
197 |
|
* false |
198 |
|
* |
199 |
|
* is added for a conflict clause (or l1 l2). Then we attempt to explain ~l1 and |
200 |
|
* ~l2. The former has no explanation (i.e., it's an input), while the latter |
201 |
|
* has explanation (or l3 ~l2). This leads to step S4 |
202 |
|
* |
203 |
|
* (or l3 ~l2) ~l3 |
204 |
|
* -------------------- CHAIN_RES |
205 |
|
* ~l2 |
206 |
|
* |
207 |
|
* being added to the LazyCDProofChain. In explaining ~l3 the step S5 |
208 |
|
* |
209 |
|
* (or l1 ~l3) ~l1 |
210 |
|
* --------------------- CHAIN_RES |
211 |
|
* ~l3 |
212 |
|
* |
213 |
|
* is added. Since ~l1 has no explanation, the process halts. Note that at this |
214 |
|
* point the step S6 has not been added to the LazyCDProofChain. This is because |
215 |
|
* to explain ~l5 we need to look at the literal premises in the proofs of |
216 |
|
* learned clauses. |
217 |
|
* |
218 |
|
* The last thing done then in case (3), after the resolution on the conflict |
219 |
|
* clause and an initial recursive explanation of propagated literals, is to |
220 |
|
* connect the refutation proof and then recursively its propagated literal |
221 |
|
* leaves, repeating until a fix point. |
222 |
|
* |
223 |
|
* In the above example the first connection yields |
224 |
|
* |
225 |
|
* (or l1 ~l3 l5) ~l5 |
226 |
|
* ---------------------- CHAIN_RES |
227 |
|
* (or l1 ~l3) ~l1 |
228 |
|
* ----------------------------- CHAIN_RES |
229 |
|
* (or l3 ~l2) ~l3 |
230 |
|
* -------------------- CHAIN_RES |
231 |
|
* (or l1 l2) ~l1 ~l2 |
232 |
|
* --------------------------- CHAIN_RES |
233 |
|
* false |
234 |
|
* |
235 |
|
* whose literal leaves are ~l1 and ~l5. The former has no explanation, but the |
236 |
|
* latter is explained by (or l1 ~l5), thus leading to step S6 |
237 |
|
* |
238 |
|
* (or l1 ~l5) ~l1 |
239 |
|
* --------------------- CHAIN_RES |
240 |
|
* ~l5 |
241 |
|
* |
242 |
|
* then the final connection |
243 |
|
* |
244 |
|
* (or l1 ~l5) ~l1 |
245 |
|
* ---------------- CHAIN_RES |
246 |
|
* (or l1 ~l3 l5) ~l5 |
247 |
|
* ---------------------- CHAIN_RES |
248 |
|
* (or l1 ~l3) ~l1 |
249 |
|
* ----------------------------- CHAIN_RES |
250 |
|
* (or l3 ~l2) ~l3 |
251 |
|
* -------------------- CHAIN_RES |
252 |
|
* (or l1 l2) ~l1 ~l2 |
253 |
|
* --------------------------- CHAIN_RES |
254 |
|
* false |
255 |
|
* |
256 |
|
* which has no more explainable literals as leaves. |
257 |
|
* |
258 |
|
* The interfaces below provide ways for the SAT solver to register its |
259 |
|
* assumptions (clausified assertions and lemmas) for the SAT proof |
260 |
|
* (registerSatAssumption), register resolution steps (startResChain / |
261 |
|
* addResolutionStep / endResChain), build the final refutation proof |
262 |
|
* (finalizeProof) and retrieve the refutation proof (getProof). So in a given |
263 |
|
* run of the SAT solver these interfaces are expected to be used in the |
264 |
|
* following order: |
265 |
|
* |
266 |
|
* (registerSatAssumptions | (startResChain (addResolutionStep)+ endResChain)*)* |
267 |
|
* finalizeProof |
268 |
|
* getProof |
269 |
|
* |
270 |
|
*/ |
271 |
64 |
class SatProofManager |
272 |
|
{ |
273 |
|
public: |
274 |
|
SatProofManager(Minisat::Solver* solver, |
275 |
|
CnfStream* cnfStream, |
276 |
|
context::UserContext* userContext, |
277 |
|
ProofNodeManager* pnm); |
278 |
|
|
279 |
|
/** Marks the start of a resolution chain. |
280 |
|
* |
281 |
|
* This call is followed by *at least one* call to addResolution step and one |
282 |
|
* call to endResChain. |
283 |
|
* |
284 |
|
* The given clause, at the node level, is registered in d_resLinks with a |
285 |
|
* null pivot, since this is the first link in the chain. |
286 |
|
* |
287 |
|
* @param start a SAT solver clause (list of literals) that will be the first |
288 |
|
* clause in a resolution chain. |
289 |
|
*/ |
290 |
|
void startResChain(const Minisat::Clause& start); |
291 |
|
/** Adds a resolution step with a clause |
292 |
|
* |
293 |
|
* There must have been a call to startResChain before any call to |
294 |
|
* addResolution step. After following calls to addResolution step there is |
295 |
|
* one call to endResChain. |
296 |
|
* |
297 |
|
* The resolution step is added to d_resLinks with the clause, at the node |
298 |
|
* level, and the literal, at the node level, as the pivot. |
299 |
|
* |
300 |
|
* @param clause the clause being resolved against |
301 |
|
* @param lit the literal occurring in clause to be the pivot of the |
302 |
|
* resolution step |
303 |
|
*/ |
304 |
|
void addResolutionStep(const Minisat::Clause& clause, Minisat::Lit lit); |
305 |
|
/** Adds a resolution step with a unit clause |
306 |
|
* |
307 |
|
* The resolution step is added to d_resLinks such that lit, at the node |
308 |
|
* level, is the pivot and and the unit clause is ~lit, at the node level. |
309 |
|
* |
310 |
|
* If the literal is marked as redundant, then a step is *not* is added to |
311 |
|
* d_resLinks. It is rather saved to d_redundandLits, whose components we will |
312 |
|
* be handled in a special manner when the resolution chain is finished. This |
313 |
|
* is because the steps corresponding to the removal of redundant literals |
314 |
|
* have to be done in a specific order. See proccessRedundantLits below. |
315 |
|
* |
316 |
|
* @param lit the literal being resolved against |
317 |
|
* @param redundant whether lit is redundant |
318 |
|
*/ |
319 |
|
void addResolutionStep(Minisat::Lit lit, bool redundant = false); |
320 |
|
/** Ends resolution chain concluding a unit clause |
321 |
|
* |
322 |
|
* This call must have been preceded by one call to startResChain and at least |
323 |
|
* one call to addResolutionStep. |
324 |
|
* |
325 |
|
* This and the version below both call the node version of this method, |
326 |
|
* described further below, which actually does the necessary processing. |
327 |
|
*/ |
328 |
|
void endResChain(Minisat::Lit lit); |
329 |
|
/** Ends resolution chain concluding a clause */ |
330 |
|
void endResChain(const Minisat::Clause& clause); |
331 |
|
/** Build refutation proof starting from conflict clause |
332 |
|
* |
333 |
|
* This method (or its variations) is only called when the SAT solver has |
334 |
|
* reached an unsatisfiable state. |
335 |
|
* |
336 |
|
* This and the versions below call the node version of this method, described |
337 |
|
* further below, which actually does the necessary processing. |
338 |
|
* |
339 |
|
* @param adding whether the conflict is coming from a freshly added clause |
340 |
|
*/ |
341 |
|
void finalizeProof(const Minisat::Clause& inConflict, bool adding = false); |
342 |
|
/** Build refutation proof starting from conflict unit clause |
343 |
|
* |
344 |
|
* @param adding whether the conflict is coming from a freshly added clause |
345 |
|
*/ |
346 |
|
void finalizeProof(Minisat::Lit inConflict, bool adding = false); |
347 |
|
/** As above, but uses the unit conflict clause saved in d_conflictLit. */ |
348 |
|
void finalizeProof(); |
349 |
|
/** Set the unit conflict clause d_conflictLit. */ |
350 |
|
void storeUnitConflict(Minisat::Lit inConflict); |
351 |
|
|
352 |
|
/** Retrive the refutation proof |
353 |
|
* |
354 |
|
* If there is no chain for false in d_resChains, meaning that this call was |
355 |
|
* made before finalizeProof, an assumption proof node is produced. |
356 |
|
*/ |
357 |
|
std::shared_ptr<ProofNode> getProof(); |
358 |
|
|
359 |
|
/** Register a unit clause input, converted to its node representation. */ |
360 |
|
void registerSatLitAssumption(Minisat::Lit lit); |
361 |
|
/** Register a set clause inputs. */ |
362 |
|
void registerSatAssumptions(const std::vector<Node>& assumps); |
363 |
|
|
364 |
|
private: |
365 |
|
/** Ends resolution chain concluding clause |
366 |
|
* |
367 |
|
* This method builds the proof of conclusion from the resolution chain |
368 |
|
* currently saved in d_resLinks. |
369 |
|
* |
370 |
|
* First each saved redundant literals in d_redundantLits is processed via |
371 |
|
* processRedundantLit. The literals in the resolution chain's conclusion are |
372 |
|
* used to verifynig which literals in the computed explanations are |
373 |
|
* redundant, i.e., don't occur in conclusionLits. The nessary resolution |
374 |
|
* steps will be added to d_resLinks. |
375 |
|
* |
376 |
|
* The proof to be built will be a CHAIN_RESOLUTION step, whose children and |
377 |
|
* arguments will be retrieved from traversing d_resLinks. Consider the |
378 |
|
* following d_resLinks (where each [~]li is its node equivalent): |
379 |
|
* |
380 |
|
* - <(or l3 l5 l6 l7), null> |
381 |
|
* - <~l5, l5> |
382 |
|
* - <(or ~l6 l7), l6> |
383 |
|
* - <(or l4 ~l7), l7> |
384 |
|
* |
385 |
|
* The resulting children and arguments for the CHAIN_RESOLUTION proof step would be: |
386 |
|
* - [(or l3 l5 l6 l7), ~l5, (or ~l6 l7), (or l4 ~l7)] |
387 |
|
* - [l5, l6, l7] |
388 |
|
* and the proof step |
389 |
|
* |
390 |
|
* (or l3 l5 l6 l7) ~l5 (or ~l6 l7) (or l4 ~l7) |
391 |
|
* --------------------------------------------------- CHAIN_RES_{l5,l6,l7} |
392 |
|
* (or l3 l4) |
393 |
|
* |
394 |
|
* The conclusion of the CHAIN_RES proof step is *not* the given conclusion of |
395 |
|
* this method. This is because conclusion is the node equivalent of the |
396 |
|
* clause in the SAT solver, which is kept modulo duplicates, reordering, and |
397 |
|
* double negation elimination. Therefore we generate the above step in the |
398 |
|
* correct way for the semantics of CHAIN_RES, based on its children and |
399 |
|
* arguments, via the d_pnm's proof checker. The resulting node n is fed into |
400 |
|
* the clause normalization in TheoryProofStepBuffer, which reduces n to |
401 |
|
* conclusion. |
402 |
|
* |
403 |
|
* All the proof steps generated to conclude conclusion from the premises in |
404 |
|
* d_resLinks are saved into d_resChainPg, which is saved as the proof |
405 |
|
* generator for lazy step added to d_resChains for the conclusion. |
406 |
|
* |
407 |
|
* @param conclusion the node-level conclusion of the resolution chain |
408 |
|
* @param conclusionLits the set of literals in the conclusion |
409 |
|
*/ |
410 |
|
void endResChain(Node conclusion, const std::set<SatLiteral>& conclusionLits); |
411 |
|
|
412 |
|
/** Explain redundant literal and generate corresponding resolution steps |
413 |
|
* |
414 |
|
* If the redundant literal has a reason, we add a resolution step with that |
415 |
|
* clause, otherwise with the negation of the redundant literal as the unit |
416 |
|
* clause. The redundant literal is the resolvent in both cases. The steps |
417 |
|
* are always added as the *first* link after last resolution step added |
418 |
|
* *before* processing redundant literals began, i.e., at d_resLinks.begin() + |
419 |
|
* pos. This is to guarantee that the links are in the correct order for the |
420 |
|
* chain resolution, see below. |
421 |
|
* |
422 |
|
* If the reason contains literals that do not occur in conclusionLits, they |
423 |
|
* are redundant and recursively processed by this method. This recursive |
424 |
|
* processing happens *before* the resolution step for lit is added. Since |
425 |
|
* steps are always added in position pos, pushing steps after that 1 |
426 |
|
* position, this guarantees that a step with a clause will occur before the |
427 |
|
* steps that eliminate its redundant literals. |
428 |
|
* |
429 |
|
* Consider d_resLinks with 3 links before the first processRedundantLit call, |
430 |
|
* i.e., pos = 3, and d_redundantLits = {l1}, with reason(l1) = (or l1 ~l2), |
431 |
|
* with ~l2 redundant. Assume ~l2 has no explanation. By processing ~l2 first, |
432 |
|
* the link <~l2, l2> will be added at position 3. Then by coming back to the |
433 |
|
* processing of l1 the link <(or l1 ~l2), l1> will also be added position 3, |
434 |
|
* with <~l2, l2> pushed to position 4. If this these links had the reverse |
435 |
|
* order the literal ~l2 would, erroneously, occur in the chain resolution |
436 |
|
* conclusion, as it is introduced by (or l1 ~l2). |
437 |
|
* |
438 |
|
* After a resolution step for a redundant literal is added, it is marked as |
439 |
|
* visited, thus avoiding adding redundunt resolution steps to the chain if |
440 |
|
* that literal occurs again in another redundant literal's reason. |
441 |
|
* |
442 |
|
* @param lit the redundant literal |
443 |
|
* @param conclusionLits the literals in the clause from which redundant |
444 |
|
* literals have been removed |
445 |
|
* @param visited cache of literals already processed |
446 |
|
* @param pos position, in d_resLinks, of last resolution step added *before* |
447 |
|
* processing redundant literals |
448 |
|
*/ |
449 |
|
void processRedundantLit(SatLiteral lit, |
450 |
|
const std::set<SatLiteral>& conclusionLits, |
451 |
|
std::set<SatLiteral>& visited, |
452 |
|
unsigned pos); |
453 |
|
/** Explain literal if it is propagated in the SAT solver |
454 |
|
* |
455 |
|
* If a literal is propagated, i.e., it has a reason in the SAT solver, that |
456 |
|
* clause is retrieved. This method is then called recursively on the negation |
457 |
|
* of each of reason's literals (that is not lit). Afterwards a |
458 |
|
* CHAIN_RESOLUTION proof step is created to conclude lit from the reason and |
459 |
|
* its literals, other than lit, negations. |
460 |
|
* |
461 |
|
* This method also tracks all the literals and clauses, at the node level, |
462 |
|
* that have been used as premises of resolutions steps in the recursive |
463 |
|
* explanations. A resolution step is only created if the conclusion does not |
464 |
|
* occur in these premises, as this would configure a cyclic proof. |
465 |
|
* |
466 |
|
* These cyclic proofs, at the node level, are naturally generated by the SAT |
467 |
|
* solver because they are so that a literal is derived from a clause (so they |
468 |
|
* are different) but both correspond to the *same node*. For example, |
469 |
|
* consider the following derivation at the SAT solver level |
470 |
|
* |
471 |
|
* [l1, l2, l3] ~l2 ~l3 |
472 |
|
* -------------------------- CHAIN_RES |
473 |
|
* [l0, ~l1] l1 |
474 |
|
* ---------------------- CHAIN_RES |
475 |
|
* l0 |
476 |
|
* |
477 |
|
* which has no issues. However, its node equivalent is |
478 |
|
* |
479 |
|
* (or a b c) (not b) (not c) |
480 |
|
* ------------------------------- CHAIN_RES |
481 |
|
* (or (or a b c) (not a)) a |
482 |
|
* --------------------------------- CHAIN_RES |
483 |
|
* (or a b c) |
484 |
|
* |
485 |
|
* which is cyclic. The issue is that l0 = (or a b c). Only at the SAT level |
486 |
|
* are l0 and [l1, l2, l3] different. |
487 |
|
* |
488 |
|
* If a cyclic proof is identified, the respective node is kept as an |
489 |
|
* assumption. |
490 |
|
* |
491 |
|
* @param lit the literal to explained |
492 |
|
* @param premises set of literals and clauses, at the node level, that |
493 |
|
* have been used as premises of resolution steps while explaining |
494 |
|
* propagations |
495 |
|
*/ |
496 |
|
void explainLit(prop::SatLiteral lit, std::unordered_set<TNode>& premises); |
497 |
|
|
498 |
|
/** Build refutation proof starting from conflict clause |
499 |
|
* |
500 |
|
* Given a conflict clause, this method handles case (3) described in the |
501 |
|
* preamble. Each of the literals in the conflict clause is either |
502 |
|
* explainable, the result of a previously saved resolution chain, or an |
503 |
|
* input. |
504 |
|
* |
505 |
|
* First, explainLit is called recursively on the negated literals from |
506 |
|
* the conflict clause. |
507 |
|
* |
508 |
|
* Second, a CHAIN_RESOLUTION proof step is added between |
509 |
|
* the conflict clause and its negated literals, concluding false. |
510 |
|
* |
511 |
|
* Third, until a fix point, the refutation proof is connected, by calling |
512 |
|
* d_resChain.getProofFor(d_false), its free assumptions are determined and, |
513 |
|
* in case any as a literal that might be explained, we call explainLit. |
514 |
|
* |
515 |
|
* The latter is called to a fix point because adding an explanation to a |
516 |
|
* propagated literal may connect it with a previously saved resolution chain, |
517 |
|
* which may have free assumptions that are literals that can be explained and |
518 |
|
* so on. |
519 |
|
* |
520 |
|
* @param inConflictNode node corresponding to conflict clause |
521 |
|
* @param inConflict literals in the conflict clause |
522 |
|
*/ |
523 |
|
void finalizeProof(Node inConflictNode, |
524 |
|
const std::vector<SatLiteral>& inConflict); |
525 |
|
|
526 |
|
/** The SAT solver to which we are managing proofs */ |
527 |
|
Minisat::Solver* d_solver; |
528 |
|
/** Pointer to the underlying cnf stream. */ |
529 |
|
CnfStream* d_cnfStream; |
530 |
|
/** The proof node manager */ |
531 |
|
ProofNodeManager* d_pnm; |
532 |
|
/** Resolution steps (links) accumulator for chain resolution. |
533 |
|
* |
534 |
|
* Each tuple has a clause and the pivot for the resolution step it is |
535 |
|
* involved on, as well as whether the pivot occurs positively/negatively or |
536 |
|
* negatively/positively in the clauses being resolved. If the third argument |
537 |
|
* is true (resp. false), the pivot occurs positively (negatively) in the |
538 |
|
* clause yielded by the resolution up to the previous link and negatively |
539 |
|
* (positively) in this link. The first link has a null pivot. Links are kept |
540 |
|
* at the node level. |
541 |
|
* |
542 |
|
* This accumulator is reset after each chain resolution. */ |
543 |
|
std::vector<std::tuple<Node, Node, bool>> d_resLinks; |
544 |
|
|
545 |
|
/** Redundant literals removed from the resolution chain's conclusion. |
546 |
|
* |
547 |
|
* This accumulator is reset after each chain resolution. */ |
548 |
|
std::vector<SatLiteral> d_redundantLits; |
549 |
|
|
550 |
|
/** |
551 |
|
* Associates clauses to their local proofs. These proofs are local and |
552 |
|
* possibly updated during solving. When the final conclusion is reached, a |
553 |
|
* final proof is built based on the proofs saved here. |
554 |
|
* |
555 |
|
* This chain is initialized so that its getProofFor method, which connects |
556 |
|
* the chain, accounts for cyclic proofs. This is so that we avoid the issue |
557 |
|
* described in explainLit. |
558 |
|
*/ |
559 |
|
LazyCDProofChain d_resChains; |
560 |
|
|
561 |
|
/** The proof generator for resolution chains */ |
562 |
|
BufferedProofGenerator d_resChainPg; |
563 |
|
|
564 |
|
/** The true/false nodes */ |
565 |
|
Node d_true; |
566 |
|
Node d_false; |
567 |
|
|
568 |
|
/** All clauses added to the SAT solver, kept in a context-dependent manner. |
569 |
|
*/ |
570 |
|
context::CDHashSet<Node> d_assumptions; |
571 |
|
|
572 |
|
/** |
573 |
|
* A placeholder that may be used to store the literal with the final |
574 |
|
* conflict. |
575 |
|
*/ |
576 |
|
SatLiteral d_conflictLit; |
577 |
|
/** Gets node equivalent to literal */ |
578 |
|
Node getClauseNode(SatLiteral satLit); |
579 |
|
/** Gets node equivalent to clause. |
580 |
|
* |
581 |
|
* To avoid generating different nodes for the same clause, modulo ordering, |
582 |
|
* an invariant assumed throughout this class, the OR node generated by this |
583 |
|
* method always has its children ordered. |
584 |
|
*/ |
585 |
|
Node getClauseNode(const Minisat::Clause& clause); |
586 |
|
/** Prints clause, as a sequence of literals, in the "sat-proof" trace. */ |
587 |
|
void printClause(const Minisat::Clause& clause); |
588 |
|
}; /* class SatProofManager */ |
589 |
|
|
590 |
|
} // namespace prop |
591 |
|
} // namespace cvc5 |
592 |
|
|
593 |
|
#endif /* CVC5__SAT_PROOF_MANAGER_H */ |