如何在重写证明中修复循环

时间:2016-01-31 11:41:54

标签: acl2

我正在尝试在ACL2中以一元表示法(O(S O)(S (S O)),...)对自然数进行建模,并证明加法的可交换性。这是我的尝试:

; a NATURAL is 'O or a list ('S n') where n' is a NATURAL
(defun naturalp (n)
  (cond ((equal n 'O) t)
        (t (and (true-listp n)
                (equal (length n) 2)
                (equal (first n) 'S)
                (naturalp (second n))))))

(defun pred (n)
  (cond ((equal n 'O) 'O)
        ((naturalp n) (second n))))

(defun succ (n)
  (list 'S n))

(defun plus (n m)
  (cond ((equal n 'O) m)
        ((naturalp n) (succ (plus (pred n) m)))))

; FIXME: cannot prove this because rewriting loops...
(defthm plus_comm                                 
  (implies (and (naturalp n) (naturalp m))
           (iff (equal (plus n m) (plus m n)) t)))

这可能不是最常用的LISPy方式,我已经习惯了模式匹配的语言。

我的问题是评论所建议的:证明者循环,试图证明同一事物的嵌套版本越来越多。我怎么阻止这个?该手册简要提到了循环重写规则,但它没有说明如何处理它们。

我的期望是这个证明会失败,给我提示完成它需要什么辅助引理。我可以使用循环证明的输出来找出可能会停止循环的引理吗?

1 个答案:

答案 0 :(得分:2)

ACL2最终会进入不同类型的循环。一种常见的类型是重写器循环,通常非常明显。例如,以下内容:

(defun f (x) x)
(defun g (x) x)
(defthm f-is-g (implies (consp x) (equal (f x) (g x))))
(defthm g-is-f (implies (consp x) (equal (g x) (f x))))
(in-theory (disable f g))
(defthm loop (equal (f (cons a b)) (cons a b)))

激发重写循环,并提供信息性的调试消息:

HARD ACL2 ERROR in REWRITE:  The call depth limit of 1000 has been
exceeded in the ACL2 rewriter.  To see why the limit was exceeded,
first execute
  :brr t
and then try the proof again, and then execute the form (cw-gstack)
or, for less verbose output, instead try (cw-gstack :frames 30).  You
will then probably notice a loop caused by some set of enabled rules,
some of which you can then disable; see :DOC disable.  Also see :DOC
rewrite-stack-limit.

不幸的是,你的例子正在进入另一种循环。特别是,看起来ACL2正在进入一个循环

  • 它导入,但是然后得到一个它不能通过重写来证明的子目标,所以
  • 它导入,但是然后得到一个它不能通过重写来证明的子目标,所以
  • ...

这不是很容易看出这是正在发生的事情。我做的事情就是在提交定理之前运行(set-gag-mode nil),然后检查打断证明器后打印的输出。

避免这种情况的一种方法是给出一个提示,特别是你可以告诉ACL2不要这样导入:

(defthm plus_comm
  (implies (and (naturalp n) (naturalp m))
           (iff (equal (plus n m) (plus m n)) t))
  :hints(("Goal" :do-not-induct t)))

但是如果你这样做那么它就会立即被卡住,因为你可能想要导入来证明这个定理。所以你真正想要告诉它的是:"引导一次,但不要引入更多。"语法有点愚蠢:

(defthm plus_comm
  (implies (and (naturalp n) (naturalp m))
           (iff (equal (plus n m) (plus m n)) t))
  :hints(("Goal"
          :induct t          ;; Induct once.
          :do-not-induct t   ;; But don't induct more than once.
      )))

这应该为您提供一个明智的检查点,然后您可以通过添加重写规则或提供进一步的提示来尝试调试。

祝你好运!