How to check satisfiability of a program using Z3? For example:
Boolean x, y
while(x is False) {
x = x or y
y = x & y
}
y = x or y
You can represent programs as a set of Horn clauses. For your program you can represent it as follows:
(set-logic HORN)
(set-option :fixedpoint.engine bmc)
(declare-fun L0 (Bool Bool) Bool)
(declare-fun L1 (Bool Bool) Bool)
(declare-fun L2 (Bool Bool) Bool)
(declare-fun L3 (Bool Bool) Bool)
(assert (forall ((x Bool) (y Bool)) (L0 x y))) ; all values of x,y are possible at L0
(assert (forall ((x Bool) (y Bool)) (=> (L0 x y) (L1 x y)))) ; from L0 move to L1 without changing x, y
(assert (forall ((x Bool) (y Bool) (x1 Bool) (y1 Bool))
(=> (and (not x) (L1 x y) (= x1 (or x y)) (= y1 (and x1 y))) (L1 x1 y1)))); assignment in while loop
(assert (forall ((x Bool) (y Bool)) (=> (and x (L1 x y)) (L2 x y)))) ; exit while loop
(assert (forall ((x Bool) (y Bool)) (=> (L2 x y) (L3 x (or x y))))) ; assignment after while loop
(assert (forall ((x Bool) (y Bool)) (=> (L3 true true) false))) ; say x = true, y = true is unreachable.
(check-sat)
I have added a last assertion to make a reachability statement.
I have also instructed Z3 to use a BMC engine to unfold the Horn clauses using
bounded model checking. Other engines are available as well, for the example the PDR/IC3
engine (set-option :fixedpoint.engine pdr), does not unfold transition relations.
Now the meaning of reachability vs. satisfiability
is going to be different for Horn clauses, as compared to a conjunction of the unfolded
transition relation:
the above clauses are UNSAT.
This does in fact correspond to a feasible path from L0 to (L3 true true).
If you change the last statement to (L3 true false), you get the answer "sat"
(The BMC problem is UNSAT). While BMC itself would not terminate on with such a loop,
it turns out that the last transition and loop exit condition are enough to prune out
the possibility of (L3 true false) so Z3 solves this problem by pre-processing the horn clauses.
You can of course also write down the transition relation for the program statements you have and unfold this directly yourself into a logical formula that you check satisfiability of.
Related
I'm using Z3 theorem prover (using Z3Py: the Z3 API in Python) to create QBF (Quantified Boolean formula).
Is there any way in Z3 to directly convert your qbf formula into Prenex normal form ?
I don't think there's a tactic to convert to Prenex, but you can surely apply the quantifier-elimination tactic and further process your formulas. Note that the transformed formulas will not really look like the originals, as they are mechanically generated.
Here's an example:
from z3 import *
f = Function('f', IntSort(), IntSort(), IntSort())
x, y = Ints('x y')
p = ForAll(x, Or(x == 2, Exists(y, f (x, y) == 0)))
print Tactic('qe')(p)
Here qe is the quantifier elimination tactic. This produces:
[[Not(Exists(x!0,
Not(Or(x!0 == 2,
Exists(x!1,
And(f(x!0, x!1) <= 0,
f(x!0, x!1) >= 0))))))]]
For a nice tutorial on tactics, see here: http://ericpony.github.io/z3py-tutorial/strategies-examples.htm
You could use the skolemize tactic (snf) which will by definition be in prenex form. However it will also eliminate existential quantifiers which is not what you want. Here's an example.
(declare-fun a (Int) Bool)
(declare-fun b (Int) Bool)
(declare-fun c (Int) Bool)
(assert
(forall ((x Int))
(or
(exists ((y Int))
(a y)
)
(exists ((z Int))
(=>
(b z)
(c x)
)
)
)
)
)
(apply
(and-then
; mode (symbol) NNF translation mode: skolem (skolem normal form), quantifiers (skolem normal form + quantifiers in NNF), full (default: skolem)
(using-params snf :mode skolem)
)
:print_benchmark true
:print false
)
When Z3 is given the above it will responds with something like
(declare-fun c (Int) Bool)
(declare-fun b (Int) Bool)
(declare-fun a (Int) Bool)
(assert (forall ((x Int))
(or (exists ((y Int)) (a y)) (exists ((z Int)) (=> (b z) (c x))))))
(check-sat)
You can see the available tactics by running
echo "(help-tactic)" | ./z3 -in | less
from a bash shell.
Unfortunately I can't see one that states it does conversion to prenex.
I am trying to prove with Z3 the theorem in general topology given at
TPTP-Topology
I am translating the code given there using the following Z3-SMT-LIB code
;; File : TOP001-2 : TPTP v6.0.0. Released v1.0.0.
;; Domain : Topology
;; Problem : Topology generated by a basis forms a topological space, part 1
(declare-sort S)
(declare-sort Q)
(declare-sort P)
(declare-fun elemcoll (S Q) Bool)
(declare-fun elemset (P S) Bool)
(declare-fun unionmemb (Q) S)
(declare-fun f1 (Q P) S)
(declare-fun f11 (Q S) P)
(declare-fun basis (S Q) Bool)
(declare-fun Subset (S S) Bool)
(declare-fun topbasis (Q) Q)
;; union of members axiom 1.
(assert (forall ((U P) (Vf Q)) (or (not (elemset U (unionmemb Vf)))
(elemset U (f1 Vf U) ) ) ))
;; union of members axiom 2.
(assert (forall ((U P) (Vf Q)) (or (not (elemset U (unionmemb Vf)))
(elemcoll (f1 Vf U) Vf ) ) ))
;; basis for topology, axiom 28
(assert (forall ((X S) (Vf Q)) (or (not (basis X Vf)) (= (unionmemb Vf) X ) ) ))
;; Topology generated by a basis, axiom 40.
(assert (forall ((Vf Q) (U S)) (or (elemcoll U (topbasis Vf))
(elemset (f11 Vf U) U)) ))
;; Set theory, axiom 7.
(assert (forall ((X S) (Y Q)) (or (not (elemcoll X Y)) (Subset X (unionmemb Y) ) ) ))
;; Set theory, axiom 8.
(assert (forall ((X S) (Y S) (U P)) (or (not (Subset X Y)) (not (elemset U X))
(elemset U Y) )))
;; Set theory, axiom 9.
(assert (forall ((X S)) (Subset X X ) ))
;; Set theory, axiom 10.
(assert (forall ((X S) (Y S) (Z S)) (or (not (= X Y)) (not (Subset Z X)) (Subset Z Y) ) ))
;; Set theory, axiom 11.
(assert (forall ((X S) (Y S) (Z S)) (or (not (= X Y)) (not (Subset X Z)) (Subset Y Z) ) ))
(check-sat)
(push)
(declare-fun cx () S)
(declare-fun f () Q)
(assert (basis cx f))
(assert (not (elemcoll cx (topbasis f))))
(check-sat)
(pop)
(push)
(assert (basis cx f))
(assert (elemcoll cx (topbasis f)))
(check-sat)
(pop)
The corresponding output is
sat
sat
sat
Please run this example online here
The first sat is correct; but the second sat is wrong, it must be unsat. In other words, Z3 is saying that the theorem and its negation are true simultaneously.
Please let me know what happens in this case. Many thanks. All the best.
It is possible that both a formula and the negation of the formula is consistent with respect to a background theory T. In particular, when T is not complete, then there are sentences that are neither consequences of T nor inconsistent with T. In your case the theory T is the set of topology axioms.
You can use the command (get-model) to obtain a model that satisfies the axioms and the sentence.
I have a problem required to solve a set of nonlinear polynomial constraints. Can z3 always give a result (sat or unsat) when handling nonlinear real arithmetic.
Is the result also sound?
Yes, it is complete assuming (1) availability of resources, and (2) you only use real constraints so that the nlsat tactic is used, as the last I checked, it wasn't full integrated with the other solvers, see the below questions/answers for more details. Here's a simple example illustrating this (at least by default, rise4fun link: http://rise4fun.com/Z3/SRZ8 ):
(declare-fun x () Real)
(declare-fun y () Real)
(declare-fun z () Real)
(assert (>= (* 2 (^ x 2)) (* y z)))
(assert (> x 100))
(assert (< y 0))
(assert (< z 0))
(assert (> (^ y 2) 1234))
(assert (< (^ z 3) -25))
(check-sat) ; sat
(get-model)
(declare-fun b () Int)
(assert (> b x))
(check-sat) ; unknown
Z3 Theorem Prover: Pythagorean Theorem (Non-Linear Artithmetic)
mixing reals and bit-vectors
z3 produces unknown for assertions without quantifiers
z3 existential theory of the reals
Combining nonlinear Real with linear Int
Z3 support for nonlinear arithmetic
Encoding returns "unknown"
For the incremental question, it may be possible to use nlsat with incremental solving, but in this simple example applying a standard method (rise4fun link: http://rise4fun.com/Z3/Ce1F and see: Soft/Hard constraints in Z3 ) there is an unknown, although a model assignment is made, so it may be useful for your purposes. If not, you can try push/pop: Incremental solving in Z3 using push command
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
(declare-const p1 Bool)
(declare-const p2 Bool)
(declare-const p3 Bool)
(declare-const p4 Bool)
(declare-const p5 Bool)
(declare-const p6 Bool)
(declare-const p7 Bool)
(declare-fun x () Real)
(declare-fun y () Real)
(declare-fun z () Real)
(assert (=> p1 (>= (* 2 (^ x 2)) (* y z))))
(assert (=> p2 (> x 100)))
(assert (=> p3 (< y 0)))
(assert (=> p4 (< z 0)))
(assert (=> p5 (> (^ y 2) 1234)))
(assert (=> p6 (< (^ z 3) -25)))
(assert (=> p7 (< x 50)))
(check-sat p1 p2 p3 p4 p5 p6 p7) ; unsat
(get-unsat-core) ; (p2 p7)
(check-sat p1 p2 p3 p4 p5 p6) ; unknown, removed one of the unsat core clauses
(get-model)
(declare-fun b () Int)
(assert (> b x))
(check-sat) ; unknown
It appears that reasoning about XOR causes explosive memory use for Z3 (commit 210bca8f456361f696152be909e33a4e8b58607f2). For example, deriving a+b+c from something that is AC equivalent to a+b+c+x+x+y+y+z+z:
(declare-fun known (Bool) Bool)
(declare-fun p (Bool Bool Bool) Bool)
; Lift xor
(assert (forall ((x Bool) (y Bool))
(=> (and (known x) (known y)) (known (xor x y)))))
; Can reason about xor well
(assert (exists ((a1 Bool) (b1 Bool) (c1 Bool) (ra Bool) (rb Bool) (rc Bool))
(and (p a1 b1 c1)
(known (xor a1 (xor ra rc)))
(known (xor b1 (xor rb ra)))
(known (xor c1 (xor rc rb))))))
; Assert that we can derive a+b+c.
; Note: The behavior (non-termination) is the same when this example is
; inverted (forall ... not ...)
(assert (exists ((a1 Bool) (b1 Bool) (c1 Bool))
(and (p a1 b1 c1)
(known (xor a1 (xor b1 c1))))))
(check-sat)
Is this an accepted limitation? Are there alternate formulations I can use to answer queries like this with Z3?
Continuity: I had previously misused the HORN logic for this task.
The problem is that the assertion
(assert (forall ((x Bool) (y Bool))
(=> (and (known x) (known y)) (known (xor x y)))))
is really bad for the E-matching engine. This is one of the engines used to handle quantifiers in Z3.
There are many possible workarounds.
1) Use quantifier elimination. You just have to replace (check-sat) with (check-sat-using (then qe smt))
2) Annotate the quantifier with a :weight attribute. The E-matching engine will stop producing new instances earlier. Here is an example:
(assert (forall ((x Bool) (y Bool))
(! (=> (and (known x) (known y)) (known (xor x y)))
:weight 10)))
3) Disable the E-matching engine. Then, Z3 will use only the MBQI (model-based quantifier instantiation) engine, which is much more effective for this kind of problem. To disable E-matching, we should use
(set-option :smt.ematching false)
Remark: in Z3 version <= 4.3.1, this option is called (set-option :ematching false)
Is there any way to apply simplifications to uninterpreted functions defined in z3, rather than the goals and subgoals ?
I have the following z3 code :
(declare-fun f (Bool Bool) Bool)
(assert (forall ((b1 Bool) (b2 Bool))
(implies b2 (f b1 b2))))
(assert (exists ((b1 Bool) (b2 Bool))
(not (f b1 b2))))
(check-sat)
(get-model)
And I get the following output:
sat
(model
(define-fun b1!1 () Bool
false)
(define-fun b2!0 () Bool
false)
(define-fun k!7 ((x!1 Bool)) Bool
false)
(define-fun f!8 ((x!1 Bool) (x!2 Bool)) Bool
(ite (and (= x!1 false) (= x!2 true)) true
false))
(define-fun k!6 ((x!1 Bool)) Bool
(ite (= x!1 false) false
true))
(define-fun f ((x!1 Bool) (x!2 Bool)) Bool
(f!8 (k!7 x!1) (k!6 x!2)))
)
It turns out that by applying rewrite rules to the definition of f, we can get that
f is equal to the second argument (x!2) by the following derivation:
(f!8 (k!7 x!1) (k!6 x!2))
= (f!8 false (k!6 x!2))
= (f!8 false x!2)
=(x!2)
Is there any way to get z3 to produce the following definition automatically ?
(define-fun f ((x!1 Bool) (x!2 Bool)) Bool
(x!2))
Thanks for your help.
Regards,
Oswaldo.
One option is to ask Z3 to evaluate the expression (f x y) where x and y are fresh Boolean constants. The eval command will evaluated (f x y) in the current model, and will produce y in your example. Here is the complete example (also available online here):
(declare-fun f (Bool Bool) Bool)
; x and y are free Boolean constants that will be used to create the expression (f x y)
(declare-const x Bool)
(declare-const y Bool)
(assert (forall ((b1 Bool) (b2 Bool))
(implies b2 (f b1 b2))))
(assert (exists ((b1 Bool) (b2 Bool))
(not (f b1 b2))))
(check-sat)
(eval (f x y))