GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/substitutions.cpp Lines: 93 109 85.3 %
Date: 2021-09-15 Branches: 218 530 41.1 %

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
116847
SubstitutionMap::SubstitutionMap(context::Context* context)
26
    : d_context(),
27
      d_substitutions(context ? context : &d_context),
28
      d_substitutionCache(),
29
      d_cacheInvalidated(false),
30
116847
      d_cacheInvalidator(context ? context : &d_context, d_cacheInvalidated)
31
{
32
116847
}
33
34
12676190
struct substitution_stack_element {
35
  TNode d_node;
36
  bool d_children_added;
37
2974452
  substitution_stack_element(TNode node) : d_node(node), d_children_added(false)
38
  {
39
2974452
  }
40
};/* struct substitution_stack_element */
41
42
1791707
Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) {
43
44
1791707
  Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << endl;
45
46
1791707
  if (d_substitutions.empty()) {
47
1071140
    return t;
48
  }
49
50
  // Do a topological sort of the subexpressions and substitute them
51
1441134
  vector<substitution_stack_element> toVisit;
52
720567
  toVisit.push_back((TNode) t);
53
54
10465221
  while (!toVisit.empty())
55
  {
56
    // The current node we are processing
57
4872327
    substitution_stack_element& stackHead = toVisit.back();
58
9192079
    TNode current = stackHead.d_node;
59
60
4872327
    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
4872327
    NodeCache::iterator find = cache.find(current);
64
5265683
    if (find != cache.end()) {
65
393356
      toVisit.pop_back();
66
393356
      continue;
67
    }
68
69
4478971
    NodeMap::iterator find2 = d_substitutions.find(current);
70
4478971
    if (find2 != d_substitutions.end()) {
71
318438
      Node rhs = (*find2).second;
72
159219
      Assert(rhs != current);
73
159219
      internalSubstitute(rhs, cache);
74
159219
      d_substitutions[current] = cache[rhs];
75
159219
      cache[current] = cache[rhs];
76
159219
      toVisit.pop_back();
77
159219
      continue;
78
    }
79
80
    // Not yet substituted, so process
81
4319752
    if (stackHead.d_children_added)
82
    {
83
      // Children have been processed, so substitute
84
3795750
      NodeBuilder builder(current.getKind());
85
1897875
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
86
189103
        builder << Node(cache[current.getOperator()]);
87
      }
88
6515150
      for (unsigned i = 0; i < current.getNumChildren(); ++ i) {
89
4617275
        Assert(cache.find(current[i]) != cache.end());
90
4617275
        builder << Node(cache[current[i]]);
91
      }
92
      // Mark the substitution and continue
93
3795750
      Node result = builder;
94
1897875
      if (result != current) {
95
723859
        find = cache.find(result);
96
723859
        if (find != cache.end()) {
97
4590
          result = find->second;
98
        }
99
        else {
100
719269
          find2 = d_substitutions.find(result);
101
719269
          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
1897875
      Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << result << endl;
112
1897875
      cache[current] = result;
113
1897875
      toVisit.pop_back();
114
    }
115
    else
116
    {
117
      // Mark that we have added the children if any
118
2421877
      if (current.getNumChildren() > 0 || current.getMetaKind() == kind::metakind::PARAMETERIZED) {
119
1897875
        stackHead.d_children_added = true;
120
        // We need to add the operator, if any
121
1897875
        if(current.getMetaKind() == kind::metakind::PARAMETERIZED) {
122
378206
          TNode opNode = current.getOperator();
123
189103
          NodeCache::iterator opFind = cache.find(opNode);
124
189103
          if (opFind == cache.end()) {
125
51959
            toVisit.push_back(opNode);
126
          }
127
        }
128
        // We need to add the children
129
6515150
        for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) {
130
9234550
          TNode childNode = *child_it;
131
4617275
          NodeCache::iterator childFind = cache.find(childNode);
132
4617275
          if (childFind == cache.end()) {
133
2201926
            toVisit.push_back(childNode);
134
          }
135
        }
136
      } else {
137
        // No children, so we're done
138
524002
        Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << "): setting " << current << " -> " << current << endl;
139
524002
        cache[current] = current;
140
524002
        toVisit.pop_back();
141
      }
142
    }
143
  }
144
145
  // Return the substituted version
146
720567
  return cache[t];
147
}/* SubstitutionMap::internalSubstitute() */
148
149
150
2470815
void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache)
151
{
152
2470815
  Debug("substitution") << "SubstitutionMap::addSubstitution(" << x << ", " << t << ")" << endl;
153
2470815
  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
2470815
  Assert(x != t) << "cannot substitute a term for itself";
158
159
2470815
  d_substitutions[x] = t;
160
161
  // Also invalidate the cache if necessary
162
2470815
  if (invalidateCache) {
163
2470703
    d_cacheInvalidated = true;
164
  }
165
  else {
166
112
    d_substitutionCache[x] = d_substitutions[x];
167
  }
168
2470815
}
169
170
171
8207
void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateCache)
172
{
173
8207
  SubstitutionMap::NodeMap::const_iterator it = subMap.begin();
174
8207
  SubstitutionMap::NodeMap::const_iterator it_end = subMap.end();
175
94165
  for (; it != it_end; ++ it) {
176
42979
    Assert(d_substitutions.find((*it).first) == d_substitutions.end());
177
42979
    d_substitutions[(*it).first] = (*it).second;
178
42979
    if (!invalidateCache) {
179
      d_substitutionCache[(*it).first] = d_substitutions[(*it).first];
180
    }
181
  }
182
8207
  if (invalidateCache) {
183
8207
    d_cacheInvalidated = true;
184
  }
185
8207
}
186
187
1632488
Node SubstitutionMap::apply(TNode t, bool doRewrite) {
188
189
1632488
  Debug("substitution") << "SubstitutionMap::apply(" << t << ")" << endl;
190
191
  // Setup the cache
192
1632488
  if (d_cacheInvalidated) {
193
75802
    d_substitutionCache.clear();
194
75802
    d_cacheInvalidated = false;
195
75802
    Debug("substitution") << "-- reset the cache" << endl;
196
  }
197
198
  // Perform the substitution
199
1632488
  Node result = internalSubstitute(t, d_substitutionCache);
200
1632488
  Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl;
201
202
1632488
  if (doRewrite)
203
  {
204
1031361
    result = Rewriter::rewrite(result);
205
  }
206
207
1632486
  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
29577
}  // namespace cvc5