1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Martin Brain, Andrew Reynolds, Andres Noetzli |
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 |
|
* Theory of floating-point arithmetic. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/fp/theory_fp.h" |
17 |
|
|
18 |
|
#include <set> |
19 |
|
#include <stack> |
20 |
|
#include <unordered_set> |
21 |
|
#include <vector> |
22 |
|
|
23 |
|
#include "base/configuration.h" |
24 |
|
#include "expr/skolem_manager.h" |
25 |
|
#include "options/fp_options.h" |
26 |
|
#include "smt/logic_exception.h" |
27 |
|
#include "theory/fp/fp_converter.h" |
28 |
|
#include "theory/fp/theory_fp_rewriter.h" |
29 |
|
#include "theory/output_channel.h" |
30 |
|
#include "theory/rewriter.h" |
31 |
|
#include "theory/theory_model.h" |
32 |
|
|
33 |
|
using namespace std; |
34 |
|
|
35 |
|
namespace cvc5 { |
36 |
|
namespace theory { |
37 |
|
namespace fp { |
38 |
|
|
39 |
|
namespace helper { |
40 |
|
Node buildConjunct(const std::vector<TNode> &assumptions) { |
41 |
|
if (assumptions.size() == 0) { |
42 |
|
return NodeManager::currentNM()->mkConst<bool>(true); |
43 |
|
|
44 |
|
} else if (assumptions.size() == 1) { |
45 |
|
return assumptions[0]; |
46 |
|
|
47 |
|
} else { |
48 |
|
// \todo see bv::utils::flattenAnd |
49 |
|
|
50 |
|
NodeBuilder conjunction(kind::AND); |
51 |
|
for (std::vector<TNode>::const_iterator it = assumptions.begin(); |
52 |
|
it != assumptions.end(); ++it) { |
53 |
|
conjunction << *it; |
54 |
|
} |
55 |
|
|
56 |
|
return conjunction; |
57 |
|
} |
58 |
|
} |
59 |
|
} // namespace helper |
60 |
|
|
61 |
|
/** Constructs a new instance of TheoryFp w.r.t. the provided contexts. */ |
62 |
8954 |
TheoryFp::TheoryFp(context::Context* c, |
63 |
|
context::UserContext* u, |
64 |
|
OutputChannel& out, |
65 |
|
Valuation valuation, |
66 |
|
const LogicInfo& logicInfo, |
67 |
8954 |
ProofNodeManager* pnm) |
68 |
|
: Theory(THEORY_FP, c, u, out, valuation, logicInfo, pnm), |
69 |
|
d_notification(*this), |
70 |
|
d_registeredTerms(u), |
71 |
8954 |
d_conv(new FpConverter(u)), |
72 |
|
d_expansionRequested(false), |
73 |
|
d_realToFloatMap(u), |
74 |
|
d_floatToRealMap(u), |
75 |
|
d_abstractionMap(u), |
76 |
|
d_rewriter(u), |
77 |
|
d_state(c, u, valuation), |
78 |
17908 |
d_im(*this, d_state, pnm, "theory::fp::", false) |
79 |
|
{ |
80 |
|
// indicate we are using the default theory state and inference manager |
81 |
8954 |
d_theoryState = &d_state; |
82 |
8954 |
d_inferManager = &d_im; |
83 |
8954 |
} /* TheoryFp::TheoryFp() */ |
84 |
|
|
85 |
8954 |
TheoryRewriter* TheoryFp::getTheoryRewriter() { return &d_rewriter; } |
86 |
|
|
87 |
3117 |
ProofRuleChecker* TheoryFp::getProofChecker() { return nullptr; } |
88 |
|
|
89 |
8954 |
bool TheoryFp::needsEqualityEngine(EeSetupInfo& esi) |
90 |
|
{ |
91 |
8954 |
esi.d_notify = &d_notification; |
92 |
8954 |
esi.d_name = "theory::fp::ee"; |
93 |
8954 |
return true; |
94 |
|
} |
95 |
|
|
96 |
8954 |
void TheoryFp::finishInit() |
97 |
|
{ |
98 |
8954 |
Assert(d_equalityEngine != nullptr); |
99 |
|
// Kinds that are to be handled in the congruence closure |
100 |
|
|
101 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ABS); |
102 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_NEG); |
103 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_PLUS); |
104 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_SUB); // Removed |
105 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MULT); |
106 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_DIV); |
107 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_FMA); |
108 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_SQRT); |
109 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_REM); |
110 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_RTI); |
111 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MIN); // Removed |
112 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MAX); // Removed |
113 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MIN_TOTAL); |
114 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MAX_TOTAL); |
115 |
|
|
116 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_EQ); // Removed |
117 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_LEQ); |
118 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_LT); |
119 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_GEQ); // Removed |
120 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_GT); // Removed |
121 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISN); |
122 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISSN); |
123 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISZ); |
124 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISINF); |
125 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISNAN); |
126 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISNEG); |
127 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISPOS); |
128 |
|
|
129 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR); |
130 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT); |
131 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_REAL); |
132 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR); |
133 |
8954 |
d_equalityEngine->addFunctionKind( |
134 |
|
kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR); |
135 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_GENERIC); // |
136 |
|
// Needed in parsing, should be rewritten away |
137 |
|
|
138 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_UBV); // Removed |
139 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_SBV); // Removed |
140 |
|
// d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_REAL); // Removed |
141 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_UBV_TOTAL); |
142 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_SBV_TOTAL); |
143 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_REAL_TOTAL); |
144 |
|
|
145 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_NAN); |
146 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_INF); |
147 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_ZERO); |
148 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGN); |
149 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_EXPONENT); |
150 |
8954 |
d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND); |
151 |
8954 |
d_equalityEngine->addFunctionKind(kind::ROUNDINGMODE_BITBLAST); |
152 |
8954 |
} |
153 |
|
|
154 |
|
Node TheoryFp::abstractRealToFloat(Node node) |
155 |
|
{ |
156 |
|
Assert(node.getKind() == kind::FLOATINGPOINT_TO_FP_REAL); |
157 |
|
TypeNode t(node.getType()); |
158 |
|
Assert(t.getKind() == kind::FLOATINGPOINT_TYPE); |
159 |
|
|
160 |
|
NodeManager *nm = NodeManager::currentNM(); |
161 |
|
SkolemManager* sm = nm->getSkolemManager(); |
162 |
|
ConversionAbstractionMap::const_iterator i(d_realToFloatMap.find(t)); |
163 |
|
|
164 |
|
Node fun; |
165 |
|
if (i == d_realToFloatMap.end()) |
166 |
|
{ |
167 |
|
std::vector<TypeNode> args(2); |
168 |
|
args[0] = node[0].getType(); |
169 |
|
args[1] = node[1].getType(); |
170 |
|
fun = sm->mkDummySkolem("floatingpoint_abstract_real_to_float", |
171 |
|
nm->mkFunctionType(args, node.getType()), |
172 |
|
"floatingpoint_abstract_real_to_float", |
173 |
|
NodeManager::SKOLEM_EXACT_NAME); |
174 |
|
d_realToFloatMap.insert(t, fun); |
175 |
|
} |
176 |
|
else |
177 |
|
{ |
178 |
|
fun = (*i).second; |
179 |
|
} |
180 |
|
Node uf = nm->mkNode(kind::APPLY_UF, fun, node[0], node[1]); |
181 |
|
|
182 |
|
d_abstractionMap.insert(uf, node); |
183 |
|
|
184 |
|
return uf; |
185 |
|
} |
186 |
|
|
187 |
4 |
Node TheoryFp::abstractFloatToReal(Node node) |
188 |
|
{ |
189 |
4 |
Assert(node.getKind() == kind::FLOATINGPOINT_TO_REAL_TOTAL); |
190 |
8 |
TypeNode t(node[0].getType()); |
191 |
4 |
Assert(t.getKind() == kind::FLOATINGPOINT_TYPE); |
192 |
|
|
193 |
4 |
NodeManager *nm = NodeManager::currentNM(); |
194 |
4 |
SkolemManager* sm = nm->getSkolemManager(); |
195 |
4 |
ConversionAbstractionMap::const_iterator i(d_floatToRealMap.find(t)); |
196 |
|
|
197 |
8 |
Node fun; |
198 |
4 |
if (i == d_floatToRealMap.end()) |
199 |
|
{ |
200 |
8 |
std::vector<TypeNode> args(2); |
201 |
4 |
args[0] = t; |
202 |
4 |
args[1] = nm->realType(); |
203 |
12 |
fun = sm->mkDummySkolem("floatingpoint_abstract_float_to_real", |
204 |
8 |
nm->mkFunctionType(args, nm->realType()), |
205 |
|
"floatingpoint_abstract_float_to_real", |
206 |
|
NodeManager::SKOLEM_EXACT_NAME); |
207 |
4 |
d_floatToRealMap.insert(t, fun); |
208 |
|
} |
209 |
|
else |
210 |
|
{ |
211 |
|
fun = (*i).second; |
212 |
|
} |
213 |
4 |
Node uf = nm->mkNode(kind::APPLY_UF, fun, node[0], node[1]); |
214 |
|
|
215 |
4 |
d_abstractionMap.insert(uf, node); |
216 |
|
|
217 |
8 |
return uf; |
218 |
|
} |
219 |
|
|
220 |
2546 |
TrustNode TheoryFp::ppRewrite(TNode node, std::vector<SkolemLemma>& lems) |
221 |
|
{ |
222 |
2546 |
Trace("fp-ppRewrite") << "TheoryFp::ppRewrite(): " << node << std::endl; |
223 |
|
// first, see if we need to expand definitions |
224 |
5092 |
TrustNode texp = d_rewriter.expandDefinition(node); |
225 |
2546 |
if (!texp.isNull()) |
226 |
|
{ |
227 |
4 |
return texp; |
228 |
|
} |
229 |
|
|
230 |
5084 |
Node res = node; |
231 |
|
|
232 |
|
// Abstract conversion functions |
233 |
2542 |
if (node.getKind() == kind::FLOATINGPOINT_TO_REAL_TOTAL) |
234 |
|
{ |
235 |
4 |
res = abstractFloatToReal(node); |
236 |
|
|
237 |
|
// Generate some lemmas |
238 |
4 |
NodeManager *nm = NodeManager::currentNM(); |
239 |
|
|
240 |
|
Node pd = |
241 |
|
nm->mkNode(kind::IMPLIES, |
242 |
16 |
nm->mkNode(kind::OR, |
243 |
8 |
nm->mkNode(kind::FLOATINGPOINT_ISNAN, node[0]), |
244 |
8 |
nm->mkNode(kind::FLOATINGPOINT_ISINF, node[0])), |
245 |
16 |
nm->mkNode(kind::EQUAL, res, node[1])); |
246 |
4 |
handleLemma(pd, InferenceId::FP_PREPROCESS); |
247 |
|
|
248 |
|
Node z = |
249 |
|
nm->mkNode(kind::IMPLIES, |
250 |
8 |
nm->mkNode(kind::FLOATINGPOINT_ISZ, node[0]), |
251 |
16 |
nm->mkNode(kind::EQUAL, res, nm->mkConst(Rational(0U)))); |
252 |
4 |
handleLemma(z, InferenceId::FP_PREPROCESS); |
253 |
|
|
254 |
|
// TODO : bounds on the output from largest floats, #1914 |
255 |
|
} |
256 |
2538 |
else if (node.getKind() == kind::FLOATINGPOINT_TO_FP_REAL) |
257 |
|
{ |
258 |
|
res = abstractRealToFloat(node); |
259 |
|
|
260 |
|
// Generate some lemmas |
261 |
|
NodeManager *nm = NodeManager::currentNM(); |
262 |
|
|
263 |
|
Node nnan = |
264 |
|
nm->mkNode(kind::NOT, nm->mkNode(kind::FLOATINGPOINT_ISNAN, res)); |
265 |
|
handleLemma(nnan, InferenceId::FP_PREPROCESS); |
266 |
|
|
267 |
|
Node z = nm->mkNode( |
268 |
|
kind::IMPLIES, |
269 |
|
nm->mkNode(kind::EQUAL, node[1], nm->mkConst(Rational(0U))), |
270 |
|
nm->mkNode(kind::EQUAL, |
271 |
|
res, |
272 |
|
nm->mkConst(FloatingPoint::makeZero( |
273 |
|
res.getType().getConst<FloatingPointSize>(), false)))); |
274 |
|
handleLemma(z, InferenceId::FP_PREPROCESS); |
275 |
|
|
276 |
|
// TODO : rounding-mode specific bounds on floats that don't give infinity |
277 |
|
// BEWARE of directed rounding! #1914 |
278 |
|
} |
279 |
|
|
280 |
2542 |
if (res != node) |
281 |
|
{ |
282 |
8 |
Trace("fp-ppRewrite") << "TheoryFp::ppRewrite(): node " << node |
283 |
4 |
<< " rewritten to " << res << std::endl; |
284 |
4 |
return TrustNode::mkTrustRewrite(node, res, nullptr); |
285 |
|
} |
286 |
|
|
287 |
2538 |
return TrustNode::null(); |
288 |
|
} |
289 |
|
|
290 |
8 |
bool TheoryFp::refineAbstraction(TheoryModel *m, TNode abstract, TNode concrete) |
291 |
|
{ |
292 |
16 |
Trace("fp-refineAbstraction") << "TheoryFp::refineAbstraction(): " << abstract |
293 |
8 |
<< " vs. " << concrete << std::endl; |
294 |
8 |
Kind k = concrete.getKind(); |
295 |
8 |
if (k == kind::FLOATINGPOINT_TO_REAL_TOTAL) |
296 |
|
{ |
297 |
|
// Get the values |
298 |
8 |
Assert(m->hasTerm(abstract)); |
299 |
8 |
Assert(m->hasTerm(concrete[0])); |
300 |
8 |
Assert(m->hasTerm(concrete[1])); |
301 |
|
|
302 |
16 |
Node abstractValue = m->getValue(abstract); |
303 |
16 |
Node floatValue = m->getValue(concrete[0]); |
304 |
16 |
Node undefValue = m->getValue(concrete[1]); |
305 |
|
|
306 |
8 |
Assert(abstractValue.isConst()); |
307 |
8 |
Assert(floatValue.isConst()); |
308 |
8 |
Assert(undefValue.isConst()); |
309 |
|
|
310 |
|
// Work out the actual value for those args |
311 |
8 |
NodeManager *nm = NodeManager::currentNM(); |
312 |
|
|
313 |
|
Node evaluate = |
314 |
16 |
nm->mkNode(kind::FLOATINGPOINT_TO_REAL_TOTAL, floatValue, undefValue); |
315 |
16 |
Node concreteValue = Rewriter::rewrite(evaluate); |
316 |
8 |
Assert(concreteValue.isConst()); |
317 |
|
|
318 |
16 |
Trace("fp-refineAbstraction") |
319 |
16 |
<< "TheoryFp::refineAbstraction(): " << concrete[0] << " = " |
320 |
8 |
<< floatValue << std::endl |
321 |
16 |
<< "TheoryFp::refineAbstraction(): " << concrete[1] << " = " |
322 |
8 |
<< undefValue << std::endl |
323 |
8 |
<< "TheoryFp::refineAbstraction(): " << abstract << " = " |
324 |
8 |
<< abstractValue << std::endl |
325 |
8 |
<< "TheoryFp::refineAbstraction(): " << concrete << " = " |
326 |
8 |
<< concreteValue << std::endl; |
327 |
|
|
328 |
8 |
if (abstractValue != concreteValue) |
329 |
|
{ |
330 |
|
// Need refinement lemmas |
331 |
|
// only in the normal and subnormal case |
332 |
4 |
Assert(floatValue.getConst<FloatingPoint>().isNormal() |
333 |
|
|| floatValue.getConst<FloatingPoint>().isSubnormal()); |
334 |
|
|
335 |
|
Node defined = nm->mkNode( |
336 |
|
kind::AND, |
337 |
8 |
nm->mkNode(kind::NOT, |
338 |
8 |
nm->mkNode(kind::FLOATINGPOINT_ISNAN, concrete[0])), |
339 |
8 |
nm->mkNode(kind::NOT, |
340 |
24 |
nm->mkNode(kind::FLOATINGPOINT_ISINF, concrete[0]))); |
341 |
|
// First the "forward" constraints |
342 |
|
Node fg = nm->mkNode( |
343 |
|
kind::IMPLIES, |
344 |
|
defined, |
345 |
16 |
nm->mkNode( |
346 |
|
kind::EQUAL, |
347 |
8 |
nm->mkNode(kind::FLOATINGPOINT_GEQ, concrete[0], floatValue), |
348 |
16 |
nm->mkNode(kind::GEQ, abstract, concreteValue))); |
349 |
4 |
handleLemma(fg, InferenceId::FP_PREPROCESS); |
350 |
|
|
351 |
|
Node fl = nm->mkNode( |
352 |
|
kind::IMPLIES, |
353 |
|
defined, |
354 |
16 |
nm->mkNode( |
355 |
|
kind::EQUAL, |
356 |
8 |
nm->mkNode(kind::FLOATINGPOINT_LEQ, concrete[0], floatValue), |
357 |
16 |
nm->mkNode(kind::LEQ, abstract, concreteValue))); |
358 |
4 |
handleLemma(fl, InferenceId::FP_PREPROCESS); |
359 |
|
|
360 |
|
// Then the backwards constraints |
361 |
|
Node floatAboveAbstract = Rewriter::rewrite( |
362 |
24 |
nm->mkNode(kind::FLOATINGPOINT_TO_FP_REAL, |
363 |
8 |
nm->mkConst(FloatingPointToFPReal( |
364 |
8 |
concrete[0].getType().getConst<FloatingPointSize>())), |
365 |
8 |
nm->mkConst(ROUND_TOWARD_POSITIVE), |
366 |
8 |
abstractValue)); |
367 |
|
|
368 |
|
Node bg = nm->mkNode( |
369 |
|
kind::IMPLIES, |
370 |
|
defined, |
371 |
16 |
nm->mkNode( |
372 |
|
kind::EQUAL, |
373 |
8 |
nm->mkNode( |
374 |
|
kind::FLOATINGPOINT_GEQ, concrete[0], floatAboveAbstract), |
375 |
16 |
nm->mkNode(kind::GEQ, abstract, abstractValue))); |
376 |
4 |
handleLemma(bg, InferenceId::FP_PREPROCESS); |
377 |
|
|
378 |
|
Node floatBelowAbstract = Rewriter::rewrite( |
379 |
24 |
nm->mkNode(kind::FLOATINGPOINT_TO_FP_REAL, |
380 |
8 |
nm->mkConst(FloatingPointToFPReal( |
381 |
8 |
concrete[0].getType().getConst<FloatingPointSize>())), |
382 |
8 |
nm->mkConst(ROUND_TOWARD_NEGATIVE), |
383 |
8 |
abstractValue)); |
384 |
|
|
385 |
|
Node bl = nm->mkNode( |
386 |
|
kind::IMPLIES, |
387 |
|
defined, |
388 |
16 |
nm->mkNode( |
389 |
|
kind::EQUAL, |
390 |
8 |
nm->mkNode( |
391 |
|
kind::FLOATINGPOINT_LEQ, concrete[0], floatBelowAbstract), |
392 |
16 |
nm->mkNode(kind::LEQ, abstract, abstractValue))); |
393 |
4 |
handleLemma(bl, InferenceId::FP_PREPROCESS); |
394 |
|
// TODO : see if the overflow conditions could be improved #1914 |
395 |
|
|
396 |
4 |
return true; |
397 |
|
} |
398 |
|
else |
399 |
|
{ |
400 |
|
// No refinement needed |
401 |
4 |
return false; |
402 |
|
} |
403 |
|
} |
404 |
|
else if (k == kind::FLOATINGPOINT_TO_FP_REAL) |
405 |
|
{ |
406 |
|
// Get the values |
407 |
|
Assert(m->hasTerm(abstract)); |
408 |
|
Assert(m->hasTerm(concrete[0])); |
409 |
|
Assert(m->hasTerm(concrete[1])); |
410 |
|
|
411 |
|
Node abstractValue = m->getValue(abstract); |
412 |
|
Node rmValue = m->getValue(concrete[0]); |
413 |
|
Node realValue = m->getValue(concrete[1]); |
414 |
|
|
415 |
|
Assert(abstractValue.isConst()); |
416 |
|
Assert(rmValue.isConst()); |
417 |
|
Assert(realValue.isConst()); |
418 |
|
|
419 |
|
// Work out the actual value for those args |
420 |
|
NodeManager *nm = NodeManager::currentNM(); |
421 |
|
|
422 |
|
Node evaluate = |
423 |
|
nm->mkNode(kind::FLOATINGPOINT_TO_FP_REAL, |
424 |
|
nm->mkConst(FloatingPointToFPReal( |
425 |
|
concrete.getType().getConst<FloatingPointSize>())), |
426 |
|
rmValue, |
427 |
|
realValue); |
428 |
|
Node concreteValue = Rewriter::rewrite(evaluate); |
429 |
|
Assert(concreteValue.isConst()); |
430 |
|
|
431 |
|
Trace("fp-refineAbstraction") |
432 |
|
<< "TheoryFp::refineAbstraction(): " << concrete[0] << " = " << rmValue |
433 |
|
<< std::endl |
434 |
|
<< "TheoryFp::refineAbstraction(): " << concrete[1] << " = " |
435 |
|
<< realValue << std::endl |
436 |
|
<< "TheoryFp::refineAbstraction(): " << abstract << " = " |
437 |
|
<< abstractValue << std::endl |
438 |
|
<< "TheoryFp::refineAbstraction(): " << concrete << " = " |
439 |
|
<< concreteValue << std::endl; |
440 |
|
|
441 |
|
if (abstractValue != concreteValue) |
442 |
|
{ |
443 |
|
Assert(!abstractValue.getConst<FloatingPoint>().isNaN()); |
444 |
|
Assert(!concreteValue.getConst<FloatingPoint>().isNaN()); |
445 |
|
|
446 |
|
Node correctRoundingMode = nm->mkNode(kind::EQUAL, concrete[0], rmValue); |
447 |
|
// TODO : Generalise to all rounding modes #1914 |
448 |
|
|
449 |
|
// First the "forward" constraints |
450 |
|
Node fg = nm->mkNode( |
451 |
|
kind::IMPLIES, |
452 |
|
correctRoundingMode, |
453 |
|
nm->mkNode( |
454 |
|
kind::EQUAL, |
455 |
|
nm->mkNode(kind::GEQ, concrete[1], realValue), |
456 |
|
nm->mkNode(kind::FLOATINGPOINT_GEQ, abstract, concreteValue))); |
457 |
|
handleLemma(fg, InferenceId::FP_PREPROCESS); |
458 |
|
|
459 |
|
Node fl = nm->mkNode( |
460 |
|
kind::IMPLIES, |
461 |
|
correctRoundingMode, |
462 |
|
nm->mkNode( |
463 |
|
kind::EQUAL, |
464 |
|
nm->mkNode(kind::LEQ, concrete[1], realValue), |
465 |
|
nm->mkNode(kind::FLOATINGPOINT_LEQ, abstract, concreteValue))); |
466 |
|
handleLemma(fl, InferenceId::FP_PREPROCESS); |
467 |
|
|
468 |
|
// Then the backwards constraints |
469 |
|
if (!abstractValue.getConst<FloatingPoint>().isInfinite()) |
470 |
|
{ |
471 |
|
Node realValueOfAbstract = |
472 |
|
Rewriter::rewrite(nm->mkNode(kind::FLOATINGPOINT_TO_REAL_TOTAL, |
473 |
|
abstractValue, |
474 |
|
nm->mkConst(Rational(0U)))); |
475 |
|
|
476 |
|
Node bg = nm->mkNode( |
477 |
|
kind::IMPLIES, |
478 |
|
correctRoundingMode, |
479 |
|
nm->mkNode( |
480 |
|
kind::EQUAL, |
481 |
|
nm->mkNode(kind::GEQ, concrete[1], realValueOfAbstract), |
482 |
|
nm->mkNode(kind::FLOATINGPOINT_GEQ, abstract, abstractValue))); |
483 |
|
handleLemma(bg, InferenceId::FP_PREPROCESS); |
484 |
|
|
485 |
|
Node bl = nm->mkNode( |
486 |
|
kind::IMPLIES, |
487 |
|
correctRoundingMode, |
488 |
|
nm->mkNode( |
489 |
|
kind::EQUAL, |
490 |
|
nm->mkNode(kind::LEQ, concrete[1], realValueOfAbstract), |
491 |
|
nm->mkNode(kind::FLOATINGPOINT_LEQ, abstract, abstractValue))); |
492 |
|
handleLemma(bl, InferenceId::FP_PREPROCESS); |
493 |
|
} |
494 |
|
|
495 |
|
return true; |
496 |
|
} |
497 |
|
else |
498 |
|
{ |
499 |
|
// No refinement needed |
500 |
|
return false; |
501 |
|
} |
502 |
|
} |
503 |
|
else |
504 |
|
{ |
505 |
|
Unreachable() << "Unknown abstraction"; |
506 |
|
} |
507 |
|
|
508 |
|
return false; |
509 |
|
} |
510 |
|
|
511 |
1922 |
void TheoryFp::convertAndEquateTerm(TNode node) { |
512 |
1922 |
Trace("fp-convertTerm") << "TheoryFp::convertTerm(): " << node << std::endl; |
513 |
1922 |
size_t oldAdditionalAssertions = d_conv->d_additionalAssertions.size(); |
514 |
|
|
515 |
3844 |
Node converted(d_conv->convert(node)); |
516 |
|
|
517 |
1922 |
if (converted != node) { |
518 |
950 |
Debug("fp-convertTerm") |
519 |
475 |
<< "TheoryFp::convertTerm(): before " << node << std::endl; |
520 |
950 |
Debug("fp-convertTerm") |
521 |
475 |
<< "TheoryFp::convertTerm(): after " << converted << std::endl; |
522 |
|
} |
523 |
|
|
524 |
1922 |
size_t newAdditionalAssertions = d_conv->d_additionalAssertions.size(); |
525 |
1922 |
Assert(oldAdditionalAssertions <= newAdditionalAssertions); |
526 |
|
|
527 |
2204 |
while (oldAdditionalAssertions < newAdditionalAssertions) { |
528 |
282 |
Node addA = d_conv->d_additionalAssertions[oldAdditionalAssertions]; |
529 |
|
|
530 |
282 |
Debug("fp-convertTerm") << "TheoryFp::convertTerm(): additional assertion " |
531 |
141 |
<< addA << std::endl; |
532 |
|
|
533 |
|
#ifdef SYMFPUPROPISBOOL |
534 |
|
handleLemma(addA, false, true); |
535 |
|
#else |
536 |
141 |
NodeManager *nm = NodeManager::currentNM(); |
537 |
|
|
538 |
141 |
handleLemma( |
539 |
282 |
nm->mkNode(kind::EQUAL, addA, nm->mkConst(::cvc5::BitVector(1U, 1U))), |
540 |
|
InferenceId::FP_EQUATE_TERM); |
541 |
|
#endif |
542 |
|
|
543 |
141 |
++oldAdditionalAssertions; |
544 |
|
} |
545 |
|
|
546 |
|
// Equate the floating-point atom and the converted one. |
547 |
|
// Also adds the bit-vectors to the bit-vector solver. |
548 |
1922 |
if (node.getType().isBoolean()) { |
549 |
625 |
if (converted != node) { |
550 |
475 |
Assert(converted.getType().isBitVector()); |
551 |
|
|
552 |
475 |
NodeManager *nm = NodeManager::currentNM(); |
553 |
|
|
554 |
|
#ifdef SYMFPUPROPISBOOL |
555 |
|
handleLemma(nm->mkNode(kind::EQUAL, node, converted)); |
556 |
|
#else |
557 |
475 |
handleLemma( |
558 |
950 |
nm->mkNode(kind::EQUAL, |
559 |
|
node, |
560 |
950 |
nm->mkNode(kind::EQUAL, |
561 |
|
converted, |
562 |
950 |
nm->mkConst(::cvc5::BitVector(1U, 1U)))), |
563 |
|
InferenceId::FP_EQUATE_TERM); |
564 |
|
#endif |
565 |
|
|
566 |
|
} else { |
567 |
150 |
Assert((node.getKind() == kind::EQUAL)); |
568 |
|
} |
569 |
|
|
570 |
1297 |
} else if (node.getType().isBitVector()) { |
571 |
767 |
if (converted != node) { |
572 |
|
Assert(converted.getType().isBitVector()); |
573 |
|
|
574 |
|
handleLemma( |
575 |
|
NodeManager::currentNM()->mkNode(kind::EQUAL, node, converted), |
576 |
|
InferenceId::FP_EQUATE_TERM); |
577 |
|
} |
578 |
|
} |
579 |
|
|
580 |
3844 |
return; |
581 |
|
} |
582 |
|
|
583 |
3377 |
void TheoryFp::registerTerm(TNode node) { |
584 |
3377 |
Trace("fp-registerTerm") << "TheoryFp::registerTerm(): " << node << std::endl; |
585 |
|
|
586 |
3377 |
if (!isRegistered(node)) { |
587 |
1922 |
Kind k = node.getKind(); |
588 |
1922 |
Assert(k != kind::FLOATINGPOINT_TO_FP_GENERIC |
589 |
|
&& k != kind::FLOATINGPOINT_SUB && k != kind::FLOATINGPOINT_EQ |
590 |
|
&& k != kind::FLOATINGPOINT_GEQ && k != kind::FLOATINGPOINT_GT); |
591 |
|
|
592 |
1922 |
bool success = d_registeredTerms.insert(node); |
593 |
|
(void)success; // Only used for assertion |
594 |
1922 |
Assert(success); |
595 |
|
|
596 |
|
// Add to the equality engine |
597 |
1922 |
if (k == kind::EQUAL) |
598 |
|
{ |
599 |
485 |
d_equalityEngine->addTriggerPredicate(node); |
600 |
|
} |
601 |
|
else |
602 |
|
{ |
603 |
1437 |
d_equalityEngine->addTerm(node); |
604 |
|
} |
605 |
|
|
606 |
|
// Give the expansion of classifications in terms of equalities |
607 |
|
// This should make equality reasoning slightly more powerful. |
608 |
1922 |
if ((k == kind::FLOATINGPOINT_ISNAN) || (k == kind::FLOATINGPOINT_ISZ) |
609 |
1893 |
|| (k == kind::FLOATINGPOINT_ISINF)) |
610 |
|
{ |
611 |
55 |
NodeManager *nm = NodeManager::currentNM(); |
612 |
55 |
FloatingPointSize s = node[0].getType().getConst<FloatingPointSize>(); |
613 |
110 |
Node equalityAlias = Node::null(); |
614 |
|
|
615 |
55 |
if (k == kind::FLOATINGPOINT_ISNAN) |
616 |
|
{ |
617 |
22 |
equalityAlias = nm->mkNode( |
618 |
44 |
kind::EQUAL, node[0], nm->mkConst(FloatingPoint::makeNaN(s))); |
619 |
|
} |
620 |
33 |
else if (k == kind::FLOATINGPOINT_ISZ) |
621 |
|
{ |
622 |
21 |
equalityAlias = nm->mkNode( |
623 |
|
kind::OR, |
624 |
14 |
nm->mkNode(kind::EQUAL, |
625 |
|
node[0], |
626 |
14 |
nm->mkConst(FloatingPoint::makeZero(s, true))), |
627 |
14 |
nm->mkNode(kind::EQUAL, |
628 |
|
node[0], |
629 |
14 |
nm->mkConst(FloatingPoint::makeZero(s, false)))); |
630 |
|
} |
631 |
26 |
else if (k == kind::FLOATINGPOINT_ISINF) |
632 |
|
{ |
633 |
78 |
equalityAlias = nm->mkNode( |
634 |
|
kind::OR, |
635 |
52 |
nm->mkNode(kind::EQUAL, |
636 |
|
node[0], |
637 |
52 |
nm->mkConst(FloatingPoint::makeInf(s, true))), |
638 |
52 |
nm->mkNode(kind::EQUAL, |
639 |
|
node[0], |
640 |
52 |
nm->mkConst(FloatingPoint::makeInf(s, false)))); |
641 |
|
} |
642 |
|
else |
643 |
|
{ |
644 |
|
Unreachable() << "Only isNaN, isInf and isZero have aliases"; |
645 |
|
} |
646 |
|
|
647 |
55 |
handleLemma(nm->mkNode(kind::EQUAL, node, equalityAlias), |
648 |
|
InferenceId::FP_REGISTER_TERM); |
649 |
|
} |
650 |
|
|
651 |
|
// Use symfpu to produce an equivalent bit-vector statement |
652 |
1922 |
convertAndEquateTerm(node); |
653 |
|
} |
654 |
3377 |
return; |
655 |
|
} |
656 |
|
|
657 |
4988 |
bool TheoryFp::isRegistered(TNode node) { |
658 |
4988 |
return !(d_registeredTerms.find(node) == d_registeredTerms.end()); |
659 |
|
} |
660 |
|
|
661 |
2488 |
void TheoryFp::preRegisterTerm(TNode node) |
662 |
|
{ |
663 |
4998 |
if (Configuration::isBuiltWithSymFPU() && !options::fpExp()) |
664 |
|
{ |
665 |
1190 |
TypeNode tn = node.getType(); |
666 |
595 |
if (tn.isFloatingPoint()) |
667 |
|
{ |
668 |
159 |
unsigned exp_sz = tn.getFloatingPointExponentSize(); |
669 |
159 |
unsigned sig_sz = tn.getFloatingPointSignificandSize(); |
670 |
159 |
if (!((exp_sz == 8 && sig_sz == 24) || (exp_sz == 11 && sig_sz == 53))) |
671 |
|
{ |
672 |
|
std::stringstream ss; |
673 |
|
ss << "FP term " << node << " with type whose size is " << exp_sz << "/" |
674 |
|
<< sig_sz |
675 |
|
<< " is not supported, only Float32 (8/24) or Float64 (11/53) types " |
676 |
|
"are supported in default mode. Try the experimental solver via " |
677 |
|
"--fp-exp. Note: There are known issues with the experimental " |
678 |
|
"solver, use at your own risk."; |
679 |
|
throw LogicException(ss.str()); |
680 |
|
} |
681 |
|
} |
682 |
|
} |
683 |
4976 |
Trace("fp-preRegisterTerm") |
684 |
2488 |
<< "TheoryFp::preRegisterTerm(): " << node << std::endl; |
685 |
2488 |
registerTerm(node); |
686 |
2488 |
return; |
687 |
|
} |
688 |
|
|
689 |
695 |
void TheoryFp::handleLemma(Node node, InferenceId id) |
690 |
|
{ |
691 |
695 |
Trace("fp") << "TheoryFp::handleLemma(): asserting " << node << std::endl; |
692 |
|
// will be preprocessed when sent, which is important because it contains |
693 |
|
// embedded ITEs |
694 |
695 |
d_im.lemma(node, id); |
695 |
695 |
} |
696 |
|
|
697 |
828 |
bool TheoryFp::propagateLit(TNode node) |
698 |
|
{ |
699 |
828 |
Trace("fp") << "TheoryFp::propagateLit(): propagate " << node << std::endl; |
700 |
828 |
return d_im.propagateLit(node); |
701 |
|
} |
702 |
|
|
703 |
|
void TheoryFp::conflictEqConstantMerge(TNode t1, TNode t2) |
704 |
|
{ |
705 |
|
Trace("fp") << "TheoryFp::conflictEqConstantMerge(): conflict detected" |
706 |
|
<< std::endl; |
707 |
|
d_im.conflictEqConstantMerge(t1, t2); |
708 |
|
} |
709 |
|
|
710 |
5651 |
bool TheoryFp::needsCheckLastEffort() |
711 |
|
{ |
712 |
|
// only need to check if we have added to the abstraction map, otherwise |
713 |
|
// postCheck below is a no-op. |
714 |
5651 |
return !d_abstractionMap.empty(); |
715 |
|
} |
716 |
|
|
717 |
21477 |
void TheoryFp::postCheck(Effort level) |
718 |
|
{ |
719 |
|
// Resolve the abstractions for the conversion lemmas |
720 |
21477 |
if (level == EFFORT_LAST_CALL) |
721 |
|
{ |
722 |
8 |
Trace("fp") << "TheoryFp::check(): checking abstractions" << std::endl; |
723 |
8 |
TheoryModel* m = getValuation().getModel(); |
724 |
8 |
bool lemmaAdded = false; |
725 |
|
|
726 |
16 |
for (AbstractionMap::const_iterator i = d_abstractionMap.begin(); |
727 |
16 |
i != d_abstractionMap.end(); |
728 |
|
++i) |
729 |
|
{ |
730 |
8 |
if (m->hasTerm((*i).first)) |
731 |
|
{ // Is actually used in the model |
732 |
8 |
lemmaAdded |= refineAbstraction(m, (*i).first, (*i).second); |
733 |
|
} |
734 |
|
} |
735 |
|
} |
736 |
|
|
737 |
21477 |
Trace("fp") << "TheoryFp::check(): completed" << std::endl; |
738 |
|
/* Checking should be handled by the bit-vector engine */ |
739 |
21477 |
} |
740 |
|
|
741 |
1104 |
bool TheoryFp::preNotifyFact( |
742 |
|
TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal) |
743 |
|
{ |
744 |
1104 |
if (atom.getKind() == kind::EQUAL) |
745 |
|
{ |
746 |
889 |
Assert(!(atom[0].getType().isFloatingPoint() |
747 |
|
|| atom[0].getType().isRoundingMode()) |
748 |
|
|| isRegistered(atom[0])); |
749 |
889 |
Assert(!(atom[1].getType().isFloatingPoint() |
750 |
|
|| atom[1].getType().isRoundingMode()) |
751 |
|
|| isRegistered(atom[1])); |
752 |
889 |
registerTerm(atom); // Needed for float equalities |
753 |
|
} |
754 |
|
else |
755 |
|
{ |
756 |
|
// A system-wide invariant; predicates are registered before they are |
757 |
|
// asserted |
758 |
215 |
Assert(isRegistered(atom)); |
759 |
|
|
760 |
215 |
if (!d_equalityEngine->isFunctionKind(atom.getKind())) |
761 |
|
{ |
762 |
|
return true; |
763 |
|
} |
764 |
|
} |
765 |
1104 |
return false; |
766 |
|
} |
767 |
|
|
768 |
|
TrustNode TheoryFp::explain(TNode n) |
769 |
|
{ |
770 |
|
Trace("fp") << "TheoryFp::explain(): explain " << n << std::endl; |
771 |
|
|
772 |
|
// All things we assert directly (and not via bit-vector) should |
773 |
|
// come from the equality engine so this should be sufficient... |
774 |
|
std::vector<TNode> assumptions; |
775 |
|
|
776 |
|
bool polarity = n.getKind() != kind::NOT; |
777 |
|
TNode atom = polarity ? n : n[0]; |
778 |
|
if (atom.getKind() == kind::EQUAL) { |
779 |
|
d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions); |
780 |
|
} else { |
781 |
|
d_equalityEngine->explainPredicate(atom, polarity, assumptions); |
782 |
|
} |
783 |
|
|
784 |
|
Node exp = helper::buildConjunct(assumptions); |
785 |
|
return TrustNode::mkTrustPropExp(n, exp, nullptr); |
786 |
|
} |
787 |
|
|
788 |
|
Node TheoryFp::getModelValue(TNode var) { |
789 |
|
return d_conv->getValue(d_valuation, var); |
790 |
|
} |
791 |
|
|
792 |
4717 |
bool TheoryFp::collectModelInfo(TheoryModel* m, |
793 |
|
const std::set<Node>& relevantTerms) |
794 |
|
{ |
795 |
|
// this override behavior to not assert equality engine |
796 |
4717 |
return collectModelValues(m, relevantTerms); |
797 |
|
} |
798 |
|
|
799 |
4717 |
bool TheoryFp::collectModelValues(TheoryModel* m, |
800 |
|
const std::set<Node>& relevantTerms) |
801 |
|
{ |
802 |
9434 |
Trace("fp-collectModelInfo") |
803 |
4717 |
<< "TheoryFp::collectModelInfo(): begin" << std::endl; |
804 |
4717 |
if (Trace.isOn("fp-collectModelInfo")) { |
805 |
|
for (std::set<Node>::const_iterator i(relevantTerms.begin()); |
806 |
|
i != relevantTerms.end(); ++i) { |
807 |
|
Trace("fp-collectModelInfo") |
808 |
|
<< "TheoryFp::collectModelInfo(): relevantTerms " << *i << std::endl; |
809 |
|
} |
810 |
|
} |
811 |
|
|
812 |
9434 |
std::unordered_set<TNode> visited; |
813 |
9434 |
std::stack<TNode> working; |
814 |
9434 |
std::set<TNode> relevantVariables; |
815 |
12499 |
for (std::set<Node>::const_iterator i(relevantTerms.begin()); |
816 |
12499 |
i != relevantTerms.end(); ++i) { |
817 |
7782 |
working.push(*i); |
818 |
|
} |
819 |
|
|
820 |
30995 |
while (!working.empty()) { |
821 |
26278 |
TNode current = working.top(); |
822 |
13139 |
working.pop(); |
823 |
|
|
824 |
|
// Ignore things that have already been explored |
825 |
13139 |
if (visited.find(current) == visited.end()) { |
826 |
7922 |
visited.insert(current); |
827 |
|
|
828 |
15844 |
TypeNode t(current.getType()); |
829 |
|
|
830 |
23350 |
if ((t.isRoundingMode() || t.isFloatingPoint()) && |
831 |
15428 |
this->isLeaf(current)) { |
832 |
3295 |
relevantVariables.insert(current); |
833 |
|
} |
834 |
|
|
835 |
13279 |
for (size_t i = 0; i < current.getNumChildren(); ++i) { |
836 |
5357 |
working.push(current[i]); |
837 |
|
} |
838 |
|
} |
839 |
|
} |
840 |
|
|
841 |
8012 |
for (std::set<TNode>::const_iterator i(relevantVariables.begin()); |
842 |
8012 |
i != relevantVariables.end(); |
843 |
|
++i) |
844 |
|
{ |
845 |
6590 |
TNode node = *i; |
846 |
|
|
847 |
6590 |
Trace("fp-collectModelInfo") |
848 |
3295 |
<< "TheoryFp::collectModelInfo(): relevantVariable " << node |
849 |
3295 |
<< std::endl; |
850 |
|
|
851 |
3295 |
if (!m->assertEquality(node, d_conv->getValue(d_valuation, node), true)) |
852 |
|
{ |
853 |
|
return false; |
854 |
|
} |
855 |
|
|
856 |
9885 |
if (Configuration::isAssertionBuild() && isLeaf(node) && !node.isConst() |
857 |
7207 |
&& node.getType().isFloatingPoint()) |
858 |
|
{ |
859 |
|
// Check that the equality engine has asssigned values to all the |
860 |
|
// components of `node` except `(sign node)` (the sign component is |
861 |
|
// assignable, meaning that the model builder can pick an arbitrary value |
862 |
|
// for it if it hasn't been assigned in the equality engine). |
863 |
610 |
NodeManager* nm = NodeManager::currentNM(); |
864 |
1220 |
Node compNaN = nm->mkNode(kind::FLOATINGPOINT_COMPONENT_NAN, node); |
865 |
1220 |
Node compInf = nm->mkNode(kind::FLOATINGPOINT_COMPONENT_INF, node); |
866 |
1220 |
Node compZero = nm->mkNode(kind::FLOATINGPOINT_COMPONENT_ZERO, node); |
867 |
|
Node compExponent = |
868 |
1220 |
nm->mkNode(kind::FLOATINGPOINT_COMPONENT_EXPONENT, node); |
869 |
|
Node compSignificand = |
870 |
1220 |
nm->mkNode(kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND, node); |
871 |
|
|
872 |
610 |
eq::EqualityEngine* ee = m->getEqualityEngine(); |
873 |
610 |
Assert(ee->hasTerm(compNaN) && ee->getRepresentative(compNaN).isConst()); |
874 |
610 |
Assert(ee->hasTerm(compInf) && ee->getRepresentative(compInf).isConst()); |
875 |
610 |
Assert(ee->hasTerm(compZero) |
876 |
|
&& ee->getRepresentative(compZero).isConst()); |
877 |
610 |
Assert(ee->hasTerm(compExponent) |
878 |
|
&& ee->getRepresentative(compExponent).isConst()); |
879 |
610 |
Assert(ee->hasTerm(compSignificand)); |
880 |
610 |
Assert(ee->getRepresentative(compSignificand).isConst()); |
881 |
|
|
882 |
|
// At most one of the flags (NaN, inf, zero) can be set |
883 |
1220 |
Node one = nm->mkConst(BitVector(1U, 1U)); |
884 |
610 |
size_t numFlags = 0; |
885 |
610 |
numFlags += ee->getRepresentative(compNaN) == one ? 1 : 0; |
886 |
610 |
numFlags += ee->getRepresentative(compInf) == one ? 1 : 0; |
887 |
610 |
numFlags += ee->getRepresentative(compZero) == one ? 1 : 0; |
888 |
610 |
Assert(numFlags <= 1); |
889 |
|
} |
890 |
|
} |
891 |
|
|
892 |
4717 |
return true; |
893 |
|
} |
894 |
|
|
895 |
510 |
bool TheoryFp::NotifyClass::eqNotifyTriggerPredicate(TNode predicate, |
896 |
|
bool value) { |
897 |
1020 |
Debug("fp-eq") |
898 |
510 |
<< "TheoryFp::eqNotifyTriggerPredicate(): call back as predicate " |
899 |
510 |
<< predicate << " is " << value << std::endl; |
900 |
|
|
901 |
510 |
if (value) { |
902 |
344 |
return d_theorySolver.propagateLit(predicate); |
903 |
|
} |
904 |
166 |
return d_theorySolver.propagateLit(predicate.notNode()); |
905 |
|
} |
906 |
|
|
907 |
318 |
bool TheoryFp::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, |
908 |
|
TNode t2, bool value) { |
909 |
636 |
Debug("fp-eq") << "TheoryFp::eqNotifyTriggerTermEquality(): call back as " |
910 |
318 |
<< t1 << (value ? " = " : " != ") << t2 << std::endl; |
911 |
|
|
912 |
318 |
if (value) { |
913 |
175 |
return d_theorySolver.propagateLit(t1.eqNode(t2)); |
914 |
|
} |
915 |
143 |
return d_theorySolver.propagateLit(t1.eqNode(t2).notNode()); |
916 |
|
} |
917 |
|
|
918 |
|
void TheoryFp::NotifyClass::eqNotifyConstantTermMerge(TNode t1, TNode t2) { |
919 |
|
Debug("fp-eq") << "TheoryFp::eqNotifyConstantTermMerge(): call back as " << t1 |
920 |
|
<< " = " << t2 << std::endl; |
921 |
|
d_theorySolver.conflictEqConstantMerge(t1, t2); |
922 |
|
} |
923 |
|
|
924 |
|
} // namespace fp |
925 |
|
} // namespace theory |
926 |
27735 |
} // namespace cvc5 |