1 /********************* */
2 /*! \file theory_fp.cpp
4 ** Top contributors (to current version):
5 ** Martin Brain, Tim King, Paul Meng
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2017 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.\endverbatim
12 ** \brief [[ Add one-line brief description here ]]
14 ** [[ Add lengthier description here ]]
15 ** \todo document this file
18 #include "theory/fp/theory_fp.h"
19 #include "theory/rewriter.h"
20 #include "theory/theory_model.h"
24 #include <unordered_set>
33 namespace removeToFPGeneric
{
35 Node
removeToFPGeneric(TNode node
) {
36 Assert(node
.getKind() == kind::FLOATINGPOINT_TO_FP_GENERIC
);
38 FloatingPointToFPGeneric info
=
39 node
.getOperator().getConst
<FloatingPointToFPGeneric
>();
41 size_t children
= node
.getNumChildren();
44 NodeManager
*nm
= NodeManager::currentNM();
47 op
= nm
->mkConst(FloatingPointToFPIEEEBitVector(info
));
48 return nm
->mkNode(op
, node
[0]);
51 Assert(children
== 2);
52 Assert(node
[0].getType().isRoundingMode());
54 TypeNode t
= node
[1].getType();
56 if (t
.isFloatingPoint()) {
57 op
= nm
->mkConst(FloatingPointToFPFloatingPoint(info
));
58 } else if (t
.isReal()) {
59 op
= nm
->mkConst(FloatingPointToFPReal(info
));
60 } else if (t
.isBitVector()) {
61 op
= nm
->mkConst(FloatingPointToFPSignedBitVector(info
));
63 throw TypeCheckingExceptionPrivate(
65 "cannot rewrite to_fp generic due to incorrect type of second "
69 return nm
->mkNode(op
, node
[0], node
[1]);
72 Unreachable("to_fp generic not rewritten");
74 } // namespace removeToFPGeneric
77 Node
buildConjunct(const std::vector
<TNode
> &assumptions
) {
78 if (assumptions
.size() == 0) {
79 return NodeManager::currentNM()->mkConst
<bool>(true);
81 } else if (assumptions
.size() == 1) {
82 return assumptions
[0];
85 // \todo see bv::utils::flattenAnd
87 NodeBuilder
<> conjunction(kind::AND
);
88 for (std::vector
<TNode
>::const_iterator it
= assumptions
.begin();
89 it
!= assumptions
.end(); ++it
) {
98 /** Constructs a new instance of TheoryFp w.r.t. the provided contexts. */
99 TheoryFp::TheoryFp(context::Context
*c
,
100 context::UserContext
*u
,
103 const LogicInfo
&logicInfo
)
104 : Theory(THEORY_FP
, c
, u
, out
, valuation
, logicInfo
),
105 d_notification(*this),
106 d_equalityEngine(d_notification
, c
, "theory::fp::ee", true),
107 d_registeredTerms(u
),
109 d_expansionRequested(false),
110 d_conflict(c
, false),
111 d_conflictNode(c
, Node::null()),
121 // Kinds that are to be handled in the congruence closure
123 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ABS
);
124 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_NEG
);
125 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_PLUS
);
126 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_SUB); // Removed
127 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_MULT
);
128 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_DIV
);
129 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_FMA
);
130 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_SQRT
);
131 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_REM
);
132 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_RTI
);
133 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_MIN); // Removed
134 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_MAX); // Removed
135 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_MIN_TOTAL
);
136 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_MAX_TOTAL
);
138 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_EQ); // Removed
139 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_LEQ
);
140 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_LT
);
141 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_GEQ); // Removed
142 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_GT); // Removed
143 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ISN
);
144 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ISSN
);
145 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ISZ
);
146 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ISINF
);
147 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ISNAN
);
148 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ISNEG
);
149 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_ISPOS
);
151 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR
);
152 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT
);
153 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_TO_FP_REAL
);
154 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR
);
155 d_equalityEngine
.addFunctionKind(
156 kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR
);
157 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_FP_GENERIC); //
158 // Needed in parsing, should be rewritten away
160 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_UBV); // Removed
161 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_SBV); // Removed
162 // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_REAL); // Removed
163 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_TO_UBV_TOTAL
);
164 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_TO_SBV_TOTAL
);
165 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_TO_REAL_TOTAL
);
167 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_NAN
);
168 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_INF
);
169 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_ZERO
);
170 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGN
);
171 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_EXPONENT
);
172 d_equalityEngine
.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND
);
173 d_equalityEngine
.addFunctionKind(kind::ROUNDINGMODE_BITBLAST
);
175 } /* TheoryFp::TheoryFp() */
177 Node
TheoryFp::minUF(Node node
) {
178 Assert(node
.getKind() == kind::FLOATINGPOINT_MIN
);
179 TypeNode
t(node
.getType());
180 Assert(t
.getKind() == kind::FLOATINGPOINT_TYPE
);
182 NodeManager
*nm
= NodeManager::currentNM();
183 ComparisonUFMap::const_iterator
i(d_minMap
.find(t
));
186 if (i
== d_minMap
.end()) {
187 std::vector
<TypeNode
> args(2);
190 fun
= nm
->mkSkolem("floatingpoint_min_zero_case",
191 nm
->mkFunctionType(args
,
192 #ifdef SYMFPUPROPISBOOL
195 nm
->mkBitVectorType(1U)
198 "floatingpoint_min_zero_case",
199 NodeManager::SKOLEM_EXACT_NAME
);
200 d_minMap
.insert(t
, fun
);
204 return nm
->mkNode(kind::APPLY_UF
, fun
, node
[1],
205 node
[0]); // Application reverses the order or arguments
208 Node
TheoryFp::maxUF(Node node
) {
209 Assert(node
.getKind() == kind::FLOATINGPOINT_MAX
);
210 TypeNode
t(node
.getType());
211 Assert(t
.getKind() == kind::FLOATINGPOINT_TYPE
);
213 NodeManager
*nm
= NodeManager::currentNM();
214 ComparisonUFMap::const_iterator
i(d_maxMap
.find(t
));
217 if (i
== d_maxMap
.end()) {
218 std::vector
<TypeNode
> args(2);
221 fun
= nm
->mkSkolem("floatingpoint_max_zero_case",
222 nm
->mkFunctionType(args
,
223 #ifdef SYMFPUPROPISBOOL
226 nm
->mkBitVectorType(1U)
229 "floatingpoint_max_zero_case",
230 NodeManager::SKOLEM_EXACT_NAME
);
231 d_maxMap
.insert(t
, fun
);
235 return nm
->mkNode(kind::APPLY_UF
, fun
, node
[1], node
[0]);
238 Node
TheoryFp::toUBVUF(Node node
) {
239 Assert(node
.getKind() == kind::FLOATINGPOINT_TO_UBV
);
241 TypeNode
target(node
.getType());
242 Assert(target
.getKind() == kind::BITVECTOR_TYPE
);
244 TypeNode
source(node
[1].getType());
245 Assert(source
.getKind() == kind::FLOATINGPOINT_TYPE
);
247 std::pair
<TypeNode
, TypeNode
> p(source
, target
);
248 NodeManager
*nm
= NodeManager::currentNM();
249 ConversionUFMap::const_iterator
i(d_toUBVMap
.find(p
));
252 if (i
== d_toUBVMap
.end()) {
253 std::vector
<TypeNode
> args(2);
254 args
[0] = nm
->roundingModeType();
256 fun
= nm
->mkSkolem("floatingpoint_to_ubv_out_of_range_case",
257 nm
->mkFunctionType(args
, target
),
258 "floatingpoint_to_ubv_out_of_range_case",
259 NodeManager::SKOLEM_EXACT_NAME
);
260 d_toUBVMap
.insert(p
, fun
);
264 return nm
->mkNode(kind::APPLY_UF
, fun
, node
[0], node
[1]);
267 Node
TheoryFp::toSBVUF(Node node
) {
268 Assert(node
.getKind() == kind::FLOATINGPOINT_TO_SBV
);
270 TypeNode
target(node
.getType());
271 Assert(target
.getKind() == kind::BITVECTOR_TYPE
);
273 TypeNode
source(node
[1].getType());
274 Assert(source
.getKind() == kind::FLOATINGPOINT_TYPE
);
276 std::pair
<TypeNode
, TypeNode
> p(source
, target
);
277 NodeManager
*nm
= NodeManager::currentNM();
278 ConversionUFMap::const_iterator
i(d_toSBVMap
.find(p
));
281 if (i
== d_toSBVMap
.end()) {
282 std::vector
<TypeNode
> args(2);
283 args
[0] = nm
->roundingModeType();
285 fun
= nm
->mkSkolem("floatingpoint_to_sbv_out_of_range_case",
286 nm
->mkFunctionType(args
, target
),
287 "floatingpoint_to_sbv_out_of_range_case",
288 NodeManager::SKOLEM_EXACT_NAME
);
289 d_toSBVMap
.insert(p
, fun
);
293 return nm
->mkNode(kind::APPLY_UF
, fun
, node
[0], node
[1]);
296 Node
TheoryFp::toRealUF(Node node
) {
297 Assert(node
.getKind() == kind::FLOATINGPOINT_TO_REAL
);
298 TypeNode
t(node
[0].getType());
299 Assert(t
.getKind() == kind::FLOATINGPOINT_TYPE
);
301 NodeManager
*nm
= NodeManager::currentNM();
302 ComparisonUFMap::const_iterator
i(d_toRealMap
.find(t
));
305 if (i
== d_toRealMap
.end()) {
306 std::vector
<TypeNode
> args(1);
308 fun
= nm
->mkSkolem("floatingpoint_to_real_infinity_and_NaN_case",
309 nm
->mkFunctionType(args
, nm
->realType()),
310 "floatingpoint_to_real_infinity_and_NaN_case",
311 NodeManager::SKOLEM_EXACT_NAME
);
312 d_toRealMap
.insert(t
, fun
);
316 return nm
->mkNode(kind::APPLY_UF
, fun
, node
[0]);
319 void TheoryFp::enableUF(LogicRequest
&lr
)
321 if (!this->d_expansionRequested
) {
322 // Needed for conversions to/from real and min/max
323 lr
.widenLogic(THEORY_UF
);
324 // THEORY_BV has to be enabled when the logic is set
325 this->d_expansionRequested
= true;
330 Node
TheoryFp::abstractRealToFloat(Node node
)
332 Assert(node
.getKind() == kind::FLOATINGPOINT_TO_FP_REAL
);
333 TypeNode
t(node
.getType());
334 Assert(t
.getKind() == kind::FLOATINGPOINT_TYPE
);
336 NodeManager
*nm
= NodeManager::currentNM();
337 ComparisonUFMap::const_iterator
i(realToFloatMap
.find(t
));
340 if (i
== realToFloatMap
.end())
342 std::vector
<TypeNode
> args(2);
343 args
[0] = node
[0].getType();
344 args
[1] = node
[1].getType();
345 fun
= nm
->mkSkolem("floatingpoint_abstract_real_to_float",
346 nm
->mkFunctionType(args
, node
.getType()),
347 "floatingpoint_abstract_real_to_float",
348 NodeManager::SKOLEM_EXACT_NAME
);
349 realToFloatMap
.insert(t
, fun
);
355 Node uf
= nm
->mkNode(kind::APPLY_UF
, fun
, node
[0], node
[1]);
357 abstractionMap
.insert(uf
, node
);
362 Node
TheoryFp::abstractFloatToReal(Node node
)
364 Assert(node
.getKind() == kind::FLOATINGPOINT_TO_REAL_TOTAL
);
365 TypeNode
t(node
[0].getType());
366 Assert(t
.getKind() == kind::FLOATINGPOINT_TYPE
);
368 NodeManager
*nm
= NodeManager::currentNM();
369 ComparisonUFMap::const_iterator
i(floatToRealMap
.find(t
));
372 if (i
== floatToRealMap
.end())
374 std::vector
<TypeNode
> args(2);
376 args
[1] = nm
->realType();
377 fun
= nm
->mkSkolem("floatingpoint_abstract_float_to_real",
378 nm
->mkFunctionType(args
, nm
->realType()),
379 "floatingpoint_abstract_float_to_real",
380 NodeManager::SKOLEM_EXACT_NAME
);
381 floatToRealMap
.insert(t
, fun
);
387 Node uf
= nm
->mkNode(kind::APPLY_UF
, fun
, node
[0], node
[1]);
389 abstractionMap
.insert(uf
, node
);
394 Node
TheoryFp::expandDefinition(LogicRequest
&lr
, Node node
)
396 Trace("fp-expandDefinition") << "TheoryFp::expandDefinition(): " << node
401 if (node
.getKind() == kind::FLOATINGPOINT_TO_FP_GENERIC
) {
402 res
= removeToFPGeneric::removeToFPGeneric(node
);
404 } else if (node
.getKind() == kind::FLOATINGPOINT_MIN
) {
406 res
= NodeManager::currentNM()->mkNode(kind::FLOATINGPOINT_MIN_TOTAL
,
407 node
[0], node
[1], minUF(node
));
409 } else if (node
.getKind() == kind::FLOATINGPOINT_MAX
) {
411 res
= NodeManager::currentNM()->mkNode(kind::FLOATINGPOINT_MAX_TOTAL
,
412 node
[0], node
[1], maxUF(node
));
414 } else if (node
.getKind() == kind::FLOATINGPOINT_TO_UBV
) {
416 FloatingPointToUBV info
= node
.getOperator().getConst
<FloatingPointToUBV
>();
417 FloatingPointToUBVTotal
newInfo(info
);
420 NodeManager::currentNM()->mkNode( // kind::FLOATINGPOINT_TO_UBV_TOTAL,
421 NodeManager::currentNM()->mkConst(newInfo
), node
[0], node
[1],
424 } else if (node
.getKind() == kind::FLOATINGPOINT_TO_SBV
) {
426 FloatingPointToSBV info
= node
.getOperator().getConst
<FloatingPointToSBV
>();
427 FloatingPointToSBVTotal
newInfo(info
);
430 NodeManager::currentNM()->mkNode( // kind::FLOATINGPOINT_TO_SBV_TOTAL,
431 NodeManager::currentNM()->mkConst(newInfo
), node
[0], node
[1],
434 } else if (node
.getKind() == kind::FLOATINGPOINT_TO_REAL
) {
436 res
= NodeManager::currentNM()->mkNode(kind::FLOATINGPOINT_TO_REAL_TOTAL
,
437 node
[0], toRealUF(node
));
443 // We will need to enable UF to abstract these in ppRewrite
444 if (res
.getKind() == kind::FLOATINGPOINT_TO_REAL_TOTAL
445 || res
.getKind() == kind::FLOATINGPOINT_TO_FP_REAL
)
451 Trace("fp-expandDefinition") << "TheoryFp::expandDefinition(): " << node
452 << " rewritten to " << res
<< std::endl
;
458 Node
TheoryFp::ppRewrite(TNode node
)
460 Trace("fp-ppRewrite") << "TheoryFp::ppRewrite(): " << node
<< std::endl
;
464 // Abstract conversion functions
465 if (node
.getKind() == kind::FLOATINGPOINT_TO_REAL_TOTAL
)
467 res
= abstractFloatToReal(node
);
469 // Generate some lemmas
470 NodeManager
*nm
= NodeManager::currentNM();
473 nm
->mkNode(kind::IMPLIES
,
475 nm
->mkNode(kind::FLOATINGPOINT_ISNAN
, node
[0]),
476 nm
->mkNode(kind::FLOATINGPOINT_ISINF
, node
[0])),
477 nm
->mkNode(kind::EQUAL
, res
, node
[1]));
481 nm
->mkNode(kind::IMPLIES
,
482 nm
->mkNode(kind::FLOATINGPOINT_ISZ
, node
[0]),
483 nm
->mkNode(kind::EQUAL
, res
, nm
->mkConst(Rational(0U))));
486 // TODO : bounds on the output from largest floats, #1914
488 else if (node
.getKind() == kind::FLOATINGPOINT_TO_FP_REAL
)
490 res
= abstractRealToFloat(node
);
492 // Generate some lemmas
493 NodeManager
*nm
= NodeManager::currentNM();
496 nm
->mkNode(kind::NOT
, nm
->mkNode(kind::FLOATINGPOINT_ISNAN
, res
));
501 nm
->mkNode(kind::EQUAL
, node
[1], nm
->mkConst(Rational(0U))),
502 nm
->mkNode(kind::EQUAL
,
504 nm
->mkConst(FloatingPoint::makeZero(
505 res
.getType().getConst
<FloatingPointSize
>(), false))));
508 // TODO : rounding-mode specific bounds on floats that don't give infinity
509 // BEWARE of directed rounding! #1914
514 Trace("fp-ppRewrite") << "TheoryFp::ppRewrite(): node " << node
515 << " rewritten to " << res
<< std::endl
;
521 bool TheoryFp::refineAbstraction(TheoryModel
*m
, TNode abstract
, TNode concrete
)
523 Trace("fp-refineAbstraction") << "TheoryFp::refineAbstraction(): " << abstract
524 << " vs. " << concrete
<< std::endl
;
525 Kind k
= concrete
.getKind();
526 if (k
== kind::FLOATINGPOINT_TO_REAL_TOTAL
)
529 Assert(m
->hasTerm(abstract
));
530 Assert(m
->hasTerm(concrete
[0]));
531 Assert(m
->hasTerm(concrete
[1]));
533 Node abstractValue
= m
->getValue(abstract
);
534 Node floatValue
= m
->getValue(concrete
[0]);
535 Node undefValue
= m
->getValue(concrete
[1]);
537 Assert(abstractValue
.isConst());
538 Assert(floatValue
.isConst());
539 Assert(undefValue
.isConst());
541 // Work out the actual value for those args
542 NodeManager
*nm
= NodeManager::currentNM();
545 nm
->mkNode(kind::FLOATINGPOINT_TO_REAL_TOTAL
, floatValue
, undefValue
);
546 Node concreteValue
= Rewriter::rewrite(evaluate
);
547 Assert(concreteValue
.isConst());
549 Trace("fp-refineAbstraction")
550 << "TheoryFp::refineAbstraction(): " << concrete
[0] << " = "
551 << floatValue
<< std::endl
552 << "TheoryFp::refineAbstraction(): " << concrete
[1] << " = "
553 << undefValue
<< std::endl
554 << "TheoryFp::refineAbstraction(): " << abstract
<< " = "
555 << abstractValue
<< std::endl
556 << "TheoryFp::refineAbstraction(): " << concrete
<< " = "
557 << concreteValue
<< std::endl
;
559 if (abstractValue
!= concreteValue
)
561 // Need refinement lemmas
562 // only in the normal and subnormal case
563 Assert(floatValue
.getConst
<FloatingPoint
>().isNormal()
564 || floatValue
.getConst
<FloatingPoint
>().isSubnormal());
566 Node defined
= nm
->mkNode(
568 nm
->mkNode(kind::NOT
,
569 nm
->mkNode(kind::FLOATINGPOINT_ISNAN
, concrete
[0])),
570 nm
->mkNode(kind::NOT
,
571 nm
->mkNode(kind::FLOATINGPOINT_ISINF
, concrete
[0])));
572 // First the "forward" constraints
573 Node fg
= nm
->mkNode(
578 nm
->mkNode(kind::FLOATINGPOINT_GEQ
, concrete
[0], floatValue
),
579 nm
->mkNode(kind::GEQ
, abstract
, concreteValue
)));
582 Node fl
= nm
->mkNode(
587 nm
->mkNode(kind::FLOATINGPOINT_LEQ
, concrete
[0], floatValue
),
588 nm
->mkNode(kind::LEQ
, abstract
, concreteValue
)));
591 // Then the backwards constraints
592 Node floatAboveAbstract
= Rewriter::rewrite(
593 nm
->mkNode(kind::FLOATINGPOINT_TO_FP_REAL
,
594 nm
->mkConst(FloatingPointToFPReal(
595 concrete
[0].getType().getConst
<FloatingPointSize
>())),
596 nm
->mkConst(roundTowardPositive
),
599 Node bg
= nm
->mkNode(
605 kind::FLOATINGPOINT_GEQ
, concrete
[0], floatAboveAbstract
),
606 nm
->mkNode(kind::GEQ
, abstract
, abstractValue
)));
609 Node floatBelowAbstract
= Rewriter::rewrite(
610 nm
->mkNode(kind::FLOATINGPOINT_TO_FP_REAL
,
611 nm
->mkConst(FloatingPointToFPReal(
612 concrete
[0].getType().getConst
<FloatingPointSize
>())),
613 nm
->mkConst(roundTowardNegative
),
616 Node bl
= nm
->mkNode(
622 kind::FLOATINGPOINT_LEQ
, concrete
[0], floatBelowAbstract
),
623 nm
->mkNode(kind::LEQ
, abstract
, abstractValue
)));
625 // TODO : see if the overflow conditions could be improved #1914
631 // No refinement needed
635 else if (k
== kind::FLOATINGPOINT_TO_FP_REAL
)
638 Assert(m
->hasTerm(abstract
));
639 Assert(m
->hasTerm(concrete
[0]));
640 Assert(m
->hasTerm(concrete
[1]));
642 Node abstractValue
= m
->getValue(abstract
);
643 Node rmValue
= m
->getValue(concrete
[0]);
644 Node realValue
= m
->getValue(concrete
[1]);
646 Assert(abstractValue
.isConst());
647 Assert(rmValue
.isConst());
648 Assert(realValue
.isConst());
650 // Work out the actual value for those args
651 NodeManager
*nm
= NodeManager::currentNM();
654 nm
->mkNode(kind::FLOATINGPOINT_TO_FP_REAL
,
655 nm
->mkConst(FloatingPointToFPReal(
656 concrete
.getType().getConst
<FloatingPointSize
>())),
659 Node concreteValue
= Rewriter::rewrite(evaluate
);
660 Assert(concreteValue
.isConst());
662 Trace("fp-refineAbstraction")
663 << "TheoryFp::refineAbstraction(): " << concrete
[0] << " = " << rmValue
665 << "TheoryFp::refineAbstraction(): " << concrete
[1] << " = "
666 << realValue
<< std::endl
667 << "TheoryFp::refineAbstraction(): " << abstract
<< " = "
668 << abstractValue
<< std::endl
669 << "TheoryFp::refineAbstraction(): " << concrete
<< " = "
670 << concreteValue
<< std::endl
;
672 if (abstractValue
!= concreteValue
)
674 Assert(!abstractValue
.getConst
<FloatingPoint
>().isNaN());
675 Assert(!concreteValue
.getConst
<FloatingPoint
>().isNaN());
677 Node correctRoundingMode
= nm
->mkNode(kind::EQUAL
, concrete
[0], rmValue
);
678 // TODO : Generalise to all rounding modes #1914
680 // First the "forward" constraints
681 Node fg
= nm
->mkNode(
686 nm
->mkNode(kind::GEQ
, concrete
[1], realValue
),
687 nm
->mkNode(kind::FLOATINGPOINT_GEQ
, abstract
, concreteValue
)));
690 Node fl
= nm
->mkNode(
695 nm
->mkNode(kind::LEQ
, concrete
[1], realValue
),
696 nm
->mkNode(kind::FLOATINGPOINT_LEQ
, abstract
, concreteValue
)));
699 // Then the backwards constraints
700 if (!abstractValue
.getConst
<FloatingPoint
>().isInfinite())
702 Node realValueOfAbstract
=
703 Rewriter::rewrite(nm
->mkNode(kind::FLOATINGPOINT_TO_REAL_TOTAL
,
705 nm
->mkConst(Rational(0U))));
707 Node bg
= nm
->mkNode(
712 nm
->mkNode(kind::GEQ
, concrete
[1], realValueOfAbstract
),
713 nm
->mkNode(kind::FLOATINGPOINT_GEQ
, abstract
, abstractValue
)));
716 Node bl
= nm
->mkNode(
721 nm
->mkNode(kind::LEQ
, concrete
[1], realValueOfAbstract
),
722 nm
->mkNode(kind::FLOATINGPOINT_LEQ
, abstract
, abstractValue
)));
730 // No refinement needed
736 Unreachable("Unknown abstraction");
742 void TheoryFp::convertAndEquateTerm(TNode node
) {
743 Trace("fp-convertTerm") << "TheoryFp::convertTerm(): " << node
<< std::endl
;
744 size_t oldAdditionalAssertions
= d_conv
.d_additionalAssertions
.size();
746 Node
converted(d_conv
.convert(node
));
748 if (converted
!= node
) {
749 Debug("fp-convertTerm")
750 << "TheoryFp::convertTerm(): before " << node
<< std::endl
;
751 Debug("fp-convertTerm")
752 << "TheoryFp::convertTerm(): after " << converted
<< std::endl
;
755 size_t newAdditionalAssertions
= d_conv
.d_additionalAssertions
.size();
756 Assert(oldAdditionalAssertions
<= newAdditionalAssertions
);
758 while (oldAdditionalAssertions
< newAdditionalAssertions
) {
759 Node addA
= d_conv
.d_additionalAssertions
[oldAdditionalAssertions
];
761 Debug("fp-convertTerm") << "TheoryFp::convertTerm(): additional assertion "
762 << addA
<< std::endl
;
764 #ifdef SYMFPUPROPISBOOL
765 handleLemma(addA
, false, true);
767 NodeManager
*nm
= NodeManager::currentNM();
770 nm
->mkNode(kind::EQUAL
, addA
, nm
->mkConst(::CVC4::BitVector(1U, 1U))));
773 ++oldAdditionalAssertions
;
776 // Equate the floating-point atom and the converted one.
777 // Also adds the bit-vectors to the bit-vector solver.
778 if (node
.getType().isBoolean()) {
779 if (converted
!= node
) {
780 Assert(converted
.getType().isBitVector());
782 NodeManager
*nm
= NodeManager::currentNM();
784 #ifdef SYMFPUPROPISBOOL
785 handleLemma(nm
->mkNode(kind::EQUAL
, node
, converted
));
788 nm
->mkNode(kind::EQUAL
, node
,
789 nm
->mkNode(kind::EQUAL
, converted
,
790 nm
->mkConst(::CVC4::BitVector(1U, 1U)))));
794 Assert((node
.getKind() == kind::EQUAL
));
797 } else if (node
.getType().isBitVector()) {
798 if (converted
!= node
) {
799 Assert(converted
.getType().isBitVector());
802 NodeManager::currentNM()->mkNode(kind::EQUAL
, node
, converted
));
809 void TheoryFp::registerTerm(TNode node
) {
810 Trace("fp-registerTerm") << "TheoryFp::registerTerm(): " << node
<< std::endl
;
812 if (!isRegistered(node
)) {
813 bool success
= d_registeredTerms
.insert(node
);
814 (void)success
; // Only used for assertion
817 // Add to the equality engine
818 if (node
.getKind() == kind::EQUAL
) {
819 d_equalityEngine
.addTriggerEquality(node
);
821 d_equalityEngine
.addTerm(node
);
824 // Give the expansion of classifications in terms of equalities
825 // This should make equality reasoning slightly more powerful.
826 if ((node
.getKind() == kind::FLOATINGPOINT_ISNAN
)
827 || (node
.getKind() == kind::FLOATINGPOINT_ISZ
)
828 || (node
.getKind() == kind::FLOATINGPOINT_ISINF
))
830 NodeManager
*nm
= NodeManager::currentNM();
831 FloatingPointSize s
= node
[0].getType().getConst
<FloatingPointSize
>();
832 Node equalityAlias
= Node::null();
834 if (node
.getKind() == kind::FLOATINGPOINT_ISNAN
)
836 equalityAlias
= nm
->mkNode(
837 kind::EQUAL
, node
[0], nm
->mkConst(FloatingPoint::makeNaN(s
)));
839 else if (node
.getKind() == kind::FLOATINGPOINT_ISZ
)
841 equalityAlias
= nm
->mkNode(
843 nm
->mkNode(kind::EQUAL
,
845 nm
->mkConst(FloatingPoint::makeZero(s
, true))),
846 nm
->mkNode(kind::EQUAL
,
848 nm
->mkConst(FloatingPoint::makeZero(s
, false))));
850 else if (node
.getKind() == kind::FLOATINGPOINT_ISINF
)
852 equalityAlias
= nm
->mkNode(
854 nm
->mkNode(kind::EQUAL
,
856 nm
->mkConst(FloatingPoint::makeInf(s
, true))),
857 nm
->mkNode(kind::EQUAL
,
859 nm
->mkConst(FloatingPoint::makeInf(s
, false))));
863 Unreachable("Only isNaN, isInf and isZero have aliases");
866 handleLemma(nm
->mkNode(kind::EQUAL
, node
, equalityAlias
));
869 // Use symfpu to produce an equivalent bit-vector statement
870 convertAndEquateTerm(node
);
875 bool TheoryFp::isRegistered(TNode node
) {
876 return !(d_registeredTerms
.find(node
) == d_registeredTerms
.end());
879 void TheoryFp::preRegisterTerm(TNode node
) {
880 Trace("fp-preRegisterTerm")
881 << "TheoryFp::preRegisterTerm(): " << node
<< std::endl
;
886 void TheoryFp::addSharedTerm(TNode node
) {
887 Trace("fp-addSharedTerm")
888 << "TheoryFp::addSharedTerm(): " << node
<< std::endl
;
889 // A system-wide invariant; terms must be registered before they are shared
890 Assert(isRegistered(node
));
894 void TheoryFp::handleLemma(Node node
) {
895 Trace("fp") << "TheoryFp::handleLemma(): asserting " << node
<< std::endl
;
897 d_out
->lemma(node
, false,
898 true); // Has to be true because it contains embedded ITEs
899 // Ignore the LemmaStatus structure for now...
904 bool TheoryFp::handlePropagation(TNode node
) {
905 Trace("fp") << "TheoryFp::handlePropagation(): propagate " << node
908 bool stat
= d_out
->propagate(node
);
910 if (!stat
) handleConflict(node
);
915 void TheoryFp::handleConflict(TNode node
) {
916 Trace("fp") << "TheoryFp::handleConflict(): conflict detected " << node
919 d_conflictNode
= node
;
921 d_out
->conflict(node
);
925 void TheoryFp::check(Effort level
) {
926 Trace("fp") << "TheoryFp::check(): started at effort level " << level
929 while (!done() && !d_conflict
) {
930 // Get all the assertions
931 Assertion assertion
= get();
932 TNode fact
= assertion
.assertion
;
934 Debug("fp") << "TheoryFp::check(): processing " << fact
<< std::endl
;
936 // Only handle equalities; the rest should be handled by
937 // the bit-vector theory
939 bool negated
= fact
.getKind() == kind::NOT
;
940 TNode predicate
= negated
? fact
[0] : fact
;
942 if (predicate
.getKind() == kind::EQUAL
) {
943 Assert(!(predicate
[0].getType().isFloatingPoint() ||
944 predicate
[0].getType().isRoundingMode()) ||
945 isRegistered(predicate
[0]));
946 Assert(!(predicate
[1].getType().isFloatingPoint() ||
947 predicate
[1].getType().isRoundingMode()) ||
948 isRegistered(predicate
[1]));
949 registerTerm(predicate
); // Needed for float equalities
952 Debug("fp-eq") << "TheoryFp::check(): adding dis-equality " << fact
[0]
954 d_equalityEngine
.assertEquality(predicate
, false, fact
);
957 Debug("fp-eq") << "TheoryFp::check(): adding equality " << fact
959 d_equalityEngine
.assertEquality(predicate
, true, fact
);
962 // A system-wide invariant; predicates are registered before they are
964 Assert(isRegistered(predicate
));
966 if (d_equalityEngine
.isFunctionKind(predicate
.getKind())) {
967 Debug("fp-eq") << "TheoryFp::check(): adding predicate " << predicate
968 << " is " << !negated
<< std::endl
;
969 d_equalityEngine
.assertPredicate(predicate
, !negated
, fact
);
974 // Resolve the abstractions for the conversion lemmas
975 // if (level == EFFORT_COMBINATION) {
976 if (level
== EFFORT_LAST_CALL
)
978 Trace("fp") << "TheoryFp::check(): checking abstractions" << std::endl
;
979 TheoryModel
*m
= getValuation().getModel();
980 bool lemmaAdded
= false;
982 for (abstractionMapType::const_iterator i
= abstractionMap
.begin();
983 i
!= abstractionMap
.end();
986 if (m
->hasTerm((*i
).first
))
987 { // Is actually used in the model
988 lemmaAdded
|= refineAbstraction(m
, (*i
).first
, (*i
).second
);
993 Trace("fp") << "TheoryFp::check(): completed" << std::endl
;
995 /* Checking should be handled by the bit-vector engine */
998 } /* TheoryFp::check() */
1000 void TheoryFp::setMasterEqualityEngine(eq::EqualityEngine
*eq
) {
1001 d_equalityEngine
.setMasterEqualityEngine(eq
);
1004 Node
TheoryFp::explain(TNode n
) {
1005 Trace("fp") << "TheoryFp::explain(): explain " << n
<< std::endl
;
1007 // All things we assert directly (and not via bit-vector) should
1008 // come from the equality engine so this should be sufficient...
1009 std::vector
<TNode
> assumptions
;
1011 bool polarity
= n
.getKind() != kind::NOT
;
1012 TNode atom
= polarity
? n
: n
[0];
1013 if (atom
.getKind() == kind::EQUAL
) {
1014 d_equalityEngine
.explainEquality(atom
[0], atom
[1], polarity
, assumptions
);
1016 d_equalityEngine
.explainPredicate(atom
, polarity
, assumptions
);
1019 return helper::buildConjunct(assumptions
);
1022 Node
TheoryFp::getModelValue(TNode var
) {
1023 return d_conv
.getValue(d_valuation
, var
);
1026 bool TheoryFp::collectModelInfo(TheoryModel
*m
)
1028 std::set
<Node
> relevantTerms
;
1030 Trace("fp-collectModelInfo")
1031 << "TheoryFp::collectModelInfo(): begin" << std::endl
;
1033 // Work out which variables are needed
1034 computeRelevantTerms(relevantTerms
);
1036 if (Trace
.isOn("fp-collectModelInfo")) {
1037 for (std::set
<Node
>::const_iterator
i(relevantTerms
.begin());
1038 i
!= relevantTerms
.end(); ++i
) {
1039 Trace("fp-collectModelInfo")
1040 << "TheoryFp::collectModelInfo(): relevantTerms " << *i
<< std::endl
;
1044 std::unordered_set
<TNode
, TNodeHashFunction
> visited
;
1045 std::stack
<TNode
> working
;
1046 std::set
<TNode
> relevantVariables
;
1047 for (std::set
<Node
>::const_iterator
i(relevantTerms
.begin());
1048 i
!= relevantTerms
.end(); ++i
) {
1052 while (!working
.empty()) {
1053 TNode current
= working
.top();
1056 // Ignore things that have already been explored
1057 if (visited
.find(current
) == visited
.end()) {
1058 visited
.insert(current
);
1060 TypeNode
t(current
.getType());
1062 if ((t
.isRoundingMode() || t
.isFloatingPoint()) &&
1063 this->isLeaf(current
)) {
1064 relevantVariables
.insert(current
);
1067 for (size_t i
= 0; i
< current
.getNumChildren(); ++i
) {
1068 working
.push(current
[i
]);
1073 for (std::set
<TNode
>::const_iterator
i(relevantVariables
.begin());
1074 i
!= relevantVariables
.end(); ++i
) {
1077 Trace("fp-collectModelInfo")
1078 << "TheoryFp::collectModelInfo(): relevantVariable " << node
1081 if (!m
->assertEquality(node
, d_conv
.getValue(d_valuation
, node
), true))
1090 bool TheoryFp::NotifyClass::eqNotifyTriggerEquality(TNode equality
,
1093 << "TheoryFp::eqNotifyTriggerEquality(): call back as equality "
1094 << equality
<< " is " << value
<< std::endl
;
1097 return d_theorySolver
.handlePropagation(equality
);
1099 return d_theorySolver
.handlePropagation(equality
.notNode());
1103 bool TheoryFp::NotifyClass::eqNotifyTriggerPredicate(TNode predicate
,
1106 << "TheoryFp::eqNotifyTriggerPredicate(): call back as predicate "
1107 << predicate
<< " is " << value
<< std::endl
;
1110 return d_theorySolver
.handlePropagation(predicate
);
1112 return d_theorySolver
.handlePropagation(predicate
.notNode());
1116 bool TheoryFp::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag
, TNode t1
,
1117 TNode t2
, bool value
) {
1118 Debug("fp-eq") << "TheoryFp::eqNotifyTriggerTermEquality(): call back as "
1119 << t1
<< (value
? " = " : " != ") << t2
<< std::endl
;
1122 return d_theorySolver
.handlePropagation(t1
.eqNode(t2
));
1124 return d_theorySolver
.handlePropagation(t1
.eqNode(t2
).notNode());
1128 void TheoryFp::NotifyClass::eqNotifyConstantTermMerge(TNode t1
, TNode t2
) {
1129 Debug("fp-eq") << "TheoryFp::eqNotifyConstantTermMerge(): call back as " << t1
1130 << " = " << t2
<< std::endl
;
1132 std::vector
<TNode
> assumptions
;
1133 d_theorySolver
.d_equalityEngine
.explainEquality(t1
, t2
, true, assumptions
);
1135 Node conflict
= helper::buildConjunct(assumptions
);
1137 d_theorySolver
.handleConflict(conflict
);
1141 } // namespace theory