1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Dejan Jovanovic, Clark Barrett, 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 |
|
* A substitution mapping for theory simplification. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/substitutions.h" |
17 |
|
#include "expr/node_algorithm.h" |
18 |
|
#include "theory/rewriter.h" |
19 |
|
|
20 |
|
using namespace std; |
21 |
|
|
22 |
|
namespace cvc5 { |
23 |
|
namespace theory { |
24 |
|
|
25 |
109020 |
SubstitutionMap::SubstitutionMap(context::Context* context) |
26 |
|
: d_context(), |
27 |
|
d_substitutions(context ? context : &d_context), |
28 |
|
d_substitutionCache(), |
29 |
|
d_cacheInvalidated(false), |
30 |
109020 |
d_cacheInvalidator(context ? context : &d_context, d_cacheInvalidated) |
31 |
|
{ |
32 |
109020 |
} |
33 |
|
|
34 |
13305925 |
struct substitution_stack_element { |
35 |
|
TNode d_node; |
36 |
|
bool d_children_added; |
37 |
3135029 |
substitution_stack_element(TNode node) : d_node(node), d_children_added(false) |
38 |
|
{ |
39 |
3135029 |
} |
40 |
|
};/* struct substitution_stack_element */ |
41 |
|
|
42 |
1721618 |
Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) { |
43 |
|
|
44 |
1721618 |
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << endl; |
45 |
|
|
46 |
1721618 |
if (d_substitutions.empty()) { |
47 |
1035141 |
return t; |
48 |
|
} |
49 |
|
|
50 |
|
// Do a topological sort of the subexpressions and substitute them |
51 |
1372954 |
vector<substitution_stack_element> toVisit; |
52 |
686477 |
toVisit.push_back((TNode) t); |
53 |
|
|
54 |
11058415 |
while (!toVisit.empty()) |
55 |
|
{ |
56 |
|
// The current node we are processing |
57 |
5185969 |
substitution_stack_element& stackHead = toVisit.back(); |
58 |
9847773 |
TNode current = stackHead.d_node; |
59 |
|
|
60 |
5185969 |
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): processing " << current << endl; |
61 |
|
|
62 |
|
// If node already in the cache we're done, pop from the stack |
63 |
5185969 |
NodeCache::iterator find = cache.find(current); |
64 |
5548942 |
if (find != cache.end()) { |
65 |
362973 |
toVisit.pop_back(); |
66 |
362973 |
continue; |
67 |
|
} |
68 |
|
|
69 |
4822996 |
NodeMap::iterator find2 = d_substitutions.find(current); |
70 |
4822996 |
if (find2 != d_substitutions.end()) { |
71 |
322384 |
Node rhs = (*find2).second; |
72 |
161192 |
Assert(rhs != current); |
73 |
161192 |
internalSubstitute(rhs, cache); |
74 |
161192 |
d_substitutions[current] = cache[rhs]; |
75 |
161192 |
cache[current] = cache[rhs]; |
76 |
161192 |
toVisit.pop_back(); |
77 |
161192 |
continue; |
78 |
|
} |
79 |
|
|
80 |
|
// Not yet substituted, so process |
81 |
4661804 |
if (stackHead.d_children_added) |
82 |
|
{ |
83 |
|
// Children have been processed, so substitute |
84 |
4101880 |
NodeBuilder builder(current.getKind()); |
85 |
2050940 |
if (current.getMetaKind() == kind::metakind::PARAMETERIZED) { |
86 |
202668 |
builder << Node(cache[current.getOperator()]); |
87 |
|
} |
88 |
6994078 |
for (unsigned i = 0; i < current.getNumChildren(); ++ i) { |
89 |
4943138 |
Assert(cache.find(current[i]) != cache.end()); |
90 |
4943138 |
builder << Node(cache[current[i]]); |
91 |
|
} |
92 |
|
// Mark the substitution and continue |
93 |
4101880 |
Node result = builder; |
94 |
2050940 |
if (result != current) { |
95 |
753668 |
find = cache.find(result); |
96 |
753668 |
if (find != cache.end()) { |
97 |
5350 |
result = find->second; |
98 |
|
} |
99 |
|
else { |
100 |
748318 |
find2 = d_substitutions.find(result); |
101 |
748318 |
if (find2 != d_substitutions.end()) { |
102 |
|
Node rhs = (*find2).second; |
103 |
|
Assert(rhs != result); |
104 |
|
internalSubstitute(rhs, cache); |
105 |
|
d_substitutions[result] = cache[rhs]; |
106 |
|
cache[result] = cache[rhs]; |
107 |
|
result = cache[rhs]; |
108 |
|
} |
109 |
|
} |
110 |
|
} |
111 |
2050940 |
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << result << endl; |
112 |
2050940 |
cache[current] = result; |
113 |
2050940 |
toVisit.pop_back(); |
114 |
|
} |
115 |
|
else |
116 |
|
{ |
117 |
|
// Mark that we have added the children if any |
118 |
2610864 |
if (current.getNumChildren() > 0 || current.getMetaKind() == kind::metakind::PARAMETERIZED) { |
119 |
2050940 |
stackHead.d_children_added = true; |
120 |
|
// We need to add the operator, if any |
121 |
2050940 |
if(current.getMetaKind() == kind::metakind::PARAMETERIZED) { |
122 |
405336 |
TNode opNode = current.getOperator(); |
123 |
202668 |
NodeCache::iterator opFind = cache.find(opNode); |
124 |
202668 |
if (opFind == cache.end()) { |
125 |
52717 |
toVisit.push_back(opNode); |
126 |
|
} |
127 |
|
} |
128 |
|
// We need to add the children |
129 |
6994078 |
for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) { |
130 |
9886276 |
TNode childNode = *child_it; |
131 |
4943138 |
NodeCache::iterator childFind = cache.find(childNode); |
132 |
4943138 |
if (childFind == cache.end()) { |
133 |
2395835 |
toVisit.push_back(childNode); |
134 |
|
} |
135 |
|
} |
136 |
|
} else { |
137 |
|
// No children, so we're done |
138 |
559924 |
Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << current << endl; |
139 |
559924 |
cache[current] = current; |
140 |
559924 |
toVisit.pop_back(); |
141 |
|
} |
142 |
|
} |
143 |
|
} |
144 |
|
|
145 |
|
// Return the substituted version |
146 |
686477 |
return cache[t]; |
147 |
|
}/* SubstitutionMap::internalSubstitute() */ |
148 |
|
|
149 |
|
|
150 |
1826372 |
void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache) |
151 |
|
{ |
152 |
1826372 |
Debug("substitution") << "SubstitutionMap::addSubstitution(" << x << ", " << t << ")" << endl; |
153 |
1826372 |
Assert(d_substitutions.find(x) == d_substitutions.end()); |
154 |
|
|
155 |
|
// this causes a later assert-fail (the rhs != current one, above) anyway |
156 |
|
// putting it here is easier to diagnose |
157 |
1826372 |
Assert(x != t) << "cannot substitute a term for itself"; |
158 |
|
|
159 |
1826372 |
d_substitutions[x] = t; |
160 |
|
|
161 |
|
// Also invalidate the cache if necessary |
162 |
1826372 |
if (invalidateCache) { |
163 |
1826260 |
d_cacheInvalidated = true; |
164 |
|
} |
165 |
|
else { |
166 |
112 |
d_substitutionCache[x] = d_substitutions[x]; |
167 |
|
} |
168 |
1826372 |
} |
169 |
|
|
170 |
|
|
171 |
7531 |
void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateCache) |
172 |
|
{ |
173 |
7531 |
SubstitutionMap::NodeMap::const_iterator it = subMap.begin(); |
174 |
7531 |
SubstitutionMap::NodeMap::const_iterator it_end = subMap.end(); |
175 |
93173 |
for (; it != it_end; ++ it) { |
176 |
42821 |
Assert(d_substitutions.find((*it).first) == d_substitutions.end()); |
177 |
42821 |
d_substitutions[(*it).first] = (*it).second; |
178 |
42821 |
if (!invalidateCache) { |
179 |
|
d_substitutionCache[(*it).first] = d_substitutions[(*it).first]; |
180 |
|
} |
181 |
|
} |
182 |
7531 |
if (invalidateCache) { |
183 |
7531 |
d_cacheInvalidated = true; |
184 |
|
} |
185 |
7531 |
} |
186 |
|
|
187 |
1560426 |
Node SubstitutionMap::apply(TNode t, bool doRewrite) { |
188 |
|
|
189 |
1560426 |
Debug("substitution") << "SubstitutionMap::apply(" << t << ")" << endl; |
190 |
|
|
191 |
|
// Setup the cache |
192 |
1560426 |
if (d_cacheInvalidated) { |
193 |
74918 |
d_substitutionCache.clear(); |
194 |
74918 |
d_cacheInvalidated = false; |
195 |
74918 |
Debug("substitution") << "-- reset the cache" << endl; |
196 |
|
} |
197 |
|
|
198 |
|
// Perform the substitution |
199 |
1560426 |
Node result = internalSubstitute(t, d_substitutionCache); |
200 |
1560426 |
Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl; |
201 |
|
|
202 |
1560426 |
if (doRewrite) |
203 |
|
{ |
204 |
960402 |
result = Rewriter::rewrite(result); |
205 |
|
} |
206 |
|
|
207 |
1560424 |
return result; |
208 |
|
} |
209 |
|
|
210 |
|
void SubstitutionMap::print(ostream& out) const { |
211 |
|
NodeMap::const_iterator it = d_substitutions.begin(); |
212 |
|
NodeMap::const_iterator it_end = d_substitutions.end(); |
213 |
|
for (; it != it_end; ++ it) { |
214 |
|
out << (*it).first << " -> " << (*it).second << endl; |
215 |
|
} |
216 |
|
} |
217 |
|
|
218 |
|
void SubstitutionMap::debugPrint() const { print(CVC5Message.getStream()); } |
219 |
|
|
220 |
|
} // namespace theory |
221 |
|
|
222 |
|
std::ostream& operator<<(std::ostream& out, const theory::SubstitutionMap::iterator& i) { |
223 |
|
return out << "[CDMap-iterator]"; |
224 |
|
} |
225 |
|
|
226 |
28191 |
} // namespace cvc5 |