问题描述
我试图证明如下陈述:
(assert (=
(mod i n)
(mod j n)))
(assert (> n 0))
(assert (not (=
(mod (+ i 1) n)
(mod (+ j 1) n))))
(check-sat)
(get-model)
其他是:
(((i % n) + j) % n) == ((i + j) % n)
((i - n + 1) % n) == ((i + 1) % n)
((((a - 1) % n) + 1) % n) == (a % n)
但是在证明这些陈述时,z3 似乎并没有终止。它们是否超出了 z3/smt 求解器的能力?
如果这是唯一的方法,我不介意做更明确的证明步骤,但这些规则似乎很基本,我不知道从哪里开始。即使在使用归纳法时,我也会很快遇到我认为是真的情况(如最初的例子),但似乎无法用 z3 证明。
我正在使用 z3 4.8.6,这是值得的。任何人都可以解释一下为什么这很困难,或者给我指出使这变得可行的论文/z3 标志的方向?
解决方法
长回答短,是的。这些类型的属性对于 SMT 求解器来说太难处理了。它们本质上涉及非线性整数算术,对此没有决策程序。求解器有一堆内置的启发式方法,可能会也可能不会回答您的查询;但更常见的是,正如您所观察到的那样,它会进入无限循环。
有关详细信息,请参阅此答案: How does Z3 handle non-linear integer arithmetic?
你能做什么
如果您想坚持使用纯按钮式解决方案,那么您真的无能为力。在某些情况下,以下行会有所帮助:
(check-sat-using (and-then qfnra-nlsat smt))
这使用实数理论来解决您的查询(NRA:非线性实数算术 - 恰好是可判定的),然后查看解决方案是否实际上是整数。显然,这并不总是有效。尤其是像 mod
这样的操作,使用这种策略将很难处理。
在实践中,我建议改为证明您财产的特定实例。也就是说,运行一堆案例,每次修复 n
:
(assert (= n 10))
然后
(assert (= n 27))
等等。显然,这不能证明所有 n
,但在实际系统中,如果您仔细选择 n
的值,您可以剔除很多非定理这样。
如果您真的想为所有 n
证明这一点,请改用定理证明器。显然,这不会是按钮,但这是最先进的。这里有很多选择:Isabelle、HOL、HOL-Light、ACL2、Coq、Lean 等等。请注意,这些定理证明者中的大多数都内置了在幕后利用 SMT 求解器来实现许多子目标的策略。因此,您可以两全其美,当然,证明本身需要在此类系统中手动分解。