GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/foreign_theory_rewrite.cpp Lines: 58 59 98.3 %
Date: 2021-09-29 Branches: 98 254 38.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Yoni Zohar, Andres Noetzli, 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
 * The foreign_theory_rewrite preprocessing pass.
14
 *
15
 * Simplifies nodes of one theory using rewrites from another.
16
 */
17
18
#include "preprocessing/passes/foreign_theory_rewrite.h"
19
20
#include "expr/node_traversal.h"
21
#include "preprocessing/assertion_pipeline.h"
22
#include "preprocessing/preprocessing_pass_context.h"
23
#include "smt/env.h"
24
#include "theory/rewriter.h"
25
#include "theory/strings/arith_entail.h"
26
27
namespace cvc5 {
28
namespace preprocessing {
29
namespace passes {
30
31
using namespace cvc5::theory;
32
33
6273
ForeignTheoryRewriter::ForeignTheoryRewriter(Env& env)
34
6273
    : EnvObj(env), d_cache(userContext())
35
{
36
6273
}
37
38
4
Node ForeignTheoryRewriter::simplify(Node n)
39
{
40
8
  std::vector<Node> toVisit;
41
4
  n = rewrite(n);
42
4
  toVisit.push_back(n);
43
  // traverse n and rewrite until fixpoint
44
84
  while (!toVisit.empty())
45
  {
46
80
    Node current = toVisit.back();
47
    // split according to three cases:
48
    // 1. We have not visited this node
49
    // 2. We visited it but did not process it
50
    // 3. We already processed and cached the node
51
40
    if (d_cache.find(current) == d_cache.end())
52
    {
53
      // current is seen for the first time.
54
      // mark it by assigning a null node
55
      // and add its children to toVisit
56
16
      d_cache[current] = Node();
57
16
      toVisit.insert(toVisit.end(), current.begin(), current.end());
58
    }
59
24
    else if (d_cache[current].get().isNull())
60
    {
61
      // current was seen but was not processed.
62
      // (a) remove from toVisit
63
16
      toVisit.pop_back();
64
      // (b) Reconstruct it with processed children
65
32
      std::vector<Node> processedChildren;
66
32
      for (Node child : current)
67
      {
68
16
        Assert(d_cache.find(child) != d_cache.end());
69
16
        Assert(!d_cache[child].get().isNull());
70
16
        processedChildren.push_back(d_cache[child]);
71
      }
72
32
      Node reconstruction = reconstructNode(current, processedChildren);
73
      // (c) process the node and store the result in the cache
74
32
      Node result = foreignRewrite(reconstruction);
75
16
      d_cache[current] = result;
76
      // (d) add the result to toVisit, unless it is the same as current
77
16
      if (current != result)
78
      {
79
4
        toVisit.push_back(result);
80
      }
81
    }
82
    else
83
    {
84
      // current was already processed
85
      // remove from toVisit and skip
86
8
      toVisit.pop_back();
87
    }
88
  }
89
8
  return d_cache[n];
90
}
91
92
20
Node ForeignTheoryRewriter::foreignRewrite(Node n)
93
{
94
  // n is a rewritten node, and so GT, LT, LEQ
95
  // should have been eliminated
96
20
  Assert(n.getKind() != kind::GT);
97
20
  Assert(n.getKind() != kind::LT);
98
20
  Assert(n.getKind() != kind::LEQ);
99
  // apply rewrites according to the structure of n
100
20
  if (n.getKind() == kind::GEQ)
101
  {
102
6
    return rewriteStringsGeq(n);
103
  }
104
14
  return n;
105
}
106
107
6
Node ForeignTheoryRewriter::rewriteStringsGeq(Node n)
108
{
109
6
  theory::strings::ArithEntail ae(d_env.getRewriter());
110
  // check if the node can be simplified to true
111
6
  if (ae.check(n[0], n[1], false))
112
  {
113
4
    return NodeManager::currentNM()->mkConst(true);
114
  }
115
2
  return n;
116
}
117
118
16
Node ForeignTheoryRewriter::reconstructNode(Node originalNode,
119
                                            std::vector<Node> newChildren)
120
{
121
  // Nodes with no children are reconstructed to themselves
122
16
  if (originalNode.getNumChildren() == 0)
123
  {
124
6
    Assert(newChildren.empty());
125
6
    return originalNode;
126
  }
127
  // re-build the node with the same kind and new children
128
10
  kind::Kind_t k = originalNode.getKind();
129
20
  NodeBuilder builder(k);
130
  // special case for parameterized nodes
131
10
  if (originalNode.getMetaKind() == kind::metakind::PARAMETERIZED)
132
  {
133
    builder << originalNode.getOperator();
134
  }
135
  // reconstruction
136
26
  for (Node child : newChildren)
137
  {
138
16
    builder << child;
139
  }
140
10
  return builder.constructNode();
141
}
142
143
6271
ForeignTheoryRewrite::ForeignTheoryRewrite(
144
6271
    PreprocessingPassContext* preprocContext)
145
    : PreprocessingPass(preprocContext, "foreign-theory-rewrite"),
146
6271
      d_ftr(preprocContext->getEnv())
147
{
148
6271
}
149
150
2
PreprocessingPassResult ForeignTheoryRewrite::applyInternal(
151
    AssertionPipeline* assertionsToPreprocess)
152
{
153
6
  for (size_t i = 0, nasserts = assertionsToPreprocess->size(); i < nasserts;
154
       ++i)
155
  {
156
4
    assertionsToPreprocess->replace(
157
8
        i, rewrite(d_ftr.simplify((*assertionsToPreprocess)[i])));
158
  }
159
2
  return PreprocessingPassResult::NO_CONFLICT;
160
}
161
162
}  // namespace passes
163
}  // namespace preprocessing
164
22746
}  // namespace cvc5