Member of a bitvector in Z3 - z3

I need to know how to do the following in z3:
forall x in L4 . x < l2
forall x in L0 and forall y in L1. x < y
(declare-const L4 (_ BitVec 6))
(declare-const L1 (_ BitVec 6))
(declare-const L0 (_ BitVec 6))
(declare-const l2 Int)
(declare-const l1 Int)
assert L0 and L1 such that x < y
(check-sat)
Result is Sat
assert L0 and L1 such that y < x
(check-sat)
Result is UnSat

I'm assuming you are using bit-vectors to encode finite sets.
So, here is a possible encoding (it is also available online here):
;; You use bit-vectors of size 6. That is, we are encoding sets that are subsets of {0, 1, 2, ... 5}
(declare-const L4 (_ BitVec 6))
(declare-const L1 (_ BitVec 6))
(declare-const L0 (_ BitVec 6))
;; I will also encode l1 and l2 as Bit-Vectors.
;; Thus, I don't need to convert them into Bit-vectors to be able to use them in Bit-vector operations.
(declare-const l1 (_ BitVec 6))
(declare-const l2 (_ BitVec 6))
;; To make the problems more interesting let us assume that l1 and l2 are <= 5
(assert (bvsle l1 (_ bv5 6)))
(assert (bvsle l2 (_ bv5 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
;; Note that: All << l is the set of values greater than l
;; In SMT-LIB, bvshl is the left shift operator <<
(= (bvand (bvshl All l) S) Empty))
;; We can use shifting to encode the set that contains all values in {0, 1, 2, 3, 4, 5} that greater than or equal to l2
(define-const GE_l2 (_ BitVec 6) (bvshl All l2))
;; To assert that forall x in L4. x < l2, we assert that the intersection of L4 and GE_l2 is empty
(assert (= (bvand GE_l2 L4) Empty))
(check-sat)
(get-model)
(define-fun is_in ((e (_ BitVec 6)) (S (_ BitVec 6))) Bool
;; True if e is an element of the "set" S.
;; That is, it checks whether the (1 << e) && S is 0
(not (= (bvand (bvshl (_ bv1 6) e) S) Empty)))
(echo "is_in tests")
;; Test: is 2 in the set {0,3}
(simplify (is_in (_ bv2 6) #b001001))
;; Test: is 0 in the set {0, 3}
(simplify (is_in (_ bv0 6) #b001001))
;; Test: is 3 in the set {0, 3}
(simplify (is_in (_ bv3 6) #b001001))
;; Test: is 4 in the set {0, 3}
(simplify (is_in (_ bv4 6) #b001001))
(echo "end is_in tests")
(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)))
(echo "is_minimal tests")
;; is 2 the minimal element in {5, 3}
(simplify (is_minimal (_ bv2 6) #b101000))
;; is 3 the minimal element in {5, 3}
(simplify (is_minimal (_ bv3 6) #b101000))
;; is 4 the minimal element in {5, 3}
(simplify (is_minimal (_ bv4 6) #b101000))
;; is 0 the minimal element in {4, 0}
(simplify (is_minimal (_ bv0 6) #b010001))
;; is 4 the minimal element in {4, 0}
(simplify (is_minimal (_ bv4 6) #b010001))
(echo "end is_minimal tests")
;; 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
; We encode that by saying that
; - L0 is empty OR
; - L1 is empty OR
; - Or Let min be the minimal value of L1 and Forall x in L0, x < min
(or (= L0 Empty)
(= L1 Empty)
(exists ((min (_ BitVec 6))) (and (is_minimal min L1) (LT_l L0 min)))))
;; To make the problem non-trivial, let us assume that L0 and L1 are not empty
(assert (not (= L0 Empty)))
(assert (not (= L1 Empty)))
(assert (LT L0 L1))
(check-sat)
(get-model)
(assert (LT L1 L0))
(check-sat)

Related

z3 bitvector operation simplified answer

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

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 ...)

BitVector in Z3 - functions for different bits

I have this code to check if other elements are contained sets.
;; 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 GT_l ((l (_ BitVec 6)) (S (_ BitVec 6))) Bool
;; True if for all x in S l < x
(= (bvand (bvnot (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
(and (is_in e S)
(= (bvand (bvsub (bvshl (_ bv1 6) e) (_ bv1 6)) S) Empty)))
(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)))))
(declare-const consoleLock (_ BitVec 6))
(declare-const l1 (_ BitVec 6))
(declare-const l2 (_ BitVec 6))
( assert (distinct consoleLock l1 l2 ) )
( assert (or (= l1 (_ bv0 6)) (= l1 (_ bv1 6)) (= l1 (_ bv2 6)) (= l1 (_ bv4 6)) ))
( assert (or (= l2 (_ bv0 6)) (= l2 (_ bv1 6)) (= l2 (_ bv2 6)) (= l2 (_ bv4 6)) ))
( assert (or (= consoleLock (_ bv0 6)) (= consoleLock (_ bv1 6)) (= consoleLock (_ bv2 6)) (= consoleLock (_ bv4 6)) ))
(declare-const L4 (_ BitVec 6))
(declare-const L1 (_ BitVec 6))
(declare-const L0 (_ BitVec 6))
(declare-const L5 (_ BitVec 6))
(assert (LT_l L0 l1))
(assert (LT L0 L1))
(assert (GT_l L1 l1))
(assert (LT_l L4 l2))
(assert (LT L4 L5))
(assert (GT_l L5 l2))
(declare-const T1 (_ BitVec 6))
(assert (= T1 l1))
(assert (LT_l T1 l2))
(declare-const T2 (_ BitVec 6))
(assert (= T2 l2))
(assert (LT_l T2 l1))
(check-sat)
(get-model)
My problem is that you want to use this code also for vectors with 8-bit and 16-bit but it doesn't work.
For example, if I replace all (_ BitVec 6) by (_ BitVec 8), the above code does not work well, because the result should be unsat but it sat.
As if to 6-bit vectors works well.
How can I make it work for different sizes of bit vectors?
We also have to adjust the constant occurring in the example: #b111111, #b000000, (_ bv1 6), etc. That being said, SMT-LIB 2.0 format is not very convenient for writing parametric problems. I think the programmatic API is easier to use to encode parametric problems.
Here is the same example encoded using the Z3 Python API. It is also available online here. We can change the size of the bit-vectors by replacing SZ = 6 with SZ = 8 or SZ = 16.
def All(sz):
return BitVecVal(2**sz - 1, sz)
def Empty(sz):
return BitVecVal(0, sz)
def LT_l(S, l):
sz = S.size()
return (All(sz) << l) & S == Empty(sz)
def GT_l(l, S):
sz = S.size()
return (~(All(sz) << l)) & S == Empty(sz)
def is_in(e, S):
sz = S.size()
one = BitVecVal(1, sz)
return (1 << e) & S != Empty(sz)
def is_minimal(e, S):
sz = S.size()
return And(is_in(e, S), ((1 << e) - 1) & S == Empty(sz))
def LT(L0, L1):
sz = L0.size()
min = BitVec('min', sz)
return Or(L0 == Empty(sz), L1 == Empty(sz), Exists([min], And(is_minimal(min, L1), LT_l(L0, min))))
SZ=6
consoleLock = BitVec('consoleLock', SZ)
l1 = BitVec('l1', SZ)
l2 = BitVec('l2', SZ)
s = Solver()
s.add(Distinct(consoleLock, l1, l2))
s.add(Or(l1 == 0, l1 == 1, l1 == 2, l1 == 4))
s.add(Or(l2 == 0, l2 == 1, l2 == 2, l2 == 4))
s.add(Or(consoleLock == 0, consoleLock == 1, consoleLock == 2, consoleLock == 4))
L4 = BitVec('L4', SZ)
L1 = BitVec('L1', SZ)
L0 = BitVec('L0', SZ)
L5 = BitVec('L5', SZ)
s.add(LT_l(L0, l1))
s.add(LT(L0, L1))
s.add(GT_l(L1, l1))
s.add(LT_l(L4, l2))
s.add(LT(L4, L5))
s.add(GT_l(L5, l2))
T1 = BitVec('T1', SZ)
s.add(T1 == l1)
s.add(LT_l(T1, l2))
T2 = BitVec('T2', SZ)
s.add(T2 == l2)
s.add(LT_l(T2, l1))
print s.check()

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.

Resources