GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/theory_uf_rewriter.cpp Lines: 76 91 83.5 %
Date: 2021-08-14 Branches: 207 472 43.9 %

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
 * Theory UF rewriter
14
 */
15
16
#include "theory/uf/theory_uf_rewriter.h"
17
18
#include "expr/node_algorithm.h"
19
#include "options/uf_options.h"
20
#include "theory/rewriter.h"
21
#include "theory/substitutions.h"
22
23
namespace cvc5 {
24
namespace theory {
25
namespace uf {
26
27
809269
RewriteResponse TheoryUfRewriter::postRewrite(TNode node)
28
{
29
809269
  if (node.getKind() == kind::EQUAL)
30
  {
31
162005
    if (node[0] == node[1])
32
    {
33
      return RewriteResponse(REWRITE_DONE,
34
61
                             NodeManager::currentNM()->mkConst(true));
35
    }
36
161944
    else if (node[0].isConst() && node[1].isConst())
37
    {
38
      // uninterpreted constants are all distinct
39
      return RewriteResponse(REWRITE_DONE,
40
28
                             NodeManager::currentNM()->mkConst(false));
41
    }
42
161916
    if (node[0] > node[1])
43
    {
44
      Node newNode =
45
60676
          NodeManager::currentNM()->mkNode(node.getKind(), node[1], node[0]);
46
30338
      return RewriteResponse(REWRITE_DONE, newNode);
47
    }
48
  }
49
778842
  if (node.getKind() == kind::APPLY_UF)
50
  {
51
623363
    if (node.getOperator().getKind() == kind::LAMBDA)
52
    {
53
21814
      Trace("uf-ho-beta") << "uf-ho-beta : beta-reducing all args of : " << node
54
10907
                          << "\n";
55
21814
      TNode lambda = node.getOperator();
56
21814
      Node ret;
57
      // build capture-avoiding substitution since in HOL shadowing may have
58
      // been introduced
59
10907
      if (options::ufHo())
60
      {
61
608
        std::vector<Node> vars;
62
608
        std::vector<Node> subs;
63
869
        for (const Node& v : lambda[0])
64
        {
65
565
          vars.push_back(v);
66
        }
67
869
        for (const Node& s : node)
68
        {
69
565
          subs.push_back(s);
70
        }
71
304
        if (Trace.isOn("uf-ho-beta"))
72
        {
73
          Trace("uf-ho-beta") << "uf-ho-beta: ..sub of " << subs.size()
74
                              << " vars into " << subs.size() << " terms :\n";
75
          for (unsigned i = 0, size = subs.size(); i < size; ++i)
76
          {
77
            Trace("uf-ho-beta")
78
                << "uf-ho-beta: .... " << vars[i] << " |-> " << subs[i] << "\n";
79
          }
80
        }
81
304
        ret = expr::substituteCaptureAvoiding(lambda[1], vars, subs);
82
304
        Trace("uf-ho-beta") << "uf-ho-beta : ..result : " << ret << "\n";
83
      }
84
      else
85
      {
86
21206
        std::vector<TNode> vars(lambda[0].begin(), lambda[0].end());
87
21206
        std::vector<TNode> subs(node.begin(), node.end());
88
10603
        ret = lambda[1].substitute(
89
            vars.begin(), vars.end(), subs.begin(), subs.end());
90
      }
91
10907
      return RewriteResponse(REWRITE_AGAIN_FULL, ret);
92
    }
93
612456
    else if (!canUseAsApplyUfOperator(node.getOperator()))
94
    {
95
34
      return RewriteResponse(REWRITE_AGAIN_FULL, getHoApplyForApplyUf(node));
96
    }
97
  }
98
155479
  else if (node.getKind() == kind::HO_APPLY)
99
  {
100
18491
    if (node[0].getKind() == kind::LAMBDA)
101
    {
102
      // resolve one argument of the lambda
103
290
      Trace("uf-ho-beta") << "uf-ho-beta : beta-reducing one argument of : "
104
145
                          << node[0] << " with " << node[1] << "\n";
105
106
      // reconstruct the lambda first to avoid variable shadowing
107
290
      Node new_body = node[0][1];
108
145
      if (node[0][0].getNumChildren() > 1)
109
      {
110
182
        std::vector<Node> new_vars(node[0][0].begin() + 1, node[0][0].end());
111
182
        std::vector<Node> largs;
112
91
        largs.push_back(
113
182
            NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, new_vars));
114
91
        largs.push_back(new_body);
115
91
        new_body = NodeManager::currentNM()->mkNode(kind::LAMBDA, largs);
116
182
        Trace("uf-ho-beta")
117
91
            << "uf-ho-beta : ....new lambda : " << new_body << "\n";
118
      }
119
120
      // build capture-avoiding substitution since in HOL shadowing may have
121
      // been introduced
122
145
      if (options::ufHo())
123
      {
124
290
        Node arg = Rewriter::rewrite(node[1]);
125
290
        Node var = node[0][0][0];
126
145
        new_body = expr::substituteCaptureAvoiding(new_body, var, arg);
127
      }
128
      else
129
      {
130
        TNode arg = Rewriter::rewrite(node[1]);
131
        TNode var = node[0][0][0];
132
        new_body = new_body.substitute(var, arg);
133
      }
134
145
      Trace("uf-ho-beta") << "uf-ho-beta : ..new body : " << new_body << "\n";
135
145
      return RewriteResponse(REWRITE_AGAIN_FULL, new_body);
136
    }
137
  }
138
767756
  return RewriteResponse(REWRITE_DONE, node);
139
}
140
141
425331
RewriteResponse TheoryUfRewriter::preRewrite(TNode node)
142
{
143
425331
  if (node.getKind() == kind::EQUAL)
144
  {
145
91914
    if (node[0] == node[1])
146
    {
147
      return RewriteResponse(REWRITE_DONE,
148
3017
                             NodeManager::currentNM()->mkConst(true));
149
    }
150
88897
    else if (node[0].isConst() && node[1].isConst())
151
    {
152
      // uninterpreted constants are all distinct
153
      return RewriteResponse(REWRITE_DONE,
154
6380
                             NodeManager::currentNM()->mkConst(false));
155
    }
156
  }
157
415934
  return RewriteResponse(REWRITE_DONE, node);
158
}
159
160
685611
Node TheoryUfRewriter::getHoApplyForApplyUf(TNode n)
161
{
162
685611
  Assert(n.getKind() == kind::APPLY_UF);
163
685611
  Node curr = n.getOperator();
164
2053802
  for (unsigned i = 0; i < n.getNumChildren(); i++)
165
  {
166
1368191
    curr = NodeManager::currentNM()->mkNode(kind::HO_APPLY, curr, n[i]);
167
  }
168
685611
  return curr;
169
}
170
Node TheoryUfRewriter::getApplyUfForHoApply(TNode n)
171
{
172
  Assert(n.getType().getNumChildren() == 2);
173
  std::vector<TNode> children;
174
  TNode curr = decomposeHoApply(n, children, true);
175
  // if operator is standard
176
  if (canUseAsApplyUfOperator(curr))
177
  {
178
    return NodeManager::currentNM()->mkNode(kind::APPLY_UF, children);
179
  }
180
  // cannot construct APPLY_UF if operator is partially applied or is not
181
  // standard
182
  return Node::null();
183
}
184
353
Node TheoryUfRewriter::decomposeHoApply(TNode n,
185
                                        std::vector<TNode>& args,
186
                                        bool opInArgs)
187
{
188
706
  TNode curr = n;
189
1511
  while (curr.getKind() == kind::HO_APPLY)
190
  {
191
579
    args.push_back(curr[1]);
192
579
    curr = curr[0];
193
  }
194
353
  if (opInArgs)
195
  {
196
113
    args.push_back(curr);
197
  }
198
353
  std::reverse(args.begin(), args.end());
199
706
  return curr;
200
}
201
612682
bool TheoryUfRewriter::canUseAsApplyUfOperator(TNode n) { return n.isVar(); }
202
203
}  // namespace uf
204
}  // namespace theory
205
29340
}  // namespace cvc5