1 /********************* */
4 ** Original author: Dejan Jovanovic
5 ** Major contributors: Morgan Deters
6 ** Minor contributors (to current version): Liana Hadarean, Clark Barrett
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2013 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
12 ** \brief [[ Add one-line brief description here ]]
14 ** [[ Add lengthier description here ]]
15 ** \todo document this file
18 #include "theory/theory.h"
19 #include "theory/rewriter.h"
20 #include "theory/rewriter_tables.h"
27 static TheoryId
theoryOf(TNode node
) {
28 return Theory::theoryOf(THEORY_OF_TYPE_BASED
, node
);
31 #ifdef CVC4_ASSERTIONS
32 static CVC4_THREADLOCAL(std::hash_set
<Node
, NodeHashFunction
>*) s_rewriteStack
= NULL
;
33 #endif /* CVC4_ASSERTIONS */
35 class RewriterInitializer
{
36 static RewriterInitializer s_rewriterInitializer
;
37 RewriterInitializer() { Rewriter::init(); }
38 ~RewriterInitializer() { Rewriter::shutdown(); }
39 };/* class RewriterInitializer */
42 * This causes initialization of the rewriter before first use,
43 * and tear-down at exit time.
45 RewriterInitializer
RewriterInitializer::s_rewriterInitializer
;
48 * TheoryEngine::rewrite() keeps a stack of things that are being pre-
49 * and post-rewritten. Each element of the stack is a
50 * RewriteStackElement.
52 struct RewriteStackElement
{
54 /** The node we're currently rewriting */
58 /** Id of the theory that's currently rewriting this node */
59 unsigned theoryId
: 8;
60 /** Id of the original theory that started the rewrite */
61 unsigned originalTheoryId
: 8;
62 /** Index of the child this node is done rewriting */
63 unsigned nextChild
: 32;
64 /** Builder for this node */
65 NodeBuilder
<> builder
;
68 * Construct a fresh stack element.
70 RewriteStackElement(TNode node
, TheoryId theoryId
) :
74 originalTheoryId(theoryId
),
79 Node
Rewriter::rewrite(TNode node
) {
80 return rewriteTo(theoryOf(node
), node
);
83 Node
Rewriter::rewriteTo(theory::TheoryId theoryId
, Node node
) {
85 #ifdef CVC4_ASSERTIONS
86 bool isEquality
= node
.getKind() == kind::EQUAL
;
88 if(s_rewriteStack
== NULL
) {
89 s_rewriteStack
= new std::hash_set
<Node
, NodeHashFunction
>();
93 Trace("rewriter") << "Rewriter::rewriteTo(" << theoryId
<< "," << node
<< ")"<< std::endl
;
95 // Check if it's been cached already
96 Node cached
= getPostRewriteCache(theoryId
, node
);
97 if (!cached
.isNull()) {
101 // Put the node on the stack in order to start the "recursive" rewrite
102 vector
<RewriteStackElement
> rewriteStack
;
103 rewriteStack
.push_back(RewriteStackElement(node
, theoryId
));
105 // Rewrite until the stack is empty
108 // Get the top of the recursion stack
109 RewriteStackElement
& rewriteStackTop
= rewriteStack
.back();
111 Trace("rewriter") << "Rewriter::rewriting: " << (TheoryId
) rewriteStackTop
.theoryId
<< "," << rewriteStackTop
.node
<< std::endl
;
113 // Before rewriting children we need to do a pre-rewrite of the node
114 if (rewriteStackTop
.nextChild
== 0) {
116 // Check if the pre-rewrite has already been done (it's in the cache)
117 Node cached
= Rewriter::getPreRewriteCache((TheoryId
) rewriteStackTop
.theoryId
, rewriteStackTop
.node
);
118 if (cached
.isNull()) {
119 // Rewrite until fix-point is reached
121 // Perform the pre-rewrite
122 RewriteResponse response
= Rewriter::callPreRewrite((TheoryId
) rewriteStackTop
.theoryId
, rewriteStackTop
.node
);
123 // Put the rewritten node to the top of the stack
124 rewriteStackTop
.node
= response
.node
;
125 TheoryId newTheory
= theoryOf(rewriteStackTop
.node
);
126 // In the pre-rewrite, if changing theories, we just call the other theories pre-rewrite
127 if (newTheory
== (TheoryId
) rewriteStackTop
.theoryId
&& response
.status
== REWRITE_DONE
) {
130 rewriteStackTop
.theoryId
= newTheory
;
133 Rewriter::setPreRewriteCache((TheoryId
) rewriteStackTop
.originalTheoryId
, rewriteStackTop
.original
, rewriteStackTop
.node
);
135 // Otherwise we're have already been pre-rewritten (in pre-rewrite cache)
137 // Continue with the cached version
138 rewriteStackTop
.node
= cached
;
139 rewriteStackTop
.theoryId
= theoryOf(cached
);
143 rewriteStackTop
.original
=rewriteStackTop
.node
;
144 // Now it's time to rewrite the children, check if this has already been done
145 Node cached
= Rewriter::getPostRewriteCache((TheoryId
) rewriteStackTop
.theoryId
, rewriteStackTop
.node
);
146 // If not, go through the children
147 if(cached
.isNull()) {
149 // The child we need to rewrite
150 unsigned child
= rewriteStackTop
.nextChild
++;
152 // To build the rewritten expression we set up the builder
154 if (rewriteStackTop
.node
.getNumChildren() > 0) {
155 // The children will add themselves to the builder once they're done
156 rewriteStackTop
.builder
<< rewriteStackTop
.node
.getKind();
157 kind::MetaKind metaKind
= rewriteStackTop
.node
.getMetaKind();
158 if (metaKind
== kind::metakind::PARAMETERIZED
) {
159 rewriteStackTop
.builder
<< rewriteStackTop
.node
.getOperator();
164 // Process the next child
165 if(child
< rewriteStackTop
.node
.getNumChildren()) {
167 Node childNode
= rewriteStackTop
.node
[child
];
168 // Push the rewrite request to the stack (NOTE: rewriteStackTop might be a bad reference now)
169 rewriteStack
.push_back(RewriteStackElement(childNode
, theoryOf(childNode
)));
170 // Go on with the rewriting
174 // Incorporate the children if necessary
175 if (rewriteStackTop
.node
.getNumChildren() > 0) {
176 rewriteStackTop
.node
= rewriteStackTop
.builder
;
177 rewriteStackTop
.theoryId
= theoryOf(rewriteStackTop
.node
);
180 // Done with all pre-rewriting, so let's do the post rewrite
182 // Do the post-rewrite
183 RewriteResponse response
= Rewriter::callPostRewrite((TheoryId
) rewriteStackTop
.theoryId
, rewriteStackTop
.node
);
184 // We continue with the response we got
185 TheoryId newTheoryId
= theoryOf(response
.node
);
186 if (newTheoryId
!= (TheoryId
) rewriteStackTop
.theoryId
|| response
.status
== REWRITE_AGAIN_FULL
) {
187 // In the post rewrite if we've changed theories, we must do a full rewrite
188 Assert(response
.node
!= rewriteStackTop
.node
);
189 //TODO: this is not thread-safe - should make this assertion dependent on sequential build
190 #ifdef CVC4_ASSERTIONS
191 Assert(s_rewriteStack
->find(response
.node
) == s_rewriteStack
->end());
192 s_rewriteStack
->insert(response
.node
);
194 rewriteStackTop
.node
= rewriteTo(newTheoryId
, response
.node
);
195 #ifdef CVC4_ASSERTIONS
196 s_rewriteStack
->erase(response
.node
);
199 } else if (response
.status
== REWRITE_DONE
) {
200 #ifdef CVC4_ASSERTIONS
201 RewriteResponse r2
= Rewriter::callPostRewrite(newTheoryId
, response
.node
);
202 Assert(r2
.node
== response
.node
);
204 rewriteStackTop
.node
= response
.node
;
207 // Check for trivial rewrite loops of size 1 or 2
208 Assert(response
.node
!= rewriteStackTop
.node
);
209 Assert(Rewriter::callPostRewrite((TheoryId
) rewriteStackTop
.theoryId
, response
.node
).node
!= rewriteStackTop
.node
);
210 rewriteStackTop
.node
= response
.node
;
212 // We're done with the post rewrite, so we add to the cache
213 Rewriter::setPostRewriteCache((TheoryId
) rewriteStackTop
.originalTheoryId
, rewriteStackTop
.original
, rewriteStackTop
.node
);
216 // We were already in cache, so just remember it
217 rewriteStackTop
.node
= cached
;
218 rewriteStackTop
.theoryId
= theoryOf(cached
);
221 // If this is the last node, just return
222 if (rewriteStack
.size() == 1) {
223 Assert(!isEquality
|| rewriteStackTop
.node
.getKind() == kind::EQUAL
|| rewriteStackTop
.node
.isConst());
224 return rewriteStackTop
.node
;
227 // We're done with this node, append it to the parent
228 rewriteStack
[rewriteStack
.size() - 2].builder
<< rewriteStackTop
.node
;
229 rewriteStack
.pop_back();
234 }/* Rewriter::rewriteTo() */
236 }/* CVC4::theory namespace */
237 }/* CVC4 namespace */