Why is this Z3 query failing - z3

I am experimenting with Z3, and more specifically with muZ, however some queries fail, and I don't understand why.
For example this definition of implication
(declare-rel imp (Bool Bool))
(declare-var post Bool)
(rule (imp false post))
(rule (=> (imp true post) post))
(query (imp true false) :print-certificate true)
gives the error (error "query failed: Illegal head. The head predicate needs to be uninterpreted and registered (as recursive) (= (:var 0) true)")
Much larger examples, with many parameters defined with the same structure work as expected. Furthermore by removing the second rule I get the error ERROR: certificates are not supported for datalog which makes me suspect that for some reason this problem is being incorrectly interpreted as datalog, and the larger problems are being interpreted as fixedpoints.
What makes this query fail?

The format form rules generally assumes that rules have uninterpreted predicates in the head. The second rule has a bound variable in the head.
If you add non-propositional features to the datalog rules, such as arithmetic,
the fixedpoint engine will seek to dispatch an engine that understands such features. You can control the engine by specifying (set-option :fixedpoint.engine 'engine-name'), where 'engine-name' is datalog/duality/pdr, etc. Support for certificates and answers vary among the engines.

Related

z3 with LIA logic can return real?

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.

forall usage in SMT

How does forall statement work in SMT? I could not find information about usage. Can you please simply explain this? There is an example from
https://rise4fun.com/Z3/Po5.
(declare-fun f (Int) Int)
(declare-fun g (Int) Int)
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(assert (forall ((x Int))
(! (= (f (g x)) x)
:pattern ((g x)))))
(assert (= (g a) c))
(assert (= (g b) c))
(assert (not (= a b)))
(check-sat)
For general information on quantifiers (and everything else SMTLib) see the official SMTLib document:
http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf
Quoting from Section 3.6.1:
Exists and forall quantifiers. These binders correspond to the usual
universal and existential quantifiers of first-order logic, except
that each variable they quantify is also associated with a sort. Both
binders have a non-empty list of variables, which abbreviates a
sequential nesting of quantifiers. Specifically, a formula of the form
(forall ((x1 σ1) (x2 σ2) · · · (xn σn)) ϕ) (3.1) has the same
semantics as the formula (forall ((x1 σ1)) (forall ((x2 σ2)) (· · ·
(forall ((xn σn)) ϕ) · · · ) (3.2) Note that the variables in the list
((x1 σ1) (x2 σ2) · · · (xn σn)) of (3.1) are not required to be
pairwise disjoint. However, because of the nested quantifier
semantics, earlier occurrences of same variable in the list are
shadowed by the last occurrence—making those earlier occurrences
useless. The same argument applies to the exists binder.
If you have a quantified assertion, that means the solver has to find a satisfying instance that makes that formula true. For a forall quantifier, this means it has to find a model that the assertion is true for all assignments to the quantified variables of the relevant sorts. And likewise, for exists the model needs to be able to exhibit a particular value satisfying the assertion.
Top-level exists quantifiers are usually left-out in SMTLib: By skolemization, declaring a top-level variable fills that need, and also has the advantage of showing up automatically in models. (That is, any top-level declared variable is automatically existentially quantified.)
Using forall will typically make the logic semi-decidable. So, you're likely to get unknown as an answer if you use quantifiers, unless some heuristic can find a satisfying assignment. Similarly, while the syntax allows for nested quantifiers, most solvers will have very hard time dealing with them. Patterns can help, but they remain hard-to-use to this day. To sum up: If you use quantifiers, then SMT solvers are no longer decision-procedures: They may or may not terminate.
If you are using the Python interface for z3, also take a look at: https://ericpony.github.io/z3py-tutorial/advanced-examples.htm. It does contain some quantification examples that can clarify things for you. (Even if you don't use the Python interface, I heartily recommend going over that page to see what the capabilities are. They more or less translate to SMTLib directly.)
Hope that gets you started. Stack-overflow works the best if you ask specific questions, so feel free to ask clarification on actual code as you need.
Semantically, a quantifier forall x: T . e(x) is equivalent to e(x_1) && e(x_2) && ..., where the x_i are all the values of type T. If T has infinitely many (or statically unknown many) values, then it is intuitively clear that an SMT solver cannot simply turn a quantifier into the equivalent conjunction.
The classical approach in this case are patterns (also called triggers), pioneered by Simplify and available in Z3 and others. The idea is rather simple: users annotate a quantifier with a syntactical pattern that serves a heuristic for when (and how) to instantiate the quantifier.
Here is an example (in pseudo-code):
assume forall x :: {foo(x)} foo(x) ==> false
Here, {foo(x)} is the pattern, indicating to the SMT solver that the quantifier should be instantiated whenever the solver gets a ground term foo(something). For example:
assume forall x :: {foo(x)} foo(x) ==> 0 < x
assume foo(y)
assert 0 < y
Since the ground term foo(y) matches the trigger foo(x) when the quantified variable x is instantiated with y, the solver will instantiate the quantifier accordingly and learn 0 < y.
Patterns and quantfier triggering is difficult, though. Consider this example:
assume forall x :: {foo(x)} (foo(x) || bar(x)) ==> 0 < y
assume bar(y)
assert 0 < y
Here, the quantifier won't be instantiated because the ground term bar(y) does not match the chosen pattern.
The previous example shows that patterns can cause incompletenesses. However, they can also cause termination problems. Consider this example:
assume forall x :: {f(x)} !f(x) || f(f(x))
assert f(y)
The pattern now admits a matching loop, which can cause nontermination. Ground term f(y) allows to instantiate the quantifier, which yields the ground term f(f(y)). Unfortunately, f(f(y)) matches the trigger (instantiate x with f(y)), which yields f(f(f(y))) ...
Patterns are dreaded by many and indeed tricky to get right. On the other hand, working out a triggering strategy (given a set of quantifiers, find patterns that allow the right instantiations, but ideally not more than these) ultimately "only" required logical reasoning and discipline.
Good starting points are:
* https://rise4fun.com/Z3/tutorial/, section "Quantifiers"
* http://moskal.me/smt/e-matching.pdf
* https://dl.acm.org/citation.cfm?id=1670416
* http://viper.ethz.ch/tutorial/, section "Quantifiers"
Z3 also has offers Model-based Quantifier Instantiation (MBQI), an approach to quantifiers that doesn't use patterns. As far as I know, it is unfortunately also much less well documented, but the Z3 tutorial has a short section on MBQI as well.

∃-queries and ∀-queries with Z3 fixedpoint engine

I'm confused and struggling to understand how two different input formats for Z3 fixedpoint engine are related. Short example: suppose I want to prove the existance of negative numbers. I declare a function that returns 1 for non-negative numbers and 0 for negative and then asking solver to fail if there are arguments for which function returns 0. But there is one restriction: I want solver to respond sat when there exists at least one negative number and unsat if all numbers are non-negative.
It is trivially with using declare-rel and query format:
(declare-rel f (Int Int))
(declare-rel fail ())
(declare-var n Int)
(declare-var m Int)
(rule (=> (< n 0) (f n 0)))
(rule (=> (>= n 0) (f n 1)))
(rule (=> (and (f n m) (= m 0)) fail))
(query fail)
But it becomes tricky while using pure SMT-LIB2 format (with forall). For example, straightforward
(set-logic HORN)
(declare-fun f (Int Int) Bool)
(declare-fun fail () Bool)
(assert (forall ((n Int))
(=> (< n 0) (f n 0))))
(assert (forall ((n Int))
(=> (>= n 0) (f n 1))))
(assert (forall ((n Int) (m Int))
(=> (and (f n m) (= m 0)) fail)))
(assert (not fail))
(check-sat)
returns unsat. Unsurprisingly, changing (= m 0) to (= m 1) results the same. We can get sat only implying fail from (= m 2). The problem is that I can't understand, how to ask solver using this format.
How I'm understanding it at the moment, while using forall-form we can ask to find only ∀-solutions, i.e. the answer sat means that solver managed to find interpretation (or invariant) satisfiying all assertions for all values, and unsat means that there are no such functions. In other words, it tries to prove, putting the 'proof' (the invariant) into the model (obviously, when sat).
On the contrary, when querying the solution in the declare-rel format solver searches the solution for some variables, just like the constraints are under the ∃-quantifier. In other words, it gives the counter-example. It can only print the invariant in case of unsat.
I have a couple of questions:
Am I understanding it correct? I feel like I miss some key ideas. For example, a general idea of how to express (query ...) in terms of (assert (forall ...)) will be really helpfull (and will answer question 2 automaticly).
Is there a way to solve such ∃-constraints (outputting sat when counterexample was found) with pure SMT-LIB2 format? If yes then how?
First of all, the format that uses "declare-rel", "declare-var", "rule" and "query" is a custom extension to SMT-LIB2. The "declare-var" feature is convenient for omitting bound variables from multiple rules. It also allows formulating Datalog rules with stratified negation and the semantics of this is what you should expect from stratified negation. By convention it uses "sat" to indicate that a query has a derivation, and "unsat" that no derivation exists for a query.
It turns out that standard SMT-LIB2 can express pretty much what you want for
Horn clauses without negation. Rules become implications and queries are implications of the form: (=> query false), or as you wrote it (not query).
A derivation in the custom format corresponds to a proof of the empty clause (e.g., proof of "query", which then proves "false"). So existence of a derivation means that the SMT-LIB2 assertions are "unsat". Conversely, if there is an interpretation (a model) for the Horn clauses, then such a model establishes that there is no derivation. The clauses are "sat".
In other words:
"sat" for datalog extension <=> "unsat" for SMT-LIB2 formulation
"unsat" for datalog extension <=> "sat" for SMT-LIB2 formulation
The advantage of using the pure SMT-LIB2 format, when it applies, is that
there are no special syntax extensions. These are plain SMT formulas and
others who wish to solve this class of formulas don't have to write special
extensions, they just have to ensure that the solvers that are tuned to
Horn clauses recognize the appropriate class of formulas. (Z3's implementation
of the HORN fragment does allow some flexibility in writing down Horn clauses.
You can have disjunctions in the bodies and you can have Curried implications).
There is one drawback with using the SMT-LIB2 format that the rule-based format helps with: when there is a derivation of the query, then the rule-based format has pragmas for printing elements of a tuple. Note that in general the query relation can take arguments. This feature is useful for finite domain relations.
Your example above uses integers, so the relations are not finite domain, but examples in the online-tutorial contain finite domain instances.
Now a derivation of a query also corresponds to a resolution proof. You can extract a resolution proof from the SMT-LIB2 case, but I have to say it is rather
convoluted and I have not found a way to use it effectively. The "duality" engine for Horn clauses generates derivations in a more accessible format than
the default proof format of Z3. Either way, it is likely that users run into obstacles if they try to work with the proof certificates because they are rarely used. The rule-based format does have another feature that assembles a set of predicates with instances that correspond to a derivation trail. It is easier to eyeball this output.

Why does a query result changes if comment an intermediate `(check-sat)` call?

While debugging UNSAT query I noticed an interesting difference in the query status. The query structure is:
assert(...)
(push) ; commenting any of these two calls
(check-sat) ; makes the whole query UNSAT, otherwise it is SAT
assert(...)
(check-sat) ; SAT or UNSAT depending on existence of previous call
(exit)
There are no pop calls in the query. The query that triggers this behaviour is here.
Ideas why?
Note: I don't actually need incrementality, it is for debugging purposes only. Z3 version is 3.2.
This is a bug in one of the quantifier reasoning engines. This bug will be fixed. In the meantime, you can avoid the bug by using datatypes instead of uninterpreted sorts + cardinality constraints. That is, you declare Q and T as:
(declare-datatypes () ((Q q_accept_S13 q_T0_init q_accept_S7
q_accept_S6 q_accept_S5 q_accept_S4 q_T0_S3 q_accept_S12 q_accept_S10
q_accept_S9 q_accept_all)))
(declare-datatypes () ((T t_0 t_1 t_2 t_3 t_4 t_5 t_6 t_7)))
The declarations above are essentially defining two "enumeration" types.
With these declarations, you will get a consistent answer for the second query.

Rewriting of Formulas

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)

Resources