1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Dejan Jovanovic, Morgan Deters |
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 |
|
* The theory preprocessor. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/theory_preprocessor.h" |
17 |
|
|
18 |
|
#include "expr/skolem_manager.h" |
19 |
|
#include "proof/lazy_proof.h" |
20 |
|
#include "smt/logic_exception.h" |
21 |
|
#include "theory/logic_info.h" |
22 |
|
#include "theory/rewriter.h" |
23 |
|
#include "theory/theory_engine.h" |
24 |
|
|
25 |
|
using namespace std; |
26 |
|
|
27 |
|
namespace cvc5 { |
28 |
|
namespace theory { |
29 |
|
|
30 |
9920 |
TheoryPreprocessor::TheoryPreprocessor(TheoryEngine& engine, |
31 |
|
context::UserContext* userContext, |
32 |
9920 |
ProofNodeManager* pnm) |
33 |
|
: d_engine(engine), |
34 |
9920 |
d_logicInfo(engine.getLogicInfo()), |
35 |
|
d_ppCache(userContext), |
36 |
|
d_rtfCache(userContext), |
37 |
|
d_tfr(userContext, pnm), |
38 |
|
d_tpg(pnm ? new TConvProofGenerator( |
39 |
|
pnm, |
40 |
|
userContext, |
41 |
|
TConvPolicy::FIXPOINT, |
42 |
|
TConvCachePolicy::NEVER, |
43 |
|
"TheoryPreprocessor::preprocess_rewrite", |
44 |
3784 |
&d_iqtc) |
45 |
|
: nullptr), |
46 |
|
d_tpgRtf(pnm ? new TConvProofGenerator(pnm, |
47 |
|
userContext, |
48 |
|
TConvPolicy::FIXPOINT, |
49 |
|
TConvCachePolicy::NEVER, |
50 |
|
"TheoryPreprocessor::rtf", |
51 |
3784 |
&d_iqtc) |
52 |
|
: nullptr), |
53 |
|
d_tpgRew(pnm ? new TConvProofGenerator(pnm, |
54 |
|
userContext, |
55 |
|
TConvPolicy::ONCE, |
56 |
|
TConvCachePolicy::NEVER, |
57 |
3784 |
"TheoryPreprocessor::pprew") |
58 |
|
: nullptr), |
59 |
|
d_tspg(nullptr), |
60 |
|
d_lp(pnm ? new LazyCDProof(pnm, |
61 |
|
nullptr, |
62 |
|
userContext, |
63 |
3784 |
"TheoryPreprocessor::LazyCDProof") |
64 |
34976 |
: nullptr) |
65 |
|
{ |
66 |
9920 |
if (isProofEnabled()) |
67 |
|
{ |
68 |
|
// Make the main term conversion sequence generator, which tracks up to |
69 |
|
// three conversions made in succession: |
70 |
|
// (1) rewriting |
71 |
|
// (2) (theory preprocessing+rewriting until fixed point)+term formula |
72 |
|
// removal+rewriting. |
73 |
7568 |
std::vector<ProofGenerator*> ts; |
74 |
3784 |
ts.push_back(d_tpgRew.get()); |
75 |
3784 |
ts.push_back(d_tpgRtf.get()); |
76 |
7568 |
d_tspg.reset(new TConvSeqProofGenerator( |
77 |
3784 |
pnm, ts, userContext, "TheoryPreprocessor::sequence")); |
78 |
|
} |
79 |
9920 |
} |
80 |
|
|
81 |
9920 |
TheoryPreprocessor::~TheoryPreprocessor() {} |
82 |
|
|
83 |
312348 |
TrustNode TheoryPreprocessor::preprocess(TNode node, |
84 |
|
std::vector<TrustNode>& newLemmas, |
85 |
|
std::vector<Node>& newSkolems) |
86 |
|
{ |
87 |
312348 |
return preprocessInternal(node, newLemmas, newSkolems, true); |
88 |
|
} |
89 |
|
|
90 |
771700 |
TrustNode TheoryPreprocessor::preprocessInternal( |
91 |
|
TNode node, |
92 |
|
std::vector<TrustNode>& newLemmas, |
93 |
|
std::vector<Node>& newSkolems, |
94 |
|
bool procLemmas) |
95 |
|
{ |
96 |
|
// In this method, all rewriting steps of node are stored in d_tpg. |
97 |
|
|
98 |
771700 |
Trace("tpp") << "TheoryPreprocessor::preprocess: start " << node << std::endl; |
99 |
|
|
100 |
|
// We must rewrite before preprocessing, because some terms when rewritten |
101 |
|
// may introduce new terms that are not top-level and require preprocessing. |
102 |
|
// An example of this is (forall ((x Int)) (and (tail L) (P x))) which |
103 |
|
// rewrites to (and (tail L) (forall ((x Int)) (P x))). The subterm (tail L) |
104 |
|
// must be preprocessed as a child here. |
105 |
1543400 |
Node irNode = rewriteWithProof(node, d_tpgRew.get(), true); |
106 |
|
|
107 |
|
// run theory preprocessing |
108 |
1543400 |
TrustNode tpp = theoryPreprocess(irNode, newLemmas, newSkolems); |
109 |
1543382 |
Node ppNode = tpp.getNode(); |
110 |
|
|
111 |
771691 |
if (Trace.isOn("tpp-debug")) |
112 |
|
{ |
113 |
|
if (node != irNode) |
114 |
|
{ |
115 |
|
Trace("tpp-debug") << "after initial rewriting : " << irNode << std::endl; |
116 |
|
} |
117 |
|
if (irNode != ppNode) |
118 |
|
{ |
119 |
|
Trace("tpp-debug") |
120 |
|
<< "after preprocessing + rewriting and term formula removal : " |
121 |
|
<< ppNode << std::endl; |
122 |
|
} |
123 |
|
Trace("tpp-debug") << "TheoryPreprocessor::preprocess: finish" << std::endl; |
124 |
|
} |
125 |
|
|
126 |
771691 |
if (procLemmas) |
127 |
|
{ |
128 |
|
// Also must preprocess the new lemmas. This is especially important for |
129 |
|
// formulas containing witness terms whose bodies are not in preprocessed |
130 |
|
// form, as term formula removal introduces new lemmas for these that |
131 |
|
// require theory-preprocessing. |
132 |
742647 |
size_t i = 0; |
133 |
800735 |
while (i < newLemmas.size()) |
134 |
|
{ |
135 |
58088 |
TrustNode cur = newLemmas[i]; |
136 |
29044 |
newLemmas[i] = preprocessLemmaInternal(cur, newLemmas, newSkolems, false); |
137 |
29044 |
Trace("tpp") << "Final lemma : " << newLemmas[i].getProven() << std::endl; |
138 |
29044 |
i++; |
139 |
|
} |
140 |
|
} |
141 |
|
|
142 |
771691 |
if (node == ppNode) |
143 |
|
{ |
144 |
1192376 |
Trace("tpp-debug") << "...TheoryPreprocessor::preprocess returned no change" |
145 |
596188 |
<< std::endl; |
146 |
|
// no change |
147 |
596188 |
return TrustNode::null(); |
148 |
|
} |
149 |
|
|
150 |
|
// Now, sequence the conversion steps if proofs are enabled. |
151 |
351006 |
TrustNode tret; |
152 |
175503 |
if (isProofEnabled()) |
153 |
|
{ |
154 |
162180 |
std::vector<Node> cterms; |
155 |
81090 |
cterms.push_back(node); |
156 |
81090 |
cterms.push_back(irNode); |
157 |
81090 |
cterms.push_back(ppNode); |
158 |
|
// We have that: |
159 |
|
// node -> irNode via rewriting |
160 |
|
// irNode -> ppNode via theory-preprocessing + rewriting + tf removal |
161 |
81090 |
tret = d_tspg->mkTrustRewriteSequence(cterms); |
162 |
81090 |
tret.debugCheckClosed("tpp-debug", "TheoryPreprocessor::lemma_ret"); |
163 |
|
} |
164 |
|
else |
165 |
|
{ |
166 |
94413 |
tret = TrustNode::mkTrustRewrite(node, ppNode, nullptr); |
167 |
|
} |
168 |
|
|
169 |
351006 |
Trace("tpp-debug") << "...TheoryPreprocessor::preprocess returned " |
170 |
175503 |
<< tret.getNode() << std::endl; |
171 |
351006 |
Trace("tpp") << "TheoryPreprocessor::preprocess: return " << tret.getNode() |
172 |
175503 |
<< ", procLemmas=" << procLemmas |
173 |
175503 |
<< ", # lemmas = " << newLemmas.size() << std::endl; |
174 |
175503 |
return tret; |
175 |
|
} |
176 |
|
|
177 |
430308 |
TrustNode TheoryPreprocessor::preprocessLemma(TrustNode node, |
178 |
|
std::vector<TrustNode>& newLemmas, |
179 |
|
std::vector<Node>& newSkolems) |
180 |
|
{ |
181 |
430308 |
return preprocessLemmaInternal(node, newLemmas, newSkolems, true); |
182 |
|
} |
183 |
|
|
184 |
459352 |
TrustNode TheoryPreprocessor::preprocessLemmaInternal( |
185 |
|
TrustNode node, |
186 |
|
std::vector<TrustNode>& newLemmas, |
187 |
|
std::vector<Node>& newSkolems, |
188 |
|
bool procLemmas) |
189 |
|
{ |
190 |
|
// what was originally proven |
191 |
918704 |
Node lemma = node.getProven(); |
192 |
|
TrustNode tplemma = |
193 |
918704 |
preprocessInternal(lemma, newLemmas, newSkolems, procLemmas); |
194 |
459350 |
if (tplemma.isNull()) |
195 |
|
{ |
196 |
|
// no change needed |
197 |
332166 |
return node; |
198 |
|
} |
199 |
127184 |
Assert(tplemma.getKind() == TrustNodeKind::REWRITE); |
200 |
|
// what it was preprocessed to |
201 |
254368 |
Node lemmap = tplemma.getNode(); |
202 |
127184 |
Assert(lemmap != node.getProven()); |
203 |
|
// process the preprocessing |
204 |
127184 |
if (isProofEnabled()) |
205 |
|
{ |
206 |
52959 |
Assert(d_lp != nullptr); |
207 |
|
// add the original proof to the lazy proof |
208 |
105918 |
d_lp->addLazyStep( |
209 |
105918 |
node.getProven(), node.getGenerator(), PfRule::THEORY_PREPROCESS_LEMMA); |
210 |
|
// only need to do anything if lemmap changed in a non-trivial way |
211 |
52959 |
if (!CDProof::isSame(lemmap, lemma)) |
212 |
|
{ |
213 |
47895 |
d_lp->addLazyStep(tplemma.getProven(), |
214 |
|
tplemma.getGenerator(), |
215 |
|
PfRule::THEORY_PREPROCESS, |
216 |
|
true, |
217 |
|
"TheoryEngine::lemma_pp"); |
218 |
|
// ---------- from node -------------- from theory preprocess |
219 |
|
// lemma lemma = lemmap |
220 |
|
// ------------------------------------------ EQ_RESOLVE |
221 |
|
// lemmap |
222 |
95790 |
std::vector<Node> pfChildren; |
223 |
47895 |
pfChildren.push_back(lemma); |
224 |
47895 |
pfChildren.push_back(tplemma.getProven()); |
225 |
47895 |
d_lp->addStep(lemmap, PfRule::EQ_RESOLVE, pfChildren, {}); |
226 |
|
} |
227 |
|
} |
228 |
127184 |
return TrustNode::mkTrustLemma(lemmap, d_lp.get()); |
229 |
|
} |
230 |
|
|
231 |
4 |
RemoveTermFormulas& TheoryPreprocessor::getRemoveTermFormulas() |
232 |
|
{ |
233 |
4 |
return d_tfr; |
234 |
|
} |
235 |
|
|
236 |
11865422 |
struct preprocess_stack_element |
237 |
|
{ |
238 |
|
TNode node; |
239 |
|
bool children_added; |
240 |
2786206 |
preprocess_stack_element(TNode n) : node(n), children_added(false) {} |
241 |
|
}; |
242 |
|
|
243 |
771700 |
TrustNode TheoryPreprocessor::theoryPreprocess( |
244 |
|
TNode assertion, |
245 |
|
std::vector<TrustNode>& newLemmas, |
246 |
|
std::vector<Node>& newSkolems) |
247 |
|
{ |
248 |
1543400 |
Trace("theory::preprocess") |
249 |
771700 |
<< "TheoryPreprocessor::theoryPreprocess(" << assertion << ")" << endl; |
250 |
|
// spendResource(); |
251 |
|
|
252 |
|
// Do a topological sort of the subexpressions and substitute them |
253 |
1543400 |
vector<preprocess_stack_element> toVisit; |
254 |
771700 |
toVisit.push_back(assertion); |
255 |
|
|
256 |
11165034 |
while (!toVisit.empty()) |
257 |
|
{ |
258 |
|
// The current node we are processing |
259 |
5196676 |
preprocess_stack_element& stackHead = toVisit.back(); |
260 |
8858566 |
TNode current = stackHead.node; |
261 |
|
|
262 |
10393352 |
Trace("theory::preprocess-debug") |
263 |
5196676 |
<< "TheoryPreprocessor::theoryPreprocess processing " << current |
264 |
5196676 |
<< endl; |
265 |
|
|
266 |
|
// If node already in the cache we're done, pop from the stack |
267 |
6106455 |
if (d_rtfCache.find(current) != d_rtfCache.end()) |
268 |
|
{ |
269 |
909779 |
toVisit.pop_back(); |
270 |
909779 |
continue; |
271 |
|
} |
272 |
|
|
273 |
4286897 |
TheoryId tid = Theory::theoryOf(current); |
274 |
|
|
275 |
4286897 |
if (!d_logicInfo.isTheoryEnabled(tid) && tid != THEORY_SAT_SOLVER) |
276 |
|
{ |
277 |
|
stringstream ss; |
278 |
|
ss << "The logic was specified as " << d_logicInfo.getLogicString() |
279 |
|
<< ", which doesn't include " << tid |
280 |
|
<< ", but got a preprocessing-time fact for that theory." << endl |
281 |
|
<< "The fact:" << endl |
282 |
|
<< current; |
283 |
|
throw LogicException(ss.str()); |
284 |
|
} |
285 |
|
// If this is an atom, we preprocess its terms with the theory ppRewriter |
286 |
4286897 |
if (tid != THEORY_BOOL) |
287 |
|
{ |
288 |
1250032 |
std::vector<SkolemLemma> lems; |
289 |
1250032 |
Node ppRewritten = ppTheoryRewrite(current, lems); |
290 |
626744 |
for (const SkolemLemma& lem : lems) |
291 |
|
{ |
292 |
1737 |
newLemmas.push_back(lem.d_lemma); |
293 |
1737 |
newSkolems.push_back(lem.d_skolem); |
294 |
|
} |
295 |
625007 |
Assert(Rewriter::rewrite(ppRewritten) == ppRewritten); |
296 |
625007 |
if (isProofEnabled() && ppRewritten != current) |
297 |
|
{ |
298 |
|
TrustNode trn = |
299 |
7384 |
TrustNode::mkTrustRewrite(current, ppRewritten, d_tpg.get()); |
300 |
3692 |
registerTrustedRewrite(trn, d_tpgRtf.get(), true); |
301 |
|
} |
302 |
|
|
303 |
|
// Term formula removal without fixed point. We do not need to do fixed |
304 |
|
// point since newLemmas are theory-preprocessed until fixed point in |
305 |
|
// preprocessInternal (at top-level, when procLemmas=true). |
306 |
1250014 |
TrustNode ttfr = d_tfr.run(ppRewritten, newLemmas, newSkolems, false); |
307 |
1250014 |
Node rtfNode = ppRewritten; |
308 |
625007 |
if (!ttfr.isNull()) |
309 |
|
{ |
310 |
65559 |
rtfNode = ttfr.getNode(); |
311 |
65559 |
registerTrustedRewrite(ttfr, d_tpgRtf.get(), true); |
312 |
|
} |
313 |
|
// Finish the conversion by rewriting. Notice that we must consider this a |
314 |
|
// pre-rewrite since we do not recursively register the rewriting steps |
315 |
|
// of subterms of rtfNode. For example, if this step rewrites |
316 |
|
// (not A) ---> B, then if registered a pre-rewrite, it will apply when |
317 |
|
// reconstructing proofs via d_tpgRtf. However, if it is a post-rewrite |
318 |
|
// it will fail to apply if another call to this class registers A -> C, |
319 |
|
// in which case (not C) will be returned instead of B (see issue 6754). |
320 |
1250014 |
Node retNode = rewriteWithProof(rtfNode, d_tpgRtf.get(), true); |
321 |
625007 |
d_rtfCache[current] = retNode; |
322 |
625007 |
continue; |
323 |
|
} |
324 |
|
|
325 |
|
// Not yet substituted, so process |
326 |
3661881 |
if (stackHead.children_added) |
327 |
|
{ |
328 |
|
// Children have been processed, so substitute |
329 |
3570936 |
NodeBuilder builder(current.getKind()); |
330 |
1785468 |
if (current.getMetaKind() == kind::metakind::PARAMETERIZED) |
331 |
|
{ |
332 |
|
builder << current.getOperator(); |
333 |
|
} |
334 |
7705761 |
for (unsigned i = 0; i < current.getNumChildren(); ++i) |
335 |
|
{ |
336 |
5920293 |
Assert(d_rtfCache.find(current[i]) != d_rtfCache.end()); |
337 |
5920293 |
builder << d_rtfCache[current[i]].get(); |
338 |
|
} |
339 |
|
// Mark the substitution and continue |
340 |
3570936 |
Node result = builder; |
341 |
|
// always rewrite here, since current may not be in rewritten form after |
342 |
|
// reconstruction |
343 |
1785468 |
result = rewriteWithProof(result, d_tpgRtf.get(), false); |
344 |
3570936 |
Trace("theory::preprocess-debug") |
345 |
1785468 |
<< "TheoryPreprocessor::theoryPreprocess setting " << current |
346 |
1785468 |
<< " -> " << result << endl; |
347 |
1785468 |
d_rtfCache[current] = result; |
348 |
1785468 |
toVisit.pop_back(); |
349 |
|
} |
350 |
|
else |
351 |
|
{ |
352 |
|
// Mark that we have added the children if any |
353 |
1876413 |
if (current.getNumChildren() > 0) |
354 |
|
{ |
355 |
1785477 |
stackHead.children_added = true; |
356 |
|
// We need to add the children |
357 |
7705787 |
for (TNode::iterator child_it = current.begin(); |
358 |
7705787 |
child_it != current.end(); |
359 |
|
++child_it) |
360 |
|
{ |
361 |
11840620 |
TNode childNode = *child_it; |
362 |
5920310 |
if (d_rtfCache.find(childNode) == d_rtfCache.end()) |
363 |
|
{ |
364 |
2014506 |
toVisit.push_back(childNode); |
365 |
|
} |
366 |
|
} |
367 |
|
} |
368 |
|
else |
369 |
|
{ |
370 |
|
// No children, so we're done |
371 |
181872 |
Trace("theory::preprocess-debug") |
372 |
90936 |
<< "SubstitutionMap::internalSubstitute setting " << current |
373 |
90936 |
<< " -> " << current << endl; |
374 |
90936 |
d_rtfCache[current] = current; |
375 |
90936 |
toVisit.pop_back(); |
376 |
|
} |
377 |
|
} |
378 |
|
} |
379 |
771691 |
Assert(d_rtfCache.find(assertion) != d_rtfCache.end()); |
380 |
|
// Return the substituted version |
381 |
1543382 |
Node res = d_rtfCache[assertion]; |
382 |
1543382 |
return TrustNode::mkTrustRewrite(assertion, res, d_tpg.get()); |
383 |
|
} |
384 |
|
|
385 |
|
// Recursively traverse a term and call the theory rewriter on its sub-terms |
386 |
2747218 |
Node TheoryPreprocessor::ppTheoryRewrite(TNode term, |
387 |
|
std::vector<SkolemLemma>& lems) |
388 |
|
{ |
389 |
2747218 |
NodeMap::iterator find = d_ppCache.find(term); |
390 |
2747218 |
if (find != d_ppCache.end()) |
391 |
|
{ |
392 |
600592 |
return (*find).second; |
393 |
|
} |
394 |
2146626 |
if (term.getNumChildren() == 0) |
395 |
|
{ |
396 |
1100985 |
return preprocessWithProof(term, lems); |
397 |
|
} |
398 |
|
// should be in rewritten form here |
399 |
1045643 |
Assert(term == Rewriter::rewrite(term)); |
400 |
1045643 |
Trace("theory-pp") << "ppTheoryRewrite { " << term << endl; |
401 |
|
// do not rewrite inside quantifiers |
402 |
2091286 |
Node newTerm = term; |
403 |
1045643 |
if (!term.isClosure()) |
404 |
|
{ |
405 |
2036412 |
NodeBuilder newNode(term.getKind()); |
406 |
1018206 |
if (term.getMetaKind() == kind::metakind::PARAMETERIZED) |
407 |
|
{ |
408 |
202299 |
newNode << term.getOperator(); |
409 |
|
} |
410 |
3133482 |
for (const Node& nt : term) |
411 |
|
{ |
412 |
2115276 |
newNode << ppTheoryRewrite(nt, lems); |
413 |
|
} |
414 |
1018194 |
newTerm = Node(newNode); |
415 |
1018194 |
newTerm = rewriteWithProof(newTerm, d_tpg.get(), false); |
416 |
|
} |
417 |
1045631 |
newTerm = preprocessWithProof(newTerm, lems); |
418 |
1045624 |
d_ppCache[term] = newTerm; |
419 |
1045624 |
Trace("theory-pp") << "ppTheoryRewrite returning " << newTerm << "}" << endl; |
420 |
1045624 |
return newTerm; |
421 |
|
} |
422 |
|
|
423 |
4207295 |
Node TheoryPreprocessor::rewriteWithProof(Node term, |
424 |
|
TConvProofGenerator* pg, |
425 |
|
bool isPre) |
426 |
|
{ |
427 |
4207295 |
Node termr = Rewriter::rewrite(term); |
428 |
|
// store rewrite step if tracking proofs and it rewrites |
429 |
4207295 |
if (isProofEnabled()) |
430 |
|
{ |
431 |
|
// may rewrite the same term more than once, thus check hasRewriteStep |
432 |
2130688 |
if (termr != term) |
433 |
|
{ |
434 |
162574 |
Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (rewriting) " |
435 |
81287 |
<< term << " -> " << termr << std::endl; |
436 |
|
// always use term context hash 0 (default) |
437 |
81287 |
pg->addRewriteStep(term, termr, PfRule::REWRITE, {}, {term}, isPre); |
438 |
|
} |
439 |
|
} |
440 |
4207295 |
return termr; |
441 |
|
} |
442 |
|
|
443 |
2146614 |
Node TheoryPreprocessor::preprocessWithProof(Node term, |
444 |
|
std::vector<SkolemLemma>& lems) |
445 |
|
{ |
446 |
|
// Important that it is in rewritten form, to ensure that the rewrite steps |
447 |
|
// recorded in d_tpg are functional. In other words, there should not |
448 |
|
// be steps from the same term to multiple rewritten forms, which would be |
449 |
|
// the case if we registered a preprocessing step for a non-rewritten term. |
450 |
2146614 |
Assert(term == Rewriter::rewrite(term)); |
451 |
4293228 |
Trace("tpp-debug2") << "preprocessWithProof " << term |
452 |
2146614 |
<< ", #lems = " << lems.size() << std::endl; |
453 |
|
// We never call ppRewrite on equalities here, since equalities have a |
454 |
|
// special status. In particular, notice that theory preprocessing can be |
455 |
|
// called on all formulas asserted to theory engine, including those generated |
456 |
|
// as new literals appearing in lemmas. Calling ppRewrite on equalities is |
457 |
|
// incompatible with theory combination where a split on equality requested |
458 |
|
// by a theory could be preprocessed to something else, thus making theory |
459 |
|
// combination either non-terminating or result in solution soundness. |
460 |
|
// Notice that an alternative solution is to ensure that certain lemmas |
461 |
|
// (e.g. splits from theory combination) can never have theory preprocessing |
462 |
|
// applied to them. However, it is more uniform to say that theory |
463 |
|
// preprocessing is applied to all formulas. This makes it so that e.g. |
464 |
|
// theory solvers do not need to specify whether they want their lemmas to |
465 |
|
// be theory-preprocessed or not. |
466 |
2146614 |
if (term.getKind() == kind::EQUAL) |
467 |
|
{ |
468 |
305377 |
return term; |
469 |
|
} |
470 |
|
// call ppRewrite for the given theory |
471 |
3682474 |
TrustNode trn = d_engine.theoryOf(term)->ppRewrite(term, lems); |
472 |
3682456 |
Trace("tpp-debug2") << "preprocessWithProof returned " << trn |
473 |
1841228 |
<< ", #lems = " << lems.size() << std::endl; |
474 |
1841228 |
if (trn.isNull()) |
475 |
|
{ |
476 |
|
// no change, return |
477 |
1834302 |
return term; |
478 |
|
} |
479 |
13852 |
Node termr = trn.getNode(); |
480 |
6926 |
Assert(term != termr); |
481 |
6926 |
if (isProofEnabled()) |
482 |
|
{ |
483 |
3690 |
registerTrustedRewrite(trn, d_tpg.get(), false); |
484 |
|
} |
485 |
|
// Rewrite again here, which notice is a *pre* rewrite. |
486 |
6926 |
termr = rewriteWithProof(termr, d_tpg.get(), true); |
487 |
6926 |
return ppTheoryRewrite(termr, lems); |
488 |
|
} |
489 |
|
|
490 |
5224776 |
bool TheoryPreprocessor::isProofEnabled() const { return d_tpg != nullptr; } |
491 |
|
|
492 |
72941 |
void TheoryPreprocessor::registerTrustedRewrite(TrustNode trn, |
493 |
|
TConvProofGenerator* pg, |
494 |
|
bool isPre) |
495 |
|
{ |
496 |
72941 |
if (!isProofEnabled() || trn.isNull()) |
497 |
|
{ |
498 |
30465 |
return; |
499 |
|
} |
500 |
42476 |
Assert(trn.getKind() == TrustNodeKind::REWRITE); |
501 |
84952 |
Node eq = trn.getProven(); |
502 |
84952 |
Node term = eq[0]; |
503 |
84952 |
Node termr = eq[1]; |
504 |
42476 |
if (trn.getGenerator() != nullptr) |
505 |
|
{ |
506 |
77586 |
Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (generator) " |
507 |
38793 |
<< term << " -> " << termr << std::endl; |
508 |
38793 |
trn.debugCheckClosed("tpp-debug", |
509 |
|
"TheoryPreprocessor::preprocessWithProof"); |
510 |
|
// always use term context hash 0 (default) |
511 |
38793 |
pg->addRewriteStep( |
512 |
|
term, termr, trn.getGenerator(), isPre, PfRule::ASSUME, true); |
513 |
|
} |
514 |
|
else |
515 |
|
{ |
516 |
7366 |
Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (trusted) " |
517 |
3683 |
<< term << " -> " << termr << std::endl; |
518 |
|
// small step trust |
519 |
7366 |
pg->addRewriteStep(term, |
520 |
|
termr, |
521 |
|
PfRule::THEORY_PREPROCESS, |
522 |
|
{}, |
523 |
|
{term.eqNode(termr)}, |
524 |
3683 |
isPre); |
525 |
|
} |
526 |
|
} |
527 |
|
|
528 |
|
} // namespace theory |
529 |
29340 |
} // namespace cvc5 |