Recently I am learning SMT solver. Although SMT solver is a new concept to me, it reminds me of logic programming, e.g. Prolog and minikanren. So I tried a classic example of logic programming in SMT solver.
The example is appendo
relation, which we can execute it backwards. That is given an output list, returns all possible two inputs, when concating these two input lists return the output list.
The following is the appendo
relation, I implemented in z3/smt2 solver:
(define-fun-rec appendo ((l (List Int)) (s (List Int))) (List Int)
(ite (= nil l)
s
(insert (head l) (appendo (tail l) s))
))
(declare-const a (List Int))
(declare-const b (List Int))
(assert (= (appendo a b) (insert 1 (insert 2 nil))))
(check-sat)
(get-model)
(echo "solution 1:")
(eval a)
(eval b)
;; nil
;; (insert 1 (insert 2 nil))
(assert (not (= a nil)))
(assert (not (= b (insert 1 (insert 2 nil)))))
(check-sat)
(get-model)
(echo "solution 2:")
(eval a)
(eval b)
;; (insert 1 nil)
;; (insert 2 nil)
(assert (not (= a (insert 1 nil))))
(assert (not (= b (insert 2 nil))))
(check-sat)
(get-model)
(echo "solution 3:")
(eval a)
(eval b)
;; (insert 1 (insert 2 nil))
;; nil
(assert (not (= a (insert 1 (insert 2 nil)))))
(assert (not (= b nil)))
(check-sat)
;; unsat
It works though, the drawback of this implementation is that it cannot get all the satisfying models automatically.
According to this question, it seems impossible to get all the satisfying models automatically in pure smt2 (?). We must use some API binding.
I tried z3 python API for hours, but failed.
Could someone help me to convert the smt2 code above to z3py? (The z3py's docs is very brief and difficult to read, especially about how to define a recursive function, forgive me ...)
Very thanks.
The following is my uncompleted code:
from z3 import *
## Define List
def DeclareList(sort):
List = Datatype('List_of_%s' % sort.name())
List.declare('cons', ('car', sort), ('cdr', List))
List.declare('nil')
return List.create()
IntList = DeclareList(IntSort())
## Define Rec Function
appendo = RecFunction('appendo', IntList, IntList, IntList)
RecAddDefinition(appendo, [l, s], If(IntList.nil == l, s, IntList.cons(IntList.car(l), appendo(IntList.cdr(l), s)))) ## <== NameError: name 'l' is not defined
a = Const('a', IntList)
b = Const('b', IntList)
## ...