How to get "stronger" simplifications of conjunctions in Z3? - z3

Using Z3 version 2.18, I am trying to simplify formulas such as:
(and (> (- (- x 1) 1) 0) (> x 0))
(or (> (- (- x 1) 1) 0) (> x 0))
hoping to get something like: (> x 2) and (> x 0).
I am running Z3 with the following input file where F is one of the above formulas:
(set-option set-param "STRONG_CONTEXT_SIMPLIFIER" "true")
(declare-const x Int)
(simplify F)
It works well with the disjunction where I get the following output:
(let (($x35 (<= x 0)))
(not $x35))
However, with the conjunction, I get:
(not (or (<= x 0) (<= x 2)))
Is there a way to force Z3 to simplify even more the above formula ? I would hope to be able to get (not (<= x 2)).
PS: Is there a way to force Z3 to inline its output (i.e. having (not (<= x 0)) instead of (let (($x35 (<= x 0))) (not $x35)))
Thanks,
Gus

No, you can't do that on Z3 2.x.
Z3 3.x has a new (fully compliant) SMT 2.0 front-end.
Z3 3.x has several new features such as a "strategy specification language" based on tactics and tacticals. I'm not "advertising" that yet because it is working in progress. The basic idea is described in this slide deck. This language can be used to do what you want. You just have to write:
(declare-const x Int)
(assert (not (or (<= x 0) (<= x 2))))
(apply (and-then simplify propagate-bounds))
You can find all available tactics by using the commands:
(help-strategy)
(help apply)
(help check-sat-using)

Related

Does z3 support rational arithmetic for its input constraints?

In fact, does the SMT-LIB standard have a rational (not just real) sort? Going by its website, it does not.
If x is a rational and we have a constraint x^2 = 2, then we should get back ``unsatisfiable''. The closest I could get to encoding that constraint is the following:
;;(set-logic QF_NRA) ;; intentionally commented out
(declare-const x Real)
(assert (= (* x x) 2.0))
(check-sat)
(get-model)
for which z3 returns a solution, as there is a solution (irrational) in the reals. I do understand that z3 has its own rational library, which it uses, for instance, when solving QF_LRA constraints using an adaptation of the Simplex algorithm. On a related note, is there an SMT solver that supports rationals at the input level?
I'm sure it's possible to define a Rational sort using two integers as suggested by Nikolaj -- I would be interested to see that. It might be easier to just use the Real sort, and any time you want a rational, assert that it's equal to the ratio of two Ints. For example:
(set-option :pp.decimal true)
(declare-const x Real)
(declare-const p Int)
(declare-const q Int)
(assert (> q 0))
(assert (= x (/ p q)))
(assert (= x 0.5))
(check-sat)
(get-value (x p q))
This quickly comes back with
sat
((x 0.5)
(p 1)
(q 2))

Should Z3 prove monotonicity of <= (with respect to multiplication)?

This is the reduction of a more interesting problem, in which the missing property was (for positive k,M and N), that ((k % M) * N) < M*N. Below is an encoding of the simpler problem that a <= b ==> (a*c) <= (b*c). Such a query succeeds (we get unsat), but if the expression b is replaced by b+1 (as in the second query below) then we get unknown, which seems surprising. Is this the expected behaviour? Are there options to improve the handling of such inequalities? I tried with and without configuration options, and various versions of Z3, including the current unstable branch. Any tips would be much appreciated!
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(assert (> a 0))
(assert (> b 0))
(assert (> c 0))
(assert (<= a b))
(assert (not (<= (* a c) (* b c))))
(check-sat)
(assert (<= a (+ b 1)))
(assert (not (<= (* a c) (* (+ b 1) c))))
(check-sat)
This falls into nonlinear integer arithmetic (which has an undecidable decision problem, see, e.g., How does Z3 handle non-linear integer arithmetic? ), so it's actually not too surprising Z3 returns unknown for some examples, although I guess a bit surprising that it toggled between unsat and unknown for quite similar examples.
If it works for your application, you can try a type coercion: encode the constants as Real instead of Int. This will allow you to use Z3's complete solver for nonlinear real arithmetic and returns unsat with check-sat.
Alternatively, you can force Z3 to use the nonlinear solver even for the integer encoding with (check-sat-using qfnra-nlsat) as in the following based on your example (rise4fun link: http://rise4fun.com/Z3/87GW ):
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(assert (> a 0))
(assert (> b 0))
(assert (> c 0))
(assert (<= a b))
(assert (not (<= (* a c) (* b c))))
;(check-sat)
(check-sat-using qfnra-nlsat) ; unsat
(assert (<= a (+ b 1)))
(assert (not (<= (* a c) (* (+ b 1) c))))
; (check-sat)
(check-sat-using qfnra-nlsat) ; unsat
Some more questions and answers on similar subjects:
Combining nonlinear Real with linear Int
z3 fails with this system of equations
Using Z3Py online to prove that n^5 <= 5 ^n for n >= 5
Can z3 always give result when handling nonlinear real arithmetic
Z3 Theorem Prover: Pythagorean Theorem (Non-Linear Artithmetic)

Adjusting `simplify` tactic in Z3

I've got several questions about Z3 tactics, most of them concern simplify .
I noticed that linear inequalites after applying simplify are often negated.
For example (> x y) is transformed by simplify into (not (<= x y)). Ideally, I would want integer [in]equalities not to be negated, so that (not (<= x y)) is transformed into (<= y x).  I can I ensure such a behavior?
Also, among  <, <=, >, >= it would be desirable to have only one type of inequalities to be used in all integer predicates in the simplified formula, for example <=.   Can this be done?
What does :som parameter of simplify do? I can see the description that says that it is used to put polynomials in som-of-monomials form, but maybe I'm not getting it right.  Could you please give an example of different behavior of simplify with :som set to true and false?
Am I right that after applying simplify arithmetical expressions would always be represented in the form a1*t1+...+an*tn, where ai are constants and ti are distinct terms (variables, uninterpreted constants or function symbols)? In particular is always the case that subtraction operation doesn't appear in the result?
Is there any available description of the ctx-solver-simplify tactic? Superficially, I understand that this is an expensive algorithm because it uses the solver, but it would be interesting to learn more about the underlying algorithm so that I have an idea on how many solver calls I may expect, etc. Maybe you could give a refernce to a paper or give a brief sketch of the algorithm?
Finally, here it was mentioned that a tutorial on how to write tactics inside the Z3 code base might appear. Is there any yet?
Thank you.
Here is an example (with comments) that tries to answer questions 1-4. It is also available online here.
(declare-const x Int)
(declare-const y Int)
;; 1. and 2.
;; The simplifier will map strict inequalities (<, >) into non-strict ones (>=, <=)
;; Example: x < y ===> not x >= y
;; As suggested by you, for integer inequalities, we can also use
;; x < y ==> x <= y - 1
;; This choice was made because it is convenient for solvers implemented in Z3
;; Other normal forms can be used.
;; It is possible to map everything to a single inequality. This is a straightforward modificiation
;; in the Z3 simplifier. The relevant files are src/ast/rewriter/arith_rewriter.* and src/ast/rewriter/poly_rewriter.*
(simplify (<= x y))
(simplify (< x y))
(simplify (>= x y))
(simplify (> x y))
;; 3.
;; :som stands for sum-of-monomials. It is a normal form for polynomials.
;; It is essentially a big sum of products.
;; The simplifier applies distributivity to put a polynomial into this form.
(simplify (<= (* (+ y 2) (+ x 2)) (+ (* y y) 2)))
(simplify (<= (* (+ y 2) (+ x 2)) (+ (* y y) 2)) :som true)
;; Another relevant option is :arith-lhs. It will move all non-constant monomials to the left-hand-side.
(simplify (<= (* (+ y 2) (+ x 2)) (+ (* y y) 2)) :som true :arith-lhs true)
;; 4. Yes, you are correct.
;; The polynomials are encoded using just * and +.
(simplify (- x y))
5) ctx-solver-simplify is implemented in the file src/smt/tactic/ctx-solver-simplify.*
The code is very readable. We can add trace messages to see how it works on particular examples.
6) There is no tutorial yet on how to write tactics. However, the code base has many examples.
The directory src/tactic/core has the basic ones.

Difference between macro and quantifier in Z3

I would like to know what is the difference between following 2 statements -
Statement 1
(define-fun max_integ ((x Int) (y Int)) Int
(ite (< x y) y x))
Statement 2
(declare-fun max_integ ((Int)(Int)) Int)
(assert (forall ((x Int) (y Int)) (= (max_integ x y) (if (< x y) y x))))
I observed that when I use Statement1, my z3 constraints give me a result in 0.03 seconds. Whereas when I used Statement2, it does not finish in 2 minutes and I terminate the solver.
I would like also to know how achieve it using C-API.
Thanks !
Statement 1 is a macro. Z3 will replace every occurrence of max_integ with the ite expression. It does that during parsing time. In the second statement, by default, Z3 will not eliminate max_integ, and to be able to return sat it has to build an interpretation for the uninterpreted symbol max_integ that will satisfy the quantifier for all x and y.
Z3 has an option called :macro-finder, it will detect quantifiers that are essentially encoding macros, and will eliminate them. Here is an example (also available online here):
(set-option :macro-finder true)
(declare-fun max_integ ((Int)(Int)) Int)
(assert (forall ((x Int) (y Int)) (= (max_integ x y) (if (< x y) y x))))
(check-sat)
(get-model)
That being said, we can easily simulate macros in a programmatic API by writing a function that given Z3 expressions return a new Z3 expression. Here in an example using the Python API (also available online here):
def max(a, b):
# The function If builds a Z3 if-then-else expression
return If(a >= b, a, b)
x, y = Ints('x y')
solve(x == max(x, y), y == max(x, y), x > 0)
Yet another option is to use the C API: Z3_substitute_vars. The idea is to an expression containing free variables. Free variables are created using the API Z3_mk_bound. Each variable represents an argument. Then, we use Z3_substitute_vars to replace the variables with other expressions.

Convert formula to CNF

Is there a way to use z3 to convert a formula to CNF (using Tseitsin-style encoding)? I am looking for something like the simplify command, but guaranteeing that the returned formula is CNF.
You can use the apply command for doing it. We can provide arbitrary tactics/strategies to this command. For more information about tactics and strategies in Z3 4.0, check the tutorial http://rise4fun.com/Z3/tutorial/strategies
The command (help-tactic) can be used to display all available tactics in Z3 4.0 and their parameters. The programmatic is more convenient to use and flexible. Here is a tutorial based on the new Python API: http://rise4fun.com/Z3Py/tutorial/strategies.
The same capabilities are available in the .Net and C/C++ APIs.
The following script demonstrates how to convert a formula into CNF using this framework:
http://rise4fun.com/Z3/TEu6
The example link #Leonardo provided is broken now. Found the code using wayback machine. Posting it here so future seekers may make use of it:
(declare-const x Int)
(declare-const y Int)
(declare-const z Int)
(assert (iff (> x 0) (> y 0)))
(assert (or (and (= x 0) (= y 0)) (and (= x 1) (= y 1)) (and (= x 2) (= y 2))))
(assert (if (> x 0) (= y x) (= y (- x 1))))
(assert (> z (if (> x 0) (- x) x)))
(apply (then (! simplify :elim-and true) elim-term-ite tseitin-cnf))
(echo "Trying again without using distributivity...")
(apply (then (! simplify :elim-and true) elim-term-ite (! tseitin-cnf :distributivity false)))

Resources