return substitutionCache[t];
}
-void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache) {
+void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache, bool backSub, bool forwardSub) {
Debug("substitution") << "SubstitutionMap::addSubstitution(" << x << ", " << t << ")" << std::endl;
Assert(d_substitutions.find(x) == d_substitutions.end());
- // Temporary substitution cache
- NodeCache tempCache;
- tempCache[x] = t;
+ if (backSub) {
+ // Temporary substitution cache
+ NodeCache tempCache;
+ tempCache[x] = t;
- // Put in the new substitutions into the old ones
- NodeMap::iterator it = d_substitutions.begin();
- NodeMap::iterator it_end = d_substitutions.end();
- for(; it != it_end; ++ it) {
- d_substitutions[(*it).first] = internalSubstitute((*it).second, tempCache);
+ // Put in the new substitutions into the old ones
+ NodeMap::iterator it = d_substitutions.begin();
+ NodeMap::iterator it_end = d_substitutions.end();
+ for(; it != it_end; ++ it) {
+ d_substitutions[(*it).first] = internalSubstitute((*it).second, tempCache);
+ }
}
- // Put the new substitution in, but apply existing substitutions to rhs first
- d_substitutions[x] = apply(t);
+ // Put the new substitution in
+ d_substitutions[x] = forwardSub ? apply(t) : Node(t);
- // Also invalidate the cache
+ // Also invalidate the cache if necessary
if (invalidateCache) {
d_cacheInvalidated = true;
}
}
/**
- * Adds a substitution from x to t
+ * Adds a substitution from x to t. Typically you also want to apply this
+ * substitution to the existing set (backSub), but you do not need to
+ * apply the existing set to the new substitution (forwardSub). However,
+ * the method allows you to do either. Probably you should not do both,
+ * as it will be very difficult to maintain the invariant that no
+ * left-hand side appears on any right-hand side.
*/
- void addSubstitution(TNode x, TNode t, bool invalidateCache = true);
+ void addSubstitution(TNode x, TNode t,
+ bool invalidateCache = true,
+ bool backSub = true,
+ bool forwardSub = false);
/**
* Returns true iff x is in the substitution map
for ( ; it != iend; ++it) {
workList.push_back(*it);
}
- TNode current = workList.back();
Node currentSub;
- workList.pop_back();
+ TNode parent;
+ bool swap;
+ bool isSigned;
+ bool strict;
+ vector<TNode> delayQueueLeft;
+ vector<TNode> delayQueueRight;
+ TNode current = workList.back();
+ workList.pop_back();
for (;;) {
- TNodeMap::iterator itNodeMap;
Assert(d_visitedOnce.find(current) != d_visitedOnce.end());
- TNode parent = d_visitedOnce[current];
- bool swap = false;
- bool isSigned = false;
- bool strict = false;
+ parent = d_visitedOnce[current];
if (!parent.isNull()) {
+ swap = isSigned = strict = false;
switch (parent.getKind()) {
// If-then-else operator - any two unconstrained children makes the parent unconstrained
!d_substitutions.hasSubstitution(parent)) {
removeExpr(parent);
if (uThen) {
- if (parent[1] != current || currentSub.isNull()) {
- currentSub = parent[1];
+ if (parent[1] != current) {
+ if (parent[1].isVar()) {
+ currentSub = parent[1];
+ }
+ else {
+ Assert(d_substitutions.hasSubstitution(parent[1]));
+ currentSub = d_substitutions.apply(parent[1]);
+ }
+ }
+ else if (currentSub.isNull()) {
+ currentSub = current;
+ }
+ }
+ else if (parent[2] != current) {
+ if (parent[2].isVar()) {
+ currentSub = parent[2];
+ }
+ else {
+ Assert(d_substitutions.hasSubstitution(parent[2]));
+ currentSub = d_substitutions.apply(parent[2]);
}
}
- else if (parent[2] != current || currentSub.isNull()) {
- currentSub = parent[2];
+ else if (currentSub.isNull()) {
+ currentSub = current;
}
current = parent;
}
if (d_unconstrained.find(parent) == d_unconstrained.end() &&
!d_substitutions.hasSubstitution(parent)) {
removeExpr(parent);
- if (parent[0] != current || currentSub.isNull()) {
- currentSub = parent[0];
+ if (parent[0] != current) {
+ Assert(d_substitutions.hasSubstitution(parent[0]));
+ currentSub = d_substitutions.apply(parent[0]);
+ }
+ else if (currentSub.isNull()) {
+ currentSub = current;
}
current = parent;
}
else {
currentSub = currentSub.orNode(test);
}
+ // Delay adding this substitution - see comment at end of function
+ delayQueueLeft.push_back(current);
+ delayQueueRight.push_back(currentSub);
+ currentSub = Node();
parent = TNode();
}
break;
}
}
if (!currentSub.isNull()) {
- d_substitutions.addSubstitution(current, currentSub);
+ Assert(currentSub.isVar());
+ d_substitutions.addSubstitution(current, currentSub, false, false, false);
}
if (workList.empty()) {
break;
currentSub = Node();
workList.pop_back();
}
+ TNode left;
+ Node right;
+ // All substitutions except those arising from bitvector comparisons are
+ // substitutions t -> x where x is a variable. This allows us to build the
+ // substitution very quickly (never invalidating the substitution cache).
+ // Bitvector comparisons are more complicated and may require
+ // back-substitution and cache-invalidation. So we do these last.
+ while (!delayQueueLeft.empty()) {
+ left = delayQueueLeft.back();
+ right = d_substitutions.apply(delayQueueRight.back());
+ d_substitutions.addSubstitution(delayQueueLeft.back(), right, true, true, false);
+ delayQueueLeft.pop_back();
+ delayQueueRight.pop_back();
+ }
}