有没有办法在z3中连接两个列表?类似于ML中的@运算符?我在考虑自己定义它,但我不认为z3支持递归函数定义,即
define-fun concat ( (List l1) (List l2) List
(ite (isNil l1) (l2) (concat (tail l1) (insert (head l1) l2)) )
)
答案 0 :(得分:2)
你是正确的,SMT-Lib2不允许递归函数定义。 (在SMT-Lib2中,函数定义更像是宏,它们适用于缩写。)
通常的技巧是将这些符号声明为未解释的函数,然后将定义的等式断言为量化的公理。当然,一旦量词开始发挥作用,解算器就可以开始返回unknown
或timeout
来查找“困难”的查询。但是,Z3非常擅长于典型软件验证任务产生的许多目标,因此它应该能够证明许多感兴趣的属性。
这是一个示例,说明如何在列表上定义len
和append
,然后证明有关它们的一些定理。请注意,如果证明需要归纳,则Z3可能会超时(如下面的第二个示例所示),但Z3的未来版本也可能能够处理归纳证明。
如果你想玩游戏,这是Z3网站上这个例子的永久链接:http://rise4fun.com/Z3/RYmx
; 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)))))
; declare append as an uninterpreted function
(declare-fun append ((List Int) (List Int)) (List Int))
; assert defining equations for append as an axiom
(assert (forall ((xs (List Int)) (ys (List Int)))
(ite (= nil xs)
(= (append xs ys) ys)
(= (append xs ys) (insert (head xs) (append (tail xs) ys))))))
; declare some existential constants
(declare-fun x () Int)
(declare-fun xs () (List Int))
(declare-fun ys () (List Int))
; prove len (insert x xs) = 1 + len xs
; note that we assert the negation, so unsat means the theorem is valid
(push)
(assert (not (= (+ 1 (len xs)) (len (insert x xs)))))
(check-sat)
(pop)
; prove (len (append xs ys)) = len xs + len ys
; note that Z3 will time out since this proof requires induction
; future versions might very well be able to deal with it..
(push)
(assert (not (= (len (append xs ys)) (+ (len xs) (len ys)))))
(check-sat)
(pop)
答案 1 :(得分:2)
虽然Levent的代码有效,但如果你愿意在递归深度上设置一个界限,那么Z3通常对你的断言的麻烦要小得多。你甚至不需要依赖MBQI,这通常需要花费太多时间才能实用。从概念上讲,您需要这样做:
; the macro finder can figure out when universal declarations are macros
(set-option :macro-finder true)
(declare-fun len0 ((List Int)) Int)
(assert (forall ((xs (List Int))) (= (len0 xs) 0)))
(declare-fun len1 ((List Int)) Int)
(assert (forall ((xs (List Int))) (ite (= xs nil)
0
(+ 1 (len0 (tail xs))))))
(declare-fun len2 ((List Int)) Int)
(assert (forall ((xs (List Int))) (ite (= xs nil)
0
(+ 1 (len1 (tail xs))))))
......等等。手动编写所有这些可能会很麻烦,所以我建议使用编程API。 (无耻的插件:我一直在Racket bindings和here's how你在那里工作。)