Search code examples
z3smtcvc4

Extracting boolean terms from Z3 model when using quantifiers


I am trying to use Z3 to explore the difference between two predicates, but the model contains exist-expressions where I would expect boolean constants.

I have the following program in smtlib:

    (set-option :produce-models true)
    (declare-fun a (Int) Bool)
    (declare-const t1 Bool)
    (declare-const t2 Bool)
    (assert (= t1 (exists ((i Int)) (and (a i) (or (= i 10) (= i 11) )))))
    (assert (= t2 (exists ((i Int)) (and (a i) (and (< i 13) (< 9 i))))))
    (assert (distinct t1 t2))
    (check-sat)
    (get-value (a))
    (get-value (t1 t2))

I am trying to find the values for t1 and t2 when the problem is satisfiable.

Z3 responds with

    sat
    ((a (store (store ((as const Array) true) 11 false) 10 false)))
    ((t1 (exists ((i Int)) (and (not (= i 10)) (not (= i 11)) (or (= i 10) (= i 11)))))
     (t2 (exists ((i Int))
      (and (not (= i 10)) (not (= i 11)) (not (<= 13 i)) (not (<= i 9))))))

The model for t1 and t2 does not give me boolean constants, but expressions. How can I persuade Z3 to give me the values of these expressions? (I believe the model for t1 is actually a contradiction, so it is always false.

I don't need to do this through smtlib, using the Z3 api would be sufficient.


Solution

  • You can only get a value for top-level values. And a simple exist (i.e., one that's not nested) is equivalent to a top-level declaration. (There are ways to deal with nested exists as well, via skolemization, but that's besides the point.) So, simply pull those exist-variables to the top:

    (set-option :produce-models true)
    (declare-fun a (Int) Bool)
    (declare-const t1 Bool)
    (declare-const t2 Bool)
    (declare-const i1 Int)
    (declare-const i2 Int)
    (assert (= t1 (and (a i1) (or (= i1 10) (= i1 11) ))))
    (assert (= t2 (and (a i2) (and (< i2 13) (< 9 i2)))))
    (assert (distinct t1 t2))
    (check-sat)
    (get-value (a))
    (get-value (i1 i2))
    (get-value (t1 t2))
    

    This prints:

    sat
    ((a (store ((as const Array) true) 12 false)))
    ((i1 10)
     (i2 12))
    ((t1 true)
     (t2 false))
    

    I believe this satisfies all your constraints and gives you the values of t1 and t2, along with i1 and i2 that make them distinct as requested.