以下Z3代码在在线代码上超时:
; 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的线性函数?
答案 0 :(得分:3)
缓慢很可能是由于有问题的模式 / 触发器引起的量化实例化太多。如果您还不了解这些内容,请查看Z3 guide的相应部分。
底线:模式是一种语法启发式方法,向SMT求解器指示何时实例化量词。模式必须涵盖所有量化变量,并且模式中不允许使用解释函数,例如加法(+
)。 匹配循环是一种情况,其中每个量词实例化都会产生进一步的量化实例化。
在您的情况下,Z3可能会选择模式集:pattern ((f a) (f b))
(因为您没有明确提供模式)。这表明Z3实例化了当前证明搜索中已经发生基础项a, b
和(f a)
的每个(f b)
的量词。最初,证明搜索包含(f 2)
;因此,可以使用绑定到a, b
的{{1}}来实例化量词。这会产生2, 2
,可用于再次实例化量词(并且还与(f (+ 2 2))
组合)。因此,Z3陷入匹配循环。
这是一个争论我的观点:
(f 2)
使用明确提供的模式,您将获得原始行为(以指定的超时为模)。此外,统计数据报告了量词的大量实例化(如果增加超时,则会更多)。
如果您评论第一个模式并取消注释第二个模式,即如果您"警卫"具有虚拟触发器的量词在证明搜索中不会出现,然后Z3立即终止。不过,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)
,因为它已经知道"它没有考虑量化约束(这是unknown
的要求;它也不能显示sat
)。
有时可以重写量词以获得更好的触发行为。例如,Z3指南说明了在内射函数/反函数的上下文中。也许你能够在这里进行类似的转变。