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 |
5381 |
ProofCnfStream::ProofCnfStream(context::UserContext* u, |
27 |
|
CnfStream& cnfStream, |
28 |
|
SatProofManager* satPM, |
29 |
5381 |
ProofNodeManager* pnm) |
30 |
|
: d_cnfStream(cnfStream), |
31 |
|
d_satPM(satPM), |
32 |
|
d_proof(pnm, nullptr, u, "ProofCnfStream::LazyCDProof"), |
33 |
5381 |
d_blocked(u) |
34 |
|
{ |
35 |
5381 |
} |
36 |
|
|
37 |
500608 |
void ProofCnfStream::addBlocked(std::shared_ptr<ProofNode> pfn) |
38 |
|
{ |
39 |
500608 |
d_blocked.insert(pfn); |
40 |
500608 |
} |
41 |
|
|
42 |
832825 |
bool ProofCnfStream::isBlocked(std::shared_ptr<ProofNode> pfn) |
43 |
|
{ |
44 |
832825 |
return d_blocked.contains(pfn); |
45 |
|
} |
46 |
|
|
47 |
121472 |
std::shared_ptr<ProofNode> ProofCnfStream::getProofFor(Node f) |
48 |
|
{ |
49 |
121472 |
return d_proof.getProofFor(f); |
50 |
|
} |
51 |
|
|
52 |
648196 |
bool ProofCnfStream::hasProofFor(Node f) |
53 |
|
{ |
54 |
648196 |
return d_proof.hasStep(f) || d_proof.hasGenerator(f); |
55 |
|
} |
56 |
|
|
57 |
|
std::string ProofCnfStream::identify() const { return "ProofCnfStream"; } |
58 |
|
|
59 |
609352 |
void ProofCnfStream::normalizeAndRegister(TNode clauseNode) |
60 |
|
{ |
61 |
1218704 |
Node normClauseNode = d_psb.factorReorderElimDoubleNeg(clauseNode); |
62 |
609352 |
if (Trace.isOn("cnf") && normClauseNode != clauseNode) |
63 |
|
{ |
64 |
|
Trace("cnf") << push |
65 |
|
<< "ProofCnfStream::normalizeAndRegister: steps to normalized " |
66 |
|
<< normClauseNode << "\n" |
67 |
|
<< pop; |
68 |
|
} |
69 |
609352 |
d_satPM->registerSatAssumptions({normClauseNode}); |
70 |
609352 |
} |
71 |
|
|
72 |
98297 |
void ProofCnfStream::convertAndAssert(TNode node, |
73 |
|
bool negated, |
74 |
|
bool removable, |
75 |
|
ProofGenerator* pg) |
76 |
|
{ |
77 |
196594 |
Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node |
78 |
196594 |
<< ", negated = " << (negated ? "true" : "false") |
79 |
98297 |
<< ", removable = " << (removable ? "true" : "false") << ")\n"; |
80 |
98297 |
d_cnfStream.d_removable = removable; |
81 |
98297 |
if (pg) |
82 |
|
{ |
83 |
142900 |
Trace("cnf") << "ProofCnfStream::convertAndAssert: pg: " << pg->identify() |
84 |
71450 |
<< "\n"; |
85 |
142900 |
Node toJustify = negated ? node.notNode() : static_cast<Node>(node); |
86 |
71450 |
d_proof.addLazyStep(toJustify, |
87 |
|
pg, |
88 |
|
PfRule::ASSUME, |
89 |
|
true, |
90 |
|
"ProofCnfStream::convertAndAssert:cnf"); |
91 |
|
} |
92 |
98297 |
convertAndAssert(node, negated); |
93 |
|
// process saved steps in buffer |
94 |
98297 |
const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps(); |
95 |
2408378 |
for (const std::pair<Node, ProofStep>& step : steps) |
96 |
|
{ |
97 |
2310081 |
d_proof.addStep(step.first, step.second); |
98 |
|
} |
99 |
98297 |
d_psb.clear(); |
100 |
98297 |
} |
101 |
|
|
102 |
168539 |
void ProofCnfStream::convertAndAssert(TNode node, bool negated) |
103 |
|
{ |
104 |
337078 |
Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node |
105 |
168539 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
106 |
168539 |
switch (node.getKind()) |
107 |
|
{ |
108 |
22372 |
case kind::AND: convertAndAssertAnd(node, negated); break; |
109 |
34728 |
case kind::OR: convertAndAssertOr(node, negated); break; |
110 |
14 |
case kind::XOR: convertAndAssertXor(node, negated); break; |
111 |
19108 |
case kind::IMPLIES: convertAndAssertImplies(node, negated); break; |
112 |
7067 |
case kind::ITE: convertAndAssertIte(node, negated); break; |
113 |
23065 |
case kind::NOT: |
114 |
|
{ |
115 |
|
// track double negation elimination |
116 |
23065 |
if (negated) |
117 |
|
{ |
118 |
616 |
d_proof.addStep(node[0], PfRule::NOT_NOT_ELIM, {node.notNode()}, {}); |
119 |
1232 |
Trace("cnf") |
120 |
616 |
<< "ProofCnfStream::convertAndAssert: NOT_NOT_ELIM added norm " |
121 |
616 |
<< node[0] << "\n"; |
122 |
|
} |
123 |
23065 |
convertAndAssert(node[0], !negated); |
124 |
23065 |
break; |
125 |
|
} |
126 |
36449 |
case kind::EQUAL: |
127 |
36449 |
if (node[0].getType().isBoolean()) |
128 |
|
{ |
129 |
5830 |
convertAndAssertIff(node, negated); |
130 |
5830 |
break; |
131 |
|
} |
132 |
|
CVC5_FALLTHROUGH; |
133 |
|
default: |
134 |
|
{ |
135 |
|
// negate |
136 |
112710 |
Node nnode = negated ? node.negate() : static_cast<Node>(node); |
137 |
|
// Atoms |
138 |
56355 |
SatLiteral lit = toCNF(node, negated); |
139 |
56355 |
bool added = d_cnfStream.assertClause(nnode, lit); |
140 |
56355 |
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 |
56355 |
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 |
33598 |
d_satPM->registerSatAssumptions({nnode}); |
157 |
56355 |
} |
158 |
|
} |
159 |
|
} |
160 |
168539 |
} |
161 |
|
|
162 |
22372 |
void ProofCnfStream::convertAndAssertAnd(TNode node, bool negated) |
163 |
|
{ |
164 |
44744 |
Trace("cnf") << "ProofCnfStream::convertAndAssertAnd(" << node |
165 |
22372 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
166 |
22372 |
Assert(node.getKind() == kind::AND); |
167 |
22372 |
if (!negated) |
168 |
|
{ |
169 |
|
// If the node is a conjunction, we handle each conjunct separately |
170 |
5060 |
NodeManager* nm = NodeManager::currentNM(); |
171 |
51169 |
for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i) |
172 |
|
{ |
173 |
|
// Create a proof step for each n_i |
174 |
92218 |
Node iNode = nm->mkConst<Rational>(i); |
175 |
46109 |
d_proof.addStep(node[i], PfRule::AND_ELIM, {node}, {iNode}); |
176 |
92218 |
Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: AND_ELIM " << i |
177 |
46109 |
<< " added norm " << node[i] << "\n"; |
178 |
46109 |
convertAndAssert(node[i], false); |
179 |
|
} |
180 |
|
} |
181 |
|
else |
182 |
|
{ |
183 |
|
// If the node is a disjunction, we construct a clause and assert it |
184 |
17312 |
unsigned i, size = node.getNumChildren(); |
185 |
34624 |
SatClause clause(size); |
186 |
173267 |
for (i = 0; i < size; ++i) |
187 |
|
{ |
188 |
155955 |
clause[i] = toCNF(node[i], true); |
189 |
|
} |
190 |
17312 |
bool added = d_cnfStream.assertClause(node.negate(), clause); |
191 |
|
// register proof step |
192 |
17312 |
if (added) |
193 |
|
{ |
194 |
34522 |
std::vector<Node> disjuncts; |
195 |
173054 |
for (i = 0; i < size; ++i) |
196 |
|
{ |
197 |
155793 |
disjuncts.push_back(node[i].notNode()); |
198 |
|
} |
199 |
34522 |
Node clauseNode = NodeManager::currentNM()->mkNode(kind::OR, disjuncts); |
200 |
17261 |
d_proof.addStep(clauseNode, PfRule::NOT_AND, {node.notNode()}, {}); |
201 |
34522 |
Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: NOT_AND added " |
202 |
17261 |
<< clauseNode << "\n"; |
203 |
17261 |
normalizeAndRegister(clauseNode); |
204 |
|
} |
205 |
|
} |
206 |
22372 |
} |
207 |
|
|
208 |
34728 |
void ProofCnfStream::convertAndAssertOr(TNode node, bool negated) |
209 |
|
{ |
210 |
69456 |
Trace("cnf") << "ProofCnfStream::convertAndAssertOr(" << node |
211 |
34728 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
212 |
34728 |
Assert(node.getKind() == kind::OR); |
213 |
34728 |
if (!negated) |
214 |
|
{ |
215 |
|
// If the node is a disjunction, we construct a clause and assert it |
216 |
34590 |
unsigned size = node.getNumChildren(); |
217 |
69180 |
SatClause clause(size); |
218 |
146626 |
for (unsigned i = 0; i < size; ++i) |
219 |
|
{ |
220 |
112036 |
clause[i] = toCNF(node[i], false); |
221 |
|
} |
222 |
34590 |
normalizeAndRegister(node); |
223 |
34590 |
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 |
138 |
NodeManager* nm = NodeManager::currentNM(); |
230 |
1008 |
for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i) |
231 |
|
{ |
232 |
|
// Create a proof step for each (not n_i) |
233 |
1740 |
Node iNode = nm->mkConst<Rational>(i); |
234 |
4350 |
d_proof.addStep( |
235 |
3480 |
node[i].notNode(), PfRule::NOT_OR_ELIM, {node.notNode()}, {iNode}); |
236 |
1740 |
Trace("cnf") << "ProofCnfStream::convertAndAssertOr: NOT_OR_ELIM " << i |
237 |
870 |
<< " added norm " << node[i].notNode() << "\n"; |
238 |
870 |
convertAndAssert(node[i], true); |
239 |
|
} |
240 |
|
} |
241 |
34728 |
} |
242 |
|
|
243 |
14 |
void ProofCnfStream::convertAndAssertXor(TNode node, bool negated) |
244 |
|
{ |
245 |
28 |
Trace("cnf") << "ProofCnfStream::convertAndAssertXor(" << node |
246 |
14 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
247 |
14 |
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 |
2 |
SatLiteral p = toCNF(node[0], false); |
286 |
2 |
SatLiteral q = toCNF(node[1], false); |
287 |
|
bool added; |
288 |
2 |
NodeManager* nm = NodeManager::currentNM(); |
289 |
|
// Construct the clause ~p v q |
290 |
4 |
SatClause clause1(2); |
291 |
2 |
clause1[0] = ~p; |
292 |
2 |
clause1[1] = q; |
293 |
2 |
added = d_cnfStream.assertClause(node.negate(), clause1); |
294 |
2 |
if (added) |
295 |
|
{ |
296 |
4 |
Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]); |
297 |
2 |
d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM2, {node.notNode()}, {}); |
298 |
4 |
Trace("cnf") |
299 |
2 |
<< "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM2 added " |
300 |
2 |
<< clauseNode << "\n"; |
301 |
2 |
normalizeAndRegister(clauseNode); |
302 |
|
} |
303 |
|
// Construct the clause ~q v p |
304 |
4 |
SatClause clause2(2); |
305 |
2 |
clause2[0] = p; |
306 |
2 |
clause2[1] = ~q; |
307 |
2 |
added = d_cnfStream.assertClause(node.negate(), clause2); |
308 |
2 |
if (added) |
309 |
|
{ |
310 |
4 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode()); |
311 |
2 |
d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM1, {node.notNode()}, {}); |
312 |
4 |
Trace("cnf") |
313 |
2 |
<< "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM1 added " |
314 |
2 |
<< clauseNode << "\n"; |
315 |
2 |
normalizeAndRegister(clauseNode); |
316 |
|
} |
317 |
|
} |
318 |
14 |
} |
319 |
|
|
320 |
5830 |
void ProofCnfStream::convertAndAssertIff(TNode node, bool negated) |
321 |
|
{ |
322 |
11660 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIff(" << node |
323 |
5830 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
324 |
5830 |
if (!negated) |
325 |
|
{ |
326 |
|
// p <=> q |
327 |
5749 |
Trace("cnf") << push; |
328 |
5749 |
SatLiteral p = toCNF(node[0], false); |
329 |
5749 |
SatLiteral q = toCNF(node[1], false); |
330 |
5749 |
Trace("cnf") << pop; |
331 |
|
bool added; |
332 |
5749 |
NodeManager* nm = NodeManager::currentNM(); |
333 |
|
// Construct the clauses ~p v q |
334 |
11498 |
SatClause clause1(2); |
335 |
5749 |
clause1[0] = ~p; |
336 |
5749 |
clause1[1] = q; |
337 |
5749 |
added = d_cnfStream.assertClause(node, clause1); |
338 |
5749 |
if (added) |
339 |
|
{ |
340 |
10144 |
Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]); |
341 |
5072 |
d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM1, {node}, {}); |
342 |
10144 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM1 added " |
343 |
5072 |
<< clauseNode << "\n"; |
344 |
5072 |
normalizeAndRegister(clauseNode); |
345 |
|
} |
346 |
|
// Construct the clauses ~q v p |
347 |
11498 |
SatClause clause2(2); |
348 |
5749 |
clause2[0] = p; |
349 |
5749 |
clause2[1] = ~q; |
350 |
5749 |
added = d_cnfStream.assertClause(node, clause2); |
351 |
5749 |
if (added) |
352 |
|
{ |
353 |
9906 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode()); |
354 |
4953 |
d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM2, {node}, {}); |
355 |
9906 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM2 added " |
356 |
4953 |
<< clauseNode << "\n"; |
357 |
4953 |
normalizeAndRegister(clauseNode); |
358 |
|
} |
359 |
|
} |
360 |
|
else |
361 |
|
{ |
362 |
|
// ~(p <=> q) is the same as p XOR q |
363 |
81 |
Trace("cnf") << push; |
364 |
81 |
SatLiteral p = toCNF(node[0], false); |
365 |
81 |
SatLiteral q = toCNF(node[1], false); |
366 |
81 |
Trace("cnf") << pop; |
367 |
|
bool added; |
368 |
81 |
NodeManager* nm = NodeManager::currentNM(); |
369 |
|
// Construct the clauses ~p v ~q |
370 |
162 |
SatClause clause1(2); |
371 |
81 |
clause1[0] = ~p; |
372 |
81 |
clause1[1] = ~q; |
373 |
81 |
added = d_cnfStream.assertClause(node.negate(), clause1); |
374 |
81 |
if (added) |
375 |
|
{ |
376 |
|
Node clauseNode = |
377 |
144 |
nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode()); |
378 |
144 |
d_proof.addStep( |
379 |
72 |
clauseNode, PfRule::NOT_EQUIV_ELIM2, {node.notNode()}, {}); |
380 |
144 |
Trace("cnf") |
381 |
72 |
<< "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM2 added " |
382 |
72 |
<< clauseNode << "\n"; |
383 |
72 |
normalizeAndRegister(clauseNode); |
384 |
|
} |
385 |
|
// Construct the clauses q v p |
386 |
162 |
SatClause clause2(2); |
387 |
81 |
clause2[0] = p; |
388 |
81 |
clause2[1] = q; |
389 |
81 |
added = d_cnfStream.assertClause(node.negate(), clause2); |
390 |
81 |
if (added) |
391 |
|
{ |
392 |
142 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[1]); |
393 |
142 |
d_proof.addStep( |
394 |
71 |
clauseNode, PfRule::NOT_EQUIV_ELIM1, {node.notNode()}, {}); |
395 |
142 |
Trace("cnf") |
396 |
71 |
<< "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM1 added " |
397 |
71 |
<< clauseNode << "\n"; |
398 |
71 |
normalizeAndRegister(clauseNode); |
399 |
|
} |
400 |
|
} |
401 |
5830 |
} |
402 |
|
|
403 |
19108 |
void ProofCnfStream::convertAndAssertImplies(TNode node, bool negated) |
404 |
|
{ |
405 |
38216 |
Trace("cnf") << "ProofCnfStream::convertAndAssertImplies(" << node |
406 |
19108 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
407 |
19108 |
if (!negated) |
408 |
|
{ |
409 |
|
// ~p v q |
410 |
19009 |
SatLiteral p = toCNF(node[0], false); |
411 |
19009 |
SatLiteral q = toCNF(node[1], false); |
412 |
|
// Construct the clause ~p || q |
413 |
38018 |
SatClause clause(2); |
414 |
19009 |
clause[0] = ~p; |
415 |
19009 |
clause[1] = q; |
416 |
19009 |
bool added = d_cnfStream.assertClause(node, clause); |
417 |
19009 |
if (added) |
418 |
|
{ |
419 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
420 |
36118 |
kind::OR, node[0].notNode(), node[1]); |
421 |
18059 |
d_proof.addStep(clauseNode, PfRule::IMPLIES_ELIM, {node}, {}); |
422 |
36118 |
Trace("cnf") |
423 |
18059 |
<< "ProofCnfStream::convertAndAssertImplies: IMPLIES_ELIM added " |
424 |
18059 |
<< clauseNode << "\n"; |
425 |
18059 |
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 |
19108 |
} |
446 |
|
|
447 |
7067 |
void ProofCnfStream::convertAndAssertIte(TNode node, bool negated) |
448 |
|
{ |
449 |
14134 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIte(" << node |
450 |
7067 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
451 |
|
// ITE(p, q, r) |
452 |
7067 |
SatLiteral p = toCNF(node[0], false); |
453 |
7067 |
SatLiteral q = toCNF(node[1], negated); |
454 |
7067 |
SatLiteral r = toCNF(node[2], negated); |
455 |
|
bool added; |
456 |
7067 |
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 |
14134 |
Node nnode = negated ? node.negate() : static_cast<Node>(node); |
463 |
|
// (~p v q) |
464 |
14134 |
SatClause clause1(2); |
465 |
7067 |
clause1[0] = ~p; |
466 |
7067 |
clause1[1] = q; |
467 |
7067 |
added = d_cnfStream.assertClause(nnode, clause1); |
468 |
7067 |
if (added) |
469 |
|
{ |
470 |
|
// redo the negation here to avoid silent double negation elimination |
471 |
7016 |
if (!negated) |
472 |
|
{ |
473 |
13214 |
Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]); |
474 |
6607 |
d_proof.addStep(clauseNode, PfRule::ITE_ELIM1, {node}, {}); |
475 |
13214 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM1 added " |
476 |
6607 |
<< clauseNode << "\n"; |
477 |
6607 |
normalizeAndRegister(clauseNode); |
478 |
|
} |
479 |
|
else |
480 |
|
{ |
481 |
|
Node clauseNode = |
482 |
818 |
nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode()); |
483 |
409 |
d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM1, {node.notNode()}, {}); |
484 |
818 |
Trace("cnf") |
485 |
409 |
<< "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM1 added " |
486 |
409 |
<< clauseNode << "\n"; |
487 |
409 |
normalizeAndRegister(clauseNode); |
488 |
|
} |
489 |
|
} |
490 |
|
// (p v r) |
491 |
14134 |
SatClause clause2(2); |
492 |
7067 |
clause2[0] = p; |
493 |
7067 |
clause2[1] = r; |
494 |
7067 |
added = d_cnfStream.assertClause(nnode, clause2); |
495 |
7067 |
if (added) |
496 |
|
{ |
497 |
|
// redo the negation here to avoid silent double negation elimination |
498 |
6919 |
if (!negated) |
499 |
|
{ |
500 |
13020 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[2]); |
501 |
6510 |
d_proof.addStep(clauseNode, PfRule::ITE_ELIM2, {node}, {}); |
502 |
13020 |
Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM2 added " |
503 |
6510 |
<< clauseNode << "\n"; |
504 |
6510 |
normalizeAndRegister(clauseNode); |
505 |
|
} |
506 |
|
else |
507 |
|
{ |
508 |
818 |
Node clauseNode = nm->mkNode(kind::OR, node[0], node[2].notNode()); |
509 |
409 |
d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM2, {node.notNode()}, {}); |
510 |
818 |
Trace("cnf") |
511 |
409 |
<< "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM2 added " |
512 |
409 |
<< clauseNode << "\n"; |
513 |
409 |
normalizeAndRegister(clauseNode); |
514 |
|
} |
515 |
|
} |
516 |
7067 |
} |
517 |
|
|
518 |
15225 |
void ProofCnfStream::convertPropagation(TrustNode trn) |
519 |
|
{ |
520 |
30450 |
Node proven = trn.getProven(); |
521 |
30450 |
Trace("cnf") << "ProofCnfStream::convertPropagation: proven explanation" |
522 |
15225 |
<< 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 |
15225 |
bool proofLogging = trn.getGenerator() != nullptr; |
527 |
15225 |
if (proofLogging) |
528 |
|
{ |
529 |
15225 |
Assert(trn.getGenerator()->getProofFor(proven)->isClosed()); |
530 |
30450 |
Trace("cnf-steps") << proven << " by explainPropagation " |
531 |
15225 |
<< trn.identifyGenerator() << std::endl; |
532 |
15225 |
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 |
15225 |
NodeManager* nm = NodeManager::currentNM(); |
541 |
30450 |
Node clauseImpliesElim; |
542 |
15225 |
if (proofLogging) |
543 |
|
{ |
544 |
15225 |
clauseImpliesElim = nm->mkNode(kind::OR, proven[0].notNode(), proven[1]); |
545 |
30450 |
Trace("cnf") << "ProofCnfStream::convertPropagation: adding " |
546 |
30450 |
<< PfRule::IMPLIES_ELIM << " rule to conclude " |
547 |
15225 |
<< clauseImpliesElim << "\n"; |
548 |
15225 |
d_proof.addStep(clauseImpliesElim, PfRule::IMPLIES_ELIM, {proven}, {}); |
549 |
|
} |
550 |
30450 |
Node clauseExp; |
551 |
|
// need to eliminate AND |
552 |
15225 |
if (proven[0].getKind() == kind::AND) |
553 |
|
{ |
554 |
28360 |
std::vector<Node> disjunctsAndNeg{proven[0]}; |
555 |
28360 |
std::vector<Node> disjunctsRes; |
556 |
133878 |
for (unsigned i = 0, size = proven[0].getNumChildren(); i < size; ++i) |
557 |
|
{ |
558 |
119698 |
disjunctsAndNeg.push_back(proven[0][i].notNode()); |
559 |
119698 |
disjunctsRes.push_back(proven[0][i].notNode()); |
560 |
|
} |
561 |
14180 |
disjunctsRes.push_back(proven[1]); |
562 |
14180 |
clauseExp = nm->mkNode(kind::OR, disjunctsRes); |
563 |
14180 |
if (proofLogging) |
564 |
|
{ |
565 |
|
// add proof steps to convert into clause |
566 |
28360 |
Node clauseAndNeg = nm->mkNode(kind::OR, disjunctsAndNeg); |
567 |
14180 |
d_proof.addStep(clauseAndNeg, PfRule::CNF_AND_NEG, {}, {proven[0]}); |
568 |
70900 |
d_proof.addStep(clauseExp, |
569 |
|
PfRule::RESOLUTION, |
570 |
|
{clauseAndNeg, clauseImpliesElim}, |
571 |
56720 |
{nm->mkConst(true), proven[0]}); |
572 |
|
} |
573 |
|
} |
574 |
|
else |
575 |
|
{ |
576 |
1045 |
clauseExp = nm->mkNode(kind::OR, proven[0].notNode(), proven[1]); |
577 |
|
} |
578 |
15225 |
normalizeAndRegister(clauseExp); |
579 |
|
// consume steps |
580 |
15225 |
if (proofLogging) |
581 |
|
{ |
582 |
15225 |
const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps(); |
583 |
170754 |
for (const std::pair<Node, ProofStep>& step : steps) |
584 |
|
{ |
585 |
155529 |
d_proof.addStep(step.first, step.second); |
586 |
|
} |
587 |
15225 |
d_psb.clear(); |
588 |
|
} |
589 |
15225 |
} |
590 |
|
|
591 |
26663 |
void ProofCnfStream::ensureLiteral(TNode n) |
592 |
|
{ |
593 |
26663 |
Trace("cnf") << "ProofCnfStream::ensureLiteral(" << n << ")\n"; |
594 |
26663 |
if (d_cnfStream.hasLiteral(n)) |
595 |
|
{ |
596 |
25686 |
d_cnfStream.ensureMappingForLiteral(n); |
597 |
25686 |
return; |
598 |
|
} |
599 |
|
// remove top level negation. We don't need to track this because it's a |
600 |
|
// literal. |
601 |
977 |
n = n.getKind() == kind::NOT ? n[0] : n; |
602 |
977 |
if (theory::Theory::theoryOf(n) == theory::THEORY_BOOL && !n.isVar()) |
603 |
|
{ |
604 |
|
// These are not removable |
605 |
16 |
d_cnfStream.d_removable = false; |
606 |
16 |
SatLiteral lit = toCNF(n, false); |
607 |
|
// Store backward-mappings |
608 |
|
// These may already exist |
609 |
16 |
d_cnfStream.d_literalToNodeMap.insert_safe(lit, n); |
610 |
16 |
d_cnfStream.d_literalToNodeMap.insert_safe(~lit, n.notNode()); |
611 |
|
} |
612 |
|
else |
613 |
|
{ |
614 |
961 |
d_cnfStream.convertAtom(n); |
615 |
|
} |
616 |
|
} |
617 |
|
|
618 |
777092 |
SatLiteral ProofCnfStream::toCNF(TNode node, bool negated) |
619 |
|
{ |
620 |
1554184 |
Trace("cnf") << "toCNF(" << node |
621 |
777092 |
<< ", negated = " << (negated ? "true" : "false") << ")\n"; |
622 |
777092 |
SatLiteral lit; |
623 |
|
// If the node has already has a literal, return it (maybe negated) |
624 |
777092 |
if (d_cnfStream.hasLiteral(node)) |
625 |
|
{ |
626 |
514528 |
Trace("cnf") << "toCNF(): already translated\n"; |
627 |
514528 |
lit = d_cnfStream.getLiteral(node); |
628 |
|
// Return the (maybe negated) literal |
629 |
514528 |
return !negated ? lit : ~lit; |
630 |
|
} |
631 |
|
|
632 |
|
// Handle each Boolean operator case |
633 |
262564 |
switch (node.getKind()) |
634 |
|
{ |
635 |
46877 |
case kind::AND: lit = handleAnd(node); break; |
636 |
30998 |
case kind::OR: lit = handleOr(node); break; |
637 |
10749 |
case kind::XOR: lit = handleXor(node); break; |
638 |
986 |
case kind::IMPLIES: lit = handleImplies(node); break; |
639 |
5887 |
case kind::ITE: lit = handleIte(node); break; |
640 |
23142 |
case kind::NOT: lit = ~toCNF(node[0]); break; |
641 |
75264 |
case kind::EQUAL: |
642 |
200680 |
lit = node[0].getType().isBoolean() ? handleIff(node) |
643 |
125416 |
: d_cnfStream.convertAtom(node); |
644 |
75264 |
break; |
645 |
68661 |
default: |
646 |
|
{ |
647 |
68661 |
lit = d_cnfStream.convertAtom(node); |
648 |
|
} |
649 |
68661 |
break; |
650 |
|
} |
651 |
|
// Return the (maybe negated) literal |
652 |
262564 |
return !negated ? lit : ~lit; |
653 |
|
} |
654 |
|
|
655 |
46877 |
SatLiteral ProofCnfStream::handleAnd(TNode node) |
656 |
|
{ |
657 |
46877 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
658 |
46877 |
Assert(node.getKind() == kind::AND) << "Expecting an AND expression!"; |
659 |
46877 |
Assert(node.getNumChildren() > 1) << "Expecting more than 1 child!"; |
660 |
46877 |
Assert(!d_cnfStream.d_removable) |
661 |
|
<< "Removable clauses cannot contain Boolean structure"; |
662 |
46877 |
Trace("cnf") << "ProofCnfStream::handleAnd(" << node << ")\n"; |
663 |
|
// Number of children |
664 |
46877 |
unsigned size = node.getNumChildren(); |
665 |
|
// Transform all the children first (remembering the negation) |
666 |
93754 |
SatClause clause(size + 1); |
667 |
228304 |
for (unsigned i = 0; i < size; ++i) |
668 |
|
{ |
669 |
181427 |
Trace("cnf") << push; |
670 |
181427 |
clause[i] = ~toCNF(node[i]); |
671 |
181427 |
Trace("cnf") << pop; |
672 |
|
} |
673 |
|
// Create literal for the node |
674 |
46877 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
675 |
|
bool added; |
676 |
46877 |
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 |
228304 |
for (unsigned i = 0; i < size; ++i) |
681 |
|
{ |
682 |
181427 |
Trace("cnf") << push; |
683 |
181427 |
added = d_cnfStream.assertClause(node.negate(), ~lit, ~clause[i]); |
684 |
181427 |
Trace("cnf") << pop; |
685 |
181427 |
if (added) |
686 |
|
{ |
687 |
335574 |
Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[i]); |
688 |
335574 |
Node iNode = nm->mkConst<Rational>(i); |
689 |
167787 |
d_proof.addStep(clauseNode, PfRule::CNF_AND_POS, {}, {node, iNode}); |
690 |
335574 |
Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_POS " << i |
691 |
167787 |
<< " added " << clauseNode << "\n"; |
692 |
167787 |
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 |
46877 |
clause[size] = lit; |
699 |
|
// This needs to go last, as the clause might get modified by the SAT solver |
700 |
46877 |
Trace("cnf") << push; |
701 |
46877 |
added = d_cnfStream.assertClause(node, clause); |
702 |
46877 |
Trace("cnf") << pop; |
703 |
46877 |
if (added) |
704 |
|
{ |
705 |
91084 |
std::vector<Node> disjuncts{node}; |
706 |
222562 |
for (unsigned i = 0; i < size; ++i) |
707 |
|
{ |
708 |
177020 |
disjuncts.push_back(node[i].notNode()); |
709 |
|
} |
710 |
91084 |
Node clauseNode = nm->mkNode(kind::OR, disjuncts); |
711 |
45542 |
d_proof.addStep(clauseNode, PfRule::CNF_AND_NEG, {}, {node}); |
712 |
91084 |
Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_NEG added " |
713 |
45542 |
<< clauseNode << "\n"; |
714 |
45542 |
normalizeAndRegister(clauseNode); |
715 |
|
} |
716 |
93754 |
return lit; |
717 |
|
} |
718 |
|
|
719 |
30998 |
SatLiteral ProofCnfStream::handleOr(TNode node) |
720 |
|
{ |
721 |
30998 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
722 |
30998 |
Assert(node.getKind() == kind::OR) << "Expecting an OR expression!"; |
723 |
30998 |
Assert(node.getNumChildren() > 1) << "Expecting more then 1 child!"; |
724 |
30998 |
Assert(!d_cnfStream.d_removable) |
725 |
|
<< "Removable clauses can not contain Boolean structure"; |
726 |
30998 |
Trace("cnf") << "ProofCnfStream::handleOr(" << node << ")\n"; |
727 |
|
// Number of children |
728 |
30998 |
unsigned size = node.getNumChildren(); |
729 |
|
// Transform all the children first |
730 |
61996 |
SatClause clause(size + 1); |
731 |
116897 |
for (unsigned i = 0; i < size; ++i) |
732 |
|
{ |
733 |
85899 |
clause[i] = toCNF(node[i]); |
734 |
|
} |
735 |
|
// Create literal for the node |
736 |
30998 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
737 |
|
bool added; |
738 |
30998 |
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 |
116897 |
for (unsigned i = 0; i < size; ++i) |
743 |
|
{ |
744 |
85899 |
added = d_cnfStream.assertClause(node, lit, ~clause[i]); |
745 |
85899 |
if (added) |
746 |
|
{ |
747 |
158146 |
Node clauseNode = nm->mkNode(kind::OR, node, node[i].notNode()); |
748 |
158146 |
Node iNode = nm->mkConst<Rational>(i); |
749 |
79073 |
d_proof.addStep(clauseNode, PfRule::CNF_OR_NEG, {}, {node, iNode}); |
750 |
158146 |
Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_NEG " << i << " added " |
751 |
79073 |
<< clauseNode << "\n"; |
752 |
79073 |
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 |
30998 |
clause[size] = ~lit; |
758 |
|
// This needs to go last, as the clause might get modified by the SAT solver |
759 |
30998 |
added = d_cnfStream.assertClause(node.negate(), clause); |
760 |
30998 |
if (added) |
761 |
|
{ |
762 |
60244 |
std::vector<Node> disjuncts{node.notNode()}; |
763 |
113147 |
for (unsigned i = 0; i < size; ++i) |
764 |
|
{ |
765 |
83025 |
disjuncts.push_back(node[i]); |
766 |
|
} |
767 |
60244 |
Node clauseNode = nm->mkNode(kind::OR, disjuncts); |
768 |
30122 |
d_proof.addStep(clauseNode, PfRule::CNF_OR_POS, {}, {node}); |
769 |
60244 |
Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_POS added " << clauseNode |
770 |
30122 |
<< "\n"; |
771 |
30122 |
normalizeAndRegister(clauseNode); |
772 |
|
} |
773 |
61996 |
return lit; |
774 |
|
} |
775 |
|
|
776 |
10749 |
SatLiteral ProofCnfStream::handleXor(TNode node) |
777 |
|
{ |
778 |
10749 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
779 |
10749 |
Assert(node.getKind() == kind::XOR) << "Expecting an XOR expression!"; |
780 |
10749 |
Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!"; |
781 |
10749 |
Assert(!d_cnfStream.d_removable) |
782 |
|
<< "Removable clauses can not contain Boolean structure"; |
783 |
10749 |
Trace("cnf") << "ProofCnfStream::handleXor(" << node << ")\n"; |
784 |
10749 |
SatLiteral a = toCNF(node[0]); |
785 |
10749 |
SatLiteral b = toCNF(node[1]); |
786 |
10749 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
787 |
|
bool added; |
788 |
10749 |
added = d_cnfStream.assertClause(node.negate(), a, b, ~lit); |
789 |
10749 |
if (added) |
790 |
|
{ |
791 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
792 |
21354 |
kind::OR, node.notNode(), node[0], node[1]); |
793 |
10677 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS1, {}, {node}); |
794 |
21354 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS1 added " |
795 |
10677 |
<< clauseNode << "\n"; |
796 |
10677 |
normalizeAndRegister(clauseNode); |
797 |
|
} |
798 |
10749 |
added = d_cnfStream.assertClause(node.negate(), ~a, ~b, ~lit); |
799 |
10749 |
if (added) |
800 |
|
{ |
801 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
802 |
21290 |
kind::OR, node.notNode(), node[0].notNode(), node[1].notNode()); |
803 |
10645 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS2, {}, {node}); |
804 |
21290 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS2 added " |
805 |
10645 |
<< clauseNode << "\n"; |
806 |
10645 |
normalizeAndRegister(clauseNode); |
807 |
|
} |
808 |
10749 |
added = d_cnfStream.assertClause(node, a, ~b, lit); |
809 |
10749 |
if (added) |
810 |
|
{ |
811 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
812 |
21276 |
kind::OR, node, node[0], node[1].notNode()); |
813 |
10638 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG2, {}, {node}); |
814 |
21276 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG2 added " |
815 |
10638 |
<< clauseNode << "\n"; |
816 |
10638 |
normalizeAndRegister(clauseNode); |
817 |
|
} |
818 |
10749 |
added = d_cnfStream.assertClause(node, ~a, b, lit); |
819 |
10749 |
if (added) |
820 |
|
{ |
821 |
|
Node clauseNode = NodeManager::currentNM()->mkNode( |
822 |
21364 |
kind::OR, node, node[0].notNode(), node[1]); |
823 |
10682 |
d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG1, {}, {node}); |
824 |
21364 |
Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG1 added " |
825 |
10682 |
<< clauseNode << "\n"; |
826 |
10682 |
normalizeAndRegister(clauseNode); |
827 |
|
} |
828 |
10749 |
return lit; |
829 |
|
} |
830 |
|
|
831 |
25112 |
SatLiteral ProofCnfStream::handleIff(TNode node) |
832 |
|
{ |
833 |
25112 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
834 |
25112 |
Assert(node.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!"; |
835 |
25112 |
Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!"; |
836 |
25112 |
Trace("cnf") << "handleIff(" << node << ")\n"; |
837 |
|
// Convert the children to CNF |
838 |
25112 |
SatLiteral a = toCNF(node[0]); |
839 |
25112 |
SatLiteral b = toCNF(node[1]); |
840 |
|
// Create literal for the node |
841 |
25112 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
842 |
|
bool added; |
843 |
25112 |
NodeManager* nm = NodeManager::currentNM(); |
844 |
|
// lit -> ((a-> b) & (b->a)) |
845 |
|
// ~lit | ((~a | b) & (~b | a)) |
846 |
|
// (~a | b | ~lit) & (~b | a | ~lit) |
847 |
25112 |
added = d_cnfStream.assertClause(node.negate(), ~a, b, ~lit); |
848 |
25112 |
if (added) |
849 |
|
{ |
850 |
|
Node clauseNode = |
851 |
49692 |
nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]); |
852 |
24846 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS1, {}, {node}); |
853 |
49692 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS1 added " |
854 |
24846 |
<< clauseNode << "\n"; |
855 |
24846 |
normalizeAndRegister(clauseNode); |
856 |
|
} |
857 |
25112 |
added = d_cnfStream.assertClause(node.negate(), a, ~b, ~lit); |
858 |
25112 |
if (added) |
859 |
|
{ |
860 |
|
Node clauseNode = |
861 |
47918 |
nm->mkNode(kind::OR, node.notNode(), node[0], node[1].notNode()); |
862 |
23959 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS2, {}, {node}); |
863 |
47918 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS2 added " |
864 |
23959 |
<< clauseNode << "\n"; |
865 |
23959 |
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 |
25112 |
added = d_cnfStream.assertClause(node, ~a, ~b, lit); |
873 |
25112 |
if (added) |
874 |
|
{ |
875 |
|
Node clauseNode = |
876 |
49576 |
nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode()); |
877 |
24788 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG2, {}, {node}); |
878 |
49576 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG2 added " |
879 |
24788 |
<< clauseNode << "\n"; |
880 |
24788 |
normalizeAndRegister(clauseNode); |
881 |
|
} |
882 |
25112 |
added = d_cnfStream.assertClause(node, a, b, lit); |
883 |
25112 |
if (added) |
884 |
|
{ |
885 |
48010 |
Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[1]); |
886 |
24005 |
d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG1, {}, {node}); |
887 |
48010 |
Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG1 added " |
888 |
24005 |
<< clauseNode << "\n"; |
889 |
24005 |
normalizeAndRegister(clauseNode); |
890 |
|
} |
891 |
25112 |
return lit; |
892 |
|
} |
893 |
|
|
894 |
986 |
SatLiteral ProofCnfStream::handleImplies(TNode node) |
895 |
|
{ |
896 |
986 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
897 |
986 |
Assert(node.getKind() == kind::IMPLIES) << "Expecting an IMPLIES expression!"; |
898 |
986 |
Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!"; |
899 |
986 |
Assert(!d_cnfStream.d_removable) |
900 |
|
<< "Removable clauses can not contain Boolean structure"; |
901 |
986 |
Trace("cnf") << "ProofCnfStream::handleImplies(" << node << ")\n"; |
902 |
|
// Convert the children to cnf |
903 |
986 |
SatLiteral a = toCNF(node[0]); |
904 |
986 |
SatLiteral b = toCNF(node[1]); |
905 |
986 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
906 |
|
bool added; |
907 |
986 |
NodeManager* nm = NodeManager::currentNM(); |
908 |
|
// lit -> (a->b) |
909 |
|
// ~lit | ~ a | b |
910 |
986 |
added = d_cnfStream.assertClause(node.negate(), ~lit, ~a, b); |
911 |
986 |
if (added) |
912 |
|
{ |
913 |
|
Node clauseNode = |
914 |
1952 |
nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]); |
915 |
976 |
d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_POS, {}, {node}); |
916 |
1952 |
Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_POS added " |
917 |
976 |
<< clauseNode << "\n"; |
918 |
976 |
normalizeAndRegister(clauseNode); |
919 |
|
} |
920 |
|
// (a->b) -> lit |
921 |
|
// ~(~a | b) | lit |
922 |
|
// (a | l) & (~b | l) |
923 |
986 |
added = d_cnfStream.assertClause(node, a, lit); |
924 |
986 |
if (added) |
925 |
|
{ |
926 |
1960 |
Node clauseNode = nm->mkNode(kind::OR, node, node[0]); |
927 |
980 |
d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG1, {}, {node}); |
928 |
1960 |
Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG1 added " |
929 |
980 |
<< clauseNode << "\n"; |
930 |
980 |
normalizeAndRegister(clauseNode); |
931 |
|
} |
932 |
986 |
added = d_cnfStream.assertClause(node, ~b, lit); |
933 |
986 |
if (added) |
934 |
|
{ |
935 |
1968 |
Node clauseNode = nm->mkNode(kind::OR, node, node[1].notNode()); |
936 |
984 |
d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG2, {}, {node}); |
937 |
1968 |
Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG2 added " |
938 |
984 |
<< clauseNode << "\n"; |
939 |
984 |
normalizeAndRegister(clauseNode); |
940 |
|
} |
941 |
986 |
return lit; |
942 |
|
} |
943 |
|
|
944 |
5887 |
SatLiteral ProofCnfStream::handleIte(TNode node) |
945 |
|
{ |
946 |
5887 |
Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!"; |
947 |
5887 |
Assert(node.getKind() == kind::ITE); |
948 |
5887 |
Assert(node.getNumChildren() == 3); |
949 |
5887 |
Assert(!d_cnfStream.d_removable) |
950 |
|
<< "Removable clauses can not contain Boolean structure"; |
951 |
11774 |
Trace("cnf") << "handleIte(" << node[0] << " " << node[1] << " " << node[2] |
952 |
5887 |
<< ")\n"; |
953 |
5887 |
SatLiteral condLit = toCNF(node[0]); |
954 |
5887 |
SatLiteral thenLit = toCNF(node[1]); |
955 |
5887 |
SatLiteral elseLit = toCNF(node[2]); |
956 |
|
// create literal to the node |
957 |
5887 |
SatLiteral lit = d_cnfStream.newLiteral(node); |
958 |
|
bool added; |
959 |
5887 |
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 |
5887 |
added = d_cnfStream.assertClause(node.negate(), ~lit, thenLit, elseLit); |
967 |
5887 |
if (added) |
968 |
|
{ |
969 |
11682 |
Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[1], node[2]); |
970 |
5841 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS3, {}, {node}); |
971 |
11682 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS3 added " |
972 |
5841 |
<< clauseNode << "\n"; |
973 |
5841 |
normalizeAndRegister(clauseNode); |
974 |
|
} |
975 |
5887 |
added = d_cnfStream.assertClause(node.negate(), ~lit, ~condLit, thenLit); |
976 |
5887 |
if (added) |
977 |
|
{ |
978 |
|
Node clauseNode = |
979 |
11522 |
nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]); |
980 |
5761 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS1, {}, {node}); |
981 |
11522 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS1 added " |
982 |
5761 |
<< clauseNode << "\n"; |
983 |
5761 |
normalizeAndRegister(clauseNode); |
984 |
|
} |
985 |
5887 |
added = d_cnfStream.assertClause(node.negate(), ~lit, condLit, elseLit); |
986 |
5887 |
if (added) |
987 |
|
{ |
988 |
11162 |
Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[0], node[2]); |
989 |
5581 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS2, {}, {node}); |
990 |
11162 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS2 added " |
991 |
5581 |
<< clauseNode << "\n"; |
992 |
5581 |
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 |
5887 |
added = d_cnfStream.assertClause(node, lit, ~thenLit, ~elseLit); |
1001 |
5887 |
if (added) |
1002 |
|
{ |
1003 |
|
Node clauseNode = |
1004 |
11698 |
nm->mkNode(kind::OR, node, node[1].notNode(), node[2].notNode()); |
1005 |
5849 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG3, {}, {node}); |
1006 |
11698 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG3 added " |
1007 |
5849 |
<< clauseNode << "\n"; |
1008 |
5849 |
normalizeAndRegister(clauseNode); |
1009 |
|
} |
1010 |
5887 |
added = d_cnfStream.assertClause(node, lit, ~condLit, ~thenLit); |
1011 |
5887 |
if (added) |
1012 |
|
{ |
1013 |
|
Node clauseNode = |
1014 |
11552 |
nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode()); |
1015 |
5776 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG1, {}, {node}); |
1016 |
11552 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG1 added " |
1017 |
5776 |
<< clauseNode << "\n"; |
1018 |
5776 |
normalizeAndRegister(clauseNode); |
1019 |
|
} |
1020 |
5887 |
added = d_cnfStream.assertClause(node, lit, condLit, ~elseLit); |
1021 |
5887 |
if (added) |
1022 |
|
{ |
1023 |
11152 |
Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[2].notNode()); |
1024 |
5576 |
d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG2, {}, {node}); |
1025 |
11152 |
Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG2 added " |
1026 |
5576 |
<< clauseNode << "\n"; |
1027 |
5576 |
normalizeAndRegister(clauseNode); |
1028 |
|
} |
1029 |
5887 |
return lit; |
1030 |
|
} |
1031 |
|
|
1032 |
|
} // namespace prop |
1033 |
31125 |
} // namespace cvc5 |