1 /********************* */
2 /*! \file substitutions.cpp
4 ** Top contributors (to current version):
5 ** Dejan Jovanovic, Clark Barrett, Morgan Deters
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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.\endverbatim
12 ** \brief A substitution mapping for theory simplification
14 ** A substitution mapping for theory simplification.
17 #include "theory/substitutions.h"
18 #include "expr/node_algorithm.h"
19 #include "theory/rewriter.h"
26 struct substitution_stack_element
{
28 bool d_children_added
;
29 substitution_stack_element(TNode node
) : d_node(node
), d_children_added(false)
32 };/* struct substitution_stack_element */
34 Node
SubstitutionMap::internalSubstitute(TNode t
, NodeCache
& cache
) {
36 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< ")" << endl
;
38 if (d_substitutions
.empty()) {
42 // Do a topological sort of the subexpressions and substitute them
43 vector
<substitution_stack_element
> toVisit
;
44 toVisit
.push_back((TNode
) t
);
46 while (!toVisit
.empty())
48 // The current node we are processing
49 substitution_stack_element
& stackHead
= toVisit
.back();
50 TNode current
= stackHead
.d_node
;
52 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< "): processing " << current
<< endl
;
54 // If node already in the cache we're done, pop from the stack
55 NodeCache::iterator find
= cache
.find(current
);
56 if (find
!= cache
.end()) {
61 if (!d_substituteUnderQuantifiers
&& current
.isClosure())
63 Debug("substitution::internal") << "--not substituting under quantifier" << endl
;
64 cache
[current
] = current
;
69 NodeMap::iterator find2
= d_substitutions
.find(current
);
70 if (find2
!= d_substitutions
.end()) {
71 Node rhs
= (*find2
).second
;
72 Assert(rhs
!= current
);
73 internalSubstitute(rhs
, cache
);
74 d_substitutions
[current
] = cache
[rhs
];
75 cache
[current
] = cache
[rhs
];
80 // Not yet substituted, so process
81 if (stackHead
.d_children_added
)
83 // Children have been processed, so substitute
84 NodeBuilder
<> builder(current
.getKind());
85 if (current
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
86 builder
<< Node(cache
[current
.getOperator()]);
88 for (unsigned i
= 0; i
< current
.getNumChildren(); ++ i
) {
89 Assert(cache
.find(current
[i
]) != cache
.end());
90 builder
<< Node(cache
[current
[i
]]);
92 // Mark the substitution and continue
93 Node result
= builder
;
94 if (result
!= current
) {
95 find
= cache
.find(result
);
96 if (find
!= cache
.end()) {
97 result
= find
->second
;
100 find2
= d_substitutions
.find(result
);
101 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
];
111 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< "): setting " << current
<< " -> " << result
<< endl
;
112 cache
[current
] = result
;
117 // Mark that we have added the children if any
118 if (current
.getNumChildren() > 0 || current
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
119 stackHead
.d_children_added
= true;
120 // We need to add the operator, if any
121 if(current
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
122 TNode opNode
= current
.getOperator();
123 NodeCache::iterator opFind
= cache
.find(opNode
);
124 if (opFind
== cache
.end()) {
125 toVisit
.push_back(opNode
);
128 // We need to add the children
129 for(TNode::iterator child_it
= current
.begin(); child_it
!= current
.end(); ++ child_it
) {
130 TNode childNode
= *child_it
;
131 NodeCache::iterator childFind
= cache
.find(childNode
);
132 if (childFind
== cache
.end()) {
133 toVisit
.push_back(childNode
);
137 // No children, so we're done
138 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t
<< "): setting " << current
<< " -> " << current
<< endl
;
139 cache
[current
] = current
;
145 // Return the substituted version
147 }/* SubstitutionMap::internalSubstitute() */
150 void SubstitutionMap::addSubstitution(TNode x
, TNode t
, bool invalidateCache
)
152 Debug("substitution") << "SubstitutionMap::addSubstitution(" << x
<< ", " << t
<< ")" << endl
;
153 Assert(d_substitutions
.find(x
) == d_substitutions
.end());
155 // this causes a later assert-fail (the rhs != current one, above) anyway
156 // putting it here is easier to diagnose
157 Assert(x
!= t
) << "cannot substitute a term for itself";
159 d_substitutions
[x
] = t
;
161 // Also invalidate the cache if necessary
162 if (invalidateCache
) {
163 d_cacheInvalidated
= true;
166 d_substitutionCache
[x
] = d_substitutions
[x
];
171 void SubstitutionMap::addSubstitutions(SubstitutionMap
& subMap
, bool invalidateCache
)
173 SubstitutionMap::NodeMap::const_iterator it
= subMap
.begin();
174 SubstitutionMap::NodeMap::const_iterator it_end
= subMap
.end();
175 for (; it
!= it_end
; ++ it
) {
176 Assert(d_substitutions
.find((*it
).first
) == d_substitutions
.end());
177 d_substitutions
[(*it
).first
] = (*it
).second
;
178 if (!invalidateCache
) {
179 d_substitutionCache
[(*it
).first
] = d_substitutions
[(*it
).first
];
182 if (invalidateCache
) {
183 d_cacheInvalidated
= true;
187 Node
SubstitutionMap::apply(TNode t
) {
189 Debug("substitution") << "SubstitutionMap::apply(" << t
<< ")" << endl
;
192 if (d_cacheInvalidated
) {
193 d_substitutionCache
.clear();
194 d_cacheInvalidated
= false;
195 Debug("substitution") << "-- reset the cache" << endl
;
198 // Perform the substitution
199 Node result
= internalSubstitute(t
, d_substitutionCache
);
200 Debug("substitution") << "SubstitutionMap::apply(" << t
<< ") => " << result
<< endl
;
205 void SubstitutionMap::print(ostream
& out
) const {
206 NodeMap::const_iterator it
= d_substitutions
.begin();
207 NodeMap::const_iterator it_end
= d_substitutions
.end();
208 for (; it
!= it_end
; ++ it
) {
209 out
<< (*it
).first
<< " -> " << (*it
).second
<< endl
;
213 void SubstitutionMap::debugPrint() const { print(CVC4Message
.getStream()); }
215 }/* CVC4::theory namespace */
217 std::ostream
& operator<<(std::ostream
& out
, const theory::SubstitutionMap::iterator
& i
) {
218 return out
<< "[CDMap-iterator]";
221 }/* CVC4 namespace */