Michael Norrish
Michael Norrish

Reputation: 412

Encoding let-expressions in Z3

The following code encodes a "record" with two fields array-fld and blist-fld. I've defined the update functions for these fields, and then asserted a property that should be true (but which z3 reports as unknown). This is Z3 version 4.0, run as z3 -smt2 -in:

(declare-datatypes ()
                   ((mystruct (mk-mystruct
                                 (array-fld (Array Int Int))
                                 (blist-fld (List Bool))))))
(define-fun array-fld-upd ((v (Array Int Int)) (obj mystruct)) mystruct
  (mk-mystruct v (blist-fld obj)))
(define-fun blist-fld-upd ((v (List Bool)) (obj mystruct)) mystruct
  (mk-mystruct (array-fld obj) v))

(push)
(assert
 (forall ((z0 mystruct))
         (exists ((array-val (Array Int Int)))
                 (and (= array-val (array-fld z0))
                      (= (select (array-fld
                                  (array-fld-upd (store array-val 2 4) z0)) 3)
                         (select (array-fld z0) 3))))))
(check-sat)

If I manually unwind/eliminate the existential by substituting out the equation array-val binding, I get

(pop)
(assert
 (forall ((z0 mystruct))
         (= (select (array-fld (array-fld-upd (store (array-fld z0) 2 4) z0)) 3)
            (select (array-fld z0) 3))))
(check-sat)

and this is happily resolved as sat.

I guess there are four questions bound up in this:

  1. Is there a way to invoke z3 to get it to solve the first instance as well as the second?
  2. Should I be encoding my records/structs differently?
  3. Should I be encoding my let-expressions differently (it is these that lead to the existential quantification)?
  4. Or, should I just expand out the let-expressions directly (I could do this myself, but it might lead to large terms if there are lots of references).

Upvotes: 2

Views: 1416

Answers (1)

Nikolaj Bjorner
Nikolaj Bjorner

Reputation: 8359

It seems from the question that you can use proper let expressions. Then it will be easier for Z3:

(declare-datatypes ()
               ((mystruct (mk-mystruct
                             (array-fld (Array Int Int))
                             (blist-fld (List Bool))))))
(define-fun array-fld-upd ((v (Array Int Int)) (obj mystruct)) mystruct
  (mk-mystruct v (blist-fld obj)))
(define-fun blist-fld-upd ((v (List Bool)) (obj mystruct)) mystruct
  (mk-mystruct (array-fld obj) v))

(push)
(assert
 (forall ((z0 mystruct))
    (let ((array-val (array-fld z0)))
                  (= (select (array-fld
                              (array-fld-upd (store array-val 2 4) z0)) 3)
                     (select (array-fld z0) 3)))))
 (check-sat)

Upvotes: 3

Related Questions