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