1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Haniel Barbosa, Andrew Reynolds, 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 |
|
* Implementation of the proof-producing CNF stream. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "prop/proof_cnf_stream.h" |
17 |
|
|
18 |
|
#include "options/smt_options.h" |
19 |
|
#include "prop/minisat/minisat.h" |
20 |
|
#include "theory/builtin/proof_checker.h" |
21 |
|
#include "util/rational.h" |
22 |
|
|
23 |
|
namespace cvc5 { |
24 |
|
namespace prop { |
25 |
|
|
26 |
1254 |
ProofCnfStream::ProofCnfStream(context::UserContext* u, |
27 |
|
CnfStream& cnfStream, |
28 |
|
SatProofManager* satPM, |
29 |
1254 |
ProofNodeManager* pnm) |
30 |
|
: d_cnfStream(cnfStream), |
31 |
|
d_satPM(satPM), |
32 |
|
d_proof(pnm, nullptr, u, "ProofCnfStream::LazyCDProof"), |
33 |
1254 |
d_blocked(u) |
34 |
|
{ |
35 |
1254 |
} |
36 |
|
|
37 |
555126 |
void ProofCnfStream::addBlocked(std::shared_ptr<ProofNode> pfn) |
38 |
|
{ |
39 |
555126 |
d_blocked.insert(pfn); |
40 |
555126 |
} |
41 |
|
|
42 |
890182 |
bool ProofCnfStream::isBlocked(std::shared_ptr<ProofNode> pfn) |
43 |
|
{ |
44 |
890182 |
return d_blocked.contains(pfn); |
45 |
|
} |
46 |
|
|
47 |
119928 |
std::shared_ptr<ProofNode> ProofCnfStream::getProofFor(Node f) |
48 |
|
{ |
49 |
119928 |
return d_proof.getProofFor(f); |
50 |
|
} |
51 |
|
|
52 |
697282 |
bool ProofCnfStream::hasProofFor(Node f) |
53 |
|
{ |
54 |
697282 |
return d_proof.hasStep(f) || d_proof.hasGenerator(f); |
55 |
|
} |
56 |
|
|
57 |
|
std::string ProofCnfStream::identify() const { return "ProofCnfStream"; } |
58 |
|
|
59 |
705023 |
void ProofCnfStream::normalizeAndRegister(TNode clauseNode) |
60 |
|
{ |
61 |
1410046 |
Node normClauseNode = d_psb.factorReorderElimDoubleNeg(clauseNode); |
62 |
705023 |
if (Trace.isOn("cnf") && normClauseNode != clauseNode) |
63 |
|
{ |
64 |
|
Trace("cnf") << push |
65 |
|
<< "ProofCnfStream::normalizeAndRegister: steps to normalized " |
66 |
|
<< normClauseNode << "\n" |
67 |
|
<< pop; |
68 |
|
} |
69 |
705023 |
d_satPM->registerSatAssumptions({normClauseNode}); |
70 |
705023 |
} |
71 |
|
|
72 |
84292 |
void ProofCnfStream::convertAndAssert(TNode node, |
73 |
|
bool negated, |
74 |
|
bool removable, |
75 |
|
ProofGenerator* pg) |
76 |
|
{ |
77 |
168584 |
Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node |
78 |
168584 |
<< ", negated = " << (negated ? "true" : "false") |
79 |
84292 |
<< ", removable = " << (removable ? "true" : "false") << ")\n"; |
80 |
84292 |
d_cnfStream.d_removable = removable; |
81 |
84292 |
if (pg) |
82 |
|
{ |
83 |
128676 |
Trace("cnf") << "ProofCnfStream::convertAndAssert: pg: " << pg->identify() |
84 |
64338 |
<< "\n"; |
85 |
128676 |
Node toJustify = negated ? node.notNode() : static_cast<Node>(node); |
86 |
64338 |
d_proof.addLazyStep(toJustify, |
87 |
|
pg, |
88 |
|
PfRule::ASSUME, |
89 |
|
true, |
90 |
|
"ProofCnfStream::convertAndAssert:cnf"); |
91 |
|
} |
92 |
84292 |
convertAndAssert(node, negated); |
93 |
|
// process saved steps in buffer |
94 |
84292 |
const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps(); |
95 |
2765338 |
for (const std::pair<Node, ProofStep>& step : steps) |
96 |
|
{ |
97 |
2681046 |
d_proof.addStep(step.first, step.second); |
98 |
|
} |
99 |
84292 |
d_psb.clear(); |
100 |
84292 |
} |
101 |
|
|
102 |
147730 |
void ProofCnfStream::convertAndAssert(TNode node, bool negated) |
103 |
|
{ |
104 |
295460 |
Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node |
105 |
147730 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
106 |
147730 |
switch (node.getKind()) |
107 |
|
{ |
108 |
18586 |
case kind::AND: convertAndAssertAnd(node, negated); break; |
109 |
32695 |
case kind::OR: convertAndAssertOr(node, negated); break; |
110 |
12 |
case kind::XOR: convertAndAssertXor(node, negated); break; |
111 |
15168 |
case kind::IMPLIES: convertAndAssertImplies(node, negated); break; |
112 |
4800 |
case kind::ITE: convertAndAssertIte(node, negated); break; |
113 |
22390 |
case kind::NOT: |
114 |
|
{ |
115 |
|
// track double negation elimination |
116 |
22390 |
if (negated) |
117 |
|
{ |
118 |
629 |
d_proof.addStep(node[0], PfRule::NOT_NOT_ELIM, {node.notNode()}, {}); |
119 |
1258 |
Trace("cnf") |
120 |
629 |
<< "ProofCnfStream::convertAndAssert: NOT_NOT_ELIM added norm " |
121 |
629 |
<< node[0] << "\n"; |
122 |
|
} |
123 |
22390 |
convertAndAssert(node[0], !negated); |
124 |
22390 |
break; |
125 |
|
} |
126 |
35740 |
case kind::EQUAL: |
127 |
35740 |
if (node[0].getType().isBoolean()) |
128 |
|
{ |
129 |
6119 |
convertAndAssertIff(node, negated); |
130 |
6119 |
break; |
131 |
|
} |
132 |
|
CVC5_FALLTHROUGH; |
133 |
|
default: |
134 |
|
{ |
135 |
|
// negate |
136 |
95920 |
Node nnode = negated ? node.negate() : static_cast<Node>(node); |
137 |
|
// Atoms |
138 |
47960 |
SatLiteral lit = toCNF(node, negated); |
139 |
47960 |
bool added = d_cnfStream.assertClause(nnode, lit); |
140 |
47960 |
if (negated && added && nnode != node.notNode()) |
141 |
|
{ |
142 |
|
// track double negation elimination |
143 |
|
// (not (not n)) |
144 |
|
// -------------- NOT_NOT_ELIM |
145 |
|
// n |
146 |
|
d_proof.addStep(nnode, PfRule::NOT_NOT_ELIM, {node.notNode()}, {}); |
147 |
|
Trace("cnf") |
148 |
|
<< "ProofCnfStream::convertAndAssert: NOT_NOT_ELIM added norm " |
149 |
|
<< nnode << "\n"; |
150 |
|
} |
151 |
47960 |
if (added) |
152 |
|
{ |
153 |
|
// note that we do not need to do the normalization here since this is |
154 |
|
// not a clause and double negation is tracked in a dedicated manner |
155 |
|
// above |
156 |
28805 |
d_satPM->registerSatAssumptions({nnode}); |
157 |
47960 |
} |
158 |
|
} |
159 |
|
} |
160 |
147730 |
} |
161 |
|
|
162 |
18586 |
void ProofCnfStream::convertAndAssertAnd(TNode node, bool negated) |
163 |
|
{ |
164 |
37172 |
Trace("cnf") << "ProofCnfStream::convertAndAssertAnd(" << node |
165 |
18586 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
166 |
18586 |
Assert(node.getKind() == kind::AND); |
167 |
18586 |
if (!negated) |
168 |
|
{ |
169 |
|
// If the node is a conjunction, we handle each conjunct separately |
170 |
2777 |
NodeManager* nm = NodeManager::currentNM(); |
171 |
42823 |
for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i) |
172 |
|
{ |
173 |
|
// Create a proof step for each n_i |
174 |
80092 |
Node iNode = nm->mkConst<Rational>(i); |
175 |
40046 |
d_proof.addStep(node[i], PfRule::AND_ELIM, {node}, {iNode}); |
176 |
80092 |
Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: AND_ELIM " << i |
177 |
40046 |
<< " added norm " << node[i] << "\n"; |
178 |
40046 |
convertAndAssert(node[i], false); |
179 |
|
} |
180 |
|
} |
181 |
|
else |
182 |
|
{ |
183 |
|
// If the node is a disjunction, we construct a clause and assert it |
184 |
15809 |
unsigned i, size = node.getNumChildren(); |
185 |
31618 |
SatClause clause(size); |
186 |
158690 |
for (i = 0; i < size; ++i) |
187 |
|
{ |
188 |
142881 |
clause[i] = toCNF(node[i], true); |
189 |
|
} |
190 |
15809 |
bool added = d_cnfStream.assertClause(node.negate(), clause); |
191 |
|
// register proof step |
192 |
15809 |
if (added) |
193 |
|
{ |
194 |
31540 |
std::vector<Node> disjuncts; |
195 |
158513 |
for (i = 0; i < size; ++i) |
196 |
|
{ |
197 |
142743 |
disjuncts.push_back(node[i].notNode()); |
198 |
|
} |
199 |
31540 |
Node clauseNode = NodeManager::currentNM()->mkNode(kind::OR, disjuncts); |
200 |
15770 |
d_proof.addStep(clauseNode, PfRule::NOT_AND, {node.notNode()}, {}); |
201 |
31540 |
Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: NOT_AND added " |
202 |
15770 |
<< clauseNode << "\n"; |
203 |
15770 |
normalizeAndRegister(clauseNode); |
204 |
|
} |
205 |
|
} |
206 |
18586 |
} |
207 |
|
|
208 |
32695 |
void ProofCnfStream::convertAndAssertOr(TNode node, bool negated) |
209 |
|
{ |
210 |
65390 |
Trace("cnf") << "ProofCnfStream::convertAndAssertOr(" << node |
211 |
32695 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
212 |
32695 |
Assert(node.getKind() == kind::OR); |
213 |
32695 |
if (!negated) |
214 |
|
{ |
215 |
|
// If the node is a disjunction, we construct a clause and assert it |
216 |
32599 |
unsigned size = node.getNumChildren(); |
217 |
65198 |
SatClause clause(size); |
218 |
140982 |
for (unsigned i = 0; i < size; ++i) |
219 |
|
{ |
220 |
108383 |
clause[i] = toCNF(node[i], false); |
221 |
|
} |
222 |
32599 |
normalizeAndRegister(node); |
223 |
32599 |
d_cnfStream.assertClause(node, clause); |
224 |
|
} |
225 |
|
else |
226 |
|
{ |
227 |
|
// If the node is a negated disjunction, we handle it as a conjunction of |
228 |
|
// the negated arguments |
229 |
96 |
NodeManager* nm = NodeManager::currentNM(); |
230 |
900 |
for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i) |
231 |
|
{ |
232 |
|
// Create a proof step for each (not n_i) |
233 |
1608 |
Node iNode = nm->mkConst<Rational>(i); |
234 |
4020 |
d_proof.addStep( |
235 |
3216 |
node[i].notNode(), PfRule::NOT_OR_ELIM, {node.notNode()}, {iNode}); |
236 |
1608 |
Trace("cnf") << "ProofCnfStream::convertAndAssertOr: NOT_OR_ELIM " << i |
237 |
804 |
<< " added norm " << node[i].notNode() << "\n"; |
238 |
804 |
convertAndAssert(node[i], true); |
239 |
|
} |
240 |
|
} |
241 |
32695 |
} |
242 |
|
|
243 |
12 |
void ProofCnfStream::convertAndAssertXor(TNode node, bool negated) |
244 |
|
{ |
245 |
24 |
Trace("cnf") << "ProofCnfStream::convertAndAssertXor(" << node |
246 |
12 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
247 |
12 |
if (!negated) |
248 |
|
{ |
249 |
|
// p XOR q |
250 |
12 |
SatLiteral p = toCNF(node[0], false); |
251 |
12 |
SatLiteral q = toCNF(node[1], false); |
252 |
|
bool added; |
253 |
12 |
NodeManager* nm = NodeManager::currentNM(); |
254 |
|
// Construct the clause (~p v ~q) |
255 |
24 |
SatClause clause1(2); |
256 |
12 |
clause1[0] = ~p; |
257 |
12 |
clause1[1] = ~q; |
258 |
12 |
added = d_cnfStream.assertClause(node, clause1); |
259 |
12 |
if (added) |
260 |
|
{ |
261 |
|
Node clauseNode = |
262 |
22 |
nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode()); |
263 |
11 |
d_proof.addStep(clauseNode, PfRule::XOR_ELIM2, {node}, {}); |
264 |
22 |
Trace("cnf") << "ProofCnfStream::convertAndAssertXor: XOR_ELIM2 added " |
265 |
11 |
<< clauseNode << "\n"; |
266 |
11 |
normalizeAndRegister(clauseNode); |
267 |
|
} |
268 |
|
// Construct the clause (p v q) |
269 |
24 |
SatClause clause2(2); |
270 |
12 |
clause2[0] = p; |
271 |
12 |
clause2[1] = q; |
272 |
12 |
added = d_cnfStream.assertClause(node, clause2); |
273 |
12 |
if (added) |
274 |
|
{ |
275 |
22 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[1]); |
276 |
11 |
d_proof.addStep(clauseNode, PfRule::XOR_ELIM1, {node}, {}); |
277 |
22 |
Trace("cnf") << "ProofCnfStream::convertAndAssertXor: XOR_ELIM1 added " |
278 |
11 |
<< clauseNode << "\n"; |
279 |
11 |
normalizeAndRegister(clauseNode); |
280 |
|
} |
281 |
|
} |
282 |
|
else |
283 |
|
{ |
284 |
|
// ~(p XOR q) is the same as p <=> q |
285 |
|
SatLiteral p = toCNF(node[0], false); |
286 |
|
SatLiteral q = toCNF(node[1], false); |
287 |
|
bool added; |
288 |
|
NodeManager* nm = NodeManager::currentNM(); |
289 |
|
// Construct the clause ~p v q |
290 |
|
SatClause clause1(2); |
291 |
|
clause1[0] = ~p; |
292 |
|
clause1[1] = q; |
293 |
|
added = d_cnfStream.assertClause(node.negate(), clause1); |
294 |
|
if (added) |
295 |
|
{ |
296 |
|
Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]); |
297 |
|
d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM2, {node.notNode()}, {}); |
298 |
|
Trace("cnf") |
299 |
|
<< "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM2 added " |
300 |
|
<< clauseNode << "\n"; |
301 |
|
normalizeAndRegister(clauseNode); |
302 |
|
} |
303 |
|
// Construct the clause ~q v p |
304 |
|
SatClause clause2(2); |
305 |
|
clause2[0] = p; |
306 |
|
clause2[1] = ~q; |
307 |
|
added = d_cnfStream.assertClause(node.negate(), clause2); |
308 |
|
if (added) |
309 |
|
{ |
310 |
|
Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode()); |
311 |
|
d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM1, {node.notNode()}, {}); |
312 |
|
Trace("cnf") |
313 |
|
<< "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM1 added " |
314 |
|
<< clauseNode << "\n"; |
315 |
|
normalizeAndRegister(clauseNode); |
316 |
|
} |
317 |
|
} |
318 |
12 |
} |
319 |
|
|
320 |
6119 |
void ProofCnfStream::convertAndAssertIff(TNode node, bool negated) |
321 |
|
{ |
322 |
12238 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIff(" << node |
323 |
6119 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
324 |
6119 |
if (!negated) |
325 |
|
{ |
326 |
|
// p <=> q |
327 |
6083 |
Trace("cnf") << push; |
328 |
6083 |
SatLiteral p = toCNF(node[0], false); |
329 |
6083 |
SatLiteral q = toCNF(node[1], false); |
330 |
6083 |
Trace("cnf") << pop; |
331 |
|
bool added; |
332 |
6083 |
NodeManager* nm = NodeManager::currentNM(); |
333 |
|
// Construct the clauses ~p v q |
334 |
12166 |
SatClause clause1(2); |
335 |
6083 |
clause1[0] = ~p; |
336 |
6083 |
clause1[1] = q; |
337 |
6083 |
added = d_cnfStream.assertClause(node, clause1); |
338 |
6083 |
if (added) |
339 |
|
{ |
340 |
10882 |
Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]); |
341 |
5441 |
d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM1, {node}, {}); |
342 |
10882 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM1 added " |
343 |
5441 |
<< clauseNode << "\n"; |
344 |
5441 |
normalizeAndRegister(clauseNode); |
345 |
|
} |
346 |
|
// Construct the clauses ~q v p |
347 |
12166 |
SatClause clause2(2); |
348 |
6083 |
clause2[0] = p; |
349 |
6083 |
clause2[1] = ~q; |
350 |
6083 |
added = d_cnfStream.assertClause(node, clause2); |
351 |
6083 |
if (added) |
352 |
|
{ |
353 |
10720 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode()); |
354 |
5360 |
d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM2, {node}, {}); |
355 |
10720 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM2 added " |
356 |
5360 |
<< clauseNode << "\n"; |
357 |
5360 |
normalizeAndRegister(clauseNode); |
358 |
|
} |
359 |
|
} |
360 |
|
else |
361 |
|
{ |
362 |
|
// ~(p <=> q) is the same as p XOR q |
363 |
36 |
Trace("cnf") << push; |
364 |
36 |
SatLiteral p = toCNF(node[0], false); |
365 |
36 |
SatLiteral q = toCNF(node[1], false); |
366 |
36 |
Trace("cnf") << pop; |
367 |
|
bool added; |
368 |
36 |
NodeManager* nm = NodeManager::currentNM(); |
369 |
|
// Construct the clauses ~p v ~q |
370 |
72 |
SatClause clause1(2); |
371 |
36 |
clause1[0] = ~p; |
372 |
36 |
clause1[1] = ~q; |
373 |
36 |
added = d_cnfStream.assertClause(node.negate(), clause1); |
374 |
36 |
if (added) |
375 |
|
{ |
376 |
|
Node clauseNode = |
377 |
70 |
nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode()); |
378 |
70 |
d_proof.addStep( |
379 |
35 |
clauseNode, PfRule::NOT_EQUIV_ELIM2, {node.notNode()}, {}); |
380 |
70 |
Trace("cnf") |
381 |
35 |
<< "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM2 added " |
382 |
35 |
<< clauseNode << "\n"; |
383 |
35 |
normalizeAndRegister(clauseNode); |
384 |
|
} |
385 |
|
// Construct the clauses q v p |
386 |
72 |
SatClause clause2(2); |
387 |
36 |
clause2[0] = p; |
388 |
36 |
clause2[1] = q; |
389 |
36 |
added = d_cnfStream.assertClause(node.negate(), clause2); |
390 |
36 |
if (added) |
391 |
|
{ |
392 |
68 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[1]); |
393 |
68 |
d_proof.addStep( |
394 |
34 |
clauseNode, PfRule::NOT_EQUIV_ELIM1, {node.notNode()}, {}); |
395 |
68 |
Trace("cnf") |
396 |
34 |
<< "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM1 added " |
397 |
34 |
<< clauseNode << "\n"; |
398 |
34 |
normalizeAndRegister(clauseNode); |
399 |
|
} |
400 |
|
} |
401 |
6119 |
} |
402 |
|
|
403 |
15168 |
void ProofCnfStream::convertAndAssertImplies(TNode node, bool negated) |
404 |
|
{ |
405 |
30336 |
Trace("cnf") << "ProofCnfStream::convertAndAssertImplies(" << node |
406 |
15168 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
407 |
15168 |
if (!negated) |
408 |
|
{ |
409 |
|
// ~p v q |
410 |
15069 |
SatLiteral p = toCNF(node[0], false); |
411 |
15069 |
SatLiteral q = toCNF(node[1], false); |
412 |
|
// Construct the clause ~p || q |
413 |
30138 |
SatClause clause(2); |
414 |
15069 |
clause[0] = ~p; |
415 |
15069 |
clause[1] = q; |
416 |
15069 |
bool added = d_cnfStream.assertClause(node, clause); |
417 |
15069 |
if (added) |
418 |
|
{ |
419 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
420 |
28812 |
kind::OR, node[0].notNode(), node[1]); |
421 |
14406 |
d_proof.addStep(clauseNode, PfRule::IMPLIES_ELIM, {node}, {}); |
422 |
28812 |
Trace("cnf") |
423 |
14406 |
<< "ProofCnfStream::convertAndAssertImplies: IMPLIES_ELIM added " |
424 |
14406 |
<< clauseNode << "\n"; |
425 |
14406 |
normalizeAndRegister(clauseNode); |
426 |
|
} |
427 |
|
} |
428 |
|
else |
429 |
|
{ |
430 |
|
// ~(p => q) is the same as p ^ ~q |
431 |
|
// process p |
432 |
99 |
convertAndAssert(node[0], false); |
433 |
99 |
d_proof.addStep(node[0], PfRule::NOT_IMPLIES_ELIM1, {node.notNode()}, {}); |
434 |
198 |
Trace("cnf") |
435 |
99 |
<< "ProofCnfStream::convertAndAssertImplies: NOT_IMPLIES_ELIM1 added " |
436 |
99 |
<< node[0] << "\n"; |
437 |
|
// process ~q |
438 |
99 |
convertAndAssert(node[1], true); |
439 |
396 |
d_proof.addStep( |
440 |
297 |
node[1].notNode(), PfRule::NOT_IMPLIES_ELIM2, {node.notNode()}, {}); |
441 |
198 |
Trace("cnf") |
442 |
99 |
<< "ProofCnfStream::convertAndAssertImplies: NOT_IMPLIES_ELIM2 added " |
443 |
99 |
<< node[1].notNode() << "\n"; |
444 |
|
} |
445 |
15168 |
} |
446 |
|
|
447 |
4800 |
void ProofCnfStream::convertAndAssertIte(TNode node, bool negated) |
448 |
|
{ |
449 |
9600 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIte(" << node |
450 |
4800 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
451 |
|
// ITE(p, q, r) |
452 |
4800 |
SatLiteral p = toCNF(node[0], false); |
453 |
4800 |
SatLiteral q = toCNF(node[1], negated); |
454 |
4800 |
SatLiteral r = toCNF(node[2], negated); |
455 |
|
bool added; |
456 |
4800 |
NodeManager* nm = NodeManager::currentNM(); |
457 |
|
// Construct the clauses: |
458 |
|
// (~p v q) and (p v r) |
459 |
|
// |
460 |
|
// Note that below q and r can be used directly because whether they are |
461 |
|
// negated has been push to the literal definitions above |
462 |
9600 |
Node nnode = negated ? node.negate() : static_cast<Node>(node); |
463 |
|
// (~p v q) |
464 |
9600 |
SatClause clause1(2); |
465 |
4800 |
clause1[0] = ~p; |
466 |
4800 |
clause1[1] = q; |
467 |
4800 |
added = d_cnfStream.assertClause(nnode, clause1); |
468 |
4800 |
if (added) |
469 |
|
{ |
470 |
|
// redo the negation here to avoid silent double negation elimination |
471 |
4464 |
if (!negated) |
472 |
|
{ |
473 |
8794 |
Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]); |
474 |
4397 |
d_proof.addStep(clauseNode, PfRule::ITE_ELIM1, {node}, {}); |
475 |
8794 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM1 added " |
476 |
4397 |
<< clauseNode << "\n"; |
477 |
4397 |
normalizeAndRegister(clauseNode); |
478 |
|
} |
479 |
|
else |
480 |
|
{ |
481 |
|
Node clauseNode = |
482 |
134 |
nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode()); |
483 |
67 |
d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM1, {node.notNode()}, {}); |
484 |
134 |
Trace("cnf") |
485 |
67 |
<< "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM1 added " |
486 |
67 |
<< clauseNode << "\n"; |
487 |
67 |
normalizeAndRegister(clauseNode); |
488 |
|
} |
489 |
|
} |
490 |
|
// (p v r) |
491 |
9600 |
SatClause clause2(2); |
492 |
4800 |
clause2[0] = p; |
493 |
4800 |
clause2[1] = r; |
494 |
4800 |
added = d_cnfStream.assertClause(nnode, clause2); |
495 |
4800 |
if (added) |
496 |
|
{ |
497 |
|
// redo the negation here to avoid silent double negation elimination |
498 |
4688 |
if (!negated) |
499 |
|
{ |
500 |
9242 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[2]); |
501 |
4621 |
d_proof.addStep(clauseNode, PfRule::ITE_ELIM2, {node}, {}); |
502 |
9242 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM2 added " |
503 |
4621 |
<< clauseNode << "\n"; |
504 |
4621 |
normalizeAndRegister(clauseNode); |
505 |
|
} |
506 |
|
else |
507 |
|
{ |
508 |
134 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[2].notNode()); |
509 |
67 |
d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM2, {node.notNode()}, {}); |
510 |
134 |
Trace("cnf") |
511 |
67 |
<< "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM2 added " |
512 |
67 |
<< clauseNode << "\n"; |
513 |
67 |
normalizeAndRegister(clauseNode); |
514 |
|
} |
515 |
|
} |
516 |
4800 |
} |
517 |
|
|
518 |
18299 |
void ProofCnfStream::convertPropagation(TrustNode trn) |
519 |
|
{ |
520 |
36598 |
Node proven = trn.getProven(); |
521 |
36598 |
Trace("cnf") << "ProofCnfStream::convertPropagation: proven explanation" |
522 |
18299 |
<< proven << "\n"; |
523 |
|
// If we are not producing proofs in the theory engine there is no need to |
524 |
|
// keep track in d_proof of the clausification. We still need however to let |
525 |
|
// the SAT proof manager know that this clause is an assumption. |
526 |
18299 |
bool proofLogging = trn.getGenerator() != nullptr; |
527 |
18299 |
if (proofLogging) |
528 |
|
{ |
529 |
18299 |
Assert(trn.getGenerator()->getProofFor(proven)->isClosed()); |
530 |
36598 |
Trace("cnf-steps") << proven << " by explainPropagation " |
531 |
18299 |
<< trn.identifyGenerator() << std::endl; |
532 |
18299 |
d_proof.addLazyStep(proven, |
533 |
|
trn.getGenerator(), |
534 |
|
PfRule::ASSUME, |
535 |
|
true, |
536 |
|
"ProofCnfStream::convertPropagation"); |
537 |
|
} |
538 |
|
// since the propagation is added directly to the SAT solver via theoryProxy, |
539 |
|
// do the transformation of the lemma E1 ^ ... ^ En => P into CNF here |
540 |
18299 |
NodeManager* nm = NodeManager::currentNM(); |
541 |
36598 |
Node clauseImpliesElim; |
542 |
18299 |
if (proofLogging) |
543 |
|
{ |
544 |
18299 |
clauseImpliesElim = nm->mkNode(kind::OR, proven[0].notNode(), proven[1]); |
545 |
36598 |
Trace("cnf") << "ProofCnfStream::convertPropagation: adding " |
546 |
36598 |
<< PfRule::IMPLIES_ELIM << " rule to conclude " |
547 |
18299 |
<< clauseImpliesElim << "\n"; |
548 |
18299 |
d_proof.addStep(clauseImpliesElim, PfRule::IMPLIES_ELIM, {proven}, {}); |
549 |
|
} |
550 |
36598 |
Node clauseExp; |
551 |
|
// need to eliminate AND |
552 |
18299 |
if (proven[0].getKind() == kind::AND) |
553 |
|
{ |
554 |
34782 |
std::vector<Node> disjunctsAndNeg{proven[0]}; |
555 |
34782 |
std::vector<Node> disjunctsRes; |
556 |
163456 |
for (unsigned i = 0, size = proven[0].getNumChildren(); i < size; ++i) |
557 |
|
{ |
558 |
146065 |
disjunctsAndNeg.push_back(proven[0][i].notNode()); |
559 |
146065 |
disjunctsRes.push_back(proven[0][i].notNode()); |
560 |
|
} |
561 |
17391 |
disjunctsRes.push_back(proven[1]); |
562 |
17391 |
clauseExp = nm->mkNode(kind::OR, disjunctsRes); |
563 |
17391 |
if (proofLogging) |
564 |
|
{ |
565 |
|
// add proof steps to convert into clause |
566 |
34782 |
Node clauseAndNeg = nm->mkNode(kind::OR, disjunctsAndNeg); |
567 |
17391 |
d_proof.addStep(clauseAndNeg, PfRule::CNF_AND_NEG, {}, {proven[0]}); |
568 |
86955 |
d_proof.addStep(clauseExp, |
569 |
|
PfRule::RESOLUTION, |
570 |
|
{clauseAndNeg, clauseImpliesElim}, |
571 |
69564 |
{nm->mkConst(true), proven[0]}); |
572 |
|
} |
573 |
|
} |
574 |
|
else |
575 |
|
{ |
576 |
908 |
clauseExp = nm->mkNode(kind::OR, proven[0].notNode(), proven[1]); |
577 |
|
} |
578 |
18299 |
normalizeAndRegister(clauseExp); |
579 |
|
// consume steps |
580 |
18299 |
if (proofLogging) |
581 |
|
{ |
582 |
18299 |
const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps(); |
583 |
208442 |
for (const std::pair<Node, ProofStep>& step : steps) |
584 |
|
{ |
585 |
190143 |
d_proof.addStep(step.first, step.second); |
586 |
|
} |
587 |
18299 |
d_psb.clear(); |
588 |
|
} |
589 |
18299 |
} |
590 |
|
|
591 |
23704 |
void ProofCnfStream::ensureLiteral(TNode n) |
592 |
|
{ |
593 |
23704 |
Trace("cnf") << "ProofCnfStream::ensureLiteral(" << n << ")\n"; |
594 |
23704 |
if (d_cnfStream.hasLiteral(n)) |
595 |
|
{ |
596 |
22881 |
d_cnfStream.ensureMappingForLiteral(n); |
597 |
22881 |
return; |
598 |
|
} |
599 |
|
// remove top level negation. We don't need to track this because it's a |
600 |
|
// literal. |
601 |
823 |
n = n.getKind() == kind::NOT ? n[0] : n; |
602 |
823 |
if (theory::Theory::theoryOf(n) == theory::THEORY_BOOL && !n.isVar()) |
603 |
|
{ |
604 |
|
// These are not removable |
605 |
2 |
d_cnfStream.d_removable = false; |
606 |
2 |
SatLiteral lit = toCNF(n, false); |
607 |
|
// Store backward-mappings |
608 |
|
// These may already exist |
609 |
2 |
d_cnfStream.d_literalToNodeMap.insert_safe(lit, n); |
610 |
2 |
d_cnfStream.d_literalToNodeMap.insert_safe(~lit, n.notNode()); |
611 |
|
} |
612 |
|
else |
613 |
|
{ |
614 |
821 |
d_cnfStream.convertAtom(n); |
615 |
|
} |
616 |
|
} |
617 |
|
|
618 |
831382 |
SatLiteral ProofCnfStream::toCNF(TNode node, bool negated) |
619 |
|
{ |
620 |
1662764 |
Trace("cnf") << "toCNF(" << node |
621 |
831382 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
622 |
831382 |
SatLiteral lit; |
623 |
|
// If the node has already has a literal, return it (maybe negated) |
624 |
831382 |
if (d_cnfStream.hasLiteral(node)) |
625 |
|
{ |
626 |
575815 |
Trace("cnf") << "toCNF(): already translated\n"; |
627 |
575815 |
lit = d_cnfStream.getLiteral(node); |
628 |
|
// Return the (maybe negated) literal |
629 |
575815 |
return !negated ? lit : ~lit; |
630 |
|
} |
631 |
|
|
632 |
|
// Handle each Boolean operator case |
633 |
255567 |
switch (node.getKind()) |
634 |
|
{ |
635 |
49246 |
case kind::AND: lit = handleAnd(node); break; |
636 |
29577 |
case kind::OR: lit = handleOr(node); break; |
637 |
10790 |
case kind::XOR: lit = handleXor(node); break; |
638 |
994 |
case kind::IMPLIES: lit = handleImplies(node); break; |
639 |
7111 |
case kind::ITE: lit = handleIte(node); break; |
640 |
23180 |
case kind::NOT: lit = ~toCNF(node[0]); break; |
641 |
70549 |
case kind::EQUAL: |
642 |
186968 |
lit = node[0].getType().isBoolean() ? handleIff(node) |
643 |
116419 |
: d_cnfStream.convertAtom(node); |
644 |
70549 |
break; |
645 |
64120 |
default: |
646 |
|
{ |
647 |
64120 |
lit = d_cnfStream.convertAtom(node); |
648 |
|
} |
649 |
64120 |
break; |
650 |
|
} |
651 |
|
// Return the (maybe negated) literal |
652 |
255567 |
return !negated ? lit : ~lit; |
653 |
|
} |
654 |
|
|
655 |
49246 |
SatLiteral ProofCnfStream::handleAnd(TNode node) |
656 |
|
{ |
657 |
49246 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
658 |
49246 |
Assert(node.getKind() == kind::AND) << "Expecting an AND expression!"; |
659 |
49246 |
Assert(node.getNumChildren() > 1) << "Expecting more than 1 child!"; |
660 |
49246 |
Assert(!d_cnfStream.d_removable) |
661 |
|
<< "Removable clauses cannot contain Boolean structure"; |
662 |
49246 |
Trace("cnf") << "ProofCnfStream::handleAnd(" << node << ")\n"; |
663 |
|
// Number of children |
664 |
49246 |
unsigned size = node.getNumChildren(); |
665 |
|
// Transform all the children first (remembering the negation) |
666 |
98492 |
SatClause clause(size + 1); |
667 |
327448 |
for (unsigned i = 0; i < size; ++i) |
668 |
|
{ |
669 |
278202 |
Trace("cnf") << push; |
670 |
278202 |
clause[i] = ~toCNF(node[i]); |
671 |
278202 |
Trace("cnf") << pop; |
672 |
|
} |
673 |
|
// Create literal for the node |
674 |
49246 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
675 |
|
bool added; |
676 |
49246 |
NodeManager* nm = NodeManager::currentNM(); |
677 |
|
// lit -> (a_1 & a_2 & a_3 & ... & a_n) |
678 |
|
// ~lit | (a_1 & a_2 & a_3 & ... & a_n) |
679 |
|
// (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n) |
680 |
327448 |
for (unsigned i = 0; i < size; ++i) |
681 |
|
{ |
682 |
278202 |
Trace("cnf") << push; |
683 |
278202 |
added = d_cnfStream.assertClause(node.negate(), ~lit, ~clause[i]); |
684 |
278202 |
Trace("cnf") << pop; |
685 |
278202 |
if (added) |
686 |
|
{ |
687 |
539980 |
Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[i]); |
688 |
539980 |
Node iNode = nm->mkConst<Rational>(i); |
689 |
269990 |
d_proof.addStep(clauseNode, PfRule::CNF_AND_POS, {}, {node, iNode}); |
690 |
539980 |
Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_POS " << i |
691 |
269990 |
<< " added " << clauseNode << "\n"; |
692 |
269990 |
normalizeAndRegister(clauseNode); |
693 |
|
} |
694 |
|
} |
695 |
|
// lit <- (a_1 & a_2 & a_3 & ... a_n) |
696 |
|
// lit | ~(a_1 & a_2 & a_3 & ... & a_n) |
697 |
|
// lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n |
698 |
49246 |
clause[size] = lit; |
699 |
|
// This needs to go last, as the clause might get modified by the SAT solver |
700 |
49246 |
Trace("cnf") << push; |
701 |
49246 |
added = d_cnfStream.assertClause(node, clause); |
702 |
49246 |
Trace("cnf") << pop; |
703 |
49246 |
if (added) |
704 |
|
{ |
705 |
95888 |
std::vector<Node> disjuncts{node}; |
706 |
321733 |
for (unsigned i = 0; i < size; ++i) |
707 |
|
{ |
708 |
273789 |
disjuncts.push_back(node[i].notNode()); |
709 |
|
} |
710 |
95888 |
Node clauseNode = nm->mkNode(kind::OR, disjuncts); |
711 |
47944 |
d_proof.addStep(clauseNode, PfRule::CNF_AND_NEG, {}, {node}); |
712 |
95888 |
Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_NEG added " |
713 |
47944 |
<< clauseNode << "\n"; |
714 |
47944 |
normalizeAndRegister(clauseNode); |
715 |
|
} |
716 |
98492 |
return lit; |
717 |
|
} |
718 |
|
|
719 |
29577 |
SatLiteral ProofCnfStream::handleOr(TNode node) |
720 |
|
{ |
721 |
29577 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
722 |
29577 |
Assert(node.getKind() == kind::OR) << "Expecting an OR expression!"; |
723 |
29577 |
Assert(node.getNumChildren() > 1) << "Expecting more then 1 child!"; |
724 |
29577 |
Assert(!d_cnfStream.d_removable) |
725 |
|
<< "Removable clauses can not contain Boolean structure"; |
726 |
29577 |
Trace("cnf") << "ProofCnfStream::handleOr(" << node << ")\n"; |
727 |
|
// Number of children |
728 |
29577 |
unsigned size = node.getNumChildren(); |
729 |
|
// Transform all the children first |
730 |
59154 |
SatClause clause(size + 1); |
731 |
109292 |
for (unsigned i = 0; i < size; ++i) |
732 |
|
{ |
733 |
79715 |
clause[i] = toCNF(node[i]); |
734 |
|
} |
735 |
|
// Create literal for the node |
736 |
29577 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
737 |
|
bool added; |
738 |
29577 |
NodeManager* nm = NodeManager::currentNM(); |
739 |
|
// lit <- (a_1 | a_2 | a_3 | ... | a_n) |
740 |
|
// lit | ~(a_1 | a_2 | a_3 | ... | a_n) |
741 |
|
// (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n) |
742 |
109292 |
for (unsigned i = 0; i < size; ++i) |
743 |
|
{ |
744 |
79715 |
added = d_cnfStream.assertClause(node, lit, ~clause[i]); |
745 |
79715 |
if (added) |
746 |
|
{ |
747 |
148590 |
Node clauseNode = nm->mkNode(kind::OR, node, node[i].notNode()); |
748 |
148590 |
Node iNode = nm->mkConst<Rational>(i); |
749 |
74295 |
d_proof.addStep(clauseNode, PfRule::CNF_OR_NEG, {}, {node, iNode}); |
750 |
148590 |
Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_NEG " << i << " added " |
751 |
74295 |
<< clauseNode << "\n"; |
752 |
74295 |
normalizeAndRegister(clauseNode); |
753 |
|
} |
754 |
|
} |
755 |
|
// lit -> (a_1 | a_2 | a_3 | ... | a_n) |
756 |
|
// ~lit | a_1 | a_2 | a_3 | ... | a_n |
757 |
29577 |
clause[size] = ~lit; |
758 |
|
// This needs to go last, as the clause might get modified by the SAT solver |
759 |
29577 |
added = d_cnfStream.assertClause(node.negate(), clause); |
760 |
29577 |
if (added) |
761 |
|
{ |
762 |
57420 |
std::vector<Node> disjuncts{node.notNode()}; |
763 |
105572 |
for (unsigned i = 0; i < size; ++i) |
764 |
|
{ |
765 |
76862 |
disjuncts.push_back(node[i]); |
766 |
|
} |
767 |
57420 |
Node clauseNode = nm->mkNode(kind::OR, disjuncts); |
768 |
28710 |
d_proof.addStep(clauseNode, PfRule::CNF_OR_POS, {}, {node}); |
769 |
57420 |
Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_POS added " << clauseNode |
770 |
28710 |
<< "\n"; |
771 |
28710 |
normalizeAndRegister(clauseNode); |
772 |
|
} |
773 |
59154 |
return lit; |
774 |
|
} |
775 |
|
|
776 |
10790 |
SatLiteral ProofCnfStream::handleXor(TNode node) |
777 |
|
{ |
778 |
10790 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
779 |
10790 |
Assert(node.getKind() == kind::XOR) << "Expecting an XOR expression!"; |
780 |
10790 |
Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!"; |
781 |
10790 |
Assert(!d_cnfStream.d_removable) |
782 |
|
<< "Removable clauses can not contain Boolean structure"; |
783 |
10790 |
Trace("cnf") << "ProofCnfStream::handleXor(" << node << ")\n"; |
784 |
10790 |
SatLiteral a = toCNF(node[0]); |
785 |
10790 |
SatLiteral b = toCNF(node[1]); |
786 |
10790 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
787 |
|
bool added; |
788 |
10790 |
added = d_cnfStream.assertClause(node.negate(), a, b, ~lit); |
789 |
10790 |
if (added) |
790 |
|
{ |
791 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
792 |
21374 |
kind::OR, node.notNode(), node[0], node[1]); |
793 |
10687 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS1, {}, {node}); |
794 |
21374 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS1 added " |
795 |
10687 |
<< clauseNode << "\n"; |
796 |
10687 |
normalizeAndRegister(clauseNode); |
797 |
|
} |
798 |
10790 |
added = d_cnfStream.assertClause(node.negate(), ~a, ~b, ~lit); |
799 |
10790 |
if (added) |
800 |
|
{ |
801 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
802 |
21372 |
kind::OR, node.notNode(), node[0].notNode(), node[1].notNode()); |
803 |
10686 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS2, {}, {node}); |
804 |
21372 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS2 added " |
805 |
10686 |
<< clauseNode << "\n"; |
806 |
10686 |
normalizeAndRegister(clauseNode); |
807 |
|
} |
808 |
10790 |
added = d_cnfStream.assertClause(node, a, ~b, lit); |
809 |
10790 |
if (added) |
810 |
|
{ |
811 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
812 |
21296 |
kind::OR, node, node[0], node[1].notNode()); |
813 |
10648 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG2, {}, {node}); |
814 |
21296 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG2 added " |
815 |
10648 |
<< clauseNode << "\n"; |
816 |
10648 |
normalizeAndRegister(clauseNode); |
817 |
|
} |
818 |
10790 |
added = d_cnfStream.assertClause(node, ~a, b, lit); |
819 |
10790 |
if (added) |
820 |
|
{ |
821 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
822 |
21446 |
kind::OR, node, node[0].notNode(), node[1]); |
823 |
10723 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG1, {}, {node}); |
824 |
21446 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG1 added " |
825 |
10723 |
<< clauseNode << "\n"; |
826 |
10723 |
normalizeAndRegister(clauseNode); |
827 |
|
} |
828 |
10790 |
return lit; |
829 |
|
} |
830 |
|
|
831 |
24679 |
SatLiteral ProofCnfStream::handleIff(TNode node) |
832 |
|
{ |
833 |
24679 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
834 |
24679 |
Assert(node.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!"; |
835 |
24679 |
Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!"; |
836 |
24679 |
Trace("cnf") << "handleIff(" << node << ")\n"; |
837 |
|
// Convert the children to CNF |
838 |
24679 |
SatLiteral a = toCNF(node[0]); |
839 |
24679 |
SatLiteral b = toCNF(node[1]); |
840 |
|
// Create literal for the node |
841 |
24679 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
842 |
|
bool added; |
843 |
24679 |
NodeManager* nm = NodeManager::currentNM(); |
844 |
|
// lit -> ((a-> b) & (b->a)) |
845 |
|
// ~lit | ((~a | b) & (~b | a)) |
846 |
|
// (~a | b | ~lit) & (~b | a | ~lit) |
847 |
24679 |
added = d_cnfStream.assertClause(node.negate(), ~a, b, ~lit); |
848 |
24679 |
if (added) |
849 |
|
{ |
850 |
|
Node clauseNode = |
851 |
48768 |
nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]); |
852 |
24384 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS1, {}, {node}); |
853 |
48768 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS1 added " |
854 |
24384 |
<< clauseNode << "\n"; |
855 |
24384 |
normalizeAndRegister(clauseNode); |
856 |
|
} |
857 |
24679 |
added = d_cnfStream.assertClause(node.negate(), a, ~b, ~lit); |
858 |
24679 |
if (added) |
859 |
|
{ |
860 |
|
Node clauseNode = |
861 |
46860 |
nm->mkNode(kind::OR, node.notNode(), node[0], node[1].notNode()); |
862 |
23430 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS2, {}, {node}); |
863 |
46860 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS2 added " |
864 |
23430 |
<< clauseNode << "\n"; |
865 |
23430 |
normalizeAndRegister(clauseNode); |
866 |
|
} |
867 |
|
// (a<->b) -> lit |
868 |
|
// ~((a & b) | (~a & ~b)) | lit |
869 |
|
// (~(a & b)) & (~(~a & ~b)) | lit |
870 |
|
// ((~a | ~b) & (a | b)) | lit |
871 |
|
// (~a | ~b | lit) & (a | b | lit) |
872 |
24679 |
added = d_cnfStream.assertClause(node, ~a, ~b, lit); |
873 |
24679 |
if (added) |
874 |
|
{ |
875 |
|
Node clauseNode = |
876 |
48666 |
nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode()); |
877 |
24333 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG2, {}, {node}); |
878 |
48666 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG2 added " |
879 |
24333 |
<< clauseNode << "\n"; |
880 |
24333 |
normalizeAndRegister(clauseNode); |
881 |
|
} |
882 |
24679 |
added = d_cnfStream.assertClause(node, a, b, lit); |
883 |
24679 |
if (added) |
884 |
|
{ |
885 |
46944 |
Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[1]); |
886 |
23472 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG1, {}, {node}); |
887 |
46944 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG1 added " |
888 |
23472 |
<< clauseNode << "\n"; |
889 |
23472 |
normalizeAndRegister(clauseNode); |
890 |
|
} |
891 |
24679 |
return lit; |
892 |
|
} |
893 |
|
|
894 |
994 |
SatLiteral ProofCnfStream::handleImplies(TNode node) |
895 |
|
{ |
896 |
994 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
897 |
994 |
Assert(node.getKind() == kind::IMPLIES) << "Expecting an IMPLIES expression!"; |
898 |
994 |
Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!"; |
899 |
994 |
Assert(!d_cnfStream.d_removable) |
900 |
|
<< "Removable clauses can not contain Boolean structure"; |
901 |
994 |
Trace("cnf") << "ProofCnfStream::handleImplies(" << node << ")\n"; |
902 |
|
// Convert the children to cnf |
903 |
994 |
SatLiteral a = toCNF(node[0]); |
904 |
994 |
SatLiteral b = toCNF(node[1]); |
905 |
994 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
906 |
|
bool added; |
907 |
994 |
NodeManager* nm = NodeManager::currentNM(); |
908 |
|
// lit -> (a->b) |
909 |
|
// ~lit | ~ a | b |
910 |
994 |
added = d_cnfStream.assertClause(node.negate(), ~lit, ~a, b); |
911 |
994 |
if (added) |
912 |
|
{ |
913 |
|
Node clauseNode = |
914 |
1968 |
nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]); |
915 |
984 |
d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_POS, {}, {node}); |
916 |
1968 |
Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_POS added " |
917 |
984 |
<< clauseNode << "\n"; |
918 |
984 |
normalizeAndRegister(clauseNode); |
919 |
|
} |
920 |
|
// (a->b) -> lit |
921 |
|
// ~(~a | b) | lit |
922 |
|
// (a | l) & (~b | l) |
923 |
994 |
added = d_cnfStream.assertClause(node, a, lit); |
924 |
994 |
if (added) |
925 |
|
{ |
926 |
1976 |
Node clauseNode = nm->mkNode(kind::OR, node, node[0]); |
927 |
988 |
d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG1, {}, {node}); |
928 |
1976 |
Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG1 added " |
929 |
988 |
<< clauseNode << "\n"; |
930 |
988 |
normalizeAndRegister(clauseNode); |
931 |
|
} |
932 |
994 |
added = d_cnfStream.assertClause(node, ~b, lit); |
933 |
994 |
if (added) |
934 |
|
{ |
935 |
1984 |
Node clauseNode = nm->mkNode(kind::OR, node, node[1].notNode()); |
936 |
992 |
d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG2, {}, {node}); |
937 |
1984 |
Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG2 added " |
938 |
992 |
<< clauseNode << "\n"; |
939 |
992 |
normalizeAndRegister(clauseNode); |
940 |
|
} |
941 |
994 |
return lit; |
942 |
|
} |
943 |
|
|
944 |
7111 |
SatLiteral ProofCnfStream::handleIte(TNode node) |
945 |
|
{ |
946 |
7111 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
947 |
7111 |
Assert(node.getKind() == kind::ITE); |
948 |
7111 |
Assert(node.getNumChildren() == 3); |
949 |
7111 |
Assert(!d_cnfStream.d_removable) |
950 |
|
<< "Removable clauses can not contain Boolean structure"; |
951 |
14222 |
Trace("cnf") << "handleIte(" << node[0] << " " << node[1] << " " << node[2] |
952 |
7111 |
<< ")\n"; |
953 |
7111 |
SatLiteral condLit = toCNF(node[0]); |
954 |
7111 |
SatLiteral thenLit = toCNF(node[1]); |
955 |
7111 |
SatLiteral elseLit = toCNF(node[2]); |
956 |
|
// create literal to the node |
957 |
7111 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
958 |
|
bool added; |
959 |
7111 |
NodeManager* nm = NodeManager::currentNM(); |
960 |
|
// If ITE is true then one of the branches is true and the condition |
961 |
|
// implies which one |
962 |
|
// lit -> (ite b t e) |
963 |
|
// lit -> (t | e) & (b -> t) & (!b -> e) |
964 |
|
// lit -> (t | e) & (!b | t) & (b | e) |
965 |
|
// (!lit | t | e) & (!lit | !b | t) & (!lit | b | e) |
966 |
7111 |
added = d_cnfStream.assertClause(node.negate(), ~lit, thenLit, elseLit); |
967 |
7111 |
if (added) |
968 |
|
{ |
969 |
14128 |
Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[1], node[2]); |
970 |
7064 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS3, {}, {node}); |
971 |
14128 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS3 added " |
972 |
7064 |
<< clauseNode << "\n"; |
973 |
7064 |
normalizeAndRegister(clauseNode); |
974 |
|
} |
975 |
7111 |
added = d_cnfStream.assertClause(node.negate(), ~lit, ~condLit, thenLit); |
976 |
7111 |
if (added) |
977 |
|
{ |
978 |
|
Node clauseNode = |
979 |
13974 |
nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]); |
980 |
6987 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS1, {}, {node}); |
981 |
13974 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS1 added " |
982 |
6987 |
<< clauseNode << "\n"; |
983 |
6987 |
normalizeAndRegister(clauseNode); |
984 |
|
} |
985 |
7111 |
added = d_cnfStream.assertClause(node.negate(), ~lit, condLit, elseLit); |
986 |
7111 |
if (added) |
987 |
|
{ |
988 |
13526 |
Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[0], node[2]); |
989 |
6763 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS2, {}, {node}); |
990 |
13526 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS2 added " |
991 |
6763 |
<< clauseNode << "\n"; |
992 |
6763 |
normalizeAndRegister(clauseNode); |
993 |
|
} |
994 |
|
// If ITE is false then one of the branches is false and the condition |
995 |
|
// implies which one |
996 |
|
// !lit -> !(ite b t e) |
997 |
|
// !lit -> (!t | !e) & (b -> !t) & (!b -> !e) |
998 |
|
// !lit -> (!t | !e) & (!b | !t) & (b | !e) |
999 |
|
// (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e) |
1000 |
7111 |
added = d_cnfStream.assertClause(node, lit, ~thenLit, ~elseLit); |
1001 |
7111 |
if (added) |
1002 |
|
{ |
1003 |
|
Node clauseNode = |
1004 |
14140 |
nm->mkNode(kind::OR, node, node[1].notNode(), node[2].notNode()); |
1005 |
7070 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG3, {}, {node}); |
1006 |
14140 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG3 added " |
1007 |
7070 |
<< clauseNode << "\n"; |
1008 |
7070 |
normalizeAndRegister(clauseNode); |
1009 |
|
} |
1010 |
7111 |
added = d_cnfStream.assertClause(node, lit, ~condLit, ~thenLit); |
1011 |
7111 |
if (added) |
1012 |
|
{ |
1013 |
|
Node clauseNode = |
1014 |
13994 |
nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode()); |
1015 |
6997 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG1, {}, {node}); |
1016 |
13994 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG1 added " |
1017 |
6997 |
<< clauseNode << "\n"; |
1018 |
6997 |
normalizeAndRegister(clauseNode); |
1019 |
|
} |
1020 |
7111 |
added = d_cnfStream.assertClause(node, lit, condLit, ~elseLit); |
1021 |
7111 |
if (added) |
1022 |
|
{ |
1023 |
13516 |
Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[2].notNode()); |
1024 |
6758 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG2, {}, {node}); |
1025 |
13516 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG2 added " |
1026 |
6758 |
<< clauseNode << "\n"; |
1027 |
6758 |
normalizeAndRegister(clauseNode); |
1028 |
|
} |
1029 |
7111 |
return lit; |
1030 |
|
} |
1031 |
|
|
1032 |
|
} // namespace prop |
1033 |
29340 |
} // namespace cvc5 |