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 |
|
* [[ Add lengthier description here ]] |
14 |
|
* \todo document this file |
15 |
|
*/ |
16 |
|
|
17 |
|
#include "theory/term_registration_visitor.h" |
18 |
|
|
19 |
|
#include "base/configuration.h" |
20 |
|
#include "options/quantifiers_options.h" |
21 |
|
#include "smt/logic_exception.h" |
22 |
|
#include "theory/theory_engine.h" |
23 |
|
|
24 |
|
using namespace cvc5::theory; |
25 |
|
|
26 |
|
namespace cvc5 { |
27 |
|
|
28 |
|
std::string PreRegisterVisitor::toString() const { |
29 |
|
std::stringstream ss; |
30 |
|
TNodeToTheorySetMap::const_iterator it = d_visited.begin(); |
31 |
|
for (; it != d_visited.end(); ++ it) { |
32 |
|
ss << (*it).first << ": " << TheoryIdSetUtil::setToString((*it).second) |
33 |
|
<< std::endl; |
34 |
|
} |
35 |
|
return ss.str(); |
36 |
|
} |
37 |
|
|
38 |
|
/** |
39 |
|
* Return true if we already visited the term current with the given parent, |
40 |
|
* assuming that the set of theories in visitedTheories has already processed |
41 |
|
* current. This method is used by PreRegisterVisitor and SharedTermsVisitor |
42 |
|
* below. |
43 |
|
*/ |
44 |
7584909 |
bool isAlreadyVisited(Env& env, |
45 |
|
TheoryIdSet visitedTheories, |
46 |
|
TNode current, |
47 |
|
TNode parent) |
48 |
|
{ |
49 |
7584909 |
TheoryId currentTheoryId = Theory::theoryOf(current); |
50 |
7584909 |
if (!TheoryIdSetUtil::setContains(currentTheoryId, visitedTheories)) |
51 |
|
{ |
52 |
|
// current theory not visited, return false |
53 |
|
return false; |
54 |
|
} |
55 |
|
|
56 |
7584909 |
if (current == parent) |
57 |
|
{ |
58 |
|
// top-level and current visited, return true |
59 |
1218857 |
return true; |
60 |
|
} |
61 |
|
|
62 |
|
// The current theory has already visited it, so now it depends on the parent |
63 |
|
// and the type |
64 |
6366052 |
TheoryId parentTheoryId = Theory::theoryOf(parent); |
65 |
6366052 |
if (!TheoryIdSetUtil::setContains(parentTheoryId, visitedTheories)) |
66 |
|
{ |
67 |
|
// parent theory not visited, return false |
68 |
111247 |
return false; |
69 |
|
} |
70 |
|
|
71 |
|
// do we need to consider the type? |
72 |
12509610 |
TypeNode type = current.getType(); |
73 |
6254805 |
if (currentTheoryId == parentTheoryId && !env.isFiniteType(type)) |
74 |
|
{ |
75 |
|
// current and parent are the same theory, and we are infinite, return true |
76 |
3730180 |
return true; |
77 |
|
} |
78 |
2524625 |
TheoryId typeTheoryId = Theory::theoryOf(type); |
79 |
2524625 |
return TheoryIdSetUtil::setContains(typeTheoryId, visitedTheories); |
80 |
|
} |
81 |
|
|
82 |
15273 |
PreRegisterVisitor::PreRegisterVisitor(Env& env, TheoryEngine* engine) |
83 |
15273 |
: EnvObj(env), d_engine(engine), d_visited(context()) |
84 |
|
{ |
85 |
15273 |
} |
86 |
|
|
87 |
1629470 |
bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) { |
88 |
|
|
89 |
1629470 |
Debug("register::internal") << "PreRegisterVisitor::alreadyVisited(" << current << "," << parent << ")" << std::endl; |
90 |
|
|
91 |
3258940 |
if ((parent.isClosure() |
92 |
1615321 |
|| parent.getKind() == kind::SEP_STAR |
93 |
1615321 |
|| parent.getKind() == kind::SEP_WAND |
94 |
3244791 |
|| (parent.getKind() == kind::SEP_LABEL && current.getType().isBoolean()) |
95 |
|
) |
96 |
3273089 |
&& current != parent) |
97 |
|
{ |
98 |
5680 |
Debug("register::internal") << "quantifier:true" << std::endl; |
99 |
5680 |
return true; |
100 |
|
} |
101 |
|
|
102 |
|
// Get the theories that have already visited this node |
103 |
1623790 |
TNodeToTheorySetMap::iterator find = d_visited.find(current); |
104 |
1623790 |
if (find == d_visited.end()) { |
105 |
|
// not visited at all, return false |
106 |
873890 |
return false; |
107 |
|
} |
108 |
|
|
109 |
749900 |
TheoryIdSet visitedTheories = (*find).second; |
110 |
749900 |
return isAlreadyVisited(d_env, visitedTheories, current, parent); |
111 |
|
} |
112 |
|
|
113 |
361213 |
void PreRegisterVisitor::visit(TNode current, TNode parent) { |
114 |
|
|
115 |
361213 |
Debug("register") << "PreRegisterVisitor::visit(" << current << "," << parent << ")" << std::endl; |
116 |
361213 |
if (Debug.isOn("register::internal")) { |
117 |
|
Debug("register::internal") << toString() << std::endl; |
118 |
|
} |
119 |
|
|
120 |
|
// get the theories we already preregistered with |
121 |
361213 |
TheoryIdSet visitedTheories = d_visited[current]; |
122 |
|
|
123 |
|
// call the preregistration on current, parent or type theories and update |
124 |
|
// visitedTheories. The set of preregistering theories coincides with |
125 |
|
// visitedTheories here. |
126 |
361214 |
preRegister( |
127 |
|
d_env, d_engine, visitedTheories, current, parent, visitedTheories); |
128 |
|
|
129 |
722424 |
Debug("register::internal") |
130 |
361212 |
<< "PreRegisterVisitor::visit(" << current << "," << parent |
131 |
361212 |
<< "): now registered with " |
132 |
361212 |
<< TheoryIdSetUtil::setToString(visitedTheories) << std::endl; |
133 |
|
// update the theories set for current |
134 |
361212 |
d_visited[current] = visitedTheories; |
135 |
361212 |
Assert(d_visited.find(current) != d_visited.end()); |
136 |
361212 |
Assert(alreadyVisited(current, parent)); |
137 |
361212 |
} |
138 |
|
|
139 |
6234429 |
void PreRegisterVisitor::preRegister(Env& env, |
140 |
|
TheoryEngine* te, |
141 |
|
TheoryIdSet& visitedTheories, |
142 |
|
TNode current, |
143 |
|
TNode parent, |
144 |
|
TheoryIdSet preregTheories) |
145 |
|
{ |
146 |
|
// Preregister with the current theory, if necessary |
147 |
6234429 |
TheoryId currentTheoryId = Theory::theoryOf(current); |
148 |
6234433 |
preRegisterWithTheory( |
149 |
|
te, visitedTheories, currentTheoryId, current, parent, preregTheories); |
150 |
|
|
151 |
6234425 |
if (current != parent) |
152 |
|
{ |
153 |
|
// preregister with parent theory, if necessary |
154 |
5017123 |
TheoryId parentTheoryId = Theory::theoryOf(parent); |
155 |
5017123 |
preRegisterWithTheory( |
156 |
|
te, visitedTheories, parentTheoryId, current, parent, preregTheories); |
157 |
|
|
158 |
|
// Note that if enclosed by different theories it's shared, for example, |
159 |
|
// in read(a, f(a)), f(a) should be shared with integers. |
160 |
10034246 |
TypeNode type = current.getType(); |
161 |
5017123 |
if (currentTheoryId != parentTheoryId || env.isFiniteType(type)) |
162 |
|
{ |
163 |
|
// preregister with the type's theory, if necessary |
164 |
1828536 |
TheoryId typeTheoryId = Theory::theoryOf(type); |
165 |
1828536 |
preRegisterWithTheory( |
166 |
|
te, visitedTheories, typeTheoryId, current, parent, preregTheories); |
167 |
|
} |
168 |
|
} |
169 |
6234425 |
} |
170 |
13080088 |
void PreRegisterVisitor::preRegisterWithTheory(TheoryEngine* te, |
171 |
|
TheoryIdSet& visitedTheories, |
172 |
|
TheoryId id, |
173 |
|
TNode current, |
174 |
|
TNode parent, |
175 |
|
TheoryIdSet preregTheories) |
176 |
|
{ |
177 |
13080088 |
if (TheoryIdSetUtil::setContains(id, visitedTheories)) |
178 |
|
{ |
179 |
|
// already visited |
180 |
5460309 |
return; |
181 |
|
} |
182 |
7619779 |
visitedTheories = TheoryIdSetUtil::setInsert(id, visitedTheories); |
183 |
7619779 |
if (TheoryIdSetUtil::setContains(id, preregTheories)) |
184 |
|
{ |
185 |
|
// already pregregistered |
186 |
5349142 |
return; |
187 |
|
} |
188 |
2270637 |
if (Configuration::isAssertionBuild()) |
189 |
|
{ |
190 |
4541274 |
Debug("register::internal") |
191 |
2270637 |
<< "PreRegisterVisitor::visit(" << current << "," << parent |
192 |
2270637 |
<< "): adding " << id << std::endl; |
193 |
|
// This should never throw an exception, since theories should be |
194 |
|
// guaranteed to be initialized. |
195 |
2270637 |
if (!te->isTheoryEnabled(id)) |
196 |
|
{ |
197 |
|
const LogicInfo& l = te->getLogicInfo(); |
198 |
|
LogicInfo newLogicInfo = l.getUnlockedCopy(); |
199 |
|
newLogicInfo.enableTheory(id); |
200 |
|
newLogicInfo.lock(); |
201 |
|
std::stringstream ss; |
202 |
|
ss << "The logic was specified as " << l.getLogicString() |
203 |
|
<< ", which doesn't include " << id |
204 |
|
<< ", but found a term in that theory." << std::endl |
205 |
|
<< "You might want to extend your logic to " |
206 |
|
<< newLogicInfo.getLogicString() << std::endl; |
207 |
|
throw LogicException(ss.str()); |
208 |
|
} |
209 |
|
} |
210 |
|
// call the theory's preRegisterTerm method |
211 |
2270637 |
Theory* th = te->theoryOf(id); |
212 |
2270641 |
th->preRegisterTerm(current); |
213 |
|
} |
214 |
|
|
215 |
211956 |
void PreRegisterVisitor::start(TNode node) {} |
216 |
|
|
217 |
15273 |
SharedTermsVisitor::SharedTermsVisitor(Env& env, |
218 |
|
TheoryEngine* te, |
219 |
15273 |
SharedTermsDatabase& sharedTerms) |
220 |
|
: EnvObj(env), |
221 |
|
d_engine(te), |
222 |
|
d_sharedTerms(sharedTerms), |
223 |
15273 |
d_preregistered(context()) |
224 |
|
{ |
225 |
15273 |
} |
226 |
|
|
227 |
|
std::string SharedTermsVisitor::toString() const { |
228 |
|
std::stringstream ss; |
229 |
|
TNodeVisitedMap::const_iterator it = d_visited.begin(); |
230 |
|
for (; it != d_visited.end(); ++ it) { |
231 |
|
ss << (*it).first << ": " << TheoryIdSetUtil::setToString((*it).second) |
232 |
|
<< std::endl; |
233 |
|
} |
234 |
|
return ss.str(); |
235 |
|
} |
236 |
|
|
237 |
23707427 |
bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const { |
238 |
|
|
239 |
23707427 |
Debug("register::internal") << "SharedTermsVisitor::alreadyVisited(" << current << "," << parent << ")" << std::endl; |
240 |
|
|
241 |
47414854 |
if ((parent.isClosure() |
242 |
23548370 |
|| parent.getKind() == kind::SEP_STAR |
243 |
23547705 |
|| parent.getKind() == kind::SEP_WAND |
244 |
47255003 |
|| (parent.getKind() == kind::SEP_LABEL && current.getType().isBoolean()) |
245 |
|
) |
246 |
47577501 |
&& current != parent) |
247 |
|
{ |
248 |
69130 |
Debug("register::internal") << "quantifier:true" << std::endl; |
249 |
69130 |
return true; |
250 |
|
} |
251 |
23638297 |
TNodeVisitedMap::const_iterator find = d_visited.find(current); |
252 |
|
// If node is not visited at all, just return false |
253 |
23638297 |
if (find == d_visited.end()) { |
254 |
16803288 |
Debug("register::internal") << "1:false" << std::endl; |
255 |
16803288 |
return false; |
256 |
|
} |
257 |
|
|
258 |
6835009 |
TheoryIdSet visitedTheories = (*find).second; |
259 |
6835009 |
return isAlreadyVisited(d_env, visitedTheories, current, parent); |
260 |
|
} |
261 |
|
|
262 |
5873216 |
void SharedTermsVisitor::visit(TNode current, TNode parent) { |
263 |
|
|
264 |
5873216 |
Debug("register") << "SharedTermsVisitor::visit(" << current << "," << parent << ")" << std::endl; |
265 |
5873216 |
if (Debug.isOn("register::internal")) { |
266 |
|
Debug("register::internal") << toString() << std::endl; |
267 |
|
} |
268 |
5873216 |
TheoryIdSet visitedTheories = d_visited[current]; |
269 |
5873216 |
TheoryIdSet preregTheories = d_preregistered[current]; |
270 |
|
|
271 |
|
// preregister the term with the current, parent or type theories, as needed |
272 |
5873219 |
PreRegisterVisitor::preRegister( |
273 |
|
d_env, d_engine, visitedTheories, current, parent, preregTheories); |
274 |
|
|
275 |
|
// Record the new theories that we visited |
276 |
5873213 |
d_visited[current] = visitedTheories; |
277 |
|
|
278 |
|
// add visited theories to those who have preregistered |
279 |
5873213 |
d_preregistered[current] = |
280 |
11746426 |
TheoryIdSetUtil::setUnion(preregTheories, visitedTheories); |
281 |
|
|
282 |
|
// If there is more than two theories and a new one has been added notify the shared terms database |
283 |
5873213 |
TheoryId currentTheoryId = Theory::theoryOf(current); |
284 |
11746426 |
if (TheoryIdSetUtil::setDifference( |
285 |
5873213 |
visitedTheories, TheoryIdSetUtil::setInsert(currentTheoryId))) |
286 |
|
{ |
287 |
1397679 |
d_sharedTerms.addSharedTerm(d_atom, current, visitedTheories); |
288 |
|
} |
289 |
|
|
290 |
5873213 |
Assert(d_visited.find(current) != d_visited.end()); |
291 |
5873213 |
Assert(alreadyVisited(current, parent)); |
292 |
5873213 |
} |
293 |
|
|
294 |
1006905 |
void SharedTermsVisitor::start(TNode node) { |
295 |
1006905 |
d_visited.clear(); |
296 |
1006905 |
d_atom = node; |
297 |
1006905 |
} |
298 |
|
|
299 |
1006902 |
void SharedTermsVisitor::done(TNode node) { |
300 |
1006902 |
clear(); |
301 |
1006902 |
} |
302 |
|
|
303 |
1006902 |
void SharedTermsVisitor::clear() { |
304 |
1006902 |
d_atom = TNode(); |
305 |
1006902 |
d_visited.clear(); |
306 |
1006902 |
} |
307 |
|
|
308 |
31137 |
} // namespace cvc5 |