GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/term_canonize.cpp Lines: 100 101 99.0 %
Date: 2021-05-21 Branches: 200 366 54.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Aina Niemetz
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
 * Implementation of term canonize.
14
 */
15
16
#include "expr/term_canonize.h"
17
18
#include <sstream>
19
20
// TODO #1216: move the code in this include
21
#include "theory/quantifiers/term_util.h"
22
23
using namespace cvc5::kind;
24
25
namespace cvc5 {
26
namespace expr {
27
28
6298
TermCanonize::TermCanonize() : d_op_id_count(0), d_typ_id_count(0) {}
29
30
286566
int TermCanonize::getIdForOperator(Node op)
31
{
32
286566
  std::map<Node, int>::iterator it = d_op_id.find(op);
33
286566
  if (it == d_op_id.end())
34
  {
35
20862
    d_op_id[op] = d_op_id_count;
36
20862
    d_op_id_count++;
37
20862
    return d_op_id[op];
38
  }
39
265704
  return it->second;
40
}
41
42
44024
int TermCanonize::getIdForType(TypeNode t)
43
{
44
44024
  std::map<TypeNode, int>::iterator it = d_typ_id.find(t);
45
44024
  if (it == d_typ_id.end())
46
  {
47
1934
    d_typ_id[t] = d_typ_id_count;
48
1934
    d_typ_id_count++;
49
1934
    return d_typ_id[t];
50
  }
51
42090
  return it->second;
52
}
53
54
426020
bool TermCanonize::getTermOrder(Node a, Node b)
55
{
56
426020
  if (a.getKind() == BOUND_VARIABLE)
57
  {
58
52200
    if (b.getKind() == BOUND_VARIABLE)
59
    {
60
35525
      return getIndexForFreeVariable(a) < getIndexForFreeVariable(b);
61
    }
62
16675
    return true;
63
  }
64
373820
  if (b.getKind() != BOUND_VARIABLE)
65
  {
66
338453
    Node aop = a.hasOperator() ? a.getOperator() : a;
67
338453
    Node bop = b.hasOperator() ? b.getOperator() : b;
68
338319
    Trace("aeq-debug2") << a << "...op..." << aop << std::endl;
69
338319
    Trace("aeq-debug2") << b << "...op..." << bop << std::endl;
70
338319
    if (aop == bop)
71
    {
72
195036
      if (a.getNumChildren() == b.getNumChildren())
73
      {
74
246308
        for (unsigned i = 0, size = a.getNumChildren(); i < size; i++)
75
        {
76
246174
          if (a[i] != b[i])
77
          {
78
            // first distinct child determines the ordering
79
189598
            return getTermOrder(a[i], b[i]);
80
          }
81
        }
82
      }
83
      else
84
      {
85
5304
        return aop.getNumChildren() < bop.getNumChildren();
86
      }
87
    }
88
    else
89
    {
90
143283
      return getIdForOperator(aop) < getIdForOperator(bop);
91
    }
92
  }
93
35635
  return false;
94
}
95
96
112269
Node TermCanonize::getCanonicalFreeVar(TypeNode tn, unsigned i)
97
{
98
112269
  Assert(!tn.isNull());
99
112269
  NodeManager* nm = NodeManager::currentNM();
100
131093
  while (d_cn_free_var[tn].size() <= i)
101
  {
102
18824
    std::stringstream oss;
103
9412
    oss << tn;
104
18824
    std::string typ_name = oss.str();
105
12800
    while (typ_name[0] == '(')
106
    {
107
1694
      typ_name.erase(typ_name.begin());
108
    }
109
18824
    std::stringstream os;
110
9412
    os << typ_name[0] << i;
111
18824
    Node x = nm->mkBoundVar(os.str().c_str(), tn);
112
9412
    d_fvIndex[x] = d_cn_free_var[tn].size();
113
9412
    d_cn_free_var[tn].push_back(x);
114
  }
115
112269
  return d_cn_free_var[tn][i];
116
}
117
118
71050
size_t TermCanonize::getIndexForFreeVariable(Node v) const
119
{
120
71050
  std::map<Node, size_t>::const_iterator it = d_fvIndex.find(v);
121
71050
  if (it == d_fvIndex.end())
122
  {
123
71050
    return 0;
124
  }
125
  return it->second;
126
}
127
128
struct sortTermOrder
129
{
130
  TermCanonize* d_tu;
131
236422
  bool operator()(Node i, Node j) { return d_tu->getTermOrder(i, j); }
132
};
133
134
725415
Node TermCanonize::getCanonicalTerm(TNode n,
135
                                    bool apply_torder,
136
                                    bool doHoVar,
137
                                    std::map<TypeNode, unsigned>& var_count,
138
                                    std::map<TNode, Node>& visited)
139
{
140
725415
  std::map<TNode, Node>::iterator it = visited.find(n);
141
725415
  if (it != visited.end())
142
  {
143
157131
    return it->second;
144
  }
145
146
568284
  Trace("canon-term-debug") << "Get canonical term for " << n << std::endl;
147
568284
  if (n.getKind() == BOUND_VARIABLE)
148
  {
149
140578
    TypeNode tn = n.getType();
150
    // allocate variable
151
70289
    unsigned vn = var_count[tn];
152
70289
    var_count[tn]++;
153
140578
    Node fv = getCanonicalFreeVar(tn, vn);
154
70289
    visited[n] = fv;
155
70289
    Trace("canon-term-debug") << "...allocate variable." << std::endl;
156
70289
    return fv;
157
  }
158
497995
  else if (n.getNumChildren() > 0)
159
  {
160
    // collect children
161
279919
    Trace("canon-term-debug") << "Collect children" << std::endl;
162
559838
    std::vector<Node> cchildren;
163
860286
    for (const Node& cn : n)
164
    {
165
580367
      cchildren.push_back(cn);
166
    }
167
    // if applicable, first sort by term order
168
279919
    if (apply_torder && theory::quantifiers::TermUtil::isComm(n.getKind()))
169
    {
170
187494
      Trace("canon-term-debug")
171
93747
          << "Sort based on commutative operator " << n.getKind() << std::endl;
172
      sortTermOrder sto;
173
93747
      sto.d_tu = this;
174
93747
      std::sort(cchildren.begin(), cchildren.end(), sto);
175
    }
176
    // now make canonical
177
279919
    Trace("canon-term-debug") << "Make canonical children" << std::endl;
178
860286
    for (unsigned i = 0, size = cchildren.size(); i < size; i++)
179
    {
180
1160734
      cchildren[i] = getCanonicalTerm(
181
580367
          cchildren[i], apply_torder, doHoVar, var_count, visited);
182
    }
183
279919
    if (n.getMetaKind() == metakind::PARAMETERIZED)
184
    {
185
236268
      Node op = n.getOperator();
186
118134
      if (doHoVar)
187
      {
188
118134
        op = getCanonicalTerm(op, apply_torder, doHoVar, var_count, visited);
189
      }
190
118134
      Trace("canon-term-debug") << "Insert operator " << op << std::endl;
191
118134
      cchildren.insert(cchildren.begin(), op);
192
    }
193
559838
    Trace("canon-term-debug")
194
279919
        << "...constructing for " << n << "." << std::endl;
195
559838
    Node ret = NodeManager::currentNM()->mkNode(n.getKind(), cchildren);
196
559838
    Trace("canon-term-debug")
197
279919
        << "...constructed " << ret << " for " << n << "." << std::endl;
198
279919
    visited[n] = ret;
199
279919
    return ret;
200
  }
201
218076
  Trace("canon-term-debug") << "...return 0-child term." << std::endl;
202
218076
  return n;
203
}
204
205
26914
Node TermCanonize::getCanonicalTerm(TNode n, bool apply_torder, bool doHoVar)
206
{
207
53828
  std::map<TypeNode, unsigned> var_count;
208
53828
  std::map<TNode, Node> visited;
209
53828
  return getCanonicalTerm(n, apply_torder, doHoVar, var_count, visited);
210
}
211
212
}  // namespace expr
213
27735
}  // namespace cvc5