Z3中实现List的contains函数的方法咨询
在Z3中实现列表成员检查函数的正确方式
你提到的需求完全可以在Z3中实现,问题出在你原来的公理定义没有覆盖列表的所有情况(比如空列表nil),而且误用了未定义的谓词is-insert。下面我会一步步说明正确的实现方式:
问题分析
你的原始代码里,forall断言只处理了insert构造的列表,但没有考虑空列表nil的情况——当列表是空的时候,元素肯定不存在,这是递归的终止条件。另外,Z3不会自动生成is-insert这样的谓词,你需要通过构造器的模式来区分列表的类型。
正确实现步骤
- 确认列表数据类型的声明:你的原始声明是正确的,我们再明确一下:
(declare-datatypes (X) ((Lst (nil) (insert (head X) (tail Lst)))))
这个定义创建了一个参数化的列表类型Lst,包含空列表nil和插入元素的insert构造器。
- 定义成员检查函数的公理:我们需要用
forall断言完整定义is-in-lst的行为,覆盖两种列表情况:- 空列表
nil:任何元素都不在其中,返回false; insert构造的列表:元素等于当前head,或者递归检查tail列表。
- 空列表
完整的代码如下:
(declare-datatypes (X) ((Lst (nil) (insert (head X) (tail Lst))))) ; 声明未解释函数:参数是元素(Int)和列表(Lst Int),返回布尔值 (declare-fun is-in-lst (Int (Lst Int)) Bool) ; 定义函数的递归公理 (assert (forall ((elem Int) (lst (Lst Int))) (= (is-in-lst elem lst) (ite (is-nil lst) false ; 空列表,元素不存在 (or (= elem (head lst)) ; 等于当前头部元素 (is-in-lst elem (tail lst)) ; 递归检查尾部 ) ) ) )) ; 测试示例:声明一个列表常量l1,断言6和5都在其中 (declare-const l1 (Lst Int)) (assert (is-in-lst 6 l1)) (assert (is-in-lst 5 l1)) ; 检查可满足性并获取模型 (check-sat) (get-model)
代码解释
(is-nil lst)是Z3自动为datatype生成的谓词,用来判断列表是否是空列表;同理(is-insert lst)也可以用来判断是否是插入构造的列表,不过用ite结合is-nil更直观。- 递归定义是合法的,因为每次递归调用的
tail都是比原列表更短的列表,Z3可以处理这种well-founded的递归。
运行这段代码后,Z3会返回sat,并给出一个模型,比如l1会被实例化为包含5和6的列表(比如(insert 6 (insert 5 nil))或者其他顺序的组合)。
额外提示
如果你不想用未解释函数,也可以直接用递归定义函数(Z3支持递归函数,需要启用相应的逻辑,比如(set-logic HORN)或者使用define-fun-rec),示例如下:
(declare-datatypes (X) ((Lst (nil) (insert (head X) (tail Lst))))) (define-fun-rec is-in-lst ((elem Int) (lst (Lst Int))) Bool (ite (is-nil lst) false (or (= elem (head lst)) (is-in-lst elem (tail lst)) ) ) ) (declare-const l1 (Lst Int)) (assert (is-in-lst 6 l1)) (assert (is-in-lst 5 l1)) (check-sat) (get-model)
这种方式更简洁,不需要手动写forall公理,Z3会自动处理递归函数的语义。
内容的提问来源于stack exchange,提问作者Raph85
相关产品推荐
相关产品推荐

