I'd like to automatically prove the following statement about arbitrary size integers:
forall base a b c d,
0 <= a < base ->
0 <= b < base ->
0 <= c < base ->
0 <= d < base ->
base * a + b = base * c + d ->
b = d
This should be equivalent to the claim that the following is unsat
(assuming that the crazy hacks which generated this are correct):
(declare-const a Int)
(declare-const a0 Int)
(declare-const a1 Int)
(declare-const a2 Int)
(declare-const a3 Int)
(assert (not (or (not (and (<= 0 a0) (< a0 a)))
(or (not (and (<= 0 a1) (< a1 a)))
(or (not (and (<= 0 a2) (< a2 a)))
(or (not (and (<= 0 a3) (< a3 a)))
(or (not (= (+ ( * a a0) a1)
(+ ( * a a2) a3)))
(= a1 a3))))))))
(check-sat)
If I feed this to Z3, it returns unknown
, even though this looks like a very simple input.
So my question is: What's the right way to prove this automatically? Are there configuration options for Z3 which will make it work? Should I do a different preprocessing? Or does this problem belong to a class of problems outside Z3's "area of expertise" and I should use another tool?
Update: Here's a more readable version of the same query, using (implies A B)
instead of (or (not A) B)
:
(declare-const a Int)
(declare-const a0 Int)
(declare-const a1 Int)
(declare-const a2 Int)
(declare-const a3 Int)
(assert (not (implies (and (<= 0 a0) (< a0 a))
(implies (and (<= 0 a1) (< a1 a))
(implies (and (<= 0 a2) (< a2 a))
(implies (and (<= 0 a3) (< a3 a))
(implies (= (+ ( * a a0) a1) (+ ( * a a2) a3)) (= a1 a3))))))))
(check-sat)