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.
Related
The following code
(declare-fun f (Int) Real)
(declare-fun g (Int) Real)
(declare-const x Int)
(declare-const y Int)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-model)
returns "unknown", even though there is an obvious solution. Eliminating arguments to f and g (effectively making them constants?) results in "sat" with expected assignments. I guess, my question is: what is special about arithmetic with uninterpreted functions?
BTW, replacing * with + also results in "sat", so the issue is not about uninterpreted functions, per se, but about how they are combined.
Additional thoughts
Making the domain (very) finite does not help, e.g.,
(declare-fun f (Bool) Real)
(declare-fun g (Bool) Real)
(declare-const x Bool)
(declare-const y Bool)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-model)
returns "unknown". This is odd given that f:Bool->Real is essentially just two variables f(False) and f(True) (of course, the solver has to recognize this).
Inability to handle non-linear arithmetic over real-valued uninterpreted functions is a very severe limitation because arrays are implemented as uninterpreted functions. So, for example,
(declare-const a (Array Int Real))
(assert (= (* (select a 1) (select a 1)) 1))
(check-sat)
(get-model)
returns "unknown". In other words, any non-linear algebraic expression on real array elements involving multiplication is unsolvable:'(
It's the non-liearity introduced by the multiplication that makes the problem hard to solve, not the uninterpreted functions. In fact, you can ask the solvers why by using the get-info command:
(set-logic QF_UFNIRA)
(declare-fun f (Int) Real)
(declare-fun g (Int) Real)
(declare-const x Int)
(declare-const y Int)
(assert (= (* (f x) (g y)) 1.0))
(check-sat)
(get-info :reason-unknown)
Here're some responses I got from various solvers:
Z3:
(:reason-unknown smt tactic failed to show goal to be sat/unsat (incomplete (theory arithmetic)))
CVC4:
(:reason-unknown incomplete)
MathSAT:
(error "sat, but with non-linear terms")
So, as the solvers themselves improve and start handling more nonliear arithmetic, you might get models eventually. But, in general, nonlinear problems will always be problematic as they are undecidable when integers are involved. (Since you can code Diophantine equations using non-linear terms.)
See also How does Z3 handle non-linear integer arithmetic? for a relevant discussion from 2012.
Removing uninterpreted functions
Even if you get rid of the uninterpreted functions, you'd still be in the unknown land, so long as you mix Int and Real types and non-linear terms:
(set-logic QF_NIRA)
(declare-const f Real)
(declare-const g Real)
(declare-const x Int)
(declare-const y Int)
(assert (= (+ (* f g) (to_real (+ x y))) 1.0))
(check-sat)
(get-info :reason-unknown)
Z3 says:
(:reason-unknown "smt tactic failed to show goal to be sat/unsat (incomplete (theory arithmetic))")
So, the issue would arise with mixed types and non-linear terms.
In Non-linear arithmetic and uninterpreted functions, Leonardo de Moura states that the qfnra-nlsat tactic hasn't been fully integrated with the rest of Z3 yet. I thought that the situation has changed in two years, but apparently the integration is still not very complete.
In the example below, I use datatypes purely for "software engineering" purposes: to organize my data into records. Even though there are no uninterpreted functions, Z3 still fails to give me a solution:
(declare-datatypes () (
(Point (point (point-x Real) (point-y Real)))
(Line (line (line-a Real) (line-b Real) (line-c Real)))))
(define-fun point-line-subst ((p Point) (l Line)) Real
(+ (* (line-a l) (point-x p)) (* (line-b l) (point-y p)) (line-c l)))
(declare-const p Point)
(declare-const l Line)
(assert (> (point-y p) 20.0))
(assert (= 0.0 (point-line-subst p l)))
(check-sat-using qfnra-nlsat)
(get-model)
> unknown
(model
)
However, if I manually inline all the functions, Z3 finds a model instantly:
(declare-const x Real)
(declare-const y Real)
(declare-const a Real)
(declare-const b Real)
(declare-const c Real)
(assert (> y 20.0))
(assert (= 0.0 (+ (* a x) (* b y) c)))
(check-sat-using qfnra-nlsat)
(get-model)
> sat
(model
(define-fun y () Real
21.0)
(define-fun a () Real
0.0)
(define-fun x () Real
0.0)
(define-fun b () Real
0.0)
(define-fun c () Real
0.0)
)
My question is, is there a way to perform such an inlining automatically? I'm fine with either one of these workflows:
Launch Z3 with a tactic that says "Inline first, then apply qfnra-nlsat. I haven't found a way to do so, but maybe I wasn't looking well enough.
Launch Z3 using some version of simplify to do the inlining. Launch Z3 the second time on the result of the first invocation (the inlined version).
In other words, how to make qfnra-nlsat work with tuples?
Thank you!
That's correct, the NLSAT solver is still not integrated with the other theories. At the moment, we can only use it if we eliminate all datatypes (or elements of other theories) before running it. I believe there is no useful existing tactic inside of Z3 at the moment though, so this would have to be done beforehand. In general it's not hard to compose tactics, e.g., like this:
(check-sat-using (and-then simplify qfnra-nlsat))
but the simplifier is not strong enough to eliminate the datatype constants in this problem. (The respective implementation files are datatype_rewriter.cpp and datatype_simplifier_plugin.cpp.)
I noticed some strange behavior with Z3 4.3.1 when working with .smt2 files.
If I do (assert (= 0 0.5)) it will be satisfiable. However, if I switch the order and do (assert (= 0.5 0)) it's not satisfiable.
My guess as to what is happening is that if the first parameter is an integer, it casts both of them to integers (rounding 0.5 down to 0), then does the comparison. If I change "0" to "0.0" it works as expected. This is in contrast to most programming languages I've worked with where if either of the parameters is a floating-point number, they are both cast to floating-point numbers and compared. Is this really the expected behavior in Z3?
I think this is a consequence of lack of type-checking; z3 is being too lenient. It should simply reject such queries as they are simply not well formed.
According to the SMT-Lib standard, v2 (http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.0-r10.12.21.pdf); page 30; the core theory is defined thusly:
(theory Core
:sorts ((Bool 0))
:funs ((true Bool) (false Bool) (not Bool Bool)
(=> Bool Bool Bool :right-assoc) (and Bool Bool Bool :left-assoc)
(or Bool Bool Bool :left-assoc) (xor Bool Bool Bool :left-assoc)
(par (A) (= A A Bool :chainable))
(par (A) (distinct A A Bool :pairwise))
(par (A) (ite Bool A A A))
)
:definition
"For every expanded signature Sigma, the instance of Core with that signature
is the theory consisting of all Sigma-models in which:
- the sort Bool denotes the set {true, false} of Boolean values;
- for all sorts s in Sigma,
- (= s s Bool) denotes the function that
returns true iff its two arguments are identical;
- (distinct s s Bool) denotes the function that
returns true iff its two arguments are not identical;
- (ite Bool s s) denotes the function that
returns its second argument or its third depending on whether
its first argument is true or not;
- the other function symbols of Core denote the standard Boolean operators
as expected.
"
:values "The set of values for the sort Bool is {true, false}."
)
So, by definition equality requires the input sorts to be the same; and hence the aforementioned query should be rejected as invalid.
There might be a switch to z3 or some other setting that forces more strict type-checking than it does by default; but I would've expected this case to be caught even with the most relaxed of the implementations.
Do not rely on the implicit type conversion of any solver. Instead,
use to_real and to_int to do explicit type conversions. Only send
well-typed formulas to the solver. Then Mohamed Iguernelala's examples become the following.
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_real x) 1.5))
(check-sat)
(exit)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 (to_real x)))
(check-sat)
(exit)
Both of these return UNSAT in Z3 and CVC4. If instead, you really
wanted to find the model where x = 1 you should have instead used one
of the following.
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_int 1.5) x))
(check-sat)
(get-model)
(exit)
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x (to_int 1.5)))
(check-sat)
(get-model)
(exit)
Both of these return SAT with x = 1 in Z3 and CVC4.
Once you make all the type conversions explicit and deal only in well-typed formulas, the order of arguments to equality no longer matters (for correctness).
One of our interns, who worked on a conservative extension of SMT2 with polymorphism has noticed the same strange behavior, when he tried the understand how formulas mixing integers and reals are type-checked:
z3 (http://rise4fun.com/z3) says that the following example is SAT, and finds a model x = 1
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x 1.5))
(check-sat)
(get-model)
(exit)
But, it says that the following "equivalent" example in UNSAT
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 x))
(check-sat)
(exit)
So, this does not comply with the symmetric property of equality predicate. So, I think it's a bug.
Strictly speaking, Z3 is not SMT 2.0 compliant by default, and this is one of those cases. We can add
(set-option :smtlib2-compliant true)
and then this query is indeed rejected correctly.
Z3 is not the unique SMT solver that type-checks these examples:
CVC4 accepts them as well (even with option --smtlib-strict), and answers UNSAT in both cases of my formulas above.
Yices accepts them and answers UNSAT (after changing the logic to QF_LIA, because it does not support AUFLIRA).
With (set-logic QF_LIA), Z3 emits an error: (error "line 3 column 17: logic does not support reals").
Alt-Ergo says "typing error: Int and Real cannot be unified" in both cases. But Alt-Ergo's SMT2 parser is very limited and not heavily tested, as we concentrated on its native polymorphic language. So, it should not be taken as a reference.
I think that developers usually assume an "implicit" sub-typing relation between Int and Real. This is why these examples are successfully type-checked by Z3, CVC4 and Yices (and probably others as well).
Jochen Hoenicke gived the answer (on SMT-LIB mailing list) regarding "mixing reals and integers". Here it is:
I just wanted to point out, that the syntax may be officially correct.
There is an extension in AUFLIRA and AUFNIRA.
From http://smtlib.cs.uiowa.edu/logics/AUFLIRA.smt2
"For every operator op with declaration (op Real Real s) for some
sort s, and every term t1, t2 of sort Int and t of sort Real, the
expression
- (op t1 t) is syntactic sugar for (op (to_real t1) t)
- (op t t1) is syntactic sugar for (op t (to_real t1))
- (/ t1 t2) is syntactic sugar for (/ (to_real t1) (to_real t2)) "
One possible solution is
(declare-fun x () Real)
(declare-fun y () Real)
(assert (= x 0))
(assert (= y 0.5))
(check-sat)
(push)
(assert (= x y) )
(check-sat)
(pop)
and the output is
sat
unsat
I'm curious what the limitations on z3's map operator are. According to the z3 tutorial (http://rise4fun.com/z3/tutorial), "Z3 provides a parametrized map function on arrays. It allows applying arbitrary functions to the range of arrays."
Map appears to work when I'm mapping built-in functions or functions declared with (declare-fun ...) syntax. When I attempt to use map with function (really macros) defined with (define-fun ...) syntax, I receive the error invalid function declaration reference, named expressions (aka macros) cannot be referenced.
Is there a standard way to map user-defined functions over arrays?
Here is some code that illustrates my confusion:
;simple function, equivalent to or
(define-fun my-or ((x Bool) (y Bool)) Bool (or x y))
(assert (forall ((x Bool) (y Bool)) (= (my-or x y) (or x y))))
(check-sat)
;mapping or with map works just fine
(define-sort Set () (Array Int Bool))
(declare-const a Set)
(assert ( = a ((_ map or) a a) ))
(check-sat)
;but this fails with error
(assert ( = a ((_ map my-or) a a) ))
I'm currently hacking around the problem like this:
(define-fun my-or-impl ((x Bool) (y Bool)) Bool (or x y))
(declare-fun my-or (Bool Bool) Bool)
(assert (forall ((x Bool) (y Bool)) (= (my-or x y) (my-or-impl x y))))
(check-sat)
But I'm hoping that there's a way to solve this which doesn't involve universal quantifiers.
Unfortunately, define-fun is just a macro definition in Z3. They are implemented in the Z3 SMT 2.0 parser. They are not part of the Z3 kernel. That is, Z3 solvers do not even "see" these definitions.
The approach using declare-fun and quantifiers works, but as you said we should avoid quantifiers since they create performance problems, and it is really easy to create problems with quantifiers that Z3 can't solve.
The best option is to use (_ map or).
The best option is to use (_ map or).
Unless one wants to map a non-built-in function over an array... I guess declare-fun plus assert is the only way to go?
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)