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.
I noticed some strange behavior with Z3 4.3.1 when working with .smt2 files.
If I do (assert (= 0 0.5)) it will be satisfiable. However, if I switch the order and do (assert (= 0.5 0)) it's not satisfiable.
My guess as to what is happening is that if the first parameter is an integer, it casts both of them to integers (rounding 0.5 down to 0), then does the comparison. If I change "0" to "0.0" it works as expected. This is in contrast to most programming languages I've worked with where if either of the parameters is a floating-point number, they are both cast to floating-point numbers and compared. Is this really the expected behavior in Z3?
I think this is a consequence of lack of type-checking; z3 is being too lenient. It should simply reject such queries as they are simply not well formed.
According to the SMT-Lib standard, v2 (http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.0-r10.12.21.pdf); page 30; the core theory is defined thusly:
(theory Core
:sorts ((Bool 0))
:funs ((true Bool) (false Bool) (not Bool Bool)
(=> Bool Bool Bool :right-assoc) (and Bool Bool Bool :left-assoc)
(or Bool Bool Bool :left-assoc) (xor Bool Bool Bool :left-assoc)
(par (A) (= A A Bool :chainable))
(par (A) (distinct A A Bool :pairwise))
(par (A) (ite Bool A A A))
)
:definition
"For every expanded signature Sigma, the instance of Core with that signature
is the theory consisting of all Sigma-models in which:
- the sort Bool denotes the set {true, false} of Boolean values;
- for all sorts s in Sigma,
- (= s s Bool) denotes the function that
returns true iff its two arguments are identical;
- (distinct s s Bool) denotes the function that
returns true iff its two arguments are not identical;
- (ite Bool s s) denotes the function that
returns its second argument or its third depending on whether
its first argument is true or not;
- the other function symbols of Core denote the standard Boolean operators
as expected.
"
:values "The set of values for the sort Bool is {true, false}."
)
So, by definition equality requires the input sorts to be the same; and hence the aforementioned query should be rejected as invalid.
There might be a switch to z3 or some other setting that forces more strict type-checking than it does by default; but I would've expected this case to be caught even with the most relaxed of the implementations.
Do not rely on the implicit type conversion of any solver. Instead,
use to_real and to_int to do explicit type conversions. Only send
well-typed formulas to the solver. Then Mohamed Iguernelala's examples become the following.
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_real x) 1.5))
(check-sat)
(exit)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 (to_real x)))
(check-sat)
(exit)
Both of these return UNSAT in Z3 and CVC4. If instead, you really
wanted to find the model where x = 1 you should have instead used one
of the following.
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_int 1.5) x))
(check-sat)
(get-model)
(exit)
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x (to_int 1.5)))
(check-sat)
(get-model)
(exit)
Both of these return SAT with x = 1 in Z3 and CVC4.
Once you make all the type conversions explicit and deal only in well-typed formulas, the order of arguments to equality no longer matters (for correctness).
One of our interns, who worked on a conservative extension of SMT2 with polymorphism has noticed the same strange behavior, when he tried the understand how formulas mixing integers and reals are type-checked:
z3 (http://rise4fun.com/z3) says that the following example is SAT, and finds a model x = 1
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x 1.5))
(check-sat)
(get-model)
(exit)
But, it says that the following "equivalent" example in UNSAT
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 x))
(check-sat)
(exit)
So, this does not comply with the symmetric property of equality predicate. So, I think it's a bug.
Strictly speaking, Z3 is not SMT 2.0 compliant by default, and this is one of those cases. We can add
(set-option :smtlib2-compliant true)
and then this query is indeed rejected correctly.
Z3 is not the unique SMT solver that type-checks these examples:
CVC4 accepts them as well (even with option --smtlib-strict), and answers UNSAT in both cases of my formulas above.
Yices accepts them and answers UNSAT (after changing the logic to QF_LIA, because it does not support AUFLIRA).
With (set-logic QF_LIA), Z3 emits an error: (error "line 3 column 17: logic does not support reals").
Alt-Ergo says "typing error: Int and Real cannot be unified" in both cases. But Alt-Ergo's SMT2 parser is very limited and not heavily tested, as we concentrated on its native polymorphic language. So, it should not be taken as a reference.
I think that developers usually assume an "implicit" sub-typing relation between Int and Real. This is why these examples are successfully type-checked by Z3, CVC4 and Yices (and probably others as well).
Jochen Hoenicke gived the answer (on SMT-LIB mailing list) regarding "mixing reals and integers". Here it is:
I just wanted to point out, that the syntax may be officially correct.
There is an extension in AUFLIRA and AUFNIRA.
From http://smtlib.cs.uiowa.edu/logics/AUFLIRA.smt2
"For every operator op with declaration (op Real Real s) for some
sort s, and every term t1, t2 of sort Int and t of sort Real, the
expression
- (op t1 t) is syntactic sugar for (op (to_real t1) t)
- (op t t1) is syntactic sugar for (op t (to_real t1))
- (/ t1 t2) is syntactic sugar for (/ (to_real t1) (to_real t2)) "
One possible solution is
(declare-fun x () Real)
(declare-fun y () Real)
(assert (= x 0))
(assert (= y 0.5))
(check-sat)
(push)
(assert (= x y) )
(check-sat)
(pop)
and the output is
sat
unsat
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))
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.)
In Z3 you have to_real to obtain the Real equivalent of an Int. Is there some support to the inverse conversions, i.e., to truncation, rounding or like? In the negative case, what could be the most Z3-friendly way of defining them, if any? Many thanks to everyone will answer.
Yes, Z3 has a to_int function that converts a Real into an integer. The semantics of to_int is defined in the SMT 2.0 standard. Here is an example: http://rise4fun.com/Z3/uJ3J
(declare-fun x () Real)
(assert (= (to_int x) 2))
(assert (not (= x 2.0)))
(check-sat)
(get-model)