同一公理的编码差异

difference in encoding of the same axiom

我想知道同一个列表公理的这两种编码有什么区别:

(define-sort T1 () Int)

(declare-fun list_length ( (List T1) ) Int)

(assert (forall ( (i T1) (l (List T1)) )
                (ite (= l (as nil (List T1)))
                     (= (list_length l) 0)
                     (= (list_length (insert i l)) (+ 1 (list_length l))))))

(define-sort T1 () Int)

(declare-fun list_length ( (List T1) ) Int)

(assert (= (list_length (as nil (List T1))) 0))

(assert (forall ( (i T1) (l (List T1)) )
                (= (list_length (insert i l)) (+ 1 (list_length l)))))

对于此基准:

(declare-const a T1)
(declare-const b T1)

(assert (not
         (= (list_length (insert b (insert a (as nil (List T1))))) 2)))

(check-sat)

z3 以某种方式能够推断第二个版本而不是第一个版本(它似乎永远循环)。

编辑:与 cvc4 相同,第一个版本返回未知。

带有量词的一阶逻辑本质上是半可判定的。在 SMT 上下文中,这意味着没有决策程序来正确回答每个查询,如 sat/unsat.

(抛开理论,并不是那么重要:如果你完全忽略效率的考虑,那么有算法可以正确回答所有可满足的查询,但是有没有算法可以正确推断 unsat。在后一种情况下,它们会永远循环。但这是题外话。)

因此,为了处理量词,SMT 求解器通常采用一种称为电子匹配的技术。本质上,当他们形成一个提到未解释函数的基础术语时,他们试图 实例化 量化公理以匹配它们并相应地重写。这种技术在实践中可能非常有效,并且可以很好地解决典型的软件验证问题,但它显然不是万灵药。详见本文:https://pdfs.semanticscholar.org/4eb2/c5e05ab5c53f20c6050f8252a30cc23561be.pdf.

关于您的问题:本质上,当您拥有公理的 ite 形式时,电子匹配算法根本无法找到正确的替代来实例化您的公理。出于效率的考虑,e-matcher 真的看差不多 "exact" 个匹配项。 (对此持保留态度;它比那更聪明,但相差不大。)在这里太聪明几乎不会在实践中得到回报,因为您最终可能会生成太多匹配项并最终导致搜索爆炸 space.和往常一样,它是实用性、效率和覆盖尽可能多的案例之间的平衡。

Z3 允许指定模式在一定程度上指导搜索,但模式使用起来相当棘手且脆弱。 (我会在文档中为您指出模式的正确位置,唉,正如您自己注意到的那样,z3 文档站点暂时关闭了!)您可能想尝试一下它们是否会给您带来更好的结果.但经验法则是让你的量化公理尽可能简单明了。与第一个相比,您的第二个变体正是这样做的。对于这个特定的问题,一定要把公理分成两部分,并分别断言它们以涵盖 nil/insert 情况。将它们合为一条规则,简直超出了当前电子匹配器的能力。