为什么这个简单的Z3证明这么慢?
以下Z3代码在联机repl上超时:为什么这个简单的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上寻找
; 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指南在内射函数/逆函数的上下文中说明了这一点。也许您可以在这里执行类似的转换