1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Gereon Kremer, Aina Niemetz |
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 equality engine. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/uf/proof_equality_engine.h" |
17 |
|
|
18 |
|
#include "expr/lazy_proof_chain.h" |
19 |
|
#include "expr/proof_node.h" |
20 |
|
#include "expr/proof_node_manager.h" |
21 |
|
#include "theory/rewriter.h" |
22 |
|
#include "theory/uf/eq_proof.h" |
23 |
|
#include "theory/uf/equality_engine.h" |
24 |
|
#include "theory/uf/proof_checker.h" |
25 |
|
|
26 |
|
using namespace cvc5::kind; |
27 |
|
|
28 |
|
namespace cvc5 { |
29 |
|
namespace theory { |
30 |
|
namespace eq { |
31 |
|
|
32 |
9225 |
ProofEqEngine::ProofEqEngine(context::Context* c, |
33 |
|
context::UserContext* u, |
34 |
|
EqualityEngine& ee, |
35 |
9225 |
ProofNodeManager* pnm) |
36 |
18450 |
: EagerProofGenerator(pnm, u, "pfee::" + ee.identify()), |
37 |
|
d_ee(ee), |
38 |
|
d_factPg(c, pnm), |
39 |
|
d_pnm(pnm), |
40 |
18450 |
d_proof(pnm, nullptr, c, "pfee::LazyCDProof::" + ee.identify()), |
41 |
46125 |
d_keep(c) |
42 |
|
{ |
43 |
9225 |
NodeManager* nm = NodeManager::currentNM(); |
44 |
9225 |
d_true = nm->mkConst(true); |
45 |
9225 |
d_false = nm->mkConst(false); |
46 |
9225 |
AlwaysAssert(pnm != nullptr) |
47 |
|
<< "Should not construct ProofEqEngine without proof node manager"; |
48 |
9225 |
} |
49 |
|
|
50 |
|
bool ProofEqEngine::assertFact(Node lit, |
51 |
|
PfRule id, |
52 |
|
const std::vector<Node>& exp, |
53 |
|
const std::vector<Node>& args) |
54 |
|
{ |
55 |
|
Trace("pfee") << "pfee::assertFact " << lit << " " << id << ", exp = " << exp |
56 |
|
<< ", args = " << args << std::endl; |
57 |
|
|
58 |
|
Node atom = lit.getKind() == NOT ? lit[0] : lit; |
59 |
|
bool polarity = lit.getKind() != NOT; |
60 |
|
// register the step in the proof |
61 |
|
if (holds(atom, polarity)) |
62 |
|
{ |
63 |
|
// we do not process this fact if it already holds |
64 |
|
return false; |
65 |
|
} |
66 |
|
// Buffer the step in the fact proof generator. We do this instead of |
67 |
|
// adding explict steps to the lazy proof d_proof since CDProof has |
68 |
|
// (at most) one proof for each formula. Thus, we "claim" only the |
69 |
|
// formula that is proved by this fact. Otherwise, aliasing may occur, |
70 |
|
// which leads to cyclic or bogus proofs. |
71 |
|
ProofStep ps; |
72 |
|
ps.d_rule = id; |
73 |
|
ps.d_children = exp; |
74 |
|
ps.d_args = args; |
75 |
|
d_factPg.addStep(lit, ps); |
76 |
|
// add lazy step to proof |
77 |
|
d_proof.addLazyStep(lit, &d_factPg); |
78 |
|
// second, assert it to the equality engine |
79 |
|
Node reason = NodeManager::currentNM()->mkAnd(exp); |
80 |
|
return assertFactInternal(atom, polarity, reason); |
81 |
|
} |
82 |
|
|
83 |
1398 |
bool ProofEqEngine::assertFact(Node lit, |
84 |
|
PfRule id, |
85 |
|
Node exp, |
86 |
|
const std::vector<Node>& args) |
87 |
|
{ |
88 |
2796 |
Trace("pfee") << "pfee::assertFact " << lit << " " << id << ", exp = " << exp |
89 |
1398 |
<< ", args = " << args << std::endl; |
90 |
2796 |
Node atom = lit.getKind() == NOT ? lit[0] : lit; |
91 |
1398 |
bool polarity = lit.getKind() != NOT; |
92 |
|
// register the step in the proof |
93 |
1398 |
if (holds(atom, polarity)) |
94 |
|
{ |
95 |
|
// we do not process this fact if it already holds |
96 |
80 |
return false; |
97 |
|
} |
98 |
|
// must extract the explanation as a vector |
99 |
2636 |
std::vector<Node> expv; |
100 |
|
// Flatten (single occurrences) of AND. We do not allow nested AND, it is |
101 |
|
// the responsibilty of the caller to ensure these do not occur. |
102 |
1318 |
if (exp != d_true) |
103 |
|
{ |
104 |
832 |
if (exp.getKind() == AND) |
105 |
|
{ |
106 |
|
for (const Node& expc : exp) |
107 |
|
{ |
108 |
|
// should not have doubly nested AND |
109 |
|
Assert(expc.getKind() != AND); |
110 |
|
expv.push_back(expc); |
111 |
|
} |
112 |
|
} |
113 |
|
else |
114 |
|
{ |
115 |
832 |
expv.push_back(exp); |
116 |
|
} |
117 |
|
} |
118 |
|
// buffer the step in the fact proof generator |
119 |
2636 |
ProofStep ps; |
120 |
1318 |
ps.d_rule = id; |
121 |
1318 |
ps.d_children = expv; |
122 |
1318 |
ps.d_args = args; |
123 |
1318 |
d_factPg.addStep(lit, ps); |
124 |
|
// add lazy step to proof |
125 |
1318 |
d_proof.addLazyStep(lit, &d_factPg); |
126 |
|
// second, assert it to the equality engine |
127 |
1318 |
return assertFactInternal(atom, polarity, exp); |
128 |
|
} |
129 |
|
|
130 |
|
bool ProofEqEngine::assertFact(Node lit, Node exp, ProofStepBuffer& psb) |
131 |
|
{ |
132 |
|
Trace("pfee") << "pfee::assertFact " << lit << ", exp = " << exp |
133 |
|
<< " via buffer with " << psb.getNumSteps() << " steps" |
134 |
|
<< std::endl; |
135 |
|
Node atom = lit.getKind() == NOT ? lit[0] : lit; |
136 |
|
bool polarity = lit.getKind() != NOT; |
137 |
|
if (holds(atom, polarity)) |
138 |
|
{ |
139 |
|
// we do not process this fact if it already holds |
140 |
|
return false; |
141 |
|
} |
142 |
|
// buffer the steps in the fact proof generator |
143 |
|
const std::vector<std::pair<Node, ProofStep>>& steps = psb.getSteps(); |
144 |
|
for (const std::pair<Node, ProofStep>& step : steps) |
145 |
|
{ |
146 |
|
d_factPg.addStep(step.first, step.second); |
147 |
|
} |
148 |
|
// add lazy step to proof |
149 |
|
d_proof.addLazyStep(lit, &d_factPg); |
150 |
|
// second, assert it to the equality engine |
151 |
|
return assertFactInternal(atom, polarity, exp); |
152 |
|
} |
153 |
|
|
154 |
98204 |
bool ProofEqEngine::assertFact(Node lit, Node exp, ProofGenerator* pg) |
155 |
|
{ |
156 |
196408 |
Trace("pfee") << "pfee::assertFact " << lit << ", exp = " << exp |
157 |
98204 |
<< " via generator" << std::endl; |
158 |
196408 |
Node atom = lit.getKind() == NOT ? lit[0] : lit; |
159 |
98204 |
bool polarity = lit.getKind() != NOT; |
160 |
98204 |
if (holds(atom, polarity)) |
161 |
|
{ |
162 |
|
// we do not process this fact if it already holds |
163 |
33578 |
return false; |
164 |
|
} |
165 |
|
// note the proof generator is responsible for remembering the explanation |
166 |
64626 |
d_proof.addLazyStep(lit, pg); |
167 |
|
// second, assert it to the equality engine |
168 |
64626 |
return assertFactInternal(atom, polarity, exp); |
169 |
|
} |
170 |
|
|
171 |
3165 |
TrustNode ProofEqEngine::assertConflict(Node lit) |
172 |
|
{ |
173 |
3165 |
Trace("pfee") << "pfee::assertConflict " << lit << std::endl; |
174 |
6330 |
std::vector<TNode> assumps; |
175 |
3165 |
explainWithProof(lit, assumps, &d_proof); |
176 |
|
// lit may not be equivalent to false, but should rewrite to false |
177 |
3165 |
if (lit != d_false) |
178 |
|
{ |
179 |
3165 |
Assert(Rewriter::rewrite(lit) == d_false) |
180 |
|
<< "pfee::assertConflict: conflict literal is not rewritable to " |
181 |
|
"false"; |
182 |
6330 |
std::vector<Node> exp; |
183 |
3165 |
exp.push_back(lit); |
184 |
6330 |
std::vector<Node> args; |
185 |
3165 |
if (!d_proof.addStep(d_false, PfRule::MACRO_SR_PRED_ELIM, exp, args)) |
186 |
|
{ |
187 |
|
Assert(false) << "pfee::assertConflict: failed conflict step"; |
188 |
|
return TrustNode::null(); |
189 |
|
} |
190 |
|
} |
191 |
|
return ensureProofForFact( |
192 |
3165 |
d_false, assumps, TrustNodeKind::CONFLICT, &d_proof); |
193 |
|
} |
194 |
|
|
195 |
|
TrustNode ProofEqEngine::assertConflict(PfRule id, |
196 |
|
const std::vector<Node>& exp, |
197 |
|
const std::vector<Node>& args) |
198 |
|
{ |
199 |
|
Trace("pfee") << "pfee::assertConflict " << id << ", exp = " << exp |
200 |
|
<< ", args = " << args << std::endl; |
201 |
|
// conflict is same as lemma concluding false |
202 |
|
return assertLemma(d_false, id, exp, {}, args); |
203 |
|
} |
204 |
|
|
205 |
931 |
TrustNode ProofEqEngine::assertConflict(const std::vector<Node>& exp, |
206 |
|
ProofGenerator* pg) |
207 |
|
{ |
208 |
931 |
Assert(pg != nullptr); |
209 |
1862 |
Trace("pfee") << "pfee::assertConflict " << exp << " via generator" |
210 |
931 |
<< std::endl; |
211 |
931 |
return assertLemma(d_false, exp, {}, pg); |
212 |
|
} |
213 |
|
|
214 |
|
TrustNode ProofEqEngine::assertLemma(Node conc, |
215 |
|
PfRule id, |
216 |
|
const std::vector<Node>& exp, |
217 |
|
const std::vector<Node>& noExplain, |
218 |
|
const std::vector<Node>& args) |
219 |
|
{ |
220 |
|
Trace("pfee") << "pfee::assertLemma " << conc << " " << id |
221 |
|
<< ", exp = " << exp << ", noExplain = " << noExplain |
222 |
|
<< ", args = " << args << std::endl; |
223 |
|
Assert(conc != d_true); |
224 |
|
LazyCDProof tmpProof(d_pnm, &d_proof); |
225 |
|
LazyCDProof* curr; |
226 |
|
TrustNodeKind tnk; |
227 |
|
// same policy as above: for conflicts, use existing lazy proof |
228 |
|
if (conc == d_false) |
229 |
|
{ |
230 |
|
curr = &d_proof; |
231 |
|
tnk = TrustNodeKind::CONFLICT; |
232 |
|
} |
233 |
|
else |
234 |
|
{ |
235 |
|
curr = &tmpProof; |
236 |
|
tnk = TrustNodeKind::LEMMA; |
237 |
|
} |
238 |
|
// explain each literal in the vector |
239 |
|
std::vector<TNode> assumps; |
240 |
|
explainVecWithProof(tnk, assumps, exp, noExplain, curr); |
241 |
|
// Register the proof step. We use a separate lazy CDProof which will make |
242 |
|
// calls to curr above for the proofs of the literals in exp. |
243 |
|
LazyCDProof outer(d_pnm, curr); |
244 |
|
if (!outer.addStep(conc, id, exp, args)) |
245 |
|
{ |
246 |
|
// a step went wrong, e.g. during checking |
247 |
|
Assert(false) << "pfee::assertConflict: register proof step"; |
248 |
|
return TrustNode::null(); |
249 |
|
} |
250 |
|
// Now get the proof for conc. |
251 |
|
return ensureProofForFact(conc, assumps, tnk, &outer); |
252 |
|
} |
253 |
|
|
254 |
1892 |
TrustNode ProofEqEngine::assertLemma(Node conc, |
255 |
|
const std::vector<Node>& exp, |
256 |
|
const std::vector<Node>& noExplain, |
257 |
|
ProofGenerator* pg) |
258 |
|
{ |
259 |
1892 |
Assert(pg != nullptr); |
260 |
3784 |
Trace("pfee") << "pfee::assertLemma " << conc << ", exp = " << exp |
261 |
1892 |
<< ", noExplain = " << noExplain << " via generator" |
262 |
1892 |
<< std::endl; |
263 |
3784 |
LazyCDProof tmpProof(d_pnm, &d_proof); |
264 |
|
LazyCDProof* curr; |
265 |
|
TrustNodeKind tnk; |
266 |
|
// same policy as above: for conflicts, use existing lazy proof |
267 |
1892 |
if (conc == d_false) |
268 |
|
{ |
269 |
944 |
curr = &d_proof; |
270 |
944 |
tnk = TrustNodeKind::CONFLICT; |
271 |
|
} |
272 |
|
else |
273 |
|
{ |
274 |
948 |
curr = &tmpProof; |
275 |
948 |
tnk = TrustNodeKind::LEMMA; |
276 |
|
} |
277 |
|
// explain each literal in the vector |
278 |
3784 |
std::vector<TNode> assumps; |
279 |
1892 |
explainVecWithProof(tnk, assumps, exp, noExplain, curr); |
280 |
|
// We use a lazy proof chain here. The provided proof generator sets up the |
281 |
|
// "skeleton" that is the base of the proof we are constructing. The call to |
282 |
|
// LazyCDProofChain::getProofFor will expand the leaves of this proof via |
283 |
|
// calls to curr. |
284 |
3784 |
LazyCDProofChain outer(d_pnm, true, nullptr, curr, false); |
285 |
1892 |
outer.addLazyStep(conc, pg); |
286 |
3784 |
return ensureProofForFact(conc, assumps, tnk, &outer); |
287 |
|
} |
288 |
|
|
289 |
68452 |
TrustNode ProofEqEngine::explain(Node conc) |
290 |
|
{ |
291 |
68452 |
Trace("pfee") << "pfee::explain " << conc << std::endl; |
292 |
136904 |
LazyCDProof tmpProof(d_pnm, &d_proof); |
293 |
136904 |
std::vector<TNode> assumps; |
294 |
68452 |
explainWithProof(conc, assumps, &tmpProof); |
295 |
136904 |
return ensureProofForFact(conc, assumps, TrustNodeKind::PROP_EXP, &tmpProof); |
296 |
|
} |
297 |
|
|
298 |
1892 |
void ProofEqEngine::explainVecWithProof(TrustNodeKind& tnk, |
299 |
|
std::vector<TNode>& assumps, |
300 |
|
const std::vector<Node>& exp, |
301 |
|
const std::vector<Node>& noExplain, |
302 |
|
LazyCDProof* curr) |
303 |
|
{ |
304 |
3784 |
std::vector<Node> expn; |
305 |
4809 |
for (const Node& e : exp) |
306 |
|
{ |
307 |
2917 |
if (std::find(noExplain.begin(), noExplain.end(), e) == noExplain.end()) |
308 |
|
{ |
309 |
2774 |
explainWithProof(e, assumps, curr); |
310 |
|
} |
311 |
|
else |
312 |
|
{ |
313 |
|
// it did not have a proof; it was an assumption of the previous rule |
314 |
143 |
assumps.push_back(e); |
315 |
|
// it is not a conflict, since it may involve new literals |
316 |
143 |
tnk = TrustNodeKind::LEMMA; |
317 |
|
} |
318 |
|
} |
319 |
1892 |
} |
320 |
|
|
321 |
73509 |
TrustNode ProofEqEngine::ensureProofForFact(Node conc, |
322 |
|
const std::vector<TNode>& assumps, |
323 |
|
TrustNodeKind tnk, |
324 |
|
ProofGenerator* curr) |
325 |
|
{ |
326 |
73509 |
Trace("pfee-proof") << std::endl; |
327 |
147018 |
Trace("pfee-proof") << "pfee::ensureProofForFact: input " << conc << " via " |
328 |
73509 |
<< assumps << ", TrustNodeKind=" << tnk << std::endl; |
329 |
73509 |
NodeManager* nm = NodeManager::currentNM(); |
330 |
|
// The proof |
331 |
147018 |
std::shared_ptr<ProofNode> pf; |
332 |
73509 |
ProofGenerator* pfg = nullptr; |
333 |
|
// the explanation is the conjunction of assumptions |
334 |
147018 |
Node exp; |
335 |
|
// If proofs are enabled, generate the proof and possibly modify the |
336 |
|
// assumptions to match SCOPE. |
337 |
73509 |
Assert(curr != nullptr); |
338 |
147018 |
Trace("pfee-proof") << "pfee::ensureProofForFact: make proof for fact" |
339 |
73509 |
<< std::endl; |
340 |
|
// get the proof for conc |
341 |
147018 |
std::shared_ptr<ProofNode> pfBody = curr->getProofFor(conc); |
342 |
73509 |
if (pfBody == nullptr) |
343 |
|
{ |
344 |
|
Trace("pfee-proof") |
345 |
|
<< "pfee::ensureProofForFact: failed to make proof for fact" |
346 |
|
<< std::endl |
347 |
|
<< std::endl; |
348 |
|
// should have existed |
349 |
|
Assert(false) << "pfee::assertConflict: failed to get proof for " << conc; |
350 |
|
return TrustNode::null(); |
351 |
|
} |
352 |
|
// clone it so that we have a fresh copy |
353 |
73509 |
pfBody = d_pnm->clone(pfBody); |
354 |
73509 |
Trace("pfee-proof") << "pfee::ensureProofForFact: add scope" << std::endl; |
355 |
|
// The free assumptions must be closed by assumps, which should be passed |
356 |
|
// as arguments of SCOPE. However, some of the free assumptions may not |
357 |
|
// literally be equal to assumps, for instance, due to symmetry. In other |
358 |
|
// words, the SCOPE could be closing (= x y) in a proof with free |
359 |
|
// assumption (= y x). We modify the proof leaves to account for this |
360 |
|
// below. |
361 |
|
|
362 |
147018 |
std::vector<Node> scopeAssumps; |
363 |
|
// we first ensure the assumptions are flattened |
364 |
406283 |
for (const TNode& a : assumps) |
365 |
|
{ |
366 |
332774 |
if (a.getKind() == AND) |
367 |
|
{ |
368 |
1446 |
scopeAssumps.insert(scopeAssumps.end(), a.begin(), a.end()); |
369 |
|
} |
370 |
|
else |
371 |
|
{ |
372 |
331328 |
scopeAssumps.push_back(a); |
373 |
|
} |
374 |
|
} |
375 |
|
// Scope the proof constructed above, and connect the formula with the proof |
376 |
|
// minimize the assumptions. |
377 |
73509 |
pf = d_pnm->mkScope(pfBody, scopeAssumps, true, true); |
378 |
|
// If we have no assumptions, and are proving an explanation for propagation |
379 |
73509 |
if (scopeAssumps.empty() && tnk == TrustNodeKind::PROP_EXP) |
380 |
|
{ |
381 |
|
// Must add "true" as an explicit argument. This is to ensure that the |
382 |
|
// propagation F from true proves (=> true F) instead of F, since this is |
383 |
|
// the form required by TrustNodeKind::PROP_EXP. We do not ensure closed or |
384 |
|
// minimize here, since we already ensured the proof was closed above, and |
385 |
|
// we do not want to minimize, or else "true" would be omitted. |
386 |
848 |
scopeAssumps.push_back(nm->mkConst(true)); |
387 |
848 |
pf = d_pnm->mkScope(pf, scopeAssumps, false); |
388 |
|
} |
389 |
73509 |
exp = nm->mkAnd(scopeAssumps); |
390 |
|
// Make the lemma or conflict node. This must exactly match the conclusion |
391 |
|
// of SCOPE below. |
392 |
147018 |
Node formula; |
393 |
73509 |
if (tnk == TrustNodeKind::CONFLICT) |
394 |
|
{ |
395 |
|
// conflict is negated |
396 |
4096 |
Assert(conc == d_false); |
397 |
4096 |
formula = exp; |
398 |
|
} |
399 |
|
else |
400 |
|
{ |
401 |
69413 |
formula = |
402 |
69413 |
exp == d_true |
403 |
207010 |
? conc |
404 |
68184 |
: (conc == d_false ? exp.negate() : nm->mkNode(IMPLIES, exp, conc)); |
405 |
|
} |
406 |
147018 |
Trace("pfee-proof") << "pfee::ensureProofForFact: formula is " << formula |
407 |
73509 |
<< std::endl; |
408 |
|
// should always be non-null |
409 |
73509 |
Assert(pf != nullptr); |
410 |
73509 |
if (Trace.isOn("pfee-proof") || Trace.isOn("pfee-proof-final")) |
411 |
|
{ |
412 |
|
Trace("pfee-proof") << "pfee::ensureProofForFact: printing proof" |
413 |
|
<< std::endl; |
414 |
|
std::stringstream ss; |
415 |
|
pf->printDebug(ss); |
416 |
|
Trace("pfee-proof") << "pfee::ensureProofForFact: Proof is " << ss.str() |
417 |
|
<< std::endl; |
418 |
|
} |
419 |
|
// Should be a closed proof now. If it is not, then the overall proof |
420 |
|
// is malformed. |
421 |
73509 |
Assert(pf->isClosed()); |
422 |
73509 |
pfg = this; |
423 |
|
// set the proof for the conflict or lemma, which can be queried later |
424 |
73509 |
switch (tnk) |
425 |
|
{ |
426 |
4096 |
case TrustNodeKind::CONFLICT: setProofForConflict(formula, pf); break; |
427 |
961 |
case TrustNodeKind::LEMMA: setProofForLemma(formula, pf); break; |
428 |
68452 |
case TrustNodeKind::PROP_EXP: setProofForPropExp(conc, exp, pf); break; |
429 |
|
default: |
430 |
|
pfg = nullptr; |
431 |
|
Unhandled() << "Unhandled trust node kind " << tnk; |
432 |
|
break; |
433 |
|
} |
434 |
147018 |
Trace("pfee-proof") << "pfee::ensureProofForFact: finish" << std::endl |
435 |
73509 |
<< std::endl; |
436 |
|
// we can provide a proof for conflict, lemma or explained propagation |
437 |
73509 |
switch (tnk) |
438 |
|
{ |
439 |
4096 |
case TrustNodeKind::CONFLICT: |
440 |
4096 |
return TrustNode::mkTrustConflict(formula, pfg); |
441 |
961 |
case TrustNodeKind::LEMMA: return TrustNode::mkTrustLemma(formula, pfg); |
442 |
68452 |
case TrustNodeKind::PROP_EXP: |
443 |
68452 |
return TrustNode::mkTrustPropExp(conc, exp, pfg); |
444 |
|
default: Unhandled() << "Unhandled trust node kind " << tnk; break; |
445 |
|
} |
446 |
|
return TrustNode::null(); |
447 |
|
} |
448 |
|
|
449 |
65944 |
bool ProofEqEngine::assertFactInternal(TNode atom, bool polarity, TNode reason) |
450 |
|
{ |
451 |
131888 |
Trace("pfee-debug") << "pfee::assertFactInternal: " << atom << " " << polarity |
452 |
65944 |
<< " " << reason << std::endl; |
453 |
|
bool ret; |
454 |
65944 |
if (atom.getKind() == EQUAL) |
455 |
|
{ |
456 |
63770 |
ret = d_ee.assertEquality(atom, polarity, reason); |
457 |
|
} |
458 |
|
else |
459 |
|
{ |
460 |
2174 |
ret = d_ee.assertPredicate(atom, polarity, reason); |
461 |
|
} |
462 |
65944 |
if (ret) |
463 |
|
{ |
464 |
|
// must reference count the new atom and explanation |
465 |
65944 |
d_keep.insert(atom); |
466 |
65944 |
d_keep.insert(reason); |
467 |
|
} |
468 |
65944 |
return ret; |
469 |
|
} |
470 |
|
|
471 |
99602 |
bool ProofEqEngine::holds(TNode atom, bool polarity) |
472 |
|
{ |
473 |
99602 |
if (atom.getKind() == EQUAL) |
474 |
|
{ |
475 |
97400 |
if (!d_ee.hasTerm(atom[0]) || !d_ee.hasTerm(atom[1])) |
476 |
|
{ |
477 |
27835 |
return false; |
478 |
|
} |
479 |
200140 |
return polarity ? d_ee.areEqual(atom[0], atom[1]) |
480 |
130575 |
: d_ee.areDisequal(atom[0], atom[1], false); |
481 |
|
} |
482 |
2202 |
if (!d_ee.hasTerm(atom)) |
483 |
|
{ |
484 |
743 |
return false; |
485 |
|
} |
486 |
2918 |
TNode b = polarity ? d_true : d_false; |
487 |
1459 |
return d_ee.areEqual(atom, b); |
488 |
|
} |
489 |
|
|
490 |
74391 |
void ProofEqEngine::explainWithProof(Node lit, |
491 |
|
std::vector<TNode>& assumps, |
492 |
|
LazyCDProof* curr) |
493 |
|
{ |
494 |
74391 |
if (std::find(assumps.begin(), assumps.end(), lit) != assumps.end()) |
495 |
|
{ |
496 |
8 |
return; |
497 |
|
} |
498 |
148774 |
std::shared_ptr<eq::EqProof> pf = std::make_shared<eq::EqProof>(); |
499 |
74387 |
Trace("pfee-proof") << "pfee::explainWithProof: " << lit << std::endl; |
500 |
74387 |
bool polarity = lit.getKind() != NOT; |
501 |
148774 |
TNode atom = polarity ? lit : lit[0]; |
502 |
74387 |
Assert(atom.getKind() != AND); |
503 |
148774 |
std::vector<TNode> tassumps; |
504 |
74387 |
if (atom.getKind() == EQUAL) |
505 |
|
{ |
506 |
71817 |
if (atom[0] == atom[1]) |
507 |
|
{ |
508 |
|
return; |
509 |
|
} |
510 |
71817 |
Assert(d_ee.hasTerm(atom[0])); |
511 |
71817 |
Assert(d_ee.hasTerm(atom[1])); |
512 |
71817 |
if (!polarity) |
513 |
|
{ |
514 |
|
// ensure the explanation exists |
515 |
5014 |
AlwaysAssert(d_ee.areDisequal(atom[0], atom[1], true)); |
516 |
|
} |
517 |
71817 |
d_ee.explainEquality(atom[0], atom[1], polarity, tassumps, pf.get()); |
518 |
|
} |
519 |
|
else |
520 |
|
{ |
521 |
2570 |
Assert(d_ee.hasTerm(atom)); |
522 |
2570 |
d_ee.explainPredicate(atom, polarity, tassumps, pf.get()); |
523 |
|
} |
524 |
74387 |
Trace("pfee-proof") << "...got " << tassumps << std::endl; |
525 |
|
// avoid duplicates |
526 |
501656 |
for (TNode a : tassumps) |
527 |
|
{ |
528 |
427269 |
if (a == lit) |
529 |
|
{ |
530 |
737 |
assumps.push_back(a); |
531 |
|
} |
532 |
426532 |
else if (std::find(assumps.begin(), assumps.end(), a) == assumps.end()) |
533 |
|
{ |
534 |
331894 |
assumps.push_back(a); |
535 |
|
} |
536 |
|
} |
537 |
74387 |
if (Trace.isOn("pfee-proof")) |
538 |
|
{ |
539 |
|
Trace("pfee-proof") << "pfee::explainWithProof: add to proof ---" |
540 |
|
<< std::endl; |
541 |
|
std::stringstream sse; |
542 |
|
pf->debug_print(sse); |
543 |
|
Trace("pfee-proof") << sse.str() << std::endl; |
544 |
|
Trace("pfee-proof") << "---" << std::endl; |
545 |
|
} |
546 |
|
// add the steps in the equality engine proof to the Proof |
547 |
74387 |
pf->addToProof(curr); |
548 |
74387 |
Trace("pfee-proof") << "pfee::explainWithProof: finished" << std::endl; |
549 |
|
} |
550 |
|
|
551 |
|
} // namespace eq |
552 |
|
} // namespace theory |
553 |
27735 |
} // namespace cvc5 |