Search code examples
z3smt

Z3 Checking whether all values in array are unique


So I'm trying to check whether all values in an array is unique with the following Z3 code.

(declare-const A (Array Int Int))
(declare-const n Int)
(assert (forall ((i Int) (j Int)) (and (and (and (>= i 0) (< i n)) (and (>= j 0) (< j n)))
                                       (implies (= (select A i) (select A j)) (= i j)))))
(check-sat)

I'm quite new to Z3 so I don't quite understand the grammar and stuff, but can anyone tell me whether this code is right, and if not, where's the problem?


Solution

  • The problem as you wrote is unsat, because it says whenever 0 <= i < n and 0 <= j < n, if A[i] = A[j], then i = j. There is no array and a particular n you can pick to satisfy this constraint.

    What you really want to write is the following instead:

    (declare-const A (Array Int Int))
    (declare-const n Int)
    (assert (forall ((i Int) (j Int)) (implies (and (>= i 0) (< i n)
                                                    (>= j 0) (< j n)
                                                    (= (select A i) (select A j)))
                                               (= i j))))
    (check-sat)
    (get-model)
    

    The above says If it's the case that i and j are within bounds, and array elements are the same, then i must equal j. And this variant would be satisifiable for any n; and indeed here's what z3 reports:

    sat
    (
      (define-fun n () Int
        0)
      (define-fun A () (Array Int Int)
        ((as const (Array Int Int)) 0))
    )
    

    But note that z3 simply picked n = 0, which made it easy to satisfy the formula. Let's make sure we get a more interesting model, by adding:

    (assert (> n 2))
    

    Now we get:

    sat
    (
      (define-fun n () Int
        3)
      (define-fun A () (Array Int Int)
        (lambda ((x!1 Int))
      (let ((a!1 (ite (and (<= 1 x!1) (not (<= 2 x!1))) 7 8)))
        (ite (<= 1 x!1) (ite (and (<= 1 x!1) (<= 2 x!1)) 6 a!1) 5))))
    )
    

    and we see that z3 picked the array to have 3 elements with distinct values at positions we care about.

    Note that this sort of reasoning with quantifiers is a soft-spot for SMT solvers; while z3 is able to find models for these cases, if you keep adding quantified axioms you'll likely get unknown as the answer, or z3 (or any other SMT solver for that matter) will take longer and longer time to respond.