在z3中列出concat

在z3中列出concat,z3,Z3,有没有办法在z3中合并两个列表?类似于ML中的@运算符?我想自己定义它,但我不认为z3支持递归函数定义,即 define-fun concat ( (List l1) (List l2) List (ite (isNil l1) (l2) (concat (tail l1) (insert (head l1) l2)) ) ) 2021年更新 下面的答案写在2012年;9年前。它在很大程度上仍然是正确的;SMTLib现在通过define fun recconstruct明确允许递归函数

有没有办法在z3中合并两个列表?类似于ML中的@运算符?我想自己定义它,但我不认为z3支持递归函数定义,即

define-fun concat ( (List l1) (List l2) List 
   (ite (isNil l1) (l2) (concat (tail l1) (insert (head l1) l2)) )
)
2021年更新 下面的答案写在2012年;9年前。它在很大程度上仍然是正确的;SMTLib现在通过
define fun rec
construct明确允许递归函数定义。但是,解算器支持仍然非常弱,并且与此类函数相关的大多数感兴趣的属性仍然无法得到开箱即用的证明。底线仍然是这样的递归定义导致归纳证明,而SMT解算器根本不具备进行归纳的能力。也许再过9年,他们就能做到这一点,大概允许用户指定自己的不变量。目前,Isabelle、Coq、ACL2、HOL、Lean等定理证明者仍然是处理此类问题的最佳工具

2012年的答复 SMT-Lib2不允许递归函数定义,这是正确的。(在SMT-Lib2中,函数定义更像宏,它们适合缩写。)

通常的技巧是将这些符号声明为未解释的函数,然后将定义方程断言为量化公理。当然,一旦量词发挥作用,解算器就可以开始返回
未知
超时
,用于“困难”查询。然而,Z3在许多由典型的软件验证任务产生的目标上表现得相当出色,因此它应该能够证明许多感兴趣的属性

下面的示例演示了如何在列表上定义
len
append
,然后证明关于它们的一些定理。请注意,如果证明需要归纳,那么Z3可能会超时(如下面的第二个示例所示),但Z3的未来版本也可能能够处理归纳证明

以下是Z3网站上此示例的permalink,如果您想玩:


虽然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。(无耻的插件:我一直在研究,你也会在那里做。)

Rustan Leino()的论文“用SMT解决方案自动归纳”在这里可能也很有趣,尽管它与Z3中归纳证明的编码没有直接关系。
; 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))))))