While we are on the topic of horn clauses, I have been trying to figure out the capabilities and limitations of μZ. I taught Z3 the theory of xor over a user defined sort, but it is unable to apply the rules effectively, resulting in unknown for any interesting query. Pairing down, I obtained this example that surprisingly returns unknown:
(set-logic HORN)
(declare-fun p (Bool Bool Bool) Bool)
; Test if Z3 can discover two a1+b1+c1 by canceling ra, rb, and rc
(assert (exists ((a1 Bool) (b1 Bool) (c1 Bool) (ra Bool) (rb Bool) (rc Bool))
(and (p a1 b1 c1)
(xor (xor a1 (xor ra rc))
(xor b1 (xor rb ra))
(xor c1 (xor rc rb))))))
; Assert the adversary can not derive the secret, a+b+c.
(assert (exists ((a1 Bool) (b1 Bool) (c1 Bool))
(and (p a1 b1 c1) (xor a1 (xor b1 c1)))))
(check-sat)
Am I wrong to expect sat even when the uninterpreted p is used? I note the linked question includes an uninterpreted function, inv, but is handled by Z3. Should I have inferred this short-coming from the PDR paper or is there another publication that could illuminate the current state of Z3 PDR?
EDIT: I am guessing this result is due to the use of existential quantification. If that's the case, and given that my problem requires existentials, is there a reasonable alternative formulation?
The problem is that the benchmark is annotated as "HORN", but the formulas do not properly belong to the HORN fragment that is supported.
If you remove the
(set-logic HORN)
line, then Z3 answers sat by applying the default strategy.
With the (set-logic HORN) line, Z3 uses only the HORN strategy.
It gives up if the formula does not belong to the supported fragment.
The supported fragment of Horn clauses assume that the assertions are universally quantified
(forall quantified). The assertions should also be Horn clauses (implications), such that
the head of the implication is either an uninterpreted predicate or some formula without any
uninterpreted predicates. The body of the implication (left side of the implication)
is a conjunction of formulas, that are either an occurrence of the uninterpreted predicate
or some formula without the uninterpreted predicate.
A horn clause can also be an atomic formula consisting of an application of an uninterpreted
predicate.
The pre-processor does recognize some formulas that are not directly formulated
as implications, but it is easier for experimentation to conform with pure Horn clauses.
Here are some sample Horn clauses:
(forall ((a Bool) (b Bool)) (=> (xor a b) (p a b)))
(forall ((a Bool) (b Bool)) (=> (and (xor a b) (p a b)) false))
(p true false)
Related
I know the procedure simply by transforming each clause l1 ∨ ⋯ ∨ ln to a conjunction of n − 2 clauses .
I try to show the values satisfying the original and the final formula with Z3 to show that they are equisatisfiable as an SMT file.
For clarify can you give any example about this procedure . Thank you.
Equivalence checking is done by asking the solver if there's an assignment that can distinguish two formulas. If there's no such assignment, then you can conclude the formulas are equivalent, or in the SAT context, equi-satisfiable.
Here's a simple example:
from z3 import *
a, b, c = Bools('a b c')
fml1 = Or(And(a, b), And(a, c))
fml2 = And(a, Or(b, c))
s = Solver()
s.add(Distinct(fml1, fml2))
print(s.check())
Now if fml1 is an arbitrary SAT formula, and fml2 is a 3-SAT converted version (I'm not saying the above are SAT and 3-SAT conversions, but substitute the result of your algorithm here), then we'd expect that the SAT solver cannot distinguish them, i.e., the formula Distinct(fml1, fml2) would be unsatisfiable. Indeed, we get:
unsat
establishing that they are the same.
If you are using SMTLib only, then the template to use is:
(declare-fun a () Bool)
(declare-fun b () Bool)
(declare-fun c () Bool)
(assert (distinct (or (and a b) (and a c))
(and a (or b c))))
(check-sat)
I am using Z3 to solve my horn clauses. In the body of Horn clauses uninterpreted predicates should be positive. However, I need negation of some of uninterpreted predicates.
I have seen some examples in which negation works fine. For instance Z3 would return sat for the following example:
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (inv 0))
(assert (forall ((k Int)) (or (> k 10) (not (inv k)) (inv (+ k 1)))))
(check-sat)
But my example looks like the following for which Z3 returns unknown.
(set-logic HORN)
(declare-fun inv (Int ) Bool)
(declare-fun s ( Int ) Bool)
(assert (forall ((k Int) (pc Int))(=>(and (= pc 1)(= k 0)) (inv k ))))
(assert (forall ((k Int)(k_p Int)(pc Int)(pc_p Int))
(=>(and (inv k )(= pc 1)(= pc_p 2)(= k_p (+ k 1))(not (s pc ))(s pc_p ))
(inv k_p ))))
(check-sat)
I wonder if there is a way to rewrite my clauses to Horn clause fragment of Z3.
Your clauses are not in the Horn fragment because the predicate s is used with both polarities in the last assertion. So there are two occurrences of a predicate with positive polarity (both (s pc) and (inv k_p) are positive polarity).
A basic method to avoid polarity issues is to introduce an extra argument to s of type Bool. Consequently, you would also have to say what is the specification of s using Horn clauses so it all makes sense. The typical scenario is that s encodes the behavior of a recursive procedure and the extra Boolean argument to s would be the return value of the procedure s. Of course this encoding doesn't ensure that s is total or functional.
There is a second approach, which is to add an extra argument to "inv", where you let 's' be an array. Then the occurrences (not (s pc)) becomes (not (select s pc)), etc.
It all depends on the intent of your encoding for what makes sense.
I observed a difference in Z3's quantifier triggering behaviour (I tried 4.4.0 and 4.4.2.3f02beb8203b) that I cannot explain. Consider the following program:
(set-option :auto_config false)
(set-option :smt.mbqi false)
(declare-datatypes () ((Snap
(Snap.unit)
(Snap.combine (Snap.first Snap) (Snap.second Snap))
)))
(declare-fun fun (Snap Int) Bool)
(declare-fun bar (Int) Int)
(declare-const s1 Snap)
(declare-const s2 Snap)
(assert (forall ((i Int)) (!
(> (bar i) 0)
:pattern ((fun s1 i))
)))
(assert (fun s2 5))
(assert (not (> (bar 5) 0)))
(check-sat) ; unsat
As far as my understanding goes, the unsat is unexpected: Z3 should not be able to trigger the forall since it is guarded by the pattern (fun s1 i), and Z3 should not be able (and actually isn't) to prove that s1 = s2.
In contrast, if I declare Snap to be an uninterpreted sort, then the final check-sat yields unknown - which is what I would expect:
(set-option :auto_config false)
(set-option :smt.mbqi false)
(declare-sort Snap 0)
...
(check-sat) ; unknown
If I assume s1 and s2 to be different, i.e.
(assert (not (= s1 s2)))
then the final check-sat yields unknown in both cases.
For convenience, here is the example on rise4fun.
Q: Is the difference in behaviour a bug, or is it intended?
The assertion (not (= s1 s2)) is essential. With pattern based quantifier instantiation, the pattern matches if the current state of the search satisfies s1 = s2. In the case of algebraic data-types, Z3 tries to satisfy formulas with algebraic data-types by building a least model in terms of constructor applications. In the case of Snap as an algebraic data-type the least model for s1, s2 have them both as Snap.unit. At that point, the trigger is enabled because the terms E-match. In other words, modulo the congruences, the variable I can be instantiated such that (fun s1 I) matches (fun s2 5), but setting I <- 5. After the trigger is enabled, the quantifier is instantiated and the axiom
(=> (forall I F(I)) (F(5)))
is added (where F is the formula under the quantifier).
This then enables to infer the contradiction and infer unsat.
When Snap is uninterpreted, Z3 attempts to construct a model where terms s1 and s2 are different. Since there is nothing to force these terms to be equal they remain distinct
It's not a bug since z3 doesn't say unsat for a sat formula (or sat for an unsat one). In presence of quantified formulas, SMT solvers are (in general) not complete. So they sometimes answer unknown when they are not sure that the input formula in sat.
For your example:
a - It's normal that, with matching techniques, z3 does not prove the formula when you assume that s1 and s2 are different. In fact, there is no ground term of the form (fun s1 5) that matches the pattern (fun s1 i), and that would allow the generation of the useful instance (> (bar 5) 0) from your quantified formula;
b - When you don't assume that s1 and s2 are different, you would not be able to get the proof too. Except that z3 probably assumes internally that s1 = s2 when Snap is a datatype. This is correct as long as there is nothing that contradicts s1 = s2. Thanks to this and to matching modulo equality, the ground term (fun s2 5) matches the pattern (fun s1 i), and the needed instance to prove unsatisfiability is generated.
In the following example, I tried to use uninterpreted Boolean function like "(declare-const p (Int) Bool)" rather than single Boolean constant for each assumption. But it does not work (it gives compilation error).
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
(declare-fun p (Int) Bool)
;(declare-const p1 Bool)
;(declare-const p2 Bool)
; (declare-const p3 Bool)
;; We assert (=> p C) to track C using p
(declare-const x Int)
(declare-const y Int)
(assert (=> (p 1) (> x 10)))
;; An Boolean constant may track more than one formula
(assert (=> (p 1) (> y x)))
(assert (=> (p 2) (< y 5)))
(assert (=> (p 3) (> y 0)))
(check-sat (p 1) (p 2) (p 3))
(get-unsat-core)
Output
Z3(18, 16): ERROR: invalid check-sat command, 'not' expected, assumptions must be Boolean literals
Z3(19, 19): ERROR: unsat core is not available
I understand that it is not possible (unsupported) to use Boolean function. Is there any reason behind that? Is there different way to do that?
We have this restriction because Z3 applies many simplifications before it solves a problem. Some of them will rewrite formulas and terms. The problem that is actually solved by Z3 is very often quite different from the input problem. We would have trace back the simplified assumptions to the original assumptions, or introduce auxiliary variables. Restricting to Boolean literals avoids this issue, and makes the interface very clean. Note that this restriction does not limit the expressiveness. If you think it is too annoying to declare many Boolean variables to track different assertions. I suggest you take a look at the new Python front-end for Z3 called Z3Py. It is much more convenient to use than SMT 2.0. Here is your example in Z3Py: http://rise4fun.com/Z3Py/cL
In this example, instead of creating an uninterpreted predicate p, a "vector" (actually, it is a Python list) o Boolean constants is created.
The Z3Py online tutorial contains many examples.
It is also possible to implement in Z3Py the approach that creates auxiliary variables.
Here is the script that does the trick. I defined a function check_ext that does all the plumbing. http://rise4fun.com/Z3Py/B4
I'm trying to encode a QBF in smt-lib 2 syntax for z3. Running z3 results in a warning
WARNING: failed to find a pattern for quantifier (quantifier id: k!14)
and the satisfiability result is "unknown".
The code is as follows:
(declare-fun R (Bool Bool Bool Bool) Bool)
(assert
(forall ((x2 Bool) (x3 Bool))
(exists ((y Bool))
(forall ((x1 Bool))
(R x1 x2 x3 y)
)
)
)
)
(check-sat)
I got rid of the warning by rewriting the code to
(set-option :auto-config false)
(set-option :mbqi false)
(declare-fun R (Bool Bool Bool Bool) Bool)
(declare-fun x1 () Bool)
(declare-fun x2 () Bool)
(declare-fun x3 () Bool)
(declare-fun y () Bool)
(assert
(forall ((x2 Bool) (x3 Bool))
(!
(exists ((y Bool))
(!
(forall ((x1 Bool))
(!
(R x1 x2 x3 y)
:pattern((R x1 x2 x3 y)))
)
:pattern((R x1 x2 x3 y)))
)
:pattern((R x1 x2 x3 y)))
)
)
(check-sat)
The result for the sat-query, however, remains "unknown".
I'm guessing that I need to get the patterns right? How do I specify them for nested quantifiers? Simpler examples with quantifiers seem to work without pattern annotation, though.
The answer to What is the reason behind the warning message in Z3: "failed to find a pattern for quantifier (quantifier id: k!18) " and the z3 guide didn't help me too much, unfortunately.
This warning message can be ignored. It is just informing you that the E-matching engine will not be able to process this quantified formula.
E-matching is only effective for showing that a problem is unsatisfiable. Since your example is satisfiable, E-matching will not be very useful. That is, Z3 will not be able to return sat using the E-matching engine. Model based quantifier instantiation (MBQI) is the only engine in Z3 that is capable of showing that problems containing quantifiers are satisfiable.
Using the default configuration, Z3 will return sat for your example. It returns unknown because you disabled the MBQI module.
The MBQI engine guarantees that Z3 is a decision procedure for many fragments (see http://rise4fun.com/Z3/tutorial/guide). However, it is very expensive in general, and should be disabled when quick and approximated answers are sufficient. In this case, unknown may be read as probably sat. Verification tools such as VCC disable MBQI module since it is incapable of deciding formulas produced by them. That is, the formulas produced by VCC are not in any of the fragments that can be decided by the MBQI engine.
We say a fragment can be decided by Z3 when for any formula in the fragment Z3 will return sat or unsat (i.e., it does not return unknown). Of course, this claim assumes we have a unlimited amount of resources. That is, Z3 may also fail (i.e., return unknown) for decidable fragments when it runs out of memory, or a timeout was specified by the user.
Finally, Z3 3.2 has a bug in the MBQI engine. The bug has been fixed, and it does not affect your problem. If you need I can give you a pre-release version of Z3 4.0 which contains the bug fix.