I have a set of optimization problems in QF_BV. How can I efficiently solve them? For example, how can I use (check-sat-using (then simplify bit-blast) ...?
What follows is a fragment of a problem.
(declare-const p1_1 (_ BitVec 36))
(declare-const ps1_1 (_ BitVec 36))
(declare-const pe1_1 (_ BitVec 36))
(assert (= (_ bv0 36) (bvand ps1_1 (bvadd ps1_1 (_ bv1 36)))))
(assert (= (_ bv0 36) (bvand pe1_1 (bvadd pe1_1 (_ bv1 36)))))
(assert (and
(= p1_1 (bvxor ps1_1 pe1_1))
(not (= (_ bv0 36) (bvlshr ps1_1 (_ bv4 36))))
(=> (not (= p1_1 (_ bv0 36))) (= (concat ps1_1 #b1) (bvlshr (concat pe1_1 #b1) (_ bv4 37))))
))
(assert-soft (not (= p1_1 (_ bv0 36))) :weight 1)
(check-sat)
(get-model)
(get-objectives)
The optimizing engine (i.e., the engine that's used when you have assert-soft) doesn't work with tactics as far as I'm aware. It has its own solver and thus doesn't benefit from the general machinery of tactics.
You might want to ask and double check at https://github.com/Z3Prover/z3/discussions to see if there might be some other trick to orchestrate the behavior of the optimizing solver. (Though I doubt such a facility exists as of today.) Please report back here what you find!
Related
I encountered a problem while trying to define some rules over bit vectors in z3. If I try to solve the following file with z3
(declare-rel FunnyFun ((_ BitVec 64)))
(declare-var A (_ BitVec 64))
(declare-var B (_ BitVec 64))
(rule (=> (= B (bvadd A #x0000000000000001))
(FunnyFun B)))
(declare-rel q1 ())
(rule (=> (FunnyFun #x0000000000000001) q1))
(query q1)
I get the error
(error "query failed: Rule contains infinite sorts in rule <null>:
FunnyFun(#0) :-
(= (:var 0) (bvadd (:var 1) #x0000000000000001)).
")
Funnily enough z3 instantly gives the expected result (sat) when using smaller bit widths:
(declare-rel FunnyFun ((_ BitVec 60)))
(declare-var A (_ BitVec 60))
(declare-var B (_ BitVec 60))
(rule (=> (= B (bvadd A #x000000000000001))
(FunnyFun B)))
(declare-rel q1 ())
(rule (=> (FunnyFun #x000000000000001) q1))
(query q1)
Is this a bug or am I missing some constraints (I assumed BitVec can have an arbitrary bit width)?
I tried different z3 version (4.6.0, 4.8.3 and 4.8.5) and all of them showed this behavior.
This limitation is by design. See here: https://github.com/Z3Prover/z3/issues/1698
I need to solve the following quantified formula, and I have tried some combination of tactics, but Z3 always returns unknown. I obtained the formula from symbolic state subsumption check that we newly implemented on KLEE, which essentially is establishing the validity of entailment of two quantified bitvector formulas representing strongest postconditions. The following formula is the simplified form of the unsatisfiability test to establish an entailment validity. Does anyone know of the right combination of tactics to solve it or is there any reformulation that I could do to help Z3?
(set-logic ABV)
(declare-fun y () (Array (_ BitVec 32) (_ BitVec 8)))
(assert (bvsle (concat (select y #x00000003)
(concat (select y #x00000002)
(concat (select y #x00000001)
(select y #x00000000))))
#x00000000))
(assert (forall ((x (Array (_ BitVec 32) (_ BitVec 8))))
(let ((a!1 (concat (select x #x00000003)
(concat (select x #x00000002)
(concat (select x #x00000001)
(select x #x00000000)))))
(a!2 (concat (select y #x00000003)
(concat (select y #x00000002)
(concat (select y #x00000001)
(select y #x00000000))))))
(not (and (bvsle a!1 #x00000000)
(= ((_ extract 31 0) (bvadd #x00000004 a!1))
((_ extract 31 0) (bvadd #x00000003 a!2))))))))
(check-sat-using (then qe simplify solve-eqs bit-blast sat))
Thank you in advance.
I am using the inbuilt interpolation feature on the latest (unstable branch) version of Z3. It works fine with SMT2 formulas containing integers. It does however, throw a iz3proof_itp::proof_error and a subsequent iz3translate::unsupported error (See Below) for the following SMT2 program -
(set-option :produce-models true)
(set-logic QF_AUFBV)
(declare-fun a () (_ BitVec 32))
(declare-fun b () (_ BitVec 32))
(declare-fun x1 () (_ BitVec 32))
(declare-fun x2 () (_ BitVec 32))
(declare-fun x3 () (_ BitVec 32))
(declare-fun y1 () (_ BitVec 32))
(declare-fun y2 () (_ BitVec 32))
(compute-interpolant
(= a (_ bv0 32))
(= b (bvneg (_ bv2 32)))
(= x1 (_ bv1 32))
(= y1 (_ bv0 32))
(= x2 (bvadd x1 a))
(= x3 (bvadd x2 b))
(= y2 (bvadd y1 a))
(bvsge x3 (_ bv0 32))
)
I tried it on the online version on rise4fun, and it worked fine. So after a bit of debugging, I found that the error is thrown from inside the function find_congruence_position in file iz3proof_itp.cpp.
So I made the following simple (maybe dangerous) change to the function to take care of the proof_error atleast for now -
Changing if(x == arg(arg(con,0),i) && (y == arg(arg(con,1),i)) at line 2431
to if((x == arg(arg(con,0),i) && (y == arg(arg(con,1),i))) || (y == arg(arg(con,0),i) && (x == arg(arg(con,1),i))))
I simply or'd the condition with its copy where x and y are interchanged - I had found that x and y sometimes have their values interchanged, maybe due to some proof techniques.
This did take care of the problem, I found that using equality and non-equality, along with bvadd or bvneg with BitVecs while computing interpolants worked. For example the following file worked -
(set-option :produce-models true)
(set-logic QF_AUFBV)
(declare-fun a () (_ BitVec 32))
(declare-fun b () (_ BitVec 32))
(compute-interpolant
(= a (_ bv0 32))
(= b (bvadd a (_ bv1 32)))
(= b (_ bv0 32))
)
But then I tried using relational operators, like bvsgt or bvsge, and it threw a new error -
terminate called after throwing an instance of 'iz3translation::unsupported'
I looked more into it, found out that the expression causing the problem was -
(not ((_ bit2bool 2) x2)) - it was assigned a PR_TH_LEMMA type and the UNKNOWN_THEORY kind. It seems that there is no support for such operations.
Since the online version is working, I'd like to know if it's possible to obtain that version. I read the previous questions and answers on StackOverflow, and I'm a bit confused. Some say BitVec theory is not supported (Although these posts are old), but then how is the online version working? Or am I doing something wrong? Any help is highly appreciated.
Actually, interpolation for bit vector arithmetic is not supported. It's interesting that it works on the web version. That version is quite old, however, and I think it predates the source-available version of Z3. I can think of two possible reasons why it works:
1) That version of interpolating Z3 used the "foci" prover as a backup. Whenever it encountered a part of the proof it didn't understand, it would package that part up as a lemma and reprove it using foci. The current version does not use foci (which is a third-party tool not available in source) and relies entirely on the proof generated by Z3.
2) The older version might have been doing bit-blasting in a different way. If all the non-local proof steps are purely propositional (using just the resolution rule) then it is easy to compute an interpolant.
As far as I understand it, however, computing interpolants from an efficient bit-vector solver (using all the known pre-processing tricks) is an open problem.
I've two SMT2-Lib scripts using reals, which are morally equivalent. The only difference is that one also uses bit-vectors while the other does not.
Here's the version that uses both reals and bit-vectors:
; uses both reals and bit-vectors
(set-option :produce-models true)
(define-fun s2 () Real (root-obj (+ (^ x 2) (- 2)) 2))
(define-fun s3 () Real 0.0)
(define-fun s6 () Real (/ 1.0 1.0))
(declare-fun s0 () (_ BitVec 1))
(declare-fun s1 () (_ BitVec 1))
(assert
(let ((s4 (- s3 s2)))
(let ((s5 (ite (= #b1 s1) s2 s4)))
(let ((s7 (+ s5 s6)))
(let ((s8 (- s5 s6)))
(let ((s9 (ite (= #b1 s0) s7 s8)))
(let ((s10 (ite (>= s9 s3) #b1 #b0)))
(= s10 #b1))))))))
(check-sat)
(get-model)
Here's the morally equivalent script, using Bool instead of a bit-vector of size 1, otherwise it's essentially the same:
; uses reals only
(set-option :produce-models true)
(define-fun s2 () Real (root-obj (+ (^ x 2) (- 2)) 2))
(define-fun s3 () Real 0.0)
(define-fun s6 () Real (/ 1.0 1.0))
(declare-fun s0 () (Bool))
(declare-fun s1 () (Bool))
(assert
(let ((s4 (- s3 s2)))
(let ((s5 (ite s1 s2 s4)))
(let ((s7 (+ s5 s6)))
(let ((s8 (- s5 s6)))
(let ((s9 (ite s0 s7 s8)))
(let ((s10 (ite (>= s9 s3) #b1 #b0)))
(= s10 #b1))))))))
(check-sat)
(get-model)
For the former I get unknown from z3 (v4.1 on Mac), while the latter nicely produces sat and a model.
While SMT-Lib2 doesn't allow mixing reals and bit-vectors, I thought Z3 handled these combinations just fine. Am I mistaken? Is there a workaround?
(Note that these are generated scripts, so just using Bool instead of (_ BitVec 1) is rather costly, as it requires quite a bit of changes elsewhere.)
The new nonlinear solver is not integrated with other theories yet. It supports only real variables and Booleans. Actually, it also allows integer variables, but it is very limited support for them. It actually solves nonlinear integer problems as real problems, and just checks in the end whether each integer variable is assigned to an integer value. Moreover, this solver is the only complete procedure for nonlinear (real) arithmetic available in Z3.
Since your first problem contains Bit-vectors, the nonlinear solver is not used by Z3. Instead, Z3 uses a general purpose solver that combines many theories, but it is incomplete for nonlinear arithmetic.
That being said, I understand this is a limitation, and I'm working on that. In the (not so near) future, Z3 will have a new solver that integrates nonlinear arithmetic, arrays, bit-vectors, etc.
Finally, the bit-vector theory is a very special case, since we can easily reduce it to propositional logic in Z3.
Z3 has tactic bit-blast that applies this reduction. This tactic can reduce any nonlinear+bit-vector problem into a problem that contains only reals and Booleans. Here is an example (http://rise4fun.com/Z3/0xl).
; uses both reals and bit-vectors
(set-option :produce-models true)
(define-fun s2 () Real (root-obj (+ (^ x 2) (- 2)) 2))
(define-fun s3 () Real 0.0)
(define-fun s6 () Real (/ 1.0 1.0))
(declare-fun s0 () (_ BitVec 1))
(declare-fun s1 () (_ BitVec 1))
(declare-fun v2 () (_ BitVec 8))
(assert
(let ((s4 (- s3 s2)))
(let ((s5 (ite (= #b1 s1) s2 s4)))
(let ((s7 (+ s5 s6)))
(let ((s8 (- s5 s6)))
(let ((s9 (ite (= #b1 s0) s7 s8)))
(let ((s10 (ite (>= s9 s3) #b1 #b0)))
(= s10 #b1))))))))
(assert (or (and (not (= v2 #x00)) (not (= v2 #x01))) (bvslt v2 #x00)))
(assert (distinct (bvnot v2) #x00))
(check-sat-using (then simplify bit-blast qfnra))
(get-model)
get-value call returns an expression instead of concrete value #b01:
sat
(((trans_local true true (_ bv2 2)) (ite #b10 #b01 (ite #b00 (ite #b10 #b11 #b01) (ite #b01 (ite #b10 #b10 #b00) #b01)))))
simplify results in the same way(and it probably should). How should I use get-value to get a correct result?
Here is the query:
(set-logic UFBV)
(set-option :produce-models true)
(define-fun trans_local ((x!1 (_ BitVec 2)) (x!2 Bool) (x!3 Bool)) (_ BitVec 2)
(ite (= x!1 #b10)
(ite x!2 #b01 #b00)
(ite (= x!1 #b00)
(ite (and x!2 x!3)
#b11
(ite (and (not x!2) x!3)
#b10
(ite (and (not x!2) (not x!3)) #b00 #b01)))
(ite (= x!1 #b01) (ite (and x!2 x!3) #b10 (ite (and (not x!2) x!3) #b10 #b00)) #b01)))
)
(check-sat)
(get-value ((trans_local true true (_ bv2 2))))
Your expression is not well sorted. In Z3, define-fun is essentially a macro. Z3 3.2 does not check if macro applications are well sorted. So, you did not get any error message. This has been fixed, and the fix will be available in the next release: Z3 4.0.
That being said, you can get the expected result by fixing the sort error in the get-value statement. I guess, you intended to write:
(get-value ((trans_local (_ bv1 2) true true)))