1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli, 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 expand definitions for an SMT engine. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "smt/expand_definitions.h" |
17 |
|
|
18 |
|
#include <stack> |
19 |
|
#include <utility> |
20 |
|
|
21 |
|
#include "expr/node_manager_attributes.h" |
22 |
|
#include "preprocessing/assertion_pipeline.h" |
23 |
|
#include "proof/conv_proof_generator.h" |
24 |
|
#include "smt/env.h" |
25 |
|
#include "smt/solver_engine.h" |
26 |
|
#include "theory/rewriter.h" |
27 |
|
#include "theory/theory.h" |
28 |
|
#include "util/resource_manager.h" |
29 |
|
|
30 |
|
using namespace cvc5::preprocessing; |
31 |
|
using namespace cvc5::theory; |
32 |
|
using namespace cvc5::kind; |
33 |
|
|
34 |
|
namespace cvc5 { |
35 |
|
namespace smt { |
36 |
|
|
37 |
18633 |
ExpandDefs::ExpandDefs(Env& env) : d_env(env), d_tpg(nullptr) {} |
38 |
|
|
39 |
15884 |
ExpandDefs::~ExpandDefs() {} |
40 |
|
|
41 |
12607 |
Node ExpandDefs::expandDefinitions(TNode n, |
42 |
|
std::unordered_map<Node, Node>& cache) |
43 |
|
{ |
44 |
25214 |
TrustNode trn = expandDefinitions(n, cache, nullptr); |
45 |
25214 |
return trn.isNull() ? Node(n) : trn.getNode(); |
46 |
|
} |
47 |
|
|
48 |
12607 |
TrustNode ExpandDefs::expandDefinitions(TNode n, |
49 |
|
std::unordered_map<Node, Node>& cache, |
50 |
|
TConvProofGenerator* tpg) |
51 |
|
{ |
52 |
25214 |
const TNode orig = n; |
53 |
25214 |
std::stack<std::tuple<Node, Node, bool>> worklist; |
54 |
25214 |
std::stack<Node> result; |
55 |
12607 |
worklist.push(std::make_tuple(Node(n), Node(n), false)); |
56 |
|
// The worklist is made of triples, each is input / original node then the |
57 |
|
// output / rewritten node and finally a flag tracking whether the children |
58 |
|
// have been explored (i.e. if this is a downward or upward pass). |
59 |
|
|
60 |
12607 |
ResourceManager* rm = d_env.getResourceManager(); |
61 |
12607 |
Rewriter* rr = d_env.getRewriter(); |
62 |
55731 |
do |
63 |
|
{ |
64 |
68338 |
rm->spendResource(Resource::PreprocessStep); |
65 |
|
|
66 |
|
// n is the input / original |
67 |
|
// node is the output / result |
68 |
108856 |
Node node; |
69 |
|
bool childrenPushed; |
70 |
68338 |
std::tie(n, node, childrenPushed) = worklist.top(); |
71 |
68338 |
worklist.pop(); |
72 |
|
|
73 |
|
// Working downwards |
74 |
68338 |
if (!childrenPushed) |
75 |
|
{ |
76 |
|
// we can short circuit (variable) leaves |
77 |
71593 |
if (n.isVar()) |
78 |
|
{ |
79 |
|
// don't bother putting in the cache |
80 |
23514 |
result.push(n); |
81 |
51334 |
continue; |
82 |
|
} |
83 |
|
|
84 |
|
// maybe it's in the cache |
85 |
24565 |
std::unordered_map<Node, Node>::iterator cacheHit = cache.find(n); |
86 |
24565 |
if (cacheHit != cache.end()) |
87 |
|
{ |
88 |
8612 |
TNode ret = (*cacheHit).second; |
89 |
4306 |
result.push(ret.isNull() ? n : ret); |
90 |
4306 |
continue; |
91 |
|
} |
92 |
20259 |
theory::TheoryId tid = theory::Theory::theoryOf(node); |
93 |
20259 |
theory::TheoryRewriter* tr = rr->getTheoryRewriter(tid); |
94 |
|
|
95 |
20259 |
Assert(tr != NULL); |
96 |
40518 |
TrustNode trn = tr->expandDefinition(n); |
97 |
20259 |
if (!trn.isNull()) |
98 |
|
{ |
99 |
194 |
node = trn.getNode(); |
100 |
194 |
if (tpg != nullptr) |
101 |
|
{ |
102 |
|
tpg->addRewriteStep( |
103 |
|
n, node, trn.getGenerator(), true, PfRule::THEORY_EXPAND_DEF); |
104 |
|
} |
105 |
|
} |
106 |
|
else |
107 |
|
{ |
108 |
20065 |
node = n; |
109 |
|
} |
110 |
|
// the partial functions can fall through, in which case we still |
111 |
|
// consider their children |
112 |
60777 |
worklist.push(std::make_tuple( |
113 |
40518 |
Node(n), node, true)); // Original and rewritten result |
114 |
|
|
115 |
55731 |
for (size_t i = 0; i < node.getNumChildren(); ++i) |
116 |
|
{ |
117 |
35472 |
worklist.push( |
118 |
70944 |
std::make_tuple(node[i], |
119 |
|
node[i], |
120 |
|
false)); // Rewrite the children of the result only |
121 |
|
} |
122 |
|
} |
123 |
|
else |
124 |
|
{ |
125 |
|
// Working upwards |
126 |
|
// Reconstruct the node from it's (now rewritten) children on the stack |
127 |
|
|
128 |
20259 |
Debug("expand") << "cons : " << node << std::endl; |
129 |
20259 |
if (node.getNumChildren() > 0) |
130 |
|
{ |
131 |
|
// cout << "cons : " << node << std::endl; |
132 |
33432 |
NodeBuilder nb(node.getKind()); |
133 |
16716 |
if (node.getMetaKind() == metakind::PARAMETERIZED) |
134 |
|
{ |
135 |
1927 |
Debug("expand") << "op : " << node.getOperator() << std::endl; |
136 |
|
// cout << "op : " << node.getOperator() << std::endl; |
137 |
1927 |
nb << node.getOperator(); |
138 |
|
} |
139 |
52188 |
for (size_t i = 0, nchild = node.getNumChildren(); i < nchild; ++i) |
140 |
|
{ |
141 |
35472 |
Assert(!result.empty()); |
142 |
70944 |
Node expanded = result.top(); |
143 |
35472 |
result.pop(); |
144 |
|
// cout << "exchld : " << expanded << std::endl; |
145 |
35472 |
Debug("expand") << "exchld : " << expanded << std::endl; |
146 |
35472 |
nb << expanded; |
147 |
|
} |
148 |
16716 |
node = nb; |
149 |
|
} |
150 |
|
// Only cache once all subterms are expanded |
151 |
20259 |
cache[n] = n == node ? Node::null() : node; |
152 |
20259 |
result.push(node); |
153 |
|
} |
154 |
68338 |
} while (!worklist.empty()); |
155 |
|
|
156 |
12607 |
AlwaysAssert(result.size() == 1); |
157 |
|
|
158 |
25214 |
Node res = result.top(); |
159 |
|
|
160 |
12607 |
if (res == orig) |
161 |
|
{ |
162 |
12474 |
return TrustNode::null(); |
163 |
|
} |
164 |
133 |
return TrustNode::mkTrustRewrite(orig, res, tpg); |
165 |
|
} |
166 |
|
|
167 |
7989 |
void ExpandDefs::setProofNodeManager(ProofNodeManager* pnm) |
168 |
|
{ |
169 |
7989 |
if (d_tpg == nullptr) |
170 |
|
{ |
171 |
23967 |
d_tpg.reset(new TConvProofGenerator(pnm, |
172 |
7989 |
d_env.getUserContext(), |
173 |
|
TConvPolicy::FIXPOINT, |
174 |
|
TConvCachePolicy::NEVER, |
175 |
|
"ExpandDefs::TConvProofGenerator", |
176 |
|
nullptr, |
177 |
7989 |
true)); |
178 |
|
} |
179 |
7989 |
} |
180 |
|
|
181 |
|
} // namespace smt |
182 |
31137 |
} // namespace cvc5 |