对于以下smt文件(在Viper / Boogie生成的示例中已将其最小化),Z3返回unknown
(非常快)。
(set-option :print-success false)
(set-info :smt-lib-version 2.0)
(set-option :AUTO_CONFIG false)
(set-option :pp.bv_literals false)
(set-option :MODEL.V2 true)
(set-option :smt.PHASE_SELECTION 0)
(set-option :smt.RESTART_STRATEGY 0)
(set-option :smt.RESTART_FACTOR |1.5|)
(set-option :smt.ARITH.RANDOM_INITIAL_VALUE true)
(set-option :smt.CASE_SPLIT 3)
(set-option :smt.DELAY_UNITS true)
(set-option :NNF.SK_HACK true)
(set-option :smt.MBQI false)
(set-option :smt.QI.EAGER_THRESHOLD 100)
(set-option :TYPE_CHECK true)
(set-option :smt.BV.REFLECT true)
; (options as set by Boogie)
(declare-sort T@Seq 0)
(declare-fun Append (T@Seq T@Seq) T@Seq)
(declare-fun Empty () T@Seq)
(declare-fun Singleton (Int) T@Seq)
(declare-fun dummy () Bool)
(declare-fun Contains (T@Seq Int) Bool)
; Empty ++ s == s
(assert (forall ((s T@Seq) ) (! (= (Append Empty s) s)
:qid |_0314cbp.11:15|
:skolemid |0|
:pattern ( (Append Empty s))
)))
; (strange axiom)
; forall s0,s1 :: {s0++s1} s0 != Empty ==> dummy
(assert (forall ((s0 T@Seq) (s1 T@Seq) ) (! (=> (not (= s0 Empty)) dummy)
:qid |_0314cbp.17:15|
:skolemid |3|
:pattern ( (Append s0 s1))
)))
; forall s0,s1,x :: {(Contains s0++s1 x)} Contains s0++s1 x <==> (Contains s0 x || Contains s1 x)
(assert (forall ((s0@@0 T@Seq) (s1@@0 T@Seq) (x Int) ) (! (and (=> (Contains (Append s0@@0 s1@@0) x) (or (Contains s0@@0 x) (Contains s1@@0 x))) (=> (or (Contains s0@@0 x) (Contains s1@@0 x)) (Contains (Append s0@@0 s1@@0) x)))
:qid |_0314cbp.22:15|
:skolemid |4|
:pattern ( (Contains (Append s0@@0 s1@@0) x))
)))
(declare-fun s () T@Seq)
(declare-fun s1 () T@Seq) ; spurious term, used for assumption
(declare-fun i () Int)
(declare-fun f (Int) Bool)
(push 1)
(assert (not
; forall x_1 :: {(Contains s x_1)} f x_1
(=> (and (forall ((x_1 Int) ) (! (f x_1)
:qid |_0314cbp.34:20|
:skolemid |5|
:pattern ( (Contains s x_1))
)) (= s1 (Append s (Singleton 1)))) (=> (Contains (Append s (Singleton 1)) i ) ( f i ))))
)
(check-sat)
(pop 1)
; Invalid
我的理解是可以预期到此结果;获得我所知道的unsat
的唯一方法是实例化其模式为assert
的最后一个量词(在最后一个(Contains s x_1)
公式内)。在上下文中该术语未知。已知的(Contains (Append s (Singleton 1)) i )
可能导致实例化:qid |_0314cbp.22:15|
的量词,从而产生析取(or (Contains s i ) (Contains (Singleton 1) i))
。如果/当Z3在此分叉上分支时,前者将具有从最后一个公理获得unsat
的条件,而后者则不会。与explained elsewhere一样,Z3将回溯这些大小写分隔之间的实例化。
令我惊讶的是,可以对该示例进行许多修改以获得unsat
结果,这些修改会削弱所做的逻辑假设,或者保持不变。在每种情况下,我都无法理解为什么以上相同的理由不适用于解释应该预期unknown
。例如:
假设(= s1 (Append s (Singleton 1)))
是虚假的;术语s1
在问题中的其他地方均未使用,(Append s (Singleton 1))
在以下含义中是一个已知术语(因此它的存在不应影响潜在的电子匹配)。但是,删除它或将其替换为true
(即削弱所做的假设)将导致unsat
。
删除前两个限定词(其中第二个没有逻辑含义)将得到unsat
。
重写第三个公理以表示蕴涵(Contains s0++s1 x ==> (Contains s0 x || Contains s1 x)
)而不是if-and-only-if将导致unsat
。
删除(push 1)
和(pop 1)
将得到unsat
。
我的主要问题是,这些(行为的)变化是预期的吗,我该如何解释?另外,如果有一种很好的方法来查看Z3对问题的处理方式,并尝试为自己发现更多信息,我很乐意这样做。
我已经使用Axiom Profiler工具尝试了该示例(及其变体)。在那里我可以看到进行了相同数量的量词实例化(3),但是在关于将Contains
分布到Append
的公理的情况下,Z3有时似乎可以学习一个简化的术语,而不是完整的量词主体。如果有帮助,我可以提供更多详细信息。