how to eliminate constraint in Z3 - z3

I have a constraint like (t>=0 or t>=1) and (t<=2 or t>=2),in fact the constraint can be simplified into "t>=0", how to use z3 to get the simplified result in CNF form by using z3?
(declare-const t Int)
(assert (and
(or
(>= t 0)
(>= t 1)
)
(or
(>= t 2)
(<= t 2)
)
(>= t 0)
(<= t 1)
)
)
(apply (par-then (! simplify :elim-and true) tseitin-cnf))
However, the script doesn't work.

The simplify tactic only perform "local simplifications". That is, when simplifying an expression t, it will ignore the context of t. For example, it can simplify a + 1 - a into 1, but it will not simplify a != 0 or b = a + 1 into a != 0 or b = 1.
Contextual simplification is expensive, the simplify tactic is meant to be efficient and simple. Other tactics may be used to achieve what you want.
The tactic propagate-ineqs will propagate inequalities. However, it will not process terms nested in the formula. The tactic split-clause can be used to break the formula in cases\goals. The tactic propagate-values will propagate the value of an assertion, example: a = 0 and b >= a is simplified to a = 0 and b >= 0.
The command (help-tactic) will display all available tactics.
Here is a strategy for simplifying your example into t >= 0 and t <= 1.
(apply (then simplify propagate-values split-clause propagate-ineqs))
Note that the combinator par-then is only useful for combining tactics that produce many sub-goals.
(par-then t1 t2) applies t1 to the input goal, and applies t2 (in parallel) to every subgoal produced by t1. The split-clause tactic produces more than one subgoal. Then (for bigger examples) it may be more efficient to use:
(apply (then simplify propagate-values (par-then split-clause propagate-ineqs)))

Related

Can you limit a real variable between two bounds?

Can you limit a real variable between two bounds?
s = Solver()
input = Reals('input')
s.add(input >= -2, input <= 2)
This example return unsat for me.
In cases like this, the sexpr method of the Solver class is your friend!
You're tripping up because of the extremely weakly typed nature of the z3py bindings. The call Reals returns multiple results, which you are assigning to a single element. That is, your input variable is now a list containing one variable. This, in turn, makes the whole program meaningless, as you can observe yourself:
from z3 import *
s = Solver()
input = Reals('input')
s.add(input >= -2, input <= 2)
print s.sexpr()
This prints:
(assert true)
(assert false)
Why? Because your variable input is a list, and the bizarre rules of type promotion decided that a list is greater than or equal to -2 but less than 2. (This is totally meaningless, just the way the bindings work. There's no rhyme or reason it should be this way. One can argue it should do more type-checking and give you a proper error. But I digress.)
To solve, simply change your call of Reals to Real:
from z3 import *
s = Solver()
input = Real('input')
s.add(input >= -2, input <= 2)
print s.sexpr()
print s.check()
print s.model()
This prints:
(declare-fun input () Real)
(assert (>= input (- 2.0)))
(assert (<= input 2.0))
sat
[input = 0]
which is exactly what you wanted to say.

How to obtain parametric models using Z3?

Given this formula,
(p & (x < 0)) | (~p & (x > 0)).
How could I get these 2 "parametric" models in Z3:
{p=true, x<0}
{p=false, x>0}
When I submit this SMTLIB program to Z3,
(declare-const p Bool)
(declare-const x Int)
(assert (or (and p (< x 0)) (and (not p) (> x 0))))
(check-sat)
(get-model)
(assert (or (not p) (not (= x -1))))
(check-sat)
(get-model)
(exit)
it gives me concrete models instead (e.g. {p=true, x=-1}, {p=true, x=-2}, ...).
You can't.
SMT solvers do not produce non-concrete models; it's just not how they work. What you want is essentially some form of "simplification" in steroids, and while you can use an SMT solver to help you in simplifying expressions, you'll have to build a tool on top that understands the kind of simplifications you'd like to see. Bottom line: What you'd consider "simple" as a person, and what an automated SMT-solver sees as "simple" are usually quite different from each other; and given lack of normal forms over arbitrary theories, you cannot expect them to do a good job.
If these sorts of simplifications is what you're after, you might want to look at symbolic math packages, such as sympy, Mathematica, etc.

∃-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.

Avoiding quantifiers in Z3

I am experimenting with Z3 where I combine the theories of arithmetic, quantifiers and equality. This does not seem to be very efficient, in fact it seems to be more efficient to replace the quantifiers with all instantiated ground instances when possible. Consider the following example, in which I have encoded the unique names axiom for a function f that takes two arguments of sort Obj and returns an interpreted sort S. This axiom states that each unique list of arguments to f returns a unique object:
(declare-datatypes () ((Obj o1 o2 o3 o4 o5 o6 o7 o8)))
(declare-sort S 0)
(declare-fun f (Obj Obj) S)
(assert (forall ((o11 Obj) (o12 Obj) (o21 Obj) (o22 Obj))
(=>
(not (and (= o11 o21) (= o12 o22)))
(not (= (f o11 o12) (f o21 o22))))))
Although this is a standard way of defining such an axiom in logic, implementing it like this is computationally very expensive. It contains 4 quantified variables, which each can have 8 values. This means that this results in 8^4 = 4096 equalities. It takes Z3 0.69s and 2016 quantifier instantiations to prove this. When I write a simple script that generates the instances of this formula:
(assert (distinct (f o1 o1) (f o1 o2) .... (f o8 o7) (f o8 o8)))
It takes 0.002s to generate these axioms, and another 0.01s (or less) to prove it in Z3. When we increase the objects in the domain, or the number of arguments to the function f this different increases rapidly, and the quantified case quickly becomes unfeasible.
This makes me wonder: when we have a bounded domain, why would we use quantifiers in Z3 in the first place? I know that SMT uses heuristics to find solutions, but I get the feeling that it still cannot compete in efficiency with a simple domain-specific grounder that feeds the grounded instances to SMT, which is then nothing more than SAT solving. Is my intuition correct?
Your intuition is correct. The heuristics for handling quantifiers in Z3 are not tuned for problems where universal variables range over finite/bounded domains.
In this kind of problem, using quantifiers is a good option only if a very small percentage of the instances are needed to show that a problem is unsatisfiable.
I usually suggest that users should expand this quantifiers using the programmatic API.
Here a two related posts. They contain links to Python code that implements this approach.
Does Z3 take a longer time to give an unsat result compared to a sat result?
Quantifier Vs Non-Quantifier
Here is one of the code fragments:
VFunctionAt = Function('VFunctionAt', IntSort(), IntSort(), IntSort())
s = Solver()
s.add([VFunctionAt(V,S) >= 0 for V in range(1, 5) for S in range(1, 9)])
print s
In this example, I'm essentially encoding forall V in [1,4] S in [1,8] VFunctionAt(V,S) >= 0.
Finally, your encoding (assert (distinct (f o1 o1) (f o1 o2) .... (f o8 o7) (f o8 o8)) is way more compact than expanding the quantifier 4096 times. However, even if we use a naive encoding (just expand the quantifier 4096 times), it is stil faster to solve the expanded version.

Quantifier Vs Non-Quantifier

I have a question about Quantifiers.
Suppose that I have an array and I want to calculate array index 0, 1 and 2 for this array -
(declare-const cpuA (Array Int Int))
(assert (or (= (select cpuA 0) 0) (= (select cpuA 0) 1)))
(assert (or (= (select cpuA 1) 0) (= (select cpuA 1) 1)))
(assert (or (= (select cpuA 2) 0) (= (select cpuA 2) 1)))
Or otherwise I can specify the same using forall construct as -
(assert (forall ((x Int)) (=> (and (>= x 0) (<= x 2)) (or (= (select cpuA x) 0) (= (select cpuA x) 1)))))
Now I would like to understand the difference between two of them.
The first method executes quickly and gives a simple and readable model.
In contrast the code size with second option is very less, but the program takes time to execute. And also the solution is complex.
I would like to use the second method as my code will become smaller.
However, I want to find a readable simple model.
Quantifier reasoning is usually very expensive. In your example, the quantified formula is equivalent to the three assertions you provided.
However, that is not how Z3 decides/solves your formula. Z3 solves your formula using a technique called Model-Based Quantifier Instantiation (MBQI).
This technique can decide many fragments (see http://rise4fun.com/Z3/tutorial/guide). It is mainly effective on the fragments described in this guide.
It supports uninterpreted functions, arithmetic and bit-vector theories. It also has limited support for arrays and datatypes.
This is sufficient for solving your example. The model produced by Z3 seems more complicated because the same engine is used to decide more complicated fragments.
The model should be seem as a small functional program. You can find more information on how this approach works in the following articles:
Complete instantiation for quantified SMT formulas
Efficiently Solving Quantified Bit-Vector Formula
Note that, array theory is mainly useful for representing/modeling unbounded or big arrays. That is, the actual size of the array is not known or is too big. By big, I mean the number of array accesses (i.e., selects) in your formula is much smaller than the actual size of the array. We should ask ourselves : "do we really need arrays for modeling/solving problem X?". You may consider the following alternatives:
(Uninterpreted) functions instead of arrays. Your example can be encoded also as:
(declare-fun cpuA (Int) Int)
(assert (or (= (cpuA 0) 0) (= (cpuA 0) 1)))
(assert (or (= (cpuA 1) 0) (= (cpuA 1) 1)))
(assert (or (= (cpuA 2) 0) (= (cpuA 2) 1)))
Programmatic API. We've seen many examples where arrays (and functions) are used to provide a compact encoding. A compact and elegant encoding is not necessarily easier to solve. Actually, it is usually the other way around. You can achieve the best of both worlds (performance and compactness) using a programmatic API for Z3. In the following link, I encoded your example using one "variable" for each position of the "array". Macros/functions are used to encode constraints such as: an expression is a 0 or 1.
http://rise4fun.com/Z3Py/JF

Resources