GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/printer/let_binding.cpp Lines: 103 105 98.1 %
Date: 2021-05-22 Branches: 169 364 46.4 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds
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 let binding utility.
14
 */
15
16
#include "printer/let_binding.h"
17
18
#include <sstream>
19
20
namespace cvc5 {
21
22
53953
LetBinding::LetBinding(uint32_t thresh)
23
    : d_thresh(thresh),
24
      d_context(),
25
      d_visitList(&d_context),
26
      d_count(&d_context),
27
      d_letList(&d_context),
28
53953
      d_letMap(&d_context)
29
{
30
53953
}
31
32
47
uint32_t LetBinding::getThreshold() const { return d_thresh; }
33
34
53953
void LetBinding::process(Node n)
35
{
36
53953
  if (n.isNull() || d_thresh == 0)
37
  {
38
    // value of 0 means do not introduce let
39
    return;
40
  }
41
  // update the count of occurrences
42
53953
  updateCounts(n);
43
}
44
45
53953
void LetBinding::letify(Node n, std::vector<Node>& letList)
46
{
47
  // first, push the context
48
53953
  pushScope();
49
  // process the node
50
53953
  process(n);
51
  // now, letify
52
53953
  letify(letList);
53
53953
}
54
55
53953
void LetBinding::letify(std::vector<Node>& letList)
56
{
57
53953
  size_t prevSize = d_letList.size();
58
  // populate the d_letList and d_letMap
59
53953
  convertCountToLet();
60
  // add the new entries to the letList
61
53953
  letList.insert(letList.end(), d_letList.begin() + prevSize, d_letList.end());
62
53953
}
63
64
53953
void LetBinding::pushScope() { d_context.push(); }
65
66
53939
void LetBinding::popScope() { d_context.pop(); }
67
68
1254472
uint32_t LetBinding::getId(Node n) const
69
{
70
1254472
  NodeIdMap::const_iterator it = d_letMap.find(n);
71
1254472
  if (it == d_letMap.end())
72
  {
73
936315
    return 0;
74
  }
75
318157
  return (*it).second;
76
}
77
78
146379
Node LetBinding::convert(Node n, const std::string& prefix, bool letTop) const
79
{
80
146379
  if (d_letMap.empty())
81
  {
82
20817
    return n;
83
  }
84
125562
  NodeManager* nm = NodeManager::currentNM();
85
251124
  std::unordered_map<TNode, Node> visited;
86
125562
  std::unordered_map<TNode, Node>::iterator it;
87
251124
  std::vector<TNode> visit;
88
251124
  TNode cur;
89
125562
  visit.push_back(n);
90
2405214
  do
91
  {
92
2530776
    cur = visit.back();
93
2530776
    visit.pop_back();
94
2530776
    it = visited.find(cur);
95
96
2530776
    if (it == visited.end())
97
    {
98
1162046
      uint32_t id = getId(cur);
99
      // do not letify id 0, or n itself if letTop is false
100
1162046
      if (id > 0 && (cur != n || letTop))
101
      {
102
        // make the let variable
103
266610
        std::stringstream ss;
104
133305
        ss << prefix << id;
105
133305
        visited[cur] = nm->mkBoundVar(ss.str(), cur.getType());
106
      }
107
1028741
      else if (cur.isClosure())
108
      {
109
        // do not convert beneath quantifiers
110
9
        visited[cur] = cur;
111
      }
112
      else
113
      {
114
1028732
        visited[cur] = Node::null();
115
1028732
        visit.push_back(cur);
116
1028732
        visit.insert(visit.end(), cur.begin(), cur.end());
117
      }
118
    }
119
1368730
    else if (it->second.isNull())
120
    {
121
2057464
      Node ret = cur;
122
1028732
      bool childChanged = false;
123
2057464
      std::vector<Node> children;
124
1028732
      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
125
      {
126
45427
        children.push_back(cur.getOperator());
127
      }
128
2405214
      for (const Node& cn : cur)
129
      {
130
1376482
        it = visited.find(cn);
131
1376482
        Assert(it != visited.end());
132
1376482
        Assert(!it->second.isNull());
133
1376482
        childChanged = childChanged || cn != it->second;
134
1376482
        children.push_back(it->second);
135
      }
136
1028732
      if (childChanged)
137
      {
138
433703
        ret = nm->mkNode(cur.getKind(), children);
139
      }
140
1028718
      visited[cur] = ret;
141
    }
142
2530762
  } while (!visit.empty());
143
125548
  Assert(visited.find(n) != visited.end());
144
125548
  Assert(!visited.find(n)->second.isNull());
145
125548
  return visited[n];
146
}
147
148
53953
void LetBinding::updateCounts(Node n)
149
{
150
53953
  NodeIdMap::iterator it;
151
107906
  std::vector<Node> visit;
152
107906
  TNode cur;
153
53953
  visit.push_back(n);
154
2013928
  do
155
  {
156
2067881
    cur = visit.back();
157
2067881
    it = d_count.find(cur);
158
2067881
    if (it == d_count.end())
159
    {
160
      // do not traverse beneath quantifiers
161
1012935
      if (cur.getNumChildren() == 0 || cur.isClosure())
162
      {
163
394908
        d_visitList.push_back(cur);
164
394908
        d_count[cur] = 1;
165
394908
        visit.pop_back();
166
      }
167
      else
168
      {
169
618027
        d_count[cur] = 0;
170
618027
        visit.insert(visit.end(), cur.begin(), cur.end());
171
      }
172
    }
173
    else
174
    {
175
1054946
      if ((*it).second == 0)
176
      {
177
618027
        d_visitList.push_back(cur);
178
      }
179
1054946
      d_count[cur] = (*it).second + 1;
180
1054946
      visit.pop_back();
181
    }
182
2067881
  } while (!visit.empty());
183
53953
}
184
185
53953
void LetBinding::convertCountToLet()
186
{
187
53953
  Assert(d_thresh > 0);
188
  // Assign ids for those whose d_count is >= d_thresh, traverse in d_visitList
189
  // in order so that deeper nodes are assigned lower identifiers, which
190
  // ensures the let list can be printed.
191
53953
  NodeIdMap::const_iterator itc;
192
1066888
  for (const Node& n : d_visitList)
193
  {
194
1012935
    if (n.getNumChildren() == 0)
195
    {
196
      // do not letify terms with no children
197
394866
      continue;
198
    }
199
618069
    else if (d_letMap.find(n) != d_letMap.end())
200
    {
201
      // already letified, perhaps at a lower context
202
      continue;
203
    }
204
618069
    itc = d_count.find(n);
205
618069
    Assert(itc != d_count.end());
206
618069
    if ((*itc).second >= d_thresh)
207
    {
208
92426
      d_letList.push_back(n);
209
      // start with id 1
210
92426
      size_t id = d_letMap.size() + 1;
211
92426
      d_letMap[n] = id;
212
    }
213
  }
214
53953
}
215
216
28191
}  // namespace cvc5