Why does the following expression in z3 take a long time? - z3

What is wrong with this z3 expression?
(declare-const arg_1 Int)
(assert
(and
(not (= 0 (mod arg_1 10)))
(= 0 (mod (+ 1 arg_1) 10))))
(check-sat)
(get-model)
Trying to evaluate it with z3 hangs for ever. On the other hand, if I try either of the below, it returns immediately.
Using the first expression only
(declare-const arg_1 Int)
(assert (not (= 0 (mod arg_1 10))))
(check-sat)
(get-model)
=> sat
(model
(define-fun arg_1 () Int
1)
)
Using the second expression only
(declare-const arg_1 Int)
(assert (= 0 (mod (+ 1 arg_1) 10)))
(check-sat)
(get-model)
=> sat
(model
(define-fun arg_1 () Int
9)
)
Asserting them together in the same file also returns immediately.
(declare-const arg_1 Int)
(declare-const arg_2 Int)
(assert (= 0 (mod (+ 1 arg_1) 10)))
(assert (not (= 0 (mod arg_2 10))))
;(assert (= arg_1 arg_2))
(check-sat)
(get-model)
=> sat
(model
(define-fun arg_2 () Int
1)
(define-fun arg_1 () Int
9)
)
However, if I uncomment the arg_1 = arg_2 assertion, it will hang.

This is most likely a z3 bug. If you run the original with z3 -v:3, you get:
$ z3 -v:3 a.smt2
(smt.searching)
(smt.simplifying-clause-set :num-deleted-clauses 1)
final-check OPTIMAL
final-check OPTIMAL
...
and it keeps printing that. I tried with cvc4, yices, and mathsat; and they all solve it immediately. You should report this at https://github.com/Z3Prover/z3/issues so they can take a look at it.

Related

Is it possible to define a function with an all quantified assertion in z3 (with SMT-LIB2 interface)?

My goal is to define a function, which takes an input integer sequence and outputs an integer sequence with the same length, but containing only the first element of the input sequence. For example (in pseudo-code):
f([7,5,6]) = [7,7,7]
For this I declare a function in z3 as:
(declare-fun f ((Seq Int)) (Seq Int))
and try to force the expected behavior with the assertion:
(assert
(forall ((arr (Seq Int)))
(and
(=
(seq.len arr)
(seq.len (f arr))
)
(forall ((i Int))
(implies
(and
(>= i 0)
(< i (seq.len arr))
)
(=
(seq.at arr 0)
(seq.at (f arr) i)
)
)
)
)
))
The problem is that the program does not terminate, which I suspect is caused by the all-quantifier. To test whether my conditions are correct I declared two constants and saw that for concrete values the conditions are correct:
(define-const first (Seq Int)
(seq.++ (seq.unit 1) (seq.unit 2))
)
(declare-const second (Seq Int))
(assert
(and
(=
(seq.len first)
(seq.len second)
)
(forall ((i Int))
(implies
(and
(>= i 0)
(< i (seq.len first))
)
(=
(seq.at first 0)
(seq.at second i)
)
)
)
)
)
(check-sat)
(get-model)
My question: How would it be possible to integrate the conditions in the assertions with the expected behavior of the f function? The function should be total, which means it should be defined for all possible input sequences, but this leads me to think that an all quantifier is definitely needed in my case.
Reasoning with such recursive data-types/values is not a strong suit for SMT solvers. Most problems will require induction and SMT-solvers don't do induction out-of-the box.
Having said that, you can code what you want using the new declare-fun-rec construct:
(define-fun-rec copyHeadAux ((x (Seq Int)) (l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(seq.++ x (copyHeadAux x (seq.extract l 1 (seq.len l))))))
(define-fun copyHead ((l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at l 0) l)))
(define-fun test () (Seq Int) (seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(declare-const out (Seq Int))
(assert (= out (copyHead test)))
(check-sat)
(get-model)
When I run this, I get:
sat
(
(define-fun out () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 7) (seq.unit 7)))
(define-fun test () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(define-fun copyHead ((x!0 (Seq Int))) (Seq Int)
(ite (= 0 (seq.len x!0))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at x!0 0) x!0)))
)
which is the correct answer you're looking for. But unless your constraints only involve "constant-folding" cases (i.e., where copyHead is always applied to a constant known value), you're likely to get unknown as the answer, or have the solver go into an infinite e-matching loop.
It's best to use a proper theorem prover (Isabelle, HOL, Lean, ACL2 etc.) for reasoning with these sorts of recursive definitions. Of course, SMT solvers get better over time and maybe one day they'll be able to handle more problems like this out-of-the-box, but I wouldn't hold my breath.

Quantifier patterns in Z3

I am having trouble attempting to prove this fairly simple Z3 query.
(set-option :smt.auto-config false) ; disable automatic self configuration
(set-option :smt.mbqi false) ; disable model-based quantifier instantiation
(declare-fun sum (Int) Int)
(declare-fun list () (Array Int Int))
(declare-fun i0 () Int)
(declare-fun s0 () Int)
(declare-fun i1 () Int)
(declare-fun s1 () Int)
(assert (forall ((n Int))
(! (or (not (<= n 0)) (= (sum n) 0))
:pattern ((sum n)))))
(assert (forall ((n Int))
(! (let ((a1 (= (sum n)
(+ (select list (- n 1))
(sum (- n 1))))))
(or (<= n 0) a1))
:pattern ((sum n)))))
(assert (>= i0 0))
(assert (= s0 (sum i0)))
(assert (= i1 (+ 1 i0)))
(assert (= s1 (+ 1 s0 (select list i0))))
(assert (not (= s1 (sum i1))))
(check-sat)
Seems to me that the final assertion should instantiate the second quantified statement for i1 while the assert involving s0 should instantiate the quantifiers for i0. These two should should easily lead to UNSAT.
However, Z3 returns unknown. What am I missing?
Never mind, there was an silly error in my query.
This code:
(assert (= s1 (+ 1 s0 (select list i0))))
should have been:
(assert (= s1 (+ s0 (select list i0))))

Z3 returns model not available

If possible I'd like a second opinion on my code.
The constraints of the problem are:
a,b,c,d,e,f are non-zero integers
s1 = [a,b,c] and s2 = [d,e,f] are sets
The sum s1_i + s2_j for i,j = 0..2 has to be a perfect square
I don't understand why but my code returns model not available. Moreover, when commenting out the following lines:
(assert (and (> sqrtx4 1) (= x4 (* sqrtx4 sqrtx4))))
(assert (and (> sqrtx5 1) (= x5 (* sqrtx5 sqrtx5))))
(assert (and (> sqrtx6 1) (= x6 (* sqrtx6 sqrtx6))))
(assert (and (> sqrtx7 1) (= x7 (* sqrtx7 sqrtx7))))
(assert (and (> sqrtx8 1) (= x8 (* sqrtx8 sqrtx8))))
(assert (and (> sqrtx9 1) (= x9 (* sqrtx9 sqrtx9))))
The values for d, e, f are negative. There is no constraint that requires them to do so. I'm wondering if perhaps there are some hidden constraints that sneaked in and mess up the model.
A valid expected solution would be:
a = 3
b = 168
c = 483
d = 1
e = 193
f = 673
Edit: inserting (assert (= a 3)) and (assert (= b 168)) results in the solver finding the correct values. This only puzzles me further.
Full code:
(declare-fun sqrtx1 () Int)
(declare-fun sqrtx2 () Int)
(declare-fun sqrtx3 () Int)
(declare-fun sqrtx4 () Int)
(declare-fun sqrtx5 () Int)
(declare-fun sqrtx6 () Int)
(declare-fun sqrtx7 () Int)
(declare-fun sqrtx8 () Int)
(declare-fun sqrtx9 () Int)
(declare-fun a () Int)
(declare-fun b () Int)
(declare-fun c () Int)
(declare-fun d () Int)
(declare-fun e () Int)
(declare-fun f () Int)
(declare-fun x1 () Int)
(declare-fun x2 () Int)
(declare-fun x3 () Int)
(declare-fun x4 () Int)
(declare-fun x5 () Int)
(declare-fun x6 () Int)
(declare-fun x7 () Int)
(declare-fun x8 () Int)
(declare-fun x9 () Int)
;all numbers are non-zero integers
(assert (not (= a 0)))
(assert (not (= b 0)))
(assert (not (= c 0)))
(assert (not (= d 0)))
(assert (not (= e 0)))
(assert (not (= f 0)))
;both arrays need to be sets
(assert (not (= a b)))
(assert (not (= a c)))
(assert (not (= b c)))
(assert (not (= d e)))
(assert (not (= d f)))
(assert (not (= e f)))
(assert (and (> sqrtx1 1) (= x1 (* sqrtx1 sqrtx1))))
(assert (and (> sqrtx2 1) (= x2 (* sqrtx2 sqrtx2))))
(assert (and (> sqrtx3 1) (= x3 (* sqrtx3 sqrtx3))))
(assert (and (> sqrtx4 1) (= x4 (* sqrtx4 sqrtx4))))
(assert (and (> sqrtx5 1) (= x5 (* sqrtx5 sqrtx5))))
(assert (and (> sqrtx6 1) (= x6 (* sqrtx6 sqrtx6))))
(assert (and (> sqrtx7 1) (= x7 (* sqrtx7 sqrtx7))))
(assert (and (> sqrtx8 1) (= x8 (* sqrtx8 sqrtx8))))
(assert (and (> sqrtx9 1) (= x9 (* sqrtx9 sqrtx9))))
;all combinations of sums need to be squared
(assert (= (+ a d) x1))
(assert (= (+ a e) x2))
(assert (= (+ a f) x3))
(assert (= (+ b d) x4))
(assert (= (+ b e) x5))
(assert (= (+ b f) x6))
(assert (= (+ c d) x7))
(assert (= (+ c e) x8))
(assert (= (+ c f) x9))
(check-sat-using (then simplify solve-eqs smt))
(get-model)
(get-value (a))
(get-value (b))
(get-value (c))
(get-value (d))
(get-value (e))
(get-value (f))
Nonlinear integer arithmetic is undecidable. This means that there is no decision procedure that can decide arbitrary non-linear integer constraints to be satisfiable. This is what z3 is telling you when it says "unknown" as the answer your query.
This, of course, does not mean that individual cases cannot be answered. Z3 has certain tactics it applies to solve such formulas, but it is inherently limited in what it can handle. Your problem falls into that category: One that Z3 is just not capable of solving.
Z3 has a dedicated NRA (non-linear real arithmetic) tactic that you can utilize. It essentially treats all variables as reals, solves the problem (nonlinear real arithmetic is decidable and z3 can find all algebraic real solutions), and then checks if the results are actually integer. If not, it tries another solution over the reals. Sometimes this tactic can handle non-linear integer problems, if you happen to hit the right solution. You can trigger it using:
(check-sat-using qfnra)
Unfortunately it doesn't solve your particular problem in the time I allowed it to run. (More than 10 minutes.) It's unlikely it'll ever hit the right solution.
You really don't have many options here. SMT solvers are just not a good fit for nonlinear integer problems. In fact, as I alluded to above, there is no tool that can handle arbitrary nonlinear integer problems due to undecidability; but some tools fare better than others depending on the algorithms they use.
When you tell z3 what a and b are, you are essentially taking away much of the non-linearity, and the rest becomes easy to handle. It is possible that you can find a sequence of tactics to apply that solves your original, but such tricks are very brittle in practice and not easily discovered; as you are essentially introducing heuristics into the search and you don't have much control over how that behaves.
Side note: Your script can be improved slightly. To express that a bunch of numbers are all different, use the distinct predicate:
(assert (distinct (a b c)))
(assert (distinct (d e f)))

How to code this in Z3

I'm trying to code in Z3 a very simple problem but I got confuse and I don't know how to solve it properly.
So I have an Array with these elements (Python syntax style code):
array = [0, -1, 1, 8, 43]
And I have an access to this array using an index:
x = array[index]
And finally I want to ask z3 what index I need to use to get the element 8, in my example the solution is index = 3 (starting at 0).
I am trying to code this problem in Z3, I wrote the next lines:
(declare-const x Int)
(declare-const index Int)
(assert (= x
(ite (= index 0)
0
(ite (= index 1)
-1
(ite (= index 2)
1
(ite (= index 3)
8
(ite (= index 4)
43
999999)))))))
(assert (= x 8))
(check-sat)
(get-model)
And it is working, I had this solution:
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
But I don't like the last else, the 999999. I needed to use a magic number to know when the value is not found. I tried to see if there is a "it" construction without the else, or a NULL/None/UNSAT or any special value to don't have this problem.
What is the correct way to solve this problem?
Thank you for the help!
I know nothing about the "correct" way to solve this problem, since one should probably define "correct" in the first place.
However, there are many ways in which you can encode it as an smt2 formula.
Example 0.
By simply forcing index to fall within the domain [0, 4], you can get the ite do what you want it to do without the need for any magic number.
(declare-const x Int)
(declare-const index Int)
(assert (= x
(ite (= index 0)
0
(ite (= index 1)
-1
(ite (= index 2)
1
(ite (= index 3)
8
43))))))
(assert (and (<= 0 index) (<= index 4)))
(assert (= x 8))
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_00.smt2
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
Example 1.
(declare-const x Int)
(declare-const index Int)
(assert (ite (= index 0) (= x 0) true))
(assert (ite (= index 1) (= x (- 1)) true))
(assert (ite (= index 2) (= x 1) true))
(assert (ite (= index 3) (= x 8) true))
(assert (ite (= index 4) (= x 43) true))
(assert (and (<= 0 index) (<= index 4)))
(assert (= x 8))
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_01.smt2
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
Example 2.
(declare-const x Int)
(declare-const index Int)
(assert (or (not (= index 0)) (= x 0))) ;; (= index 0) -> (= x 0)
(assert (or (not (= index 1)) (= x (- 1))))
(assert (or (not (= index 2)) (= x 1)))
(assert (or (not (= index 3)) (= x 8)))
(assert (or (not (= index 4)) (= x 43)))
(assert (and (<= 0 index) (<= index 4)))
(assert (= x 8))
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_02.smt2
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
Example 3.
Using the Theory of Arrays
(declare-fun x () Int)
(declare-fun index () Int)
(declare-const ar (Array Int Int))
; array's locations initialization
(assert (= (store ar 0 0) ar))
(assert (= (store ar 1 (- 1)) ar))
(assert (= (store ar 2 1) ar))
(assert (= (store ar 3 8) ar))
(assert (= (store ar 4 43) ar))
; x = ar[index]
(assert (= (select ar index) x))
; bound index to fall within specified locations
(assert (and (<= 0 index) (<= index 4)))
; x = 8
(assert (= x 8))
; check
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_03.smt2
sat
(model
(define-fun x () Int
8)
(define-fun ar () (Array Int Int)
(_ as-array k!0))
(define-fun index () Int
3)
(define-fun k!0 ((x!0 Int)) Int
(ite (= x!0 2) 1
(ite (= x!0 3) 8
(ite (= x!0 1) (- 1)
(ite (= x!0 0) 0
(ite (= x!0 4) 43
5))))))
)
Other examples are possible.
Ideally one would pick the encoding for which z3 has the best performance in solving your formula. On this regard I can not help you, since I typically deal with other SMT solvers.
In general, using more complex theories (e.g. Theory of Arrays) results in the run-time executing more expensive routines so one could think that it's best to avoid it. However, I would say that in my experience this is not a general rule of thumb, since even slight variations of the encoding can result in significant performance differences and very poor or naive encodings can perform pretty bad. Therefore, it's always best to perform extensive bench-marking on various candidate encodings.

How can I write a long smt-lib expression with an existential quantifier?

I have the following expression
(declare-fun x00 () Real)
(declare-fun x01 () Real)
(declare-fun x10 () Real)
(declare-fun x11 () Real)
(declare-fun t0init () Real)
(declare-fun z0init0 () Real)
(declare-fun z0init1 () Real)
(assert (>= t0init 0))
(assert (= (+ x00 z0init0) x10))
(assert (= (+ x01 z0init1) x11))
(assert (< (+ (* 1 x00)(* 0 x01)) 0.0))
(assert (= (+ (* 0 x00)(* 1 x01)) 0.0))
(assert (< (+ (* 1 x10)(* 0 x11)) 0.0))
(assert (= (+ (* 0 x10)(* 1 x11)) 0.0))
...
(assert (< (+ (* 1 x40)(* 0 x41)) 0.0))
(assert (= (+ (* 0 x40)(* 1 x41)) 0.0))
(assert (= (+ (* 1 z4end0)(* 0 z4end1)) (* t4end 1)))
(assert (= (+ (* 0 z4end0)(* 1 z4end1)) (* t4end -2)))
and I would like to express as a simple formula in order to express the following:
(assert exists (x00 x01) ("the above expression"))
and then perform a quantifier elimination.
Is there anyone who knows how to proceed?
I know how to do it with z3py but I need some faster solution.
Thank you very much for any hint.
One possible solution is as follows
(declare-fun x00 () Real)
(declare-fun x01 () Real)
(declare-fun x10 () Real)
(declare-fun x11 () Real)
(declare-fun t0init () Real)
(declare-fun z0init0 () Real)
(declare-fun z0init1 () Real)
(define-fun conjecture () Bool
(and (>= t0init 0) (= (+ x00 z0init0) x10) (= (+ x01 z0init1) x11)))
(assert (exists ((x00 Real) (x01 Real)) conjecture))
(check-sat)
and the corresponding output is
sat
I am not sure if the quantifier elimination that you need will work with Z3. Maybe for your problem "Redlog" of "Reduce" is the better option. All the best.

Resources