simplification in Z3 - z3

(declare-datatypes () ((SE BROKEN ON OFF)))
(declare-const s SE)
(declare-const a Int)
(simplify (or (= s ON) (= s OFF) (= s BROKEN)))
(simplify (and (> a 0) (> a 1)))
The result is:
(or (= s ON) (= s OFF) (= s BROKEN))
(and (not (<= a 0)) (not (<= a 1)))
But the expected result was:
1
> a 1
Is it possible to simplify such expressions (the combinations of such expressions) in Z3?
Thank you!

The simplify command is just a bottom-up rewriter. It is fast, but will fail to simplify expressions such as the ones in your post. Z3 allows users to define their own simplification strategies using tactics. They are described in this article, and the Z3 tutorials (Python and SMT 2.0). The following posts also have additional information:
t>=1 or t>=2 => t>=1
Asymmetric behavior in ctx-solver-simplify
what's the difference between "simplify" and "ctx-solver-simplify" in z3
The first query in your example can be simplified using the tactic ctx-solver-simplify (also available online here).
(declare-datatypes () ((SE BROKEN ON OFF)))
(declare-const s SE)
(declare-const a Int)
(assert (or (= s ON) (= s OFF) (= s BROKEN)))
(assert (and (> a 0) (> a 1)))
(apply ctx-solver-simplify)
The command apply applies the tactic ctx-solver-simplify over the set of assertions, and displays the resulting set of goals. Note that, this tactic is way more expensive than the command simplify.

Related

Is it possible to use both bit-blast and soft-assert with the z3 solver?

I'm trying to use the z3 smt solver to allocate values to variables subject to constraints. As well as hard constraints I have some soft constraints (e.g. a != c). I expected to be able to specify the hard constraints with assert and the soft constraints as soft-assert and this works if I solve with (check-sat).
Some of the files are large and complex and only solve in a reasonable time if I turn on bit-blasting using (check-sat-using (then simplify solve-eqs bit-blast sat)). When I do this the soft asserts seem to be ignored (example below or at rise4fun). Is this expected? Is it possible to use both bit-blast solving and soft-assert at the same time?
The following SMT code defines 4 bitvectors, a, b, c & d which should all be able to take unique values but are only forced to do so by soft asserts. Using the check-sat (line 39) works as expected but the check-sat-using (line 38) assigns b and d to the same value.
(set-option :produce-models true)
(set-logic QF_BV)
;; Declaring all the variables
(declare-const a (_ BitVec 2))
(declare-const b (_ BitVec 2))
(declare-const c (_ BitVec 2))
(declare-const d (_ BitVec 2))
(assert (or (= a #b00)
(= a #b01)
(= a #b10)
(= a #b11)))
(assert (or (= b #b00)
(= b #b01)
(= b #b10)
(= b #b11)))
(assert (or (= c #b00)
(= c #b01)
(= c #b10)
(= c #b11)))
(assert (or (= d #b00)
(= d #b01)
(= d #b10)
(= d #b11)))
;; Soft constraints to limit reuse
(assert-soft (not (= a b)))
(assert-soft (not (= a c)))
(assert-soft (not (= a d)))
(assert-soft (not (= b c)))
(assert-soft (not (= b d)))
(assert-soft (not (= c d)))
(check-sat-using (then simplify solve-eqs bit-blast sat))
;;(check-sat)
(get-value (a
b
c
d))
Great question! When you use assert-soft the optimization engine kicks in by default. You can see this by using your program with the (check-sat) clause, and running with higher verbosity. I've put your program in a file called a.smt2:
$ z3 -v:3 a.smt2
(optimize:check-sat)
(sat.solver)
(optimize:sat)
(maxsmt)
(opt.maxres [0:6])
(sat.solver)
(opt.maxres [0:0])
found optimum
sat
((a #b01)
(b #b00)
(c #b11)
(d #b10))
So, we can see z3 is treating this as an optimization problem, which takes soft-constraints into account and gives you the "disjointness" you're seeking.
Let's do the same, but this time we'll use the check-sat call that specifies the tactics to use. We get:
$ z3 -v:3 a.smt2
(smt.searching)
sat
((a #b11)
(b #b11)
(c #b11)
(d #b10))
And this confirms your suspicion: When you tell z3 exactly what to do, it doesn't do the optimization pass. In hindsight, this is to be expected, but I do agree that it's rather surprising.
The question is then whether we can tell z3 to do the optimization explicitly. However I'm not sure if this is even possible within the tactic language. I think this question is well worthy of asking at their issues site (https://github.com/Z3Prover/z3/issues) and see if there's a magic incantation you can use to kick off the maxres engine from the tactic language. (This may not be possible due to a number of reasons, but there's no reason to speculate here.) Please report back here what you find out!

What additional axioms do we need to add so that Z3 can verify the satisfiability of programs with recurrences?

As we know Z3 has limitations with recurrences. Is there any way get the result for the following program? what will additional equation help z3 get the result?
from z3 import *
ackermann=Function('ackermann',IntSort(),IntSort(),IntSort())
m=Int('m')
n=Int('n')
s=Solver()
s.add(ForAll([n,m],Implies(And(n>=0,m>=0),ackermann(m,n) == If(m!=0,If(n!=0,ackermann(m - 1,ackermann(m,n - 1)),If(n==0,ackermann(m - 1,1),If(m==0,n + 1,0))),If(m==0,n + 1,0)))))
s.add(n>=0)
s.add(m>=0)
s.add(Not(Implies(ackermann(m,n)>=0,ackermann(m+1,0)>=0)))
s.check()
With a nested recursive definition like Ackermann's function, I don't think there's much you can do to convince Z3 (or any other SMT solver) to actually do any interesting proofs. Such properties will require clever inductive arguments, and an SMT solver is just not the right tool for this sort of verification. A theorem prover like Isabelle, HOL, Coq, ... is the better choice here.
Having said that, the basic approach to establishing recursive function properties in SMT is to literally code up the inductive hypothesis as a quantified axiom, and arrange for the property you want proven to precisely line up with that axiom when the e-matching engine kicks in so it can instantiate the quantifiers "correctly." I'm putting the word correctly in quotes here, because the matching engine will go ahead and keep instantiating the axiom in unproductive ways especially for a function like Ackermann's. Theorem provers, on the other hand, precisely give you control over the proof structure so you can explicitly guide the prover through the proof-search space.
Here's an example you can look at: list concat in z3 which is doing an inductive proof of a much simpler inductive property than you are targeting, using the SMT-Lib interface. While it won't be easy to extend it to handle your particular example, it might provide some insight into how to go about it.
In the particular case of Z3, you can also utilize its fixed-point reasoning engine using the PDR algorithm to answer queries about certain recursive functions. See http://rise4fun.com/z3/tutorialcontent/fixedpoints#h22 for an example that shows how to model McCarthy's famous 91 function as an interesting case study.
Z3 will not try to do anything by induction for you, but (as Levent Erkok mentioned) you can give it the induction hypothesis and have it check that the result follows.
This works on your example as follows.
(declare-fun ackermann (Int Int) Int)
(assert (forall ((m Int) (n Int))
(= (ackermann m n)
(ite (= m 0) (+ n 1)
(ite (= n 0) (ackermann (- m 1) 1)
(ackermann (- m 1) (ackermann m (- n 1))))))))
(declare-const m Int)
(declare-const n Int)
(assert (>= m 0))
(assert (>= n 0))
; Here's the induction hypothesis
(assert (forall ((ihm Int) (ihn Int))
(=> (and (<= 0 ihm) (<= 0 ihn)
(or (< ihm m) (and (= ihm m) (< ihn n))))
(>= (ackermann ihm ihn) 0))))
(assert (not (>= (ackermann m n) 0)))
(check-sat) ; reports unsat as desired

Speeding up Z3 on specific QF_LRA instances

I have a problem in QF_LRA, which is solved surprisingly quickly by MathSAT5 (unsat, < 5 minutes) but Z3 does not seem to make much progress (no result even after 7 days). Could this be fixed by some settings in Z3?
It contains many clauses of (roughly) these 5 types:
(assert (or (< p47a2 p8a2) (< (+ p47a0 p47a2) (+ p8a0 p8a2)) (< (+ p47a0 p47a2 p47a3) (+ p8a0 p8a2 p8a3)) (and (= p47a2 p8a2) (= (+ p47a0 p47a2) (+ p8a0 p8a2)) (= (+ p47a0 p47a2 p47a3) (+ p8a0 p8a2 p8a3)))))
(assert (= 1.0 (+ p3887a0 p3887a1 p3887a2 p3887a3)))
(assert (>= p1715a0 0.0))
(assert (= p133a2 p133a1))
(assert (or (= p379a1 0.0) (= p379a2 0.0)))
The complete problem instance can be downloaded from here in SMT2 format.
Key for solving it with MathSAT was the setting
preprocessor.simplification=8
which enables global rewriting rules (in addition to the application track settings of the SMT 2015 competition).
Is there anything similar in Z3 that I could try? Or any preprocessing / optimization of the encoding you would advise me to perform? I am relatively new to SMT; hence any help/guidance would be highly appreciated.
In the first place it would be great to get Z3 to solve this instance. As a next step I would also like to extract an unsat core, if that is important for your tipps.
Many thanks in advance!!
Replace (check-sat) with
(check-sat-using (then simplify solve-eqs (! smt :case_split 0 :relevancy 0 :auto_config false :restart_strategy 2)) :print_model true)
Z3 solves it in a minute. However, you can find better configuration here.

Z3 4.0 Extra Output in Model

When I am trying to get a model string, along with the variables that I define, I get extra output in the model as -
z3name!0=3, z3name!1=-2, z3name!10=0, z3name!11=0, z3name!12=0, z3name!13=0, z3name!14=0, z3name!15=0, z3name!2=0, z3name!3=0, z3name!4=2, z3name!5=2, z3name!6=0, z3name!7=-3, z3name!8=2, z3name!9=0
I want to know that is this erroneous output?
Or is it some intermediate variables that are being used by Z3?
Because the values for the variables I have defined seems okay to me.
I have not seen previously any such output, thus I got this doubt.
Z3 has several preprocessing steps. Some of them introduce new variables. The new variables are usually removed from the resulting model. If they are not, this is a bug. However, this bug does not affect correctness. It is just an inconvenience.
It would be great if you could post your problem. We would be able to identify which preprocessing step is not eliminating the introduced auxiliary variables.
I realize this is an old topic, but I found myself having the same "bug" as Leonardo called it. Since the OP did not post his code, I thought mine could maybe help fix it (even though this extra output is not a problem for me as long as correctness is indeed preserved).
It appears that if I change the "/" in the final assertion for, let's say, a "+" operator, the problem disappears.
(declare-fun fun0!0 () Int)
(declare-fun fun0!-1 () Int)
(declare-fun var0 () Int)
(assert (and
(and
(or (= fun0!0 0) (= fun0!0 1) (= fun0!0 2))
(or (= fun0!-1 0) (= fun0!-1 1) (= fun0!-1 2))
(or (= var0 1) (= var0 -1))
)
(and (or (= var0 0) (= var0 -1)))
))
(define-fun fun0 ((i! Int)) Int
(ite
(= i! 0)
fun0!0
(ite
(= i! -1)
fun0!-1
(- 0 1)
)
)
)
(assert (=
(fun0 var0)
(/ var0 var0)
))
(check-sat)

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