将循环语义转换为 SMT-LIB

translating loop semantics to SMT-LIB

是否有标准方法将命令式语言(例如 C 或 Java)中的 for 循环语义转换为 SMT-LIB?我正在考虑将它们定义为 SMT-LIB 公理,但它似乎是临时的,而且我知道翻译并不总是由求解器决定的,比如 z3。

不,没有标准方法。关于循环的推理通常是不可判定的。 处理循环是一半科学,一半艺术。

如今处理循环的一种流行方法是通过 Horn 子句。这是一个很好的介绍:https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/nbjorner-yurifest.pdf

经典的 "trick" 是在一定范围内展开循环。这个想法起源于硬件社区,其中有界证明更为常见。但它也适用于软件。 CBMC (https://www.cprover.org/cbmc/) 是为 C 程序执行此操作的系统。显然,这只会在展开数足够的情况下提供 "proof"。

请注意,展开可能不实用,因为它会导致代码爆炸,在这种情况下,您可以使用 "uninterpreted-function" 技巧:即展开固定次数,然后抽象剩余的计算。这可能会导致误报,即求解器可以 return 伪造模型。但是这个想法可以用在基于 CEGAR(反例引导抽象优化)的系统中。

一般来说,循环意味着不变量,涉及循环(或递归)的程序的证明需要弄清楚这些不变量是什么,并通过归纳来证明它们。 SMT 求解器不进行归纳证明。对于此类问题,最好使用真正的定理证明器(Isabelle、HOL、HOL-Light、Coq、Agda、Lean;随您选择)。请注意,如今这些系统中的大多数都可以使用 SMT 求解器作为子目标的 "oracle" 到 speed-up/discover 证明,因此从这个意义上说,您可以两全其美。特别是,精益来自 z3 血统,绝对值得一试:https://leanprover.github.io/