2

This post shows how to axiomatise a length function for Z3's built-in lists. However, the function is sort-specific (here Int) and not applicable to lists of bools or custom sorts.

; declare len as an uninterpreted function
(declare-fun len ((List Int)) Int)

; assert defining equations for len as an axiom
(assert (forall ((xs (List Int)))
  (ite (= nil xs)
    (= 0 (len xs))
    (= (+ 1 (len (tail xs))) (len xs)))))

What would be the smartest way of encoding sort-generic list functions? (If I remember correctly, functions cannot be generic per se).

Community
  • 1
  • 1
Malte Schwerhoff
  • 12,684
  • 4
  • 41
  • 71

2 Answers2

2

The SMT 2.0 format or Z3 do not support parametric axioms in SMT 2.0 scripts. One alternative is to use the programmatic APIs. You can create functions that create the len axiom for a given sort. Here is an example on how to do it using the Python API.

http://rise4fun.com/Z3Py/vNa

from z3 import *
def MkList(sort):
    List = Datatype('List')
    List.declare('insert', ('head', sort), ('tail', List))
    List.declare('nil')
    return List.create()


def MkLen(sort):
    List = MkList(sort)
    Len  = Function('len', List, IntSort())
    x    = Const('x', List)
    Ax   = ForAll(x, If(x == List.nil, Len(x) == 0, Len(x) == 1 + Len(List.tail(x))))
    return (Len, [Ax])

IntList = MkList(IntSort())
IntLen,  IntLenAxioms = MkLen(IntSort())
print IntLenAxioms
s = Solver()
l1 = Const('l1', IntList)
s.add(IntLenAxioms)
s.add(IntLen(l1) == 0)
s.add(l1 == IntList.insert(10, IntList.nil))
print s.check()
Leonardo de Moura
  • 21,065
  • 2
  • 47
  • 53
  • Looks as if I have to switch from stdio to a programmatic API sooner than I thought ... thanks! – Malte Schwerhoff Jun 20 '12 at 07:11
  • Something else: is it necessary to guard such defining equations with patterns? As I would usually do with quantified axioms. Also, the guide says that quantifiers defining pseudo-macros are automatically detected by the Model Finder. I assume that this requires :mbqi to be true (which it isn't in my case). Could you please elaborate a bit on this? – Malte Schwerhoff Jun 20 '12 at 07:16
  • If we do not provide patterns, Z3 will compute them for us. The `Len` axiom is not a pseudo-macro because it is a "recursive" definition. The option :mbqi is true by default. – Leonardo de Moura Jun 20 '12 at 14:41
  • Does this in reverse mean that all non-recursive definitions are pseudo-macros? Also, what impact do pseudo-macros have on the behaviour of Z3? If I deactivate :mbqi, are pseudo-macros still treated specially? – Malte Schwerhoff Jun 20 '12 at 15:07
  • Yes, all non-recursive definitions are treated as macros by the `:mbqi` engine. One problem is that `:mbqi` may not have a chance to run. Z3 only executes this engine when it builds a "candidate interpretation" that satisfies all quantifier-free constraints. If you want to make sure that all definitions are expanded before the search starts, you can add the option `(set-option :macro-finder true)`. – Leonardo de Moura Jun 20 '12 at 15:14
1

You could use a sort for that. The len function is defined over a generic List of a user-defined sort T. Only the first define-sort links T to an Int type.

(define-sort T () Int)
(define-sort MyList() (List T))

(declare-const listlen Int)
(declare-const a MyList)
(declare-const b MyList)
(declare-const c MyList)
(declare-const d MyList)
(declare-const e MyList)

(define-fun-rec len((l MyList)) Int
    (ite
        (= l nil)
        0
        (+ (len (tail l)) 1)
    )
)
(assert (= a nil))
(assert (= b (insert 2 a)))
(assert (= c (insert 8 b)))
(assert (= d (insert 6 c)))
(assert (= e (insert 10 d)))

(assert (= listlen (len e)))

(check-sat)
(get-model)
Julian
  • 1,694
  • 22
  • 29