对Z3列表的包含函数进行公理化的不同方法

时间:2012-06-20 13:42:53

标签: list encoding z3 axiom

将列表(on Rise4Fun)上的包含操作公理化为

(declare-fun Seq.in ((List Int) Int) Bool)

(assert (forall ((e Int))
  (not (Seq.in nil e))))

(assert (forall ((xs (List Int)) (e Int))
  (iff
    (not (= xs nil))
    (=
      (Seq.in xs e)
      (or
        (= e (head xs))
        (Seq.in (tail xs) e))))))

使Z3 4.0能够反驳断言

(declare-const x Int)
(assert (Seq.in nil x))
(check-sat) ; UNSAT, as expected

在我眼中相当于公理化

(assert (forall ((xs (List Int)) (e Int))
  (ite (= xs nil)
    (= (Seq.in xs e) false)
    (=
      (Seq.in xs e)
      (or
        (= e (head xs))
        (Seq.in (tail xs) e))))))

结果为unknown

这可能是触发器的问题,还是List域特有的东西可以解释行为上的差异?

1 个答案:

答案 0 :(得分:2)

您在rise4fun的脚本会禁用:mbqi引擎。因此,Z3将尝试仅使用E匹配来解决问题。当没有提供模式(aka触发器)时,Z3将为我们推断触发器。 Z3使用许多启发式来推断模式/触发器。其中一个与您的脚本相关,并解释了正在发生的事情。 Z3永远不会选择产生“匹配循环”的模式/触发器。我们说当Q的实例将为P产生新的匹配时,模式/触发器P为量词Q产生匹配循环。 让我们考虑量词

(assert (forall ((xs (List Int)) (e Int))
  (ite (= xs nil)
    (= (Seq.in xs e) false)
    (=
      (Seq.in xs e)
      (or
        (= e (head xs))
        (Seq.in (tail xs) e))))))

Z3将选择(Seq.in xs e)作为此量词的模式/触发器,因为它将产生匹配的循环。假设我们有一个基础术语(Seq.in a b)。该术语与模式(Seq.in xs e)匹配。使用a b实例化量词将生成与(Seq.in (tail a) b)模式匹配的术语(Seq.in xs e)。 使用(tail a)b实例化量词将生成与(Seq.in (tail (tail a)) b)模式匹配的术语(Seq.in xs e),依此类推。

在搜索过程中,Z3将使用多个阈值阻止匹配循环。但是,性能通常会受到影响。因此,默认情况下,Z3不会选择(Seq.in xs e)作为模式。相反,它会选择(Seq.in (tail xs) e)。此模式不会产生匹配循环,但它也会阻止Z3证明第二个和第三个查询不可满足。 E匹配引擎的任何限制通常由:mbqi引擎处理。但是,您的脚本中已禁用:mbqi

如果您在脚本中提供第二个和第三个查询的模式。 Z3将证明所有示例都是unsat。以下是具有显式模式/触发器的示例:

http://rise4fun.com/Z3/DkZd

即使不使用模式,第一个示例也会通过,因为只需要第一个量词来证明示例为unsat

(assert (forall ((e Int))
  (not (Seq.in nil e))))

请注意(Seq.in nil e)是此量词的完美模式,它是Z3选择的模式。

相关问题