GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/real_to_int.cpp Lines: 92 96 95.8 %
Date: 2021-08-20 Branches: 224 464 48.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Haniel Barbosa, 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
 * The RealToInt preprocessing pass.
14
 *
15
 * Converts real operations into integer operations.
16
 */
17
18
#include "preprocessing/passes/real_to_int.h"
19
20
#include <string>
21
22
#include "expr/skolem_manager.h"
23
#include "preprocessing/assertion_pipeline.h"
24
#include "preprocessing/preprocessing_pass_context.h"
25
#include "theory/arith/arith_msum.h"
26
#include "theory/rewriter.h"
27
#include "theory/theory_model.h"
28
#include "util/rational.h"
29
30
using namespace cvc5::theory;
31
32
namespace cvc5 {
33
namespace preprocessing {
34
namespace passes {
35
36
9856
RealToInt::RealToInt(PreprocessingPassContext* preprocContext)
37
    : PreprocessingPass(preprocContext, "real-to-int"),
38
9856
      d_cache(preprocContext->getUserContext())
39
{
40
9856
}
41
42
134
Node RealToInt::realToIntInternal(TNode n, NodeMap& cache, std::vector<Node>& var_eq)
43
{
44
134
  Trace("real-as-int-debug") << "Convert : " << n << std::endl;
45
134
  NodeMap::iterator find = cache.find(n);
46
134
  if (find != cache.end())
47
  {
48
40
    return (*find).second;
49
  }
50
  else
51
  {
52
94
    NodeManager* nm = NodeManager::currentNM();
53
94
    SkolemManager* sm = nm->getSkolemManager();
54
188
    Node ret = n;
55
94
    if (n.getNumChildren() > 0)
56
    {
57
129
      if ((n.getKind() == kind::EQUAL && n[0].getType().isReal())
58
48
          || n.getKind() == kind::GEQ || n.getKind() == kind::LT
59
150
          || n.getKind() == kind::GT || n.getKind() == kind::LEQ)
60
      {
61
27
        ret = Rewriter::rewrite(n);
62
27
        Trace("real-as-int-debug") << "Now looking at : " << ret << std::endl;
63
27
        if (!ret.isConst())
64
        {
65
54
          Node ret_lit = ret.getKind() == kind::NOT ? ret[0] : ret;
66
27
          bool ret_pol = ret.getKind() != kind::NOT;
67
54
          std::map<Node, Node> msum;
68
27
          if (ArithMSum::getMonomialSumLit(ret_lit, msum))
69
          {
70
            // get common coefficient
71
54
            std::vector<Node> coeffs;
72
79
            for (std::map<Node, Node>::iterator itm = msum.begin();
73
79
                 itm != msum.end();
74
                 ++itm)
75
            {
76
104
              Node v = itm->first;
77
104
              Node c = itm->second;
78
52
              if (!c.isNull())
79
              {
80
33
                Assert(c.isConst());
81
66
                coeffs.push_back(NodeManager::currentNM()->mkConst(
82
66
                    Rational(c.getConst<Rational>().getDenominator())));
83
              }
84
            }
85
            Node cc =
86
27
                coeffs.empty()
87
                    ? Node::null()
88
22
                    : (coeffs.size() == 1
89
15
                           ? coeffs[0]
90
34
                           : Rewriter::rewrite(NodeManager::currentNM()->mkNode(
91
98
                                 kind::MULT, coeffs)));
92
54
            std::vector<Node> sum;
93
79
            for (std::map<Node, Node>::iterator itm = msum.begin();
94
79
                 itm != msum.end();
95
                 ++itm)
96
            {
97
104
              Node v = itm->first;
98
104
              Node c = itm->second;
99
104
              Node s;
100
52
              if (c.isNull())
101
              {
102
19
                c = cc.isNull() ? NodeManager::currentNM()->mkConst(Rational(1))
103
                                : cc;
104
              }
105
              else
106
              {
107
33
                if (!cc.isNull())
108
                {
109
33
                  c = Rewriter::rewrite(
110
66
                      NodeManager::currentNM()->mkNode(kind::MULT, c, cc));
111
                }
112
              }
113
52
              Assert(c.getType().isInteger());
114
52
              if (v.isNull())
115
              {
116
8
                sum.push_back(c);
117
              }
118
              else
119
              {
120
88
                Node vv = realToIntInternal(v, cache, var_eq);
121
44
                if (vv.getType().isInteger())
122
                {
123
44
                  sum.push_back(
124
88
                      NodeManager::currentNM()->mkNode(kind::MULT, c, vv));
125
                }
126
                else
127
                {
128
                  throw TypeCheckingExceptionPrivate(
129
                      v,
130
                      std::string("Cannot translate to Int: ") + v.toString());
131
                }
132
              }
133
            }
134
            Node sumt =
135
27
                sum.empty()
136
27
                    ? NodeManager::currentNM()->mkConst(Rational(0))
137
27
                    : (sum.size() == 1
138
11
                           ? sum[0]
139
92
                           : NodeManager::currentNM()->mkNode(kind::PLUS, sum));
140
54
            ret = NodeManager::currentNM()->mkNode(
141
                ret_lit.getKind(),
142
                sumt,
143
54
                NodeManager::currentNM()->mkConst(Rational(0)));
144
27
            if (!ret_pol)
145
            {
146
              ret = ret.negate();
147
            }
148
27
            Trace("real-as-int") << "Convert : " << std::endl;
149
27
            Trace("real-as-int") << "   " << n << std::endl;
150
27
            Trace("real-as-int") << "   " << ret << std::endl;
151
          }
152
        }
153
      }
154
      else
155
      {
156
32
        bool childChanged = false;
157
64
        std::vector<Node> children;
158
84
        for (unsigned i = 0; i < n.getNumChildren(); i++)
159
        {
160
104
          Node nc = realToIntInternal(n[i], cache, var_eq);
161
52
          childChanged = childChanged || nc != n[i];
162
52
          children.push_back(nc);
163
        }
164
32
        if (childChanged)
165
        {
166
32
          if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
167
          {
168
2
            children.insert(children.begin(), n.getOperator());
169
          }
170
32
          ret = NodeManager::currentNM()->mkNode(n.getKind(), children);
171
        }
172
      }
173
    }
174
    else
175
    {
176
70
      TypeNode tn = n.getType();
177
35
      if (tn.isReal() && !tn.isInteger())
178
      {
179
22
        if (n.getKind() == kind::BOUND_VARIABLE)
180
        {
181
          // cannot change the type of quantified variables, since this leads
182
          // to incompleteness.
183
          throw TypeCheckingExceptionPrivate(
184
              n,
185
              std::string("Cannot translate bound variable to Int: ")
186
                  + n.toString());
187
        }
188
22
        else if (n.isVar())
189
        {
190
44
          Node toIntN = nm->mkNode(kind::TO_INTEGER, n);
191
22
          ret = sm->mkPurifySkolem(toIntN, "__realToIntInternal_var");
192
22
          var_eq.push_back(n.eqNode(ret));
193
          // add the substitution to the preprocessing context, which ensures
194
          // the model for n is correct, as well as substituting it in the input
195
          // assertions when necessary.
196
22
          d_preprocContext->addSubstitution(n, ret);
197
        }
198
      }
199
    }
200
94
    cache[n] = ret;
201
94
    return ret;
202
  }
203
}
204
205
13
PreprocessingPassResult RealToInt::applyInternal(
206
    AssertionPipeline* assertionsToPreprocess)
207
{
208
26
  std::vector<Node> var_eq;
209
51
  for (unsigned i = 0, size = assertionsToPreprocess->size(); i < size; ++i)
210
  {
211
38
    assertionsToPreprocess->replace(
212
76
        i, realToIntInternal((*assertionsToPreprocess)[i], d_cache, var_eq));
213
  }
214
26
  return PreprocessingPassResult::NO_CONFLICT;
215
}
216
217
218
}  // namespace passes
219
}  // namespace preprocessing
220
29358
}  // namespace cvc5