我正在尝试在Z3中创建一个可传递但不能自反的函数。即如果(transitive a b)
和(transitive b c)
成立,则(transitive a c)
应该成立,而(transitive a a)
不成立。
我尝试通过以下5种“测试”方法进行操作。第一个操作符合我的预期,但是第二个操作失败并导致unknown
。
(declare-datatypes () ((T T1 T2 T3)))
(declare-fun f (T T) Bool)
(assert(f T1 T2))
(assert(f T2 T3))
; Make sure that f is not reflexive
(assert
(forall ((x T))
(not (f x x))))
; Now we create the transitivity function ourselves
(define-fun-rec transitive ((x T) (y T)) Bool
(or
(f x y)
(exists ((z T))
(and
(f x z)
(transitive z y)))))
; This works and gives sat
(push)
(assert (not (transitive T1 T1)))
(assert (not (transitive T2 T2)))
(assert (not (transitive T3 T3)))
(check-sat)
(pop)
; This fails with "unknown" and the verbose flag gives: (smt.mbqi "max instantiations 1000 reached")
(push)
(assert
(forall ((x T))
(not (transitive x x))))
(check-sat)
(pop)
我的问题是:第二项测试与第一次测试有何不同?为什么最后一个给出unknown
,而前面一个给出的效果很好?
答案 0 :(得分:2)
“详细”消息是此处的提示。 mbqi
代表基于模型的量化器实例化。这是SMT解决方案中处理量词的一种方法。在第一种情况下,MBQI设法找到一个模型。但是您的transitive
函数对于MBQI来说太复杂了,因此它放弃了。增加限制可能无法解决问题,也不是长期解决方案。
长话短说,递归定义很难处理,而带量词的递归定义则更难。逻辑变得半定,而您则受试探法的支配。即使您找到了让z3为此计算模型的方法,它也将很脆弱。这些问题不适合SMT解决。最好使用适当的定理证明者,例如Isabelle,Hol,Coq,Lean。 Agda等。几乎所有这些工具都提供了“策略”来将子目标分派给SMT求解器,因此您可以两全其美。 (当然,您会失去完全的自动化功能,但是有了量词,您再也期待不到更好的了。)