3

I have two questions about how Z3 operates with regards to arrays.

1) In models, arrays have an "else" element along with a corresponding value. Is there a way to specify constraints on the "else" element on an array in the formula? For example, can we specify that the first element of an array is greater than 5 and all other elements are less than 5?

2) Upon checking the following formula via z3 at command line,

(set-logic QF_AX)
(declare-sort Index 0)
(declare-sort Element 0)
(declare-fun a1 () (Array Index Element))
(declare-fun i0 () Index)
(declare-fun i1 () Index)
(assert 
  (let 
    (
      (?v_1 (select a1 i0)) 
      (?v_2 (select a1 i1))
    )
    (
      not(= ?v_1 ?v_2)
    )
  )
)

Z3 generates the following output.

sat
(model
  ;; universe for Index:
  ;;   Index!val!1 Index!val!0
  ;; -----------
  ;; definitions for universe elements:
  (declare-fun Index!val!1 () Index)
  (declare-fun Index!val!0 () Index)
  ;; cardinality constraint:
  (forall ((x Index)) (or (= x Index!val!1) (= x Index!val!0)))
  ;; -----------
  ;; universe for Element:
  ;;   Element!val!1 Element!val!0
  ;; -----------
  ;; definitions for universe elements:
  (declare-fun Element!val!1 () Element)
  (declare-fun Element!val!0 () Element)
  ;; cardinality constraint:
  (forall ((x Element)) (or (= x Element!val!1) (= x Element!val!0)))
  ;; -----------
  (define-fun i1 () Index
    Index!val!1)
  (define-fun a1 () (Array Index Element)
    (_ as-array k!0))
  (define-fun i0 () Index
    Index!val!0)
  (define-fun k!0 ((x!1 Index)) Element
    (ite (= x!1 Index!val!0) Element!val!0
    (ite (= x!1 Index!val!1) Element!val!1
      Element!val!0)))
)

Upon checking the same formula via Z3py, the following model is generated.

[i1 = Index!val!1,
 a1 = [Index!val!0 -> Element!val!0,
       Index!val!1 -> Element!val!1,
       else -> Element!val!0],
 i0 = Index!val!0,
 k!0 = [Index!val!0 -> Element!val!0,
        Index!val!1 -> Element!val!1,
        else -> Element!val!0]]

Interestingly, the reference to k!0 in a1 is "dereferenced" in Z3py, i.e., a1 refers to FuncInterp object. Is this always the case? Specifically, if a program is walking over the model provided by Z3py, is it safe to assume that all as_array expressions will be resolved to the underlying function definition?

1 Answers1

0

Arrays are a bit of a special case, because they have a func_interp as a model. In the Python API we can rely on this being dereferenced, it's the get_interp function which does this for us:

def get_interp(self, decl):
...
    if decl.arity() == 0:
        r = _to_expr_ref(Z3_model_get_const_interp(self.ctx.ref(), self.model, decl.ast), self.ctx)
        if is_as_array(r):
            return self.get_interp(get_as_array_func(r)) # <-- Here. 
        else:
            return r
Christoph Wintersteiger
  • 8,234
  • 1
  • 16
  • 30