GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/foreign_theory_rewrite.cpp Lines: 52 53 98.1 %
Date: 2021-05-22 Branches: 92 244 37.7 %

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