为什么这个简单的Z3证明这么慢?

为什么这个简单的Z3证明这么慢?,z3,Z3,以下Z3代码在联机repl上超时: ; I want a function (declare-fun f (Int) Int) ; I want it to be linear (assert (forall ((a Int) (b Int)) ( = (+ (f a) (f b)) (f (+ a b)) ))) ; I want f(2) == 4 (assert (= (f 2) 4)) ; TIMEOUT :( (check-sat) 这个版本也是如此,它正在reals上寻找

以下Z3代码在联机repl上超时:

; I want a function
(declare-fun f (Int) Int)

; I want it to be linear
(assert (forall ((a Int) (b Int)) (
  = (+ (f a) (f b)) (f (+ a b))
)))

; I want f(2) == 4
(assert (= (f 2) 4))

; TIMEOUT :(
(check-sat)
这个版本也是如此,它正在reals上寻找一个函数:

(declare-fun f (Real) Real)
(assert (forall ((a Real) (b Real)) (
  = (+ (f a) (f b)) (f (+ a b))
)))
(assert (= (f 2) 4))
(check-sat)
当我给它一个矛盾时,它会更快:

(declare-fun f (Real) Real)
(assert (forall ((a Real) (b Real)) (
  = (+ (f a) (f b)) (f (+ a b))
)))
(assert (= (f 2) 4))
(assert (= (f 4) 7))
(check-sat)

我对定理证明者一无所知。这里什么东西这么慢?证明者在证明f(2)=4的线性函数存在时遇到了很多困难吗?

缓慢很可能是由于有问题的模式/触发器导致的量词实例化太多。如果您还不知道这些,请查看相应的部分

一句话:模式是一种语法启发,向SMT求解器指示何时实例化量词。模式必须覆盖所有量化变量,模式中不允许使用加法(
+
)等解释函数。匹配循环是一种情况,在这种情况下,每个量词实例化都会产生进一步的量词实例化

在您的例子中,Z3可能选择模式集
:pattern((fa)(fb))
(因为您没有显式地提供模式)。这建议Z3为每个
a,b
实例化量词,对于这些量词,基本术语
(f a)
(f b)
已在当前校对搜索中出现。最初,校对搜索包含
(f2)
;因此,量词可以用绑定到
2,2
a,b
实例化。这将产生
(f(+2))
,它可以用于再次实例化量词(也可以与
(f2)
)结合使用)。因此,Z3被卡在一个匹配的循环中

下面是一个片段,说明了我的观点:

(set-option :smt.qi.profile true)

(declare-fun f (Int) Int)

(declare-fun T (Int Int) Bool) ; A dummy trigger function

(assert (forall ((a Int) (b Int)) (! 
  (= (+ (f a) (f b)) (f (+ a b)))
  :pattern ((f a) (f b))
  ; :pattern ((T a b))
)))

(assert (= (f 2) 4))

(set-option :timeout 5000) ; 5s is enough
(check-sat)
(get-info :reason-unknown)
(get-info :all-statistics)
使用显式提供的模式,您将获得原始行为(以指定的超时为模)。此外,统计数据报告了大量量词的实例化(如果您增加超时时间,则更多)

如果您注释第一个模式并取消注释第二个模式,即如果您使用一个不会在校对搜索中出现的伪触发器“保护”量词,那么Z3将立即终止。Z3仍将报告
unknown
,因为它“知道”它没有考虑量化约束(这是
sat
的要求;它也不能显示
unsat

有时可以重写量词以获得更好的触发行为。例如,Z3指南在内射函数/逆函数的上下文中说明了这一点。也许您可以在这里执行类似的转换