Converting different widths of floating-point numbers - z3

I want to compare two different widths of floating-point numbers by giving an assert to z3.
For example, I want to compare between an IEEE 32-bit and an IEEE 64-bit floating-point number.
My try is shown as follows:
(set-logic QF_FPA)
(set-option :produce-models true)
(declare-fun x_64 () (_ FP 11 53))
(declare-fun x_32 () (_ FP 8 24))
(assert (== ((_ asFloat 11 53) roundNearestTiesToEven x_64 ) x_64))
(check-sat)
But I got an error message:
(error "line 5 column 59: sort mismatch")
What is the correct way to compare a 32-bit and a 64-bit number?
The z3 version I am using is 4.3.1 (linux version).

In general, these conversions are non-trivial, e.g., when converting from 64-bit down to 32-bit some precision may be lost. This is why the conversion functions take a rounding mode. The SMT standard for floating-point numbers does contain conversion functions of the following type:
; from another floating point sort
((_ to_fp eb sb) RoundingMode (_ FloatingPoint m n) (_ FloatingPoint eb sb))
So, the correct way to convert between floating-point numbers is to use the to_fp function. [Previously, the asFloat function served this purpose as well; I don't get an error using the latest unstable version of Z3 when using it.] A full example would be this:
(set-logic QF_FPA)
(set-option :produce-models true)
(declare-fun x_64 () (_ FP 11 53))
(declare-fun x_32 () (_ FP 8 24))
(assert (== ((_ to_fp 11 53) roundNearestTiesToEven x_32) x_64))
(check-sat)
which Z3 (latest unstable) accepts without errors and solves instantly. Alternatively, we could also think of casting x_64 down to 32 bit, in which case the assertion would look like this:
(assert (== ((_ to_fp 8 24) roundNearestTiesToEven x_64) x_32))

Related

Boolean matrix times vector multiplication in Z3

How to multiply a variable Boolean matrix by a Boolean vector in Z3 in a nice way? The sizes of the matrix and of vectors are known and fixed.
In my case there is only one matrix and there is no need to pass it as an argument or return it as a result of a function, so the matrix can be global.
Does it help if the matrix is a square matrix?
My current solution is:
; Maybe some other matrix representation would be better?
(declare-datatypes () ((ColumnIndex c0 c1 c2)))
(declare-fun column (ColumnIndex) (_ BitVec 4))
(define-fun scalarTimesVector ((a (_ BitVec 1)) (v (_ BitVec 4))) (_ BitVec 4)
(ite (= a #b1) v (_ bv0 4))
)
(define-fun matrixTimesVector ((vector (_ BitVec 3))) (_ BitVec 4)
(bvor
(scalarTimesVector ((_ extract 0 0) vector) (column c0))
(scalarTimesVector ((_ extract 1 1) vector) (column c1))
(scalarTimesVector ((_ extract 2 2) vector) (column c2))
)
)
What you are doing is just fine, especially given your matrix size is constant and never change. SMTLib has no notion of loops, although recent versions do allow recursive definitions of functions that can be used for this effect. See this answer for a different but related question on how to use recursion: https://stackoverflow.com/a/51140049/936310. However, I'd recommend sticking to your current code for simplicity and wider support from a variety of solvers.
In my mind, SMTLib should really be "generated" instead of directly used; and most tools use it this way. If your programming needs get more complicated, I'd recommend using a higher-level interface instead. There are interfaces to Z3 and other solvers from pretty much any language you can imagine. Python and Haskell provide really high-level bindings that get rid of most of the boilerplate for you. You also have low-level bindings from C/C++/Java if that's your choice. See using floating point arithmetic with Z3 C++ APIs for a comparison of the styles.

Interpret models returned by QF_FPABV logic

I wrote z3 query in SMT2 format using QF_FPABV logic (quantifier-free floating-point arithmetic and bit-vector logic??).
The query is shown as follows:
(set-logic QF_FPABV)
(set-option :produce-models true)
(declare-fun f0 () (_ FP 8 24))
(declare-fun f1 () (_ FP 8 24))
(declare-fun f2 () (_ FP 8 24))
(assert (= f2 (* roundNearestTiesToEven f0 f1)))
(assert (>= f2 ((_ asFloat 8 24) roundNearestTiesToEven 3.0 0)))
(check-sat)
; (check-sat-using (then simplify solve-eqs bit-blast smt))
(get-model)
With
(check-sat),
I acquired the result and the model as:
sat
(model
(define-fun f2 () (_ FP 8 24)
(as +1.44919359683990478515625p127 (_ FP 8 24)))
(define-fun f1 () (_ FP 8 24)
(as +1.476345062255859375p0 (_ FP 8 24)))
(define-fun f0 () (_ FP 8 24)
(as +1.9632179737091064453125p126 (_ FP 8 24)))
)
This is what I expect.
However, if I use
(check-sat-using (then simplify solve-eqs bit-blast smt))
instead, I acquired:
sat
(model
;; universe for RoundingMode:
;; RoundingMode!val!0
;; -----------
;; definitions for universe elements:
(declare-fun RoundingMode!val!0 () RoundingMode)
;; cardinality constraint:
(forall ((x RoundingMode)) (= x RoundingMode!val!0))
;; -----------
;; universe for (_ FP 8 24):
;; FP!val!0 FP!val!1 FP!val!2 FP!val!3
;; -----------
;; definitions for universe elements:
(declare-fun FP!val!0 () (_ FP 8 24))
(declare-fun FP!val!1 () (_ FP 8 24))
(declare-fun FP!val!2 () (_ FP 8 24))
(declare-fun FP!val!3 () (_ FP 8 24))
;; cardinality constraint:
(forall ((x (_ FP 8 24)))
(or (= x FP!val!0) (= x FP!val!1) (= x FP!val!2) (= x FP!val!3)))
;; -----------
(define-fun f1 () (_ FP 8 24)
FP!val!2)
(define-fun f0 () (_ FP 8 24)
FP!val!1)
(define-fun f2 () (_ FP 8 24)
(* roundNearestTiesToEven FP!val!1 FP!val!2))
)
This model is not trivial to interpret...
For this simple example, I can just use (check-sat) to acquire human-readable results.
For some complex examples which contains non-linear operations,
I need to use (check-sat-using (then simplify solve-eqs bit-blast smt))
to avoid getting "Unknown" from z3...
Is there any document which can teach me to interpret such non-human-readable model?
The problem here is that the floating-point theory is not fully integrated with the SMT kernel of Z3 yet (I'm working on that in a separate branch). Because of that, the kernel treats all floating-point sorts as uninterpreted and therefore the model contains definitions of those sorts (the universes). At the moment, the best way to get around that is to call the fpa2bv tactic directly, e.g., change
(check-sat-using (then simplify solve-eqs bit-blast smt))
to
(check-sat-using (then simplify fpa2bv simplify solve-eqs bit-blast smt))
It is necessary to call the simplify tactic before calling fpa2bv and it is also necessary to call the simplifier before the bit-blast tactic, because those tactics rely on the simplifier to eliminate some particular expressions.
I think this is an issue with the model-completion code in Z3. There was a similar bug quite a while ago: Z3 FP logic: produces unexpected model
I thought the issue was already addressed and the code sample in that ticket now works correctly with z3 4.3.2, but apparently the code fragment you presented here triggers a similar problem that's not quite addressed yet.

Is it possible to cast a bitvector of one bit into a boolean variable in SMTLib2?

I want to have a boolean variable that test if, e.g., the third bit of a bit vector is 0. The theory of bitvector allows to extract 1 bit as a bitvector, but not a boolean type. I wonder if I can do this cast. Thank you.
=== Update ===
I'm sorry if my question is not clear. But the answer of Nikolaj Bjorner is how to test a certain bit of a bit vector. While I want to assign the value of the first bit of a bit vector to a variable. I try to modify the example as follows:
(declare-fun x () (_ BitVec 5))
(declare-fun bit0 () Bool)
(assert (= (= #b1 ((_ extract 0 0) x)) bit0 ))
(check-sat)
And z3 complains:
(error "line 2 column 25: invalid declaration, builtin symbol bit0")
(error "line 3 column 44: invalid function application, sort mismatch on argument at position 2")
I need that variable bit0 for later use. Could you please give me a hint? Thanks.
Create an equality between the extraction of the third bit and a bit-vector with value 1 (and one bit).
E.g,
(declare-const x (_ BitVec 5))
(assert (= #b1 ((_ extract 2 2) x)))
(check-sat)
(get-model)
produces
sat
(model
(define-fun x () (_ BitVec 5)
#b00100)
)
What you are doing is just fine; it's just that bit0 is a reserved name. Just call it something else. (mybit0 would work, or some other unreserved name.)

QF_FPA? Does Z3 support IEEE-754 arithmetic?

Browsing Z3 source code, I came across a bunch of files referring to QF_FPA, which seems to stand for quantifier-free, floating-point-arithmetic. However, I don't seem to be able to locate any documentation regarding its state, or how it can be used via various front-ends (in particular SMT-Lib2). Is this an encoding of IEEE-754 FP? If so, which precisions/operations are supported? Any documentation would be most helpful..
Yes, Z3 supports floating point arithmetic as proposed by Ruemmer and Wahl in a recent SMT-workshop paper. At the current stage, there is no official FPA theory, and Z3's support is very basic (only a bit-blaster). We're not actively advertising this yet, but it can be used exactly as proposed in the paper by Ruemmer/Wahl (setting logics QF_FPA and QF_FPABV). At the moment, we are working on a new decision procedure for FPA, but it will be some time until that is available.
Here's a brief example of what an FPA SMT2 formula could look like:
(set-logic QF_FPA)
(declare-const x (_ FP 11 53))
(declare-const y (_ FP 11 53))
(declare-const r (_ FP 11 53))
(assert (and
(= x ((_ asFloat 11 53) roundTowardZero 0.5 0))
(= y ((_ asFloat 11 53) roundTowardZero 0.5 0))
(= r (+ roundTowardZero x y))
))
(check-sat)
The floating point logics are named QF_FP and QF_FPBV in v4.4.2. The link to the description of the theory in RELEASE_NOTES is broken. The correct page is http://smtlib.cs.uiowa.edu/theories-FloatingPoint.shtml. The proposed example above should be
(set-logic QF_FP)
(declare-const x (_ FloatingPoint 11 53))
(declare-const y (_ FloatingPoint 11 53))
(declare-const r (_ FloatingPoint 11 53))
(assert (and
(= x (fp #b0 #b00000000010 #b0000000000000000000000000000000000000000000000000010))
(= y (fp #b0 #b00000000010 #b0000000000000000000000000000000000000000000000000010))
(= r (fp.add roundTowardZero x y))
))
(check-sat)

Assign value to a bitvector (SMTLIB2, Z3)?

I am using Z3 version 3.0. I want to assign a value to a bitvector variable, like below.
But Z3 reports error "invalid function application, sort mismatch on argument at position 2 in line 3".
It seems wrong with my constant #x0a? how can i fix this?
Thanks
(set-logic QF_BV)
(declare-fun a () (_ BitVec 32))
(assert (= a #x0a))
(check-sat)
In the SMT-LIB 2.0 standard, #x0a is a bitvector of size 8. You get the sort mismatch error because the constant a is a bitvector of size 32.
You can avoid the type/sort error message by rewriting your example as:
(set-logic QF_BV)
(declare-fun a () (_ BitVec 32))
(assert (= a #x0000000a))
(check-sat)
SMT-LIB also supports bitvector literals of the form (_ bv[num] [size]), where [num] is in decimal notation, and [size] is the size of the bitvector.
Thus, you can also write the bitvector literal #x0000000a as (_ bv10 32).
BTW, SMT-LIB also supports bitvector literals in binary notation. For example, #b010 is a bitvector of size 3.

Resources