I just upgraded z3 from 4.1 to 4.3.1, and it seems that the smtlib2 input has changed :
now, a function/constant declaration is not deleted by a pop statement.
Here is the SMTlib2 input that works fine with z3 4.1 (and other SMT solvers...), but return with an error with z3 4.3.1 : (error "line 19 column 25: invalid declaration, constant 'bs_2' (whith the given signature) already declared")
(set-option :produce-models true)
(set-option :produce-unsat-cores true)
(set-option :interactive-mode true)
(set-option :print-success false)
(push 1)
(declare-fun bs_1 () Bool)
(push 1)
(declare-fun bs_2 () Bool)
(assert (and bs_1 (not bs_2)))
(check-sat)
(pop 1)
(push 1)
(declare-fun bs_2 () Bool)
(assert (and bs_1 (not bs_2)))
(check-sat)
(pop 1)
(pop 1)
(exit)
Removing the last bs_2 declaration works fine with z3 4.3.1, but not for z3 4.1.
Am I using the push/pop wrong ?
In Z3 4.3.1, we tried to relax some of the SMT-LIB 2.0 restrictions to make Z3 more convenient to use. For example, we can now write (+ x 2) instead of (+ x 2.0) when x is Real. Declarations are global instead of scoped like in Z3 4.1. The motivation was to allow users to encode problems more succinctly. We can use the following option to enable scoped declarations like in Z3 4.1
(set-option :global-decls false)
That being said, I understand this change is very confusing and counter-intuitive for users that are used to other SMT solvers, or read a manual describing the SMT-LIB standard. Thus, we will change the default back to (set-option :global-decls false).
Related
I am trying to solve a simple matching problem using Z3 which it claims is unsat. I have set this up the following way:
p_{x}_{y} to match up offer x with request y.
sum_{x} {p_x_y} <= 1 meaning y can only be matched once (using PbLe)
sum_{y} {p_x_y} <= 1 meaning x can only be matched once (using PbLe)
whether p_x_y is a valid match comes from an external computation that returns a Bool, so for this I have p_x_y => computation_result (i.e. if paired, then computation_result).
finally, I want to maximize the number of matchings. So I have:
maximize sum_{x} ( sum_{y} p_x_y ) (I do this with p_x_y.ite(Int(1), Int(0))).
I was able to whip this up quite quickly using z3-rs in Rust (not sure if that makes a difference). And this is the solver state before I run check on it:
Solver: (declare-fun p_0_0 () Bool)
(declare-fun p_1_0 () Bool)
(declare-fun k!0 () Int)
(declare-fun k!1 () Int)
(assert (=> p_0_0 true))
(assert (=> p_1_0 true))
(assert ((_ at-most 1) p_0_0))
(assert ((_ at-most 1) p_1_0))
(assert ((_ at-most 1) p_0_0 p_1_0))
(maximize (+ (ite p_1_0 k!1 k!0) (ite p_0_0 k!1 k!0)))
(check-sat)
Z3 claims this is Unsat and I am quite stumped. I don't see why p_0_0 = T, p_1_0 = F doesn't satisfy this formula.
Thank you very much for the help.
I can't replicate this. When I run your program, z3 prints: (after adding (get-model) at the end)
sat
(
(define-fun p_0_0 () Bool
true)
(define-fun p_1_0 () Bool
false)
(define-fun k!1 () Int
0)
(define-fun k!0 () Int
(- 1))
)
which matches your expectations.
Couple of things to make sure:
Is your z3 version "new" enough? 4.11.3 is the latest master I think
You mentioned you use it from Rust. Perhaps you didn't use the rust-API correctly? Or, maybe Rust interface has a bug.
I'd start by running it manually on your machine using the SMTLib script you've given. If you get SAT (which you should!), perhaps ask at the Rust forum as the bug is likely either in your Rust program or the Rust bindings itself. If you get UNSAT, try upgrading your z3 installation and possibly recompile the Rust bindings if that's relevant. (I'm not familiar with the Rust bindings to say if it needs a recompile or not if you upgrade your z3. It could be either way.)
A guess
Without seeing the details, it's hard to opine further. However, notice that you've posed this as an optimization problem; and asked z3 to maximize the addition of two uninterpreted integers. So, it's possible the Rust bindings are adding a call of the form:
(get-objectives)
at the end, to which z3 will respond:
sat
(objectives
((+ (ite p_1_0 k!1 k!0) (ite p_0_0 k!1 k!0)) oo)
)
That is, the objective you're maximizing is unbounded. This means there's no value for k!0 and k!1 the solver can present to you: The goal gets arbitrarily large as these get larger. It's possible the Rust interface is internally treating this as "unsat" since it cannot find the values for these constants. But that's just my guess without knowing the specifics of how the Rust bindings work.
I am experimenting with z3. I am surprised that, when setting the logic to LIA, z3 can return real numbers. For example, the following:
from z3 import *
sol = SolverFor("LIA")
vB = Real('vB')
sol.add(vB < 3)
sol.add(vB > 2)
sol.check()
print(sol.model())
returns:
[vB = 5/2]
Can someone please explain how it can be the case?
Strictly speaking, this is a "bug" in z3. Here's the equivalent SMT script:
(set-logic LIA)
(declare-fun vB () Real)
(assert (< vB 3.0))
(assert (> vB 2.0))
(check-sat)
(get-model)
If you run this with cvc4/cvc5, you get:
(error "Parse Error: a.smt2:2.23: Symbol 'Real' not declared as a type
(declare-fun vB () Real)
^
")
And Yices says:
(error "at line 2, column 20: undefined sort: Real")
CVC and Yices are correct here, since you restricted the logic to "LIA", the name "Real" is no longer defined. Z3, however, is playing loose here, and allowing reals by default. (It internally uses logics to pick which algorithms to run, but it's not always consistent in making sure the logic restricts the names available.)
You can report this at the z3 issue tracker here: https://github.com/Z3Prover/z3/issues. I suspect they're already aware of this, but would be good to have it recorded.
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
In this paper (Section 3.2), it says that z3 applies rewriting/simplification of formulas before it does any other steps.
Suppose I have a formula in QF_UF, that consists of multiple assert statements. Is there any rewriting rule that would somehow "break the barrier" between different assert statements? Or, asking the other way round: Can I be sure that rewrite rules are only applied locally, "within" one assert statement?
For example, consider the following formula:
(set-logic QF_UF)
(set-option :auto-config false)
(set-option :PROOF_MODE 2)
(declare-fun a () Bool)
(assert a)
(assert (not a))
(check-sat)
(get-proof)
Can I be sure that the proof will contain a resolution step to prove False, or is it possible that False will be concluded by a rewrite/simplification step?
The reason I am asking is that for my application, every assert statement has a special semantics. Rewriting/Simplification across several assert statements would render the resulting proof of unsatisfiability unusable (or at least: very hard to use) for me.
Z3 3.2 applies several preprocessing steps. Using (set-option :auto-config false) will disable most of them. You should also include the following two options:
(set-option :propagate-booleans false)
(set-option :propagate-values false)
how do I display the result of quantifier elimination ?
z3 seems to be happy with the following input
(set-option :elim-quantifiers true)
(declare-fun y () Real)
(simplify (exists ((x Real)) (>= x y)))
but it returns it the same as output.
Thanks
Z3 3.x has a new front-end for the SMT-LIB 2.0 input format.
In the new front-end, the command simplify is not an “umbrella” for all simplifications and pre-processing steps available in Z3.
The “do-all” approach used in Z3 2.x had several problems.
So, in Z3 3.x, we started using a fine-grain approach where the user can specify tactics/strategies for solving and/or simplifying formulas.
For example, one can write:
(declare-const x Int)
(assert (not (or (<= x 0) (<= x 2))))
(apply (and-then simplify propagate-bounds))
This new infrastructure is working in progress.
For example, Z3 3.2 does not have commands/tactics for eliminating quantifiers in the new front-end.
The commands/tactics for quantifier elimination will be available in Z3 3.3.
In the meantime, you can use the old SMT-LIB front-end for eliminating quantifiers.
You must provide the command line option -smtc to force Z3 to use the old front-end.
Moreover, the old front-end is not fully compliant with SMT-LIB 2.0. So, you must write:
(set-option ELIM_QUANTIFIERS true)
(declare-fun y () Real)
(simplify (exists ((x Real)) (>= x y)))