Working on an analyzer based on Z3 (this analyzer should detect overflows when doubles converted to long/ulong in .net), I came across a strange thing related to floating-point numbers.
Finally, I've created a small sample that shows the issue:
Both:
(assert (= ((_ fp.to_sbv 64) roundTowardZero (fp #b0 #b10000111110 #x0000000000000)) #x8000000000000000))
(check-sat)
and:
(assert (not (= ((_ fp.to_sbv 64) roundTowardZero (fp #b0 #b10000111110 #x0000000000000)) #x8000000000000000)))
(check-sat)
give me sat.
How could it happen that a rounded floating-point number may be equal to some value, and at the same time it may not be equal?
The floating point constant evaluates to
(-1)^0 * 2^(1086 - 1023) * (1 + 0) = 2^63
A Signed Bit-Vector of size e can hold values in the range [-2^(e-1), 2^(e-1) - 1]. Thus, the range of a Signed Bit-Vector of size 64 is [-2^63, 2^63 - 1].
Because 2^63 is outside that range, the conversion of 2^63 to a Signed Bit-Vector of size 64 is undefined:
In addition, fp.to_ubv and fp.to_sbv are unspecified for finite number inputs that are out of range (which includes all negative numbers for fp.to_ubv).
(source: SMT-LIB docs)
Since the conversion is undefined, the following expression
((_ fp.to_sbv 64) roundTowardZero (fp #b0 #b10000111110 #x0000000000000))
may have an arbitrary, unconstrained, 64-bit Bit-Vector value.
This explains why the equality can be found to be both true and false.
I assume you made those assertions separately of another, i.e. you asked Z3 if P is satisfiable, and (separately) if ¬P is satisfiable. This is different from asking if P ∧ ¬P is satisfiable. As an example, assume P is n = 0, for some integer n. Clearly, n could be 1, in which case ¬(n = 0) is satisfied, and n could be 0, in which case n = 0 is satisfied.
Related
Suppose I have the following (intentionally simple) subsection of constraints:
..... SOME STUFF .....
(declare-const I Int)
(assert (and (>= I 0) (<= I 1)))
(define-fun W () Int
2251799813685248
)
..... MORE STUFF .....
(maximize (* I W))
(check-sat)
(get-model)
Is the size I'm giving to W too big? Or more generally, is there a maximum size value that can be assigned in Z3 (for example if variables are stored as regular ints/floats/longs/etc instead of with variable precision)?
An Int value corresponds to a mathematical integer. It can be of an arbitrary size. There are no maximums.
For sized versions, you should use bit-vectors: (_ BV n) is the type of a bit-vector of size n, which follows machine arithmetic rules.
I was working with z3 with the following example.
f=Function('f',IntSort(),IntSort())
n=Int('n')
c=Int('c')
s=Solver()
s.add(c>=0)
s.add(f(0)==0)
s.add(ForAll([n],Implies(n>=0, f(n+1)==f(n)+10/(n-c))))
The last equation is inconsistent (since n=c would make it indeterminate). But, Z3 cannot detect this kind of inconsistencies. Is there any way in which Z3 can be made to detect it, or any other tool that can detect it?
As far as I can tell, your assertion that the last equation is inconsistent does not match the documentation of the SMT-LIB standard. The page Theories: Reals says:
Since in SMT-LIB logic all function symbols are interpreted
as total functions, terms of the form (/ t 0) are meaningful in
every instance of Reals. However, the declaration imposes no
constraints on their value. This means in particular that
for every instance theory T and
for every value v (as defined in the :values attribute) and
closed term t of sort Real,
there is a model of T that satisfies (= v (/ t 0)).
Similarly, the page Theories: Ints says:
See note in the Reals theory declaration about terms of the form
(/ t 0).
The same observation applies here to terms of the form (div t 0) and
(mod t 0).
Therefore, it stands to reason to believe that no SMT-LIB compliant tool would ever print unsat for the given formula.
Z3 does not check for division by zero because, as Patrick Trentin mentioned, the semantics of division by zero according to SMT-LIB are that it returns an unknown value.
You can manually ask Z3 to check for division by zero, to ensure that you never depend division by zero. (This is important, for example, if you are modeling a language where division by zero has a different semantics from SMT-LIB.)
For your example, this would look as follows:
(declare-fun f (Int) Int)
(declare-const c Int)
(assert (>= c 0))
(assert (= (f 0) 0))
; check for division by zero
(push)
(declare-const n Int)
(assert (>= n 0))
(assert (= (- n c) 0))
(check-sat) ; reports sat, meaning division by zero is possible
(get-model) ; an example model where division by zero would occur
(pop)
;; Supposing the check had passed (returned unsat) instead, we could
;; continue, safely knowing that division by zero could not happen in
;; the following.
(assert (forall ((n Int))
(=> (>= n 0)
(= (f (+ n 1))
(+ (f n) (/ 10 (- n c)))))))
Is division by zero included in QF_NRA?
The SMT-LIB standard is confusing in this matter. The paper where the standard is defined simply does not discuss this point, in fact NRA and QF_NRA do not appear anywhere in that document. Some information is provided on the standard website. Reals are defined as including:
- all terms of the form (/ m n) or (/ (- m) n) where
- m is a numeral other than 0,
- n is a numeral other than 0 and 1,
- as integers, m and n have no common factors besides 1.
This explicitly excludes zero from the denominator when it comes to constant values. However, later, division is defined as:
- / as a total function that coincides with the real division function
for all inputs x and y where y is non-zero,
This is followed up by a note:
Since in SMT-LIB logic all function symbols are interpreted as total
functions, terms of the form (/ t 0) *are* meaningful in every
instance of Reals. However, the declaration imposes no constraints
on their value. This means in particular that
- for every instance theory T and
- for every closed terms t1 and t2 of sort Real,
there is a model of T that satisfies (= t1 (/ t2 0)).
This is seemingly contradictory, because the first quote says that (/ m 0) is not a number in QV_NRA, but the latter quote says that / is a function such that (= t1 (/ t2 0)) is satisfiable for any t1 and t2.
The de-facto reality on the ground is that division by zero seems to be included in SMT-LIB, despite the statement that (/ m n) is only a Real number if n is nonzero. This is related to a previous question of mine: y=1/x, x=0 satisfiable in the reals?
the first quote says that (/ m 0) is not a number
No, but it does not say what number it is.
but the latter quote says that / is a function such that (= t1 (/ t2 0)) is satisfiable for any t1 and t2
This is correct.
You need to get away from the school mentality that says "division by zero is not allowed!". It is undefined. Undefined means that there is no axiom that specifies what values this is. (And this is true in school as well.)
What is f(1234)? It's undefined, so Z3 is allowed to pick any number at all. There is no difference between a / 0 and f(a) where f is some uninterpreted function. Z3 can fill in any function it likes.
Therefore, a / 0 == b is satisfiable and any a and b are OK. But (a / 0) == (a / 0) + 1 is false.
Mathematical operators are just functions. The standard partially specifies those functions.
I would like to construct an SMT formula having a number of assertions over integer linear arithmetic and Boolean variables as well as some assertions over real non-linear arithmetic and again Boolean variables. The assertions over integers and reals share only the Boolean variables. As an example, consider the following formula:
(declare-fun b () Bool)
(assert (= b true))
(declare-fun x () Int)
(declare-fun y () Int)
(declare-fun z () Int)
(assert (or (not b) (>= (+ x y) (- x (+ (* 2 z) 1)))))
(declare-fun r () Real)
(assert (or (not b) (= (+ (* r r) (* 3 r) (- 4)) 0)))
If I feed z3 with this formula, it immediately reports "unknown". But if I remove the integer part of it, I get the solution right away, which satisfies the constraint with variable "r". I presume this means that the non-linear constraint on its own is not hard for the solver. The issue should be in mixing (linear) constraints over integers and (non-linear) constraints over reals.
So my question is the following. What is the correct way to handle this kind of mixed formulas using z3 (if there is any)? My understanding of DPLL(T) is that it should be able to deal with such formulas using different theory solvers for different constraints. Please, correct me if I am wrong.
As George said in his comment, the non-linear solver in Z3 is rather fragile and the out-of-the-box performance isn't great. That said, there are a number of questions and answers about this problem here on stackoverflow, e.g., see these:
Z3 Performance with Non-Linear Arithmetic
How does Z3 handle non-linear integer arithmetic?
Z3 : strange behavior with non linear arithmetic
Non-linear arithmetic and uninterpreted functions
Z3 Theorem Prover: Pythagorean Theorem (Non-Linear Artithmetic)
Which techniques are used to handle Non-linear Integer Real problems in z3?
Satisfiablity checking in non-linear integer arithmetic by approximation
Basically, I want to ask Z3 to give me an arbitrary integer whose value is greater than 10. So I write the following statements:
(declare-const x (Int))
(assert (forall ((i Int)) (> i 10)))
(check-sat)
(get-value(x))
How can I apply this quantifier to my model? I know you can write (assert (> x 10)) to achieve this, but I mean I want a quantifier in my model so every time I declare an integer constant whose value is guaranteed to be over 10, so that I don't have to insert statement (assert (> x 10)) for every integer constant that I declared. If I have to use macros to prevent repeating code, what is the actual use of quantifiers?
You will need to constrain each int you declare individually. x > 10 is the right way to do that.
You can use macros or any other codegen technique. In the SMT solver all of that expands to regular constraints. It has no runtime impact.
forall ((i Int)) (> i 10)) means "Are all ints bigger than 10?" which is false.
Quantifiers do not quantify over all variables that you have declared. They quantify only over the bound variables, here i.