I have analyzed a formula in QF_AUFLIA with z3. The result was sat. The model returned by (get-model) contained the following lines:
(define-fun PCsc5_ () Int
(ite (= 2 false) 23 33)
According to my understanding of the SMTLIBv2 language, this statement is malformed. = should only be applied to arguments of the same sort. However, 2 has sort Int and false has sort Bool.
When I feed back just these two lines to z3, it agrees with me by saying:
invalid function application, sort mismatch on argument at position 2
Is this a bug?
If not, how am I supposed to interpret (= 2 false)?
The problem was due to a type error in the input. Z3 3.2 misses some type errors in macro applications. This problem was fixed. The next release will correctly report the type error (aka sort mismatch). Here is a minimal example that exposes the problem:
(set-option :produce-models true)
(declare-fun q (Int) Bool)
;; p1 is a macro
(define-fun p1 ((z Int) (y Int)) Bool
(ite (q y) (= z 0) (= z 1)))
(declare-const a Int)
(declare-const b Bool)
(assert (p1 a b)) ;; << TYPE ERROR: b must be an Int
(check-sat)
(get-model)
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.
I have a simple example in nonlinear integer arithmetic, namely a search for Pythagorean triples. Based on what I read in related questions (see below), I'd expect Z3 to find a solution to this problem, but it returns 'unknown'. Here is the example in SMT-LIB v2:
(declare-fun x () Int)
(declare-fun y () Int)
(declare-fun z () Int)
(declare-fun xSquared () Int)
(declare-fun ySquared () Int)
(declare-fun zSquared () Int)
(declare-fun xSquaredPlusYSquared () Int)
(assert (= xSquared (* x x)))
(assert (= ySquared (* y y)))
(assert (= zSquared (* z z)))
(assert (= xSquaredPlusYSquared (+ xSquared ySquared)))
(assert (and (> x 0) (> y 0) (> z 0) (= xSquaredPlusYSquared zSquared)))
(check-sat)
(exit)
There are a few related questions, most notably:
How does Z3 handle non-linear integer arithmetic?
Need help understanding the equation
Combining nonlinear Real with linear Int
Z3 support for nonlinear arithmetic
z3 limitations in handling nonlinear real arithmetics
It seems that Z3 won't attempt finding a solution by bit-blasting unless variables have a finite range. Replacing (check-sat) with the following command will find the solution:
(check-sat-using (then (using-params add-bounds :add-bound-lower -100 :add-bound-upper 100) smt))
Alternatively, one can add assert statements forcing each variable to have some finite range.
I was trying to represent a real number with two integer numbers as using them as the numerator and the denominator of the real number. I wrote the following program:
(declare-const a Int)
(declare-const b Int)
(declare-const f Real)
(assert (= f (/ a b)))
(assert (= f 0.5))
(assert (> b 2))
(assert (> b a))
(check-sat)
(get-model)
The program returned SAT result as follows:
sat
(model
(define-fun f () Real
(/ 1.0 2.0))
(define-fun b () Int
4)
(define-fun a () Int
2)
)
However, if I write '(assert (= f (div a b)))' instead of '(assert (= f (/ a b)))', then the result is UNSAT. Why does not div return the same result?
Moreover, and the main concern for me, I did not find a way to use operator '/' in z3 .Net API. I can see only function MkDiv, which actually for operator 'div'. Is there a way so that I can apply operator '/' in the case of z3 .Net API? Thank you in advance.
Strictly speaking neither of these formulas is SMT-LIB2 compliant, because / is a function that takes two Real inputs and produces a Real output, whereas div is a function that takes two Int inputs and produces an Int (see SMT-LIB Theories). Z3 is more relaxed and automatically converts those objects. If we enable the option smtlib2_compliant=true then it will indeed report an error in both cases.
The reason for the div version being unsatisfiable is that there is indeed no solution where f is an integer according to (= f (/ a b)), but there is indeed no integer that satisfies (= f 0.5)
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 am using Z3 from the unstable branch to experiment with Horn clauses (commit 61385c8489b7fda11b518a67fe308ea3cfe28c3d). I could make Z3 infer a few loop invariants, which was nice. Yet, with the following simple examples I am puzzled by Z3's behavior. What am I missing here?
Example 1:
(set-logic HORN)
(declare-const C Int)
(assert (> C 2))
(check-sat)
(get-model)
I would expect a model but receive "unknown".
Example 2:
(set-logic HORN)
(define-fun step ((I Int) (I1 Int)) Bool (= I1 (+ I 1)))
(define-fun post ((I1 Int)) Bool (= I1 10))
(declare-fun pre (Int) Bool)
(assert (forall ((I Int) (I1 Int)) (=> (and (pre I) (step I I1)) (post I1))))
(check-sat)
(get-model)
I would expect a model telling me something about pre (e.g., that it is false or that it holds for 9), but receive
sat
(model )
Thanks.
I am executing your Example 1 with Z3 (both online and local) and I am obtaining
WARNING: unknown logic, ignoring set-logic command
sat
(model (define-fun C () Int 3) )
I am executing your Example 2 with mathsat (local) and I am obtaining
sat
( (C 3) )
I am executing your Example 2 with Z3 (both online and local) and I am obtaining
WARNING: unknown logic, ignoring set-logic command
sat
(model
(define-fun elem!0 () Int 0)
(define-fun elem!1 () Int 0)
(define-fun pre ((x!1 Int)) Bool false)
)