summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Noetzli <andres.noetzli@gmail.com>2019-04-01 15:07:05 -0700
committerGitHub <noreply@github.com>2019-04-01 15:07:05 -0700
commit8a9ffdbb248ddcc6a41f628f6dcbc070b57e6a28 (patch)
treebf9e85f9950c2c52f7795bdebdfd0183f114060d
parent41355e412a142809f63a1939a4515486ccd4c6fb (diff)
FP: Fix wrong model due to partial assignment (#2910)
For a simple query `(not (= (fp.isSubnormal x) false))`, we were getting a wrong model. The issue was that `(sign x)` was not assigned a value and did not appear in the shared terms. In `TheoryFp::collectModelInfo()`, however, we generate an expression that connects the components of `x` to `x`, which contains `(sign x)`. As a result, the normalization while building a model did not result in a constant. This commit fixes the issue by marking `(sign x)` (and `(significand x)`) as assignable. Assignable terms can take any value while building a model if there is no existing value.
-rw-r--r--src/theory/fp/theory_fp.cpp35
-rw-r--r--src/theory/theory_model_builder.cpp8
-rw-r--r--test/regress/CMakeLists.txt1
-rw-r--r--test/regress/regress0/fp/wrong-model.smt211
4 files changed, 55 insertions, 0 deletions
diff --git a/src/theory/fp/theory_fp.cpp b/src/theory/fp/theory_fp.cpp
index 627b87ba7..4652f62d1 100644
--- a/src/theory/fp/theory_fp.cpp
+++ b/src/theory/fp/theory_fp.cpp
@@ -1084,6 +1084,41 @@ bool TheoryFp::collectModelInfo(TheoryModel *m)
{
return false;
}
+
+ if (Configuration::isAssertionBuild() && isLeaf(node) && !node.isConst()
+ && node.getType().isFloatingPoint())
+ {
+ // Check that the equality engine has asssigned values to all the
+ // components of `node` except `(sign node)` (the sign component is
+ // assignable, meaning that the model builder can pick an arbitrary value
+ // for it if it hasn't been assigned in the equality engine).
+ NodeManager* nm = NodeManager::currentNM();
+ Node compNaN = nm->mkNode(kind::FLOATINGPOINT_COMPONENT_NAN, node);
+ Node compInf = nm->mkNode(kind::FLOATINGPOINT_COMPONENT_INF, node);
+ Node compZero = nm->mkNode(kind::FLOATINGPOINT_COMPONENT_ZERO, node);
+ Node compExponent =
+ nm->mkNode(kind::FLOATINGPOINT_COMPONENT_EXPONENT, node);
+ Node compSignificand =
+ nm->mkNode(kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND, node);
+
+ eq::EqualityEngine* ee = m->getEqualityEngine();
+ Assert(ee->hasTerm(compNaN) && ee->getRepresentative(compNaN).isConst());
+ Assert(ee->hasTerm(compInf) && ee->getRepresentative(compInf).isConst());
+ Assert(ee->hasTerm(compZero)
+ && ee->getRepresentative(compZero).isConst());
+ Assert(ee->hasTerm(compExponent)
+ && ee->getRepresentative(compExponent).isConst());
+ Assert(ee->hasTerm(compSignificand));
+ Assert(ee->getRepresentative(compSignificand).isConst());
+
+ // At most one of the flags (NaN, inf, zero) can be set
+ Node one = nm->mkConst(BitVector(1U, 1U));
+ size_t numFlags = 0;
+ numFlags += ee->getRepresentative(compNaN) == one ? 1 : 0;
+ numFlags += ee->getRepresentative(compInf) == one ? 1 : 0;
+ numFlags += ee->getRepresentative(compZero) == one ? 1 : 0;
+ Assert(numFlags <= 1);
+ }
}
return true;
diff --git a/src/theory/theory_model_builder.cpp b/src/theory/theory_model_builder.cpp
index 77cdfb79b..102979056 100644
--- a/src/theory/theory_model_builder.cpp
+++ b/src/theory/theory_model_builder.cpp
@@ -47,6 +47,14 @@ bool TheoryEngineModelBuilder::isAssignable(TNode n)
return !n.getType().isFunction();
}
}
+ else if (n.getKind() == kind::FLOATINGPOINT_COMPONENT_SIGN)
+ {
+ // Extracting the sign of a floating-point number acts similar to a
+ // selector on a datatype, i.e. if `(sign x)` wasn't assigned a value, we
+ // can pick an arbitrary one. Note that the other components of a
+ // floating-point number should always be assigned a value.
+ return true;
+ }
else
{
// non-function variables, and fully applied functions
diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt
index c6ccab464..13d1540f6 100644
--- a/test/regress/CMakeLists.txt
+++ b/test/regress/CMakeLists.txt
@@ -451,6 +451,7 @@ set(regress_0_tests
regress0/fp/abs-unsound2.smt2
regress0/fp/ext-rew-test.smt2
regress0/fp/simple.smt2
+ regress0/fp/wrong-model.smt2
regress0/fuzz_1.smt
regress0/fuzz_3.smt
regress0/get-value-incremental.smt2
diff --git a/test/regress/regress0/fp/wrong-model.smt2 b/test/regress/regress0/fp/wrong-model.smt2
new file mode 100644
index 000000000..4bb7645d5
--- /dev/null
+++ b/test/regress/regress0/fp/wrong-model.smt2
@@ -0,0 +1,11 @@
+; REQUIRES: symfpu
+; EXPECT: sat
+
+; NOTE: the (set-logic ALL) is on purpose because the problem was not triggered
+; with QF_FP.
+(set-logic ALL)
+(declare-const r RoundingMode)
+(declare-const x (_ FloatingPoint 5 11))
+(declare-const y (_ FloatingPoint 5 11))
+(assert (not (= (fp.isSubnormal x) false)))
+(check-sat)
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback