GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/substitutions.cpp Lines: 93 109 85.3 %
Date: 2021-05-22 Branches: 218 532 41.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Dejan Jovanovic, Clark Barrett, 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
 * A substitution mapping for theory simplification.
14
 */
15
16
#include "theory/substitutions.h"
17
#include "expr/node_algorithm.h"
18
#include "theory/rewriter.h"
19
20
using namespace std;
21
22
namespace cvc5 {
23
namespace theory {
24
25
109034
SubstitutionMap::SubstitutionMap(context::Context* context)
26
    : d_context(),
27
      d_substitutions(context ? context : &d_context),
28
      d_substitutionCache(),
29
      d_cacheInvalidated(false),
30
109034
      d_cacheInvalidator(context ? context : &d_context, d_cacheInvalidated)
31
{
32
109034
}
33
34
13306121
struct substitution_stack_element {
35
  TNode d_node;
36
  bool d_children_added;
37
3135079
  substitution_stack_element(TNode node) : d_node(node), d_children_added(false)
38
  {
39
3135079
  }
40
};/* struct substitution_stack_element */
41
42
1723154
Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) {
43
44
1723154
  Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << endl;
45
46
1723154
  if (d_substitutions.empty()) {
47
1036643
    return t;
48
  }
49
50
  // Do a topological sort of the subexpressions and substitute them
51
1373022
  vector<substitution_stack_element> toVisit;
52
686511
  toVisit.push_back((TNode) t);
53
54
11058569
  while (!toVisit.empty())
55
  {
56
    // The current node we are processing
57
5186029
    substitution_stack_element& stackHead = toVisit.back();
58
9847866
    TNode current = stackHead.d_node;
59
60
5186029
    Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): processing " << current << endl;
61
62
    // If node already in the cache we're done, pop from the stack
63
5186029
    NodeCache::iterator find = cache.find(current);
64
5549024
    if (find != cache.end()) {
65
362995
      toVisit.pop_back();
66
362995
      continue;
67
    }
68
69
4823034
    NodeMap::iterator find2 = d_substitutions.find(current);
70
4823034
    if (find2 != d_substitutions.end()) {
71
322394
      Node rhs = (*find2).second;
72
161197
      Assert(rhs != current);
73
161197
      internalSubstitute(rhs, cache);
74
161197
      d_substitutions[current] = cache[rhs];
75
161197
      cache[current] = cache[rhs];
76
161197
      toVisit.pop_back();
77
161197
      continue;
78
    }
79
80
    // Not yet substituted, so process
81
4661837
    if (stackHead.d_children_added)
82
    {
83
      // Children have been processed, so substitute
84
4101900
      NodeBuilder builder(current.getKind());
85
2050950
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
86
202668
        builder << Node(cache[current.getOperator()]);
87
      }
88
6994111
      for (unsigned i = 0; i < current.getNumChildren(); ++ i) {
89
4943161
        Assert(cache.find(current[i]) != cache.end());
90
4943161
        builder << Node(cache[current[i]]);
91
      }
92
      // Mark the substitution and continue
93
4101900
      Node result = builder;
94
2050950
      if (result != current) {
95
753674
        find = cache.find(result);
96
753674
        if (find != cache.end()) {
97
5350
          result = find->second;
98
        }
99
        else {
100
748324
          find2 = d_substitutions.find(result);
101
748324
          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];
107
            result = cache[rhs];
108
          }
109
        }
110
      }
111
2050950
      Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << result << endl;
112
2050950
      cache[current] = result;
113
2050950
      toVisit.pop_back();
114
    }
115
    else
116
    {
117
      // Mark that we have added the children if any
118
2610887
      if (current.getNumChildren() > 0 || current.getMetaKind() == kind::metakind::PARAMETERIZED) {
119
2050950
        stackHead.d_children_added = true;
120
        // We need to add the operator, if any
121
2050950
        if(current.getMetaKind() == kind::metakind::PARAMETERIZED) {
122
405336
          TNode opNode = current.getOperator();
123
202668
          NodeCache::iterator opFind = cache.find(opNode);
124
202668
          if (opFind == cache.end()) {
125
52717
            toVisit.push_back(opNode);
126
          }
127
        }
128
        // We need to add the children
129
6994111
        for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) {
130
9886322
          TNode childNode = *child_it;
131
4943161
          NodeCache::iterator childFind = cache.find(childNode);
132
4943161
          if (childFind == cache.end()) {
133
2395851
            toVisit.push_back(childNode);
134
          }
135
        }
136
      } else {
137
        // No children, so we're done
138
559937
        Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << current << endl;
139
559937
        cache[current] = current;
140
559937
        toVisit.pop_back();
141
      }
142
    }
143
  }
144
145
  // Return the substituted version
146
686511
  return cache[t];
147
}/* SubstitutionMap::internalSubstitute() */
148
149
150
1826377
void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache)
151
{
152
1826377
  Debug("substitution") << "SubstitutionMap::addSubstitution(" << x << ", " << t << ")" << endl;
153
1826377
  Assert(d_substitutions.find(x) == d_substitutions.end());
154
155
  // this causes a later assert-fail (the rhs != current one, above) anyway
156
  // putting it here is easier to diagnose
157
1826377
  Assert(x != t) << "cannot substitute a term for itself";
158
159
1826377
  d_substitutions[x] = t;
160
161
  // Also invalidate the cache if necessary
162
1826377
  if (invalidateCache) {
163
1826265
    d_cacheInvalidated = true;
164
  }
165
  else {
166
112
    d_substitutionCache[x] = d_substitutions[x];
167
  }
168
1826377
}
169
170
171
7535
void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateCache)
172
{
173
7535
  SubstitutionMap::NodeMap::const_iterator it = subMap.begin();
174
7535
  SubstitutionMap::NodeMap::const_iterator it_end = subMap.end();
175
93179
  for (; it != it_end; ++ it) {
176
42822
    Assert(d_substitutions.find((*it).first) == d_substitutions.end());
177
42822
    d_substitutions[(*it).first] = (*it).second;
178
42822
    if (!invalidateCache) {
179
      d_substitutionCache[(*it).first] = d_substitutions[(*it).first];
180
    }
181
  }
182
7535
  if (invalidateCache) {
183
7535
    d_cacheInvalidated = true;
184
  }
185
7535
}
186
187
1561957
Node SubstitutionMap::apply(TNode t, bool doRewrite) {
188
189
1561957
  Debug("substitution") << "SubstitutionMap::apply(" << t << ")" << endl;
190
191
  // Setup the cache
192
1561957
  if (d_cacheInvalidated) {
193
74929
    d_substitutionCache.clear();
194
74929
    d_cacheInvalidated = false;
195
74929
    Debug("substitution") << "-- reset the cache" << endl;
196
  }
197
198
  // Perform the substitution
199
1561957
  Node result = internalSubstitute(t, d_substitutionCache);
200
1561957
  Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl;
201
202
1561957
  if (doRewrite)
203
  {
204
961896
    result = Rewriter::rewrite(result);
205
  }
206
207
1561955
  return result;
208
}
209
210
void SubstitutionMap::print(ostream& out) const {
211
  NodeMap::const_iterator it = d_substitutions.begin();
212
  NodeMap::const_iterator it_end = d_substitutions.end();
213
  for (; it != it_end; ++ it) {
214
    out << (*it).first << " -> " << (*it).second << endl;
215
  }
216
}
217
218
void SubstitutionMap::debugPrint() const { print(CVC5Message.getStream()); }
219
220
}  // namespace theory
221
222
std::ostream& operator<<(std::ostream& out, const theory::SubstitutionMap::iterator& i) {
223
  return out << "[CDMap-iterator]";
224
}
225
226
28194
}  // namespace cvc5