1 /********************* */
2 /*! \file substitutions.cpp
4 ** Original author: dejan
5 ** Major contributors: none
6 ** Minor contributors (to current version): none
7 ** This file is part of the CVC4 prototype.
8 ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
9 ** Courant Institute of Mathematical Sciences
10 ** New York University
11 ** See the file COPYING in the top-level source directory for licensing
12 ** information.\endverbatim
14 ** \brief A substitution mapping for theory simplification
16 ** A substitution mapping for theory simplification.
19 #include "theory/substitutions.h"
20 #include "theory/rewriter.h"
27 struct substitution_stack_element
{
30 substitution_stack_element(TNode node
)
31 : node(node
), children_added(false) {}
34 Node
SubstitutionMap::internalSubstitute(TNode t
, NodeCache
& substitutionCache
) {
36 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< ")" << std::endl
;
38 // If nothing to substitute just return the node
39 if (substitutionCache
.empty()) {
43 // Do a topological sort of the subexpressions and substitute them
44 vector
<substitution_stack_element
> toVisit
;
45 toVisit
.push_back((TNode
) t
);
47 while (!toVisit
.empty())
49 // The current node we are processing
50 substitution_stack_element
& stackHead
= toVisit
.back();
51 TNode current
= stackHead
.node
;
53 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< "): processing " << current
<< std::endl
;
55 // If node already in the cache we're done, pop from the stack
56 NodeCache::iterator find
= substitutionCache
.find(current
);
57 if (find
!= substitutionCache
.end()) {
62 // Not yet substituted, so process
63 if (stackHead
.children_added
) {
64 // Children have been processed, so substitute
65 NodeBuilder
<> builder(current
.getKind());
66 if (current
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
67 builder
<< current
.getOperator();
69 for (unsigned i
= 0; i
< current
.getNumChildren(); ++ i
) {
70 Assert(substitutionCache
.find(current
[i
]) != substitutionCache
.end());
71 builder
<< Node(substitutionCache
[current
[i
]]);
73 // Mark the substitution and continue
74 Node result
= builder
;
75 find
= substitutionCache
.find(result
);
76 if (find
!= substitutionCache
.end()) {
77 result
= find
->second
;
79 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< "): setting " << current
<< " -> " << result
<< std::endl
;
80 substitutionCache
[current
] = result
;
83 // Mark that we have added the children if any
84 if (current
.getNumChildren() > 0) {
85 stackHead
.children_added
= true;
86 // We need to add the children
87 for(TNode::iterator child_it
= current
.begin(); child_it
!= current
.end(); ++ child_it
) {
88 TNode childNode
= *child_it
;
89 NodeCache::iterator childFind
= substitutionCache
.find(childNode
);
90 if (childFind
== substitutionCache
.end()) {
91 toVisit
.push_back(childNode
);
95 // No children, so we're done
96 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< "): setting " << current
<< " -> " << current
<< std::endl
;
97 substitutionCache
[current
] = current
;
103 // Return the substituted version
104 return substitutionCache
[t
];
108 void SubstitutionMap::simplifyRHS(const SubstitutionMap
& subMap
)
110 // Put the new substitutions into the old ones
111 NodeMap::iterator it
= d_substitutions
.begin();
112 NodeMap::iterator it_end
= d_substitutions
.end();
113 for(; it
!= it_end
; ++ it
) {
114 d_substitutions
[(*it
).first
] = subMap
.apply((*it
).second
);
119 void SubstitutionMap::simplifyRHS(TNode x
, TNode t
) {
120 // Temporary substitution cache
124 // Put the new substitution into the old ones
125 NodeMap::iterator it
= d_substitutions
.begin();
126 NodeMap::iterator it_end
= d_substitutions
.end();
127 for(; it
!= it_end
; ++ it
) {
128 d_substitutions
[(*it
).first
] = internalSubstitute((*it
).second
, tempCache
);
133 /* We use subMap to simplify the left-hand sides of the current substitution map. If rewrite is true,
134 * we also apply the rewriter to the result.
135 * We want to maintain the invariant that all lhs are distinct from each other and from all rhs.
136 * If for some l -> r, l reduces to l', we try to add a new rule l' -> r. There are two cases
138 * (i) if l' is equal to some ll (in a rule ll -> rr), then if r != rr we add (r,rr) to the equation list
139 * (i) if l' is equalto some rr (in a rule ll -> rr), then if r != rr we add (r,rr) to the equation list
141 void SubstitutionMap::simplifyLHS(const SubstitutionMap
& subMap
, vector
<pair
<Node
, Node
> >& equalities
, bool rewrite
)
143 Assert(d_worklist
.empty());
144 // First, apply subMap to every LHS in d_substitutions
145 NodeMap::iterator it
= d_substitutions
.begin();
146 NodeMap::iterator it_end
= d_substitutions
.end();
148 for(; it
!= it_end
; ++ it
) {
149 newLeft
= subMap
.apply((*it
).first
);
150 if (newLeft
!= (*it
).first
) {
152 newLeft
= Rewriter::rewrite(newLeft
);
154 d_worklist
.push_back(pair
<Node
,Node
>(newLeft
, (*it
).second
));
157 processWorklist(equalities
, rewrite
);
158 Assert(d_worklist
.empty());
162 void SubstitutionMap::simplifyLHS(TNode lhs
, TNode rhs
, vector
<pair
<Node
,Node
> >& equalities
, bool rewrite
)
164 Assert(d_worklist
.empty());
165 d_worklist
.push_back(pair
<Node
,Node
>(lhs
,rhs
));
166 processWorklist(equalities
, rewrite
);
167 Assert(d_worklist
.empty());
171 void SubstitutionMap::processWorklist(vector
<pair
<Node
, Node
> >& equalities
, bool rewrite
)
173 // Add each new rewrite rule, taking care not to invalidate invariants and looking
174 // for any new rewrite rules we can learn
175 Node newLeft
, newRight
;
176 while (!d_worklist
.empty()) {
177 newLeft
= d_worklist
.back().first
;
178 newRight
= d_worklist
.back().second
;
179 d_worklist
.pop_back();
182 tempCache
[newLeft
] = newRight
;
185 unsigned size
= d_worklist
.size();
186 bool addThisRewrite
= true;
187 NodeMap::iterator it
= d_substitutions
.begin();
188 NodeMap::iterator it_end
= d_substitutions
.end();
190 for(; it
!= it_end
; ++ it
) {
192 // Check for invariant violation. If new rewrite is redundant, do nothing
193 // Otherwise, add an equality to the output equalities
194 // In either case undo any work done by this rewrite
195 if (newLeft
== (*it
).first
|| newLeft
== (*it
).second
) {
196 if ((*it
).second
!= newRight
) {
197 equalities
.push_back(pair
<Node
,Node
>((*it
).second
, newRight
));
199 while (d_worklist
.size() > size
) {
200 d_worklist
.pop_back();
202 addThisRewrite
= false;
206 newLeft2
= internalSubstitute((*it
).first
, tempCache
);
207 if (newLeft2
!= (*it
).first
) {
209 newLeft2
= Rewriter::rewrite(newLeft2
);
211 d_worklist
.push_back(pair
<Node
,Node
>(newLeft2
, (*it
).second
));
214 if (addThisRewrite
) {
215 d_substitutions
[newLeft
] = newRight
;
216 d_cacheInvalidated
= true;
222 void SubstitutionMap::addSubstitution(TNode x
, TNode t
, bool invalidateCache
, bool backSub
, bool forwardSub
) {
223 Debug("substitution") << "SubstitutionMap::addSubstitution(" << x
<< ", " << t
<< ")" << std::endl
;
224 Assert(d_substitutions
.find(x
) == d_substitutions
.end());
230 // Put the new substitution in
231 d_substitutions
[x
] = forwardSub
? apply(t
) : Node(t
);
233 // Also invalidate the cache if necessary
234 if (invalidateCache
) {
235 d_cacheInvalidated
= true;
238 d_substitutionCache
[x
] = d_substitutions
[x
];
242 static bool check(TNode node
, const SubstitutionMap::NodeMap
& substitutions
) CVC4_UNUSED
;
243 static bool check(TNode node
, const SubstitutionMap::NodeMap
& substitutions
) {
244 SubstitutionMap::NodeMap::const_iterator it
= substitutions
.begin();
245 SubstitutionMap::NodeMap::const_iterator it_end
= substitutions
.end();
246 Debug("substitution") << "checking " << node
<< std::endl
;
247 for (; it
!= it_end
; ++ it
) {
248 Debug("substitution") << "-- hasSubterm( " << (*it
).first
<< " ) ?" << std::endl
;
249 if (node
.hasSubterm((*it
).first
)) {
250 Debug("substitution") << "-- FAIL" << std::endl
;
254 Debug("substitution") << "-- SUCCEED" << std::endl
;
258 Node
SubstitutionMap::apply(TNode t
) {
260 Debug("substitution") << "SubstitutionMap::apply(" << t
<< ")" << std::endl
;
263 if (d_cacheInvalidated
) {
264 SubstitutionMap::NodeMap::const_iterator it
= d_substitutions
.begin();
265 SubstitutionMap::NodeMap::const_iterator it_end
= d_substitutions
.end();
266 d_substitutionCache
.clear();
267 for (; it
!= it_end
; ++ it
) {
268 d_substitutionCache
[(*it
).first
] = (*it
).second
;
270 d_cacheInvalidated
= false;
271 Debug("substitution") << "-- reset the cache" << std::endl
;
274 // Perform the substitution
275 Node result
= internalSubstitute(t
, d_substitutionCache
);
276 Debug("substitution") << "SubstitutionMap::apply(" << t
<< ") => " << result
<< std::endl
;
278 // Assert(check(result, d_substitutions));
283 void SubstitutionMap::print(ostream
& out
) const {
284 NodeMap::const_iterator it
= d_substitutions
.begin();
285 NodeMap::const_iterator it_end
= d_substitutions
.end();
286 for (; it
!= it_end
; ++ it
) {
287 out
<< (*it
).first
<< " -> " << (*it
).second
<< endl
;
291 void SubstitutionMap::debugPrint() const {
295 }/* CVC4::theory namespace */
297 std::ostream
& operator<<(std::ostream
& out
, const theory::SubstitutionMap::iterator
& i
) {
298 return out
<< "[CDMap-iterator]";
301 }/* CVC4 namespace */