z3 bitvector operation simplified answer - z3

Is there an easier way to get the immediate answers when doing bit-vector ops eg. a = 1 million, b = 0, what is a & b (answer: 0)
This method works but have to introduce dummy variable to store answer:
(declare-const a (_ BitVec 64))
(declare-const b (_ BitVec 64))
(declare-const ans (_ BitVec 64))
(assert (= a (_ bv1000000 64)))
(assert (= b (_ bv0000000 64)))
(assert (= ans (bvand a b)))
(check-sat)
(get-model)
This method is what I'd like but my code gives a demorgan identity:
(declare-const a (_ BitVec 64))
(declare-const b (_ BitVec 64))
(simplify (bvand a b))

You can use the model to evaluate arbitrary expressions, for instance like this:
(declare-const a (_ BitVec 64))
(declare-const b (_ BitVec 64))
(assert (= a (_ bv1000000 64)))
(assert (= b (_ bv0000000 64)))
(check-sat)
(eval (bvand a b))
says
sat
#x0000000000000000

I didn't test, but something like (apply (then propagate-values simplify)) should do the trick

Related

Understanding z3 bvsmod behavior with SSA

I am trying to learn using z3. So this question might be silly.
Why do I get a unexpected values for x___0 from Z3 when I use bvsmod as compared to bvadd in the following code. I'm using SSA to implement execution flow here.
Z3 instructions:
(set-option :pp.bv-literals false)
;
; The code
; x %= 5
; x * 2 == 8
; Implement SSA
; x1 = x0 % 5
; x1 * 2 == 8
;
(push)
(set-info :status unknown)
(declare-const x___0 (_ BitVec 32))
(declare-const x___1 (_ BitVec 32))
(assert (= x___1 (bvsmod x___0 (_ bv5 32))))
(assert (= (bvmul x___1 (_ bv2 32)) (_ bv8 32)))
(check-sat)
(get-model)
(pop)
;
; The code
; x += 1
; x * 2 == 8
; Implement SSA
; x1 = x0 + 1
; x1 * 2 == 8
;
(push)
(declare-const x___0 (_ BitVec 32))
(declare-const x___1 (_ BitVec 32))
(assert (= x___1 (bvadd x___0 (_ bv1 32))))
(assert (= (bvmul x___1 (_ bv2 32)) (_ bv8 32)))
(check-sat)
(get-model)
(pop)
Results:
sat
(model
(define-fun x___1 () (_ BitVec 32)
(_ bv4 32))
(define-fun x___0 () (_ BitVec 32)
(_ bv3720040335 32))
)
sat
(model
(define-fun x___1 () (_ BitVec 32)
(_ bv4 32))
(define-fun x___0 () (_ BitVec 32)
(_ bv3 32))
)
In case of equation where I use bvadd x___0 get a value 3, which makes sense.
Why do I get a value 3720040335 in case of bvsmod, which is no where near the expected value i.e. some value ending with 4?
There's nothing wrong with the value you are getting. Your encoding is just fine.
Notice that you are using 32-bit signed integers (implicitly implied by the call to bvsmod.) The model returned gives you the value 32-bit bit-vector value whose decimal equivalent is 3720040335. When interpreted as a signed-value, this is actually -574926961, and you can verify (-574926961) % 5 indeed equals 4 as you requested.
Note that the solver is free to give you any model that satisfies your constraints. If you want a more specific value, you'll need to add additional constraints to encode what "simple" should formally mean.
If you want to write the formula like that, you need quantifiers.
I suggest you use SMT expressions instead; sharing will happen for free.
write e.g.:
(assert (= (bvmul (bvadd x___0 (_ bv1 32)) (_ bv2 32)) (_ bv8 32)))
If you need the intermediate values, you can always later do an (eval ...)

Bug in Z3 Datalog

For the datalog program in Z3 at the bottom, the result of query
(query (CallGraph invo heap):print-answer true)
given by Z3 is:
sat
(and (= (:var 0) #b011) (= (:var 1) #b1))
However, the answer should be
sat
(and (= (:var 0) #b1) (= (:var 1) #b011))
am I right? is it a bug in Z3?
(set-option :fixedpoint.engine datalog)
(declare-rel VarPointsTo ( (_ BitVec 4) (_ BitVec 3)))
(declare-rel Reachable ( (_ BitVec 3)))
(declare-rel Alloc ( (_ BitVec 4) (_ BitVec 3) (_ BitVec 3)))
(declare-rel Move ( (_ BitVec 4) (_ BitVec 4)))
(declare-rel FldPointsTo ( (_ BitVec 3) (_ BitVec 1) (_ BitVec 3)))
(declare-rel Store ( (_ BitVec 4) (_ BitVec 4) (_ BitVec 4)))
(declare-rel StrMap ( (_ BitVec 4) (_ BitVec 1)))
(declare-rel Load ( (_ BitVec 4) (_ BitVec 4) (_ BitVec 4)))
(declare-rel VCall ( (_ BitVec 4) (_ BitVec 1) (_ BitVec 3)))
(declare-rel CallGraph ( (_ BitVec 1) (_ BitVec 3)))
(declare-rel InterProcAssign ( (_ BitVec 4) (_ BitVec 4)))
(declare-rel FormalArg ( (_ BitVec 3) (_ BitVec 1) (_ BitVec 4)))
(declare-rel ActualArg ( (_ BitVec 1) (_ BitVec 1) (_ BitVec 4)))
(declare-rel FormalReturn ( (_ BitVec 3) (_ BitVec 4)))
(declare-rel ActualReturn ( (_ BitVec 1) (_ BitVec 4)))
(declare-var var (_ BitVec 4))
(declare-var heap (_ BitVec 3))
(declare-var methHeap (_ BitVec 3))
(declare-var to (_ BitVec 4))
(declare-var from (_ BitVec 4))
(declare-var baseH (_ BitVec 3))
(declare-var fld (_ BitVec 1))
(declare-var base (_ BitVec 4))
(declare-var toMethHeap (_ BitVec 3))
(declare-var invo (_ BitVec 1))
(declare-var inMethHeap (_ BitVec 3))
(declare-var n (_ BitVec 1))
(rule (=> (and (Reachable methHeap) (Alloc var heap methHeap) )(VarPointsTo var heap)))
(rule (=> (and (Move to from) (VarPointsTo from heap) )(VarPointsTo to heap)))
(rule (=> (and (Store base var from) (and (VarPointsTo from heap) (and (VarPointsTo base baseH) (StrMap var fld) )))(FldPointsTo baseH fld heap)))
(rule (=> (and (Load to var base) (and (VarPointsTo base baseH) (and (FldPointsTo baseH fld heap) (StrMap var fld) )))(VarPointsTo to heap)))
(rule (=> (and (VCall var invo inMethHeap) (and (Reachable inMethHeap) (VarPointsTo var toMethHeap) ))(Reachable toMethHeap)))
(rule (=> (and (VCall var invo inMethHeap) (and (Reachable inMethHeap) (VarPointsTo var toMethHeap) ))(CallGraph invo toMethHeap)))
(rule (=> (and (CallGraph invo methHeap) (and (FormalArg methHeap n to) (ActualArg invo n from) ))(InterProcAssign to from)))
(rule (=> (and (CallGraph invo methHeap) (and (FormalReturn methHeap from) (ActualReturn invo to) ))(InterProcAssign to from)))
(rule (=> (and (InterProcAssign to from) (VarPointsTo from heap) )(VarPointsTo to heap)))
(rule (Alloc #b0001 #b001 #b010))
(rule (Alloc #b0010 #b001 #b010))
(rule (Reachable #b001))
(rule (Reachable #b010))
(rule (Alloc #b0011 #b011 #b001))
(rule (Alloc #b0100 #b100 #b011))
(rule (Move #b0101 #b0100))
(rule (StrMap #b0110 #b1))
(rule (Store #b0001 #b0110 #b0011))
(rule (StrMap #b0111 #b1))
(rule (Load #b1000 #b0111 #b0001))
(rule (VCall #b1000 #b1 #b001))
(rule (ActualReturn #b1 #b1001))
(query (VarPointsTo var heap):print-answer true)
(query (CallGraph invo heap):print-answer true)
(query (Reachable heap):print-answer true)
This does not appear to reproduce in the version of Z3 checked into GitHub/z3prover/z3 master branch.
The way the engine associates variable indices with variable names has been brittle and there might still be a way to trigger this bug with the newest version of Z3, although I cannot reproduce it.
The binary API exposes a more reliable API: one poses a query given one or more predicate declarations (The function from the C API is called Z3_fixedpoint_query_relations, and the other supported programming languages support similarly named functions).

Calculate minimum value of Bitvector in Z3

I have the following piece of code:
(declare-const L4 (_ BitVec 6))
(declare-const L1 (_ BitVec 6))
(declare-const L0 (_ BitVec 6))
(declare-const l2 (_ BitVec 6))
(assert (= l2 (_ bv8 6)))
;; All is encoding the set that contains {0, 1, 2, 3, 4, 5}
(define-const All (_ BitVec 6) #b111111)
;; Empty is encoding the empty set
(define-const Empty (_ BitVec 6) #b000000)
(define-fun LT_l ((S (_ BitVec 6)) (l (_ BitVec 6))) Bool
;; True if for all x in S x < l
(= (bvand (bvshl All l) S) Empty))
(define-fun is_in ((e (_ BitVec 6)) (S (_ BitVec 6))) Bool
;; True if e is an element of the "set" S.
(not (= (bvand (bvshl (_ bv1 6) e) S) Empty)))
(define-fun is_minimal ((e (_ BitVec 6)) (S (_ BitVec 6))) Bool
;; True if e is the minimal element of S
(and (is_in e S) ;; S contains e
;; (1 << e) - 1 represents the set of elements that are smaller than e
(= (bvand (bvsub (bvshl (_ bv1 6) e) (_ bv1 6)) S) Empty)))
;; To encode that forall x in L0 and forall y in L1. x < y
(define-fun LT ((L0 (_ BitVec 6)) (L1 (_ BitVec 6))) Bool
; True if forall x in L0 and forall y in L1, x < y
(or (= L0 Empty)
(= L1 Empty)
(exists ((min (_ BitVec 6))) (and (is_minimal min L1) (LT_l L0 min)))))
(assert (not (= L0 Empty)))
(assert (not (= L1 Empty)))
(assert (not (= L4 Empty)))
(assert (LT_l L4 l2))
(assert (LT L0 L1))
(check-sat)
(get-model)
(assert (LT L1 L0))
(check-sat)
When I run this code I get the model is:
sat
(model
(define-fun min!0 () (_ BitVec 6)
#b000011)
(define-fun L1 () (_ BitVec 6)
#b001000)
(define-fun L0 () (_ BitVec 6)
#b000100)
(define-fun L4 () (_ BitVec 6)
#b000100)
(define-fun l2 () (_ BitVec 6)
#b001000)
)
unsat
Why is the result of min is:
(define-fun min!0 () (_ BitVec 6)
#b000011)
and not b001000 since the smallest value of L1 is this and not b000011.
Someone can explain me?
Finally, I define the function Lt_l that checks if for all x in S x < l, but now I wanted to do GT_l that checks if for all x in S l < x. I have the following code:
(define-fun GT_l ((S (_ BitVec 6)) (l (_ BitVec 6))) Bool
(= (bvand (bvneg (bvshl (_ bv0 6) l)) S) Empty))
But this does not work why?
Thanks
In your example, you are representing sets using bit-vectors. For example, the bit-vector #b101000 represents the set {5, 3}. The output (define-fun L1 () (_ BitVec 6) #b001000) is essentially saying that L1 is the "set" {3}. One possible confusion is that bit-vectors are being used to represent sets and elements. The bit-vector min!0 represents an element. The output (define-fun min!0 () (_ BitVec 6) #b000011) is saying that min!0 is the value 3, and it is indeed the "minimal value" in L1.

soundness issue with integer/bv mixed benchmarks?

I've the following SMT-Lib2 script:
(set-option :produce-models true)
(declare-fun s0 () Int)
(declare-fun table0 (Int) (_ BitVec 8))
(assert (= (table0 0) #x00))
(assert
(let ((s3 (ite (or (< s0 0) (<= 1 s0)) #x01 (table0 s0))))
(let ((s5 (ite (bvuge s3 #x02) #b1 #b0)))
(= s5 #b1))))
(check-sat)
(get-model)
With Z3 v3.2 running on the Mac, I get:
sat
(model
;; universe for (_ BitVec 8):
;; bv!val!2 bv!val!3 bv!val!0 bv!val!1
;; -----------
;; definitions for universe elements:
(declare-fun bv!val!2 () (_ BitVec 8))
(declare-fun bv!val!3 () (_ BitVec 8))
(declare-fun bv!val!0 () (_ BitVec 8))
(declare-fun bv!val!1 () (_ BitVec 8))
;; cardinality constraint:
(forall ((x (_ BitVec 8)))
(and (= x bv!val!2) (= x bv!val!3) (= x bv!val!0) (= x bv!val!1)))
;; -----------
(define-fun s0 () Int
(- 1))
(define-fun table0 ((x!1 Int)) (_ BitVec 8)
(ite (= x!1 0) bv!val!0
(ite (= x!1 (- 1)) bv!val!3
bv!val!0)))
)
Which states that s0 = -1 is a model. However, with s0 = -1, we have s3 = 1 and s5 = #b0, which makes the assertion false. In fact, I'm quite sure the benchmark as stated is unsatisfiable.
One thing I noticed in the Z3 output is the quantified formula it gives for the cardinality constraint. It says:
;; cardinality constraint:
(forall ((x (_ BitVec 8)))
(and (= x bv!val!2) (= x bv!val!3) (= x bv!val!0) (= x bv!val!1)))
The assertion is a conjunction, which sounds rather weird; shouldn't that be a disjunction? I'm not sure if this is the root-cause of the problem, but it sure sounds fishy.
There are two problems in Z3.
First, you are correct, there is a typo in the model printer. It should be a "or" instead of an "and". The second problem is that Z3 did not install the bit-vector theory and treated (_ BitVec 8) as a uninterpreted sort. This was a bug in the preprocessor that is used to decide in which logic the problem is in. You can workaround this bug by adding the following command in the beginning of the file:
(set-option :auto-config false)
These bugs have been fixed, and the fix will be available in the next release.

Z3 QBVF questions

Following up to the previous discussion: Z3: Extracting existential model-values
Is there a difference between:
(declare-fun sx ((_ BitVec 16)) (_ BitVec 16))
(assert (forall ((y (_ BitVec 16))) (bvuge y (sx y))))
And
(declare-fun sx ((_ BitVec 16)) (_ BitVec 16))
(declare-fun y () (_ BitVec 16))
(assert (bvuge y (sx y)))
As far as Z3 is concerned? That is, will I still get the QBVF solver for the latter automatically?
Also, upon experimentation I found that if I issue:
(eval (sx #x8000))
After a (check-sat) call, it works fine (which is great). What would be better is if I could also say:
(eval (sx (get-value (y))))
Alas, for that query Z3 complains that it's an invalid function application. Is there a way to use the eval function in that manner?
Thanks!
The scripts
(declare-fun sx ((_ BitVec 16)) (_ BitVec 16))
(assert (forall ((y (_ BitVec 16))) (bvuge y (sx y))))
and
(declare-fun sx ((_ BitVec 16)) (_ BitVec 16))
(declare-fun y () (_ BitVec 16))
(assert (bvuge y (sx y)))
are not equivalent. The second is actually equisatisfiable to
(declare-fun sx ((_ BitVec 16)) (_ BitVec 16))
(assert (exists ((y (_ BitVec 16))) (bvuge y (sx y))))
Regarding the eval command, you can reference any uninterpreted constant and function symbol. Thus, you can write:
(declare-fun sx ((_ BitVec 16)) (_ BitVec 16))
(declare-fun y () (_ BitVec 16))
(assert (bvuge y (sx y)))
(check-sat)
(eval (sx y))
The command (eval (sx y)) will not work for the first script because y is a universal variable.

Resources