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