We have encountered constraints for which Z3 returns sat but if we then add a certain named assertion then Z3 returns unknown. One example is:
(declare-fun a () Real)
(declare-fun b () Bool)
(assert (and (<= 0.1 a) (<= a 10.0)))
(assert (= b (= 1.0 (/ 1.0 a))))
(check-sat)
Z3 reports that this is satisfiable as expected. We can additionally assert that b is either true or false, both of which are satisfiable as expected. However, if we use a named assertion for the value of b then the result of the satisfiability check can become unknown depending on the value. With the value true, Z3 still returns sat:
(set-option :produce-unsat-cores true)
(declare-fun a () Real)
(declare-fun b () Bool)
(assert (and (<= 0.1 a) (<= a 10.0)))
(assert (= b (= 1.0 (/ 1.0 a))))
(assert (! (= b true) :named c))
(check-sat)
Using the value false, Z3 returns unknown:
(set-option :produce-unsat-cores true)
(declare-fun a () Real)
(declare-fun b () Bool)
(assert (and (<= 0.1 a) (<= a 10.0)))
(assert (= b (= 1.0 (/ 1.0 a))))
(assert (! (= b false) :named c))
(check-sat)
Checking the reason for the unknown result (with (get-info :reason-unknown)) returns (incomplete (theory arithmetic)).
It appears that z3 is just picking the wrong tactic in the latter case. Replace your check-sat call with:
(check-sat-using qfnra-nlsat)
And z3 says sat in both cases.
Why z3 ends up picking a different tactic is a difficult question to answer; I'd recommend filing this as a ticket at their github site; they might be missing a heuristic.
Side note: I found this by running both cases with -v:10 and skimming through the verbose output. It's not a bad way to see what z3 is doing for short-enough benchmarks.
For the following formula
(declare-fun i () Int)
(declare-fun #I () Int)
(declare-fun r2 () (Array Int Int))
(assert (= i 4))
(assert (forall ((#I Int))
(! (=> (and (>= #I 0) (< #I i)) (= (select r2 #I) 0))
:weight 10
:skolemid test
:qid test)))
(check-sat)
(get-model)
The Java API returns:
SATISFIABLE
(define-fun i () Int 4)
(define-fun #I () Int (- 1))
Why it generate specific value for quantifier variable "#I"?
Note that #I is declared twice:
(declare-fun #I () Int)
...
(assert (forall ((#I Int)) ...
Thus, it is indeed both, existential and universal. I've taken the liberty of copying this over into our issue tracker. As discussed there, this is not a bug: "Within the term namespace, bound variables can shadow one another as well as function symbol names ..." is what the SMT2 standard says (Remark 2, Sec. 3.3).
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)
)
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)