GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/foreign_theory_rewrite.cpp Lines: 53 54 98.1 %
Date: 2021-09-07 Branches: 92 242 38.0 %

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