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