Horn clauses in Z3 - z3

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.

Related

Interaction between quantifiers and sets in z3

I am currently trying to use Z3 to encode a simple program logic for an untyped language with sets.
My symbolic execution engine needs to prove the validity of the following formula:
To this end, we ask Z3 to check the satisfiability of:
which we then encode as the following SMT-LIB formula:
(define-sort Set () (Array Real Bool))
(define-fun singleton ((x Real)) Set
(store
((as const (Array Real Bool)) false)
x
true))
(define-fun set-union ((x Set) (y Set)) Set
((_ map (or (Bool Bool) Bool)) x y))
(declare-const head Real)
(declare-const tail Set)
(declare-const result Set)
(declare-const value Real)
(assert (forall ((x Real)) (=> (select tail x) (> x head))))
(assert (> head value))
(assert
(forall ((result Set))
(let ((phi1
(forall ((x Real)) (=> (select result x) (> x value))))
(phi2
(= result (union (singleton head) tail))))
(not (and phi1 phi2)))))
(check-sat)
When given this formula, the solver immediately outputs unknown.
My guess is that the problem lies on quantifying over a variable that is bound to a set.
To check this, I simplified the formula above, obtaining:
which we then encode as the following SMT-LIB formula:
(define-sort Set () (Array Real Bool))
(define-fun singleton ((x Real)) Set
(store
((as const (Array Real Bool)) false)
x
true))
(define-fun set-union ((x Set) (y Set)) Set
((_ map (or (Bool Bool) Bool)) x y))
(declare-const head Real)
(declare-const tail Set)
(declare-const result Set)
(declare-const value Real)
(assert (forall ((x Real))(=> (select tail x) (> x head))))
(assert (> head value))
(assert
(not
(forall ((x Real))
(=> (select (union (singleton head) tail) x)
(not (<= x value))))))
(check-sat)
When given this formula, the solver immediately outputs
unsat.
This confirms my guess that the problem lies on the quantification
over a variable that is bound to a set.
My question is whether or not Z3 supports formulae that include
quantification over sets. And, if so, what am I doing wrong?
Quantifier reasoning is always hard for SMT solvers, and in this case you have nested quantifiers. I'm not surprised to hear Z3 simply said Unknown in the first case. Also note that you are quantifying over what's essentially a function (Sets as you implemented are really functions), which makes it even more difficult. But even if you quantified over simpler things, nested quantifiers are never going to be easy to discharge.
Did you try skolemizing your formula, putting it into prenex-normal form, and getting rid of the existentials? That might get you a bit further though you might have to come up with appropriate patterns for instantiation.

Minor change results in "unknown" - related to quantifier preprocessing?

The following "minimal" program, distilled from a much larger program, is expected to yield unsat (and does). However, uncommenting the additional conjunct in the quantifier AX-1 changes the result to unknown (in Z3 4.5.0 x64 on Windows 10).
(set-option :auto_config false)
(set-option :smt.mbqi false)
(declare-fun foo (Int) Bool)
(declare-const k Real)
(assert (forall ((i Int)) (!
(and
(< 0.0 k)
; (implies (<= 0 i) (< 0.0 k)) ;;; ---- uncomment this line ----
)
:pattern ((foo i))
:qid |AX-1|)))
(assert (forall ((i Int)) (!
(foo i)
:pattern ((foo i))
:qid |AX-2|)))
(declare-const j Int)
(assert (< j 0))
; (push) ;;; doesn't make a difference
(assert (not
(ite
(foo j)
(< 0.0 k)
false)))
; (set-option :smt.qi.profile true)
(check-sat)
; (get-info :all-statistics)
; (pop)
The quantifier instantiation statistics show that AX-2 is instantiated in both cases, but AX-1 is only instantiated if the additional conjunct is not included. My assumption is that in the latter case, Z3 eliminates the quantifier since the quantified variable doesn't occur in the body.
However, I find it surprising that the version with the additional conjunct - in which Z3 presumably doesn't eliminate the quantifier - yields unknown, since the trigger for the quantifier ((foo j)) should be available.
Question: Is this behaviour expected - and if so, why?
Confirmed as a bug, see Github issue 935.

Why is Z3 not able to solve this instance without a seemingly trivial modification?

The original problem is:
(declare-const a Real)
(declare-const b Bool)
(declare-const c Int)
(assert (distinct a 0.))
(assert (= b (distinct (* a a) 0.)))
(assert (= c (ite b 1 0)))
(assert (not (distinct c 0)))
(check-sat)
The result is unknown.
But the last two constraints, taken together, are equivalent to (assert (= b false)), and after performing this rewrite by hand
(declare-const a Real)
(declare-const b Bool)
(declare-const c Int)
(assert (distinct a 0.))
(assert (= b (distinct (* a a) 0.)))
(assert (= b false))
;(assert (= c (ite b 1 0)))
;(assert (not (distinct c 0)))
(check-sat)
Z3 is now able to solve this instance (it is unsat).
Why can Z3 solve the second instance but not the first one, even though the first instance can be simplified to the second?
edit:
While locating the problem I found something very strange.
Z3 solves the following instance and returns "unsat":
(declare-fun a() Real)
(declare-fun b() Bool)
(declare-fun c() Int)
(assert (distinct a 0.0))
(assert (= b (distinct (* a a) 0.0)))
(assert (= b false))
;(assert (= c 0))
(check-sat)
But if I uncomment (assert (= c 0)), the solver returns "unknown", even though c=0 has nothing to do with the above assertions.
The problem here is that expressions like (* a a) are non-linear and Z3's default solver for non-linear problems gives up because it thinks it's too hard. Z3 does have another solver, but that one has very limited theory combination, i.e., you won't be able to use it for mixed Boolean, bit-vector, array, etc, problems, but only for arithmetic problems. It's easy to test by replacing the (check-sat) command with (check-sat-using qfnra-nlsat).

z3 4.3.2 fails to find a model for Why3-generated (satisfiable) goals

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.

slow invariant inference with Horn clauses in Z3

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)

Resources