I've played with the following example in Z3/Horn (unstable branch)
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (inv 0))
(assert (forall ((I Int)) (=> (and (<= I 1000) (inv I)) (inv (+ I 1)))))
(assert (forall ((I Int)) (=> (inv I) (<= I 10000))))
(check-sat)
(get-model)
It takes 8.5s to infer the invariant x≤1001. This is unexpectedly long...
Time increases to 19 seconds if I replace 1000 by 1500 and to 34 seconds if I replace 1000 by 2000. This seems to indicate quadratic behaviour with respect to the loop bound.
I find it curious that it takes so much time to verify an assertion that is clearly inductive...
To close the loop on this question.
First of all, it is a very good example to illustrate some points.
The PDR engine in Z3 uses a monolithic strategy for generating
intermediary assertions. Intuitively, it is based on under-approximating
strongest post-conditions. It does not attempt to search within the spectrum
of interpolant strengths.
The example converges much faster (instantly)
if applying a magic set transformation (e.g, inverting the transition system):
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (forall ((I Int)) (=> (not (<= I 10000)) (inv I))))
(assert (forall ((I Int)) (=> (and (<= I 1000) (inv (+ I 1))) (inv I))))
(assert (forall ((I Int)) (=> (inv I) (not (= I 0)))))
(check-sat)
(get-model)
Related
I have a program that runs Z3 version 4.8.8 - 64 bit, with incremental input: the program starts Z3 once, executes many rounds of input-output to Z3, and then stops Z3. For performance reasons, running Z3 without incremental input is not an option.
Each round, the program inputs some (assert ...) statements to Z3, inputs (check-sat) to Z3, then gets the output of (check-sat) from Z3.
I have two rounds of input-output: the first round of inputs is as in z3.sat:
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
which means: f is an even Int greater or equals to 2.
And the second round of inputs is as in z3.unsat:
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
which means: if f is an even Int greater or equals to 2, then there exists an alpha where alpha=f/2.
I assume that running Z3 with incremental input is similar to concatenating the two rounds of input, z3.sat and z3.unsat, into one input, as in z3.combined:
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
Running:
z3 -smt2 z3.sat outputs sat
z3 -smt2 z3.unsat outputs unsat
z3 -smt2 z3.combined outputs errors, because the (assert ...) statements from the first round do not disappear:
sat
(error "line 8 column 21: invalid declaration, constant 'f' (with the given signature) already declared")
(error "line 9 column 21: invalid declaration, constant 'n' (with the given signature) already declared")
unknown
So it seems (push 1) and (pop 1) statements are needed for Z3 to forget previous assertion sets, so I added these statements at the start and end of z3.sat and z3.unsat, and re-concatenated z3.pushpop.sat and z3.pushpop.unsat to get z3.pushpop.combined.
z3.pushpop.sat:
(push 1)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
(pop 1)
z3.pushpop.unsat:
(push 1)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
(pop 1)
z3.pushpop.combined:
(push 1)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
(pop 1)
(push 1)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
(pop 1)
However, now running:
z3 -smt2 z3.pushpop.sat outputs sat
z3 -smt2 z3.pushpop.unsat outputs unknown
z3 -smt2 z3.pushpop.combined outputs:
sat
unknown
Why does z3 -smt2 z3.pushpop.unsat output unknown?
As Malte mentioned, the presence of pus/pop triggers "weaker" solvers in z3. (There are many technical reasons for this, but I agree from an end-user view-point, the change in behavior is unfortunate and can be rather confusing.)
But there are commands that let you do what you want without resorting to push and pop. Instead of it, simply insert:
(reset)
when you want to "start" a new session, and this will make sure it'll all work. That is, drop the push/pop and when you concatenate, insert a (reset) in between.
A slightly better approach
While the above will work, in general you only want to forget assertions, but not definitions. That is, you want to "remember" that you have an f and an n in the environment. If this is your use case, then put the following at the top of your script:
(set-option :global-declarations true)
and when you want to "switch" to a new problem, issue:
(reset-assertions)
This way, you won't have to "repeat" the declarations each time. That is, your entire interaction should look like:
(set-option :global-declarations true)
(declare-fun f () Int)
(declare-fun n () Int)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not false))
(check-sat)
(reset-assertions)
(assert (< 1 n))
(assert (<= 2 f))
(assert (= (+ (+ 1 f) 1) (+ n n)))
(assert (not (exists ((alpha Int)) (= (* 2 alpha) f))))
(check-sat)
which produces:
sat
unsat
Reference
All of this is documented in the official SMTLib document. See Section 3.9, pg. 44, for the descripton of global-declarations, and Section 4.2.2, pg. 59, for the description of (reset-assertions).
Incremental mode forces Z3 to use different theory subsolvers, as explained by one of the developers in this SO answer. These "incremental mode" subsolvers are often less effective than the "regular" ones, or at least may behave differently. As far as I know, Z3 switches to incremental mode whenever an SMT program contains push-pop scopes or multiple check-sats.
You initially say that not using incremental mode is not an option, but at least your file z3.pushpop.combined looks easily splitable. Another option might be to reset Z3 (I think the SMT command (reset) exists for that purpose) in between, instead of having push-pop blocks. If what I claim above is correct, however, this wouldn't prevent Z3 from staying in non-incremental mode. You could consider asking the developers via a "question issue" on Z3's issue tracker.
(set-option :smt.mbqi true)
(declare-fun R(Int) Int)
(declare-const a Int)
(assert (= (R 0) 0))
(assert (forall ((n Int)) (=> (> n 0) (= (R n ) (+ (R (- n 1)) 1)))))
(assert (not (= a 5)))
(assert (not (= (R a) 5)))
(check-sat)
I have tried the above code in Z3,But Z3 unable to answer.Can you please guide me where i have made the mistake ?
As a general pattern don't expect MBQI to produce models
involving functions that
only have an infinite range of different values.
If you really must, then you can use the define-fun-rec construct to define
a recursive function. Z3 currently trusts that the definition
is well-formed (e.g., that the equation corresponding to the function
definition is satisfiable).
(set-option :smt.mbqi true)
(declare-fun F (Int) Int)
(define-fun-rec R ((n Int)) Int
(if (= n 0) 0
(if (> n 0) (+ (R (- n 1)) 1)
(F n))))
(declare-const a Int)
(assert (not (= a 5)))
(assert (not (= (R a) 5)))
(check-sat)
(get-model)
Z3 uses recursively defined functions passively during search: whenever
there is a candidate model for the ground portion of the constraints, it
checks that the function graph is adequately defined on the values of the candidate model. If it isn't, then the function definition is instantiated on the selected values until it is well defined on the values that are relevant
to the ground constraints.
I'm trying to use Why3's Z3 back-end in order to retrieve models that can then be used to derive test cases exhibiting bugs in programs. However, Z3 version 4.3.2 seems unable to answer sat for any Why3 goal. It looks like some of the axiomatic definitions used by Why3 somehow confuse Z3. For instance, the following example (which is a tiny part of what Why3 generates)
(declare-fun abs1 (Int) Int)
;; abs_def
(assert
(forall ((x Int)) (ite (<= 0 x) (= (abs1 x) x) (= (abs1 x) (- x)))))
(check-sat)
results in timeout with the following command line:
z3 -smt2 model.partial=true file.smt2 -T:10
On the other hand, changing the definition to
(declare-fun abs1 (Int) Int)
;; abs_def
(assert
(forall ((x Int)) (=> (<= 0 x) (= (abs1 x) x))))
(assert
(forall ((x Int)) (=> (> 0 x) (= (abs1 x) (- x)))))
will get me a model (which looks pretty reasonable)
(model
(define-fun abs1 ((x!1 Int)) Int
(ite (>= x!1 0) x!1 (* (- 1) x!1)))
)
but if I try to add the next axiom present in the original Why3 file, namely
;; Abs_pos
(assert (forall ((x Int)) (<= 0 (abs1 x))))
again Z3 answers timeout.
Is there something I'm missing in the configuration of Z3? Moreover, in previous versions of Why3, there was an option MODEL_ON_TIMEOUT, which allowed to retrieve a model in such circumstances. Even though there was no guarantee that this was a real model since Z3 could not finish to check it, in practice such models generally contained all the information I needed. However, I haven't found a similar option in 4.3.2. Does it still exist?
Update The last axiom Abs_pos was wrong (I toyed a bit with Why3's output before posting here and ended up pasting an incorrect version of the issue). This is now fixed.
The additional axiom
(assert (not (forall ((x Int)) (<= 0 (abs1 x)))))
makes the problem unsatisfiable, since abs1 always returns a non-negative integer and with the additional axiom you require the existence of a negative result for abs1 for some x. The web version of Z3 returns unsat as expected, see here.
Z3 now supports solving for inductive invariants (implying a desired property) if the semantics of the program to analyze is given as Horn clauses.
The version in the master branch of the Z3 source code on z3.codeplex.com however does not support this feature. Since Z3 solves these Horn clauses problems by the PDR algorithm, which uses interpolation, I compiled instead the interp branch (d8b31773b809), which supports (set-logic HORN).
As far as I understood, a Horn-clause problem is to be specified with unknown predicates representing invariants, and a predicate over X×Y is just a function from X×Y to Bool. So far so good.
The first example I tried is just a problem of inferring an inductive invariant for a for(int i=0; i<=10; i++) loop.
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (inv 0))
(assert (forall ((I Int)) (or (> I 10) (not (inv I)) (inv (+ I 1)))))
(check-sat)
So far so good, got sat. Now just added (assert (not (inv 15)) and I got unsat. I then tried
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (inv 0))
(assert (not (inv 15)))
(check-sat)
and got unsat.
What am I doing wrong?
Use the "unstable" branch.
The "interp" branch is for internal development and the state of this branch can fluctuate.
I get the answer "sat" on your second problem.
A slightly more interesting version of the first problem is:
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (inv 0))
(assert (forall ((I Int)) (or (> I 10) (not (inv I)) (inv (+ I 1)))))
(assert (forall ((I Int)) (=> (inv I) (<= I 11))))
(check-sat)
(get-model)
It produces the obvious inductive invariant.
If you replace the last assertion by
(assert (forall ((I Int)) (=> (inv I) (<= I 10))))
Instead you get a (hard to read) proof.
I have 3 variables a, b and c. I need to calculate c = absolute(b-a).
I encode this statement in Z3 as
(assert (>= c 0))
(assert (or (= c (- a b) (= c (- b a))))
I was thinking, is there a more efficient way of writing it in Z3?
Does Z3 have internal support for calculating absolute value?
Also, I hope there won't be any performance penalty for writing code like this, rather than using some other way.
Your encoding is correct. However, users usually encode the absolute value function using
(define-fun absolute ((x Int)) Int
(ite (>= x 0) x (- x)))
Then, they can write constraints such as:
(assert (= c (absolute (- a b))))
Here is the complete example (also available online at rise4fun):
(define-fun absolute ((x Int)) Int
(ite (>= x 0) x (- x)))
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(assert (= a 3))
(assert (= b 4))
(assert (= c (absolute (- a b))))
(check-sat)
(get-model)