【问题标题】:Error in defining Ackermann in Coq在 Coq 中定义 Ackermann 时出错
【发布时间】:2012-04-24 05:53:25
【问题描述】:

我正在尝试在 Coq 中定义 Ackermann-Peters 函数,但收到一条我不理解的错误消息。如您所见,我将 Ackermann 的参数 a, b 打包成一对 ab;我提供了一个为参数定义排序函数的排序。然后我使用Function 形式定义Ackermann 本身,为它提供ab 参数的排序函数。

Require Import Recdef.    
Definition ack_ordering (ab1 ab2 : nat * nat) :=
    match (ab1, ab2) with
    |((a1, b1), (a2, b2)) => 
       (a1 > a2) \/ ((a1 = a2) /\ (b1 > b2))   
    end.
Function ack (ab : nat * nat) {wf ack_ordering} : nat :=
match ab with
| (0, b) => b + 1
| (a, 0) => ack (a-1, 1)
| (a, b) => ack (a-1, ack (a, b-1))
end.

我得到的是以下错误消息:

错误:没有这样的部分变量或假设:ack

我不确定是什么困扰了 Coq,但是在搜索互联网时,我发现了一个建议,使用通过排序或度量定义的递归函数可能存在问题,其中递归调用发生在匹配项中。但是,使用预测 fstsnd 以及 if-then-else 会生成不同的错误消息。有人可以建议如何在 Coq 中定义 Ackermann 吗?

【问题讨论】:

  • 我今天遇到了同样的问题。你找到解决办法了吗?
  • @AbhishekAnand 已经有一段时间了......我在下面用Program Fixpoint 提供了一个解决方案。您找到Function 的解决方案了吗?
  • 不,我没有。谢谢你的回答。

标签: coq ackermann totality


【解决方案1】:

看来Function 解决不了这个问题。但是,它的表弟Program Fixpoint 可以。

让我们首先定义一些处理有根据的引理:

Require Import Coq.Program.Wf.
Require Import Coq.Arith.Arith.

Definition lexicographic_ordering (ab1 ab2 : nat * nat) : Prop :=
  match ab1, ab2 with
  | (a1, b1), (a2, b2) => 
      (a1 < a2) \/ ((a1 = a2) /\ (b1 < b2))
  end.

(* this is defined in stdlib, but unfortunately it is opaque *)
Lemma lt_wf_ind :
  forall n (P:nat -> Prop), (forall n, (forall m, m < n -> P m) -> P n) -> P n.
Proof. intro p; intros; elim (lt_wf p); auto with arith. Defined.

(* this is defined in stdlib, but unfortunately it is opaque too *)
Lemma lt_wf_double_ind :
  forall P:nat -> nat -> Prop,
    (forall n m,
      (forall p (q:nat), p < n -> P p q) ->
      (forall p, p < m -> P n p) -> P n m) -> forall n m, P n m.
Proof.
  intros P Hrec p. pattern p. apply lt_wf_ind.
  intros n H q. pattern q. apply lt_wf_ind. auto.
Defined.

Lemma lexicographic_ordering_wf : well_founded lexicographic_ordering.
Proof.
  intros (a, b); pattern a, b; apply lt_wf_double_ind.
  intros m n H1 H2.
  constructor; intros (m', n') [G | [-> G]].
  - now apply H1.
  - now apply H2.
Defined.

现在我们可以定义 Ackermann-Péter 函数:

Program Fixpoint ack (ab : nat * nat) {wf lexicographic_ordering ab} : nat :=
  match ab with
  | (0, b) => b + 1
  | (S a, 0) => ack (a, 1)
  | (S a, S b) => ack (a, ack (S a, b))
  end.
Next Obligation.
  inversion Heq_ab; subst. left; auto. Defined.
Next Obligation.
  apply lexicographic_ordering_wf. Defined.

一些简单的测试证明我们可以使用ack 进行计算:

Example test1 : ack (1, 2) = 4 := eq_refl.
Example test2 : ack (3, 4) = 125 := eq_refl.  (* this may take several seconds *)

使用 M. Sozeau 和 C. Mangin 的 Equations 插件,可以这样定义函数:

From Equations Require Import Equations Subterm.

Equations ack (p : nat * nat) : nat :=
ack p by rec p (lexprod _ _ lt lt) :=
ack (pair 0 n) := n + 1;
ack (pair (S m) 0) := ack (m, 1);
ack (pair (S m) (S n)) := ack (m, ack (S m, n)).

很遗憾,由于issue #81,无法对对使用( , ) 表示法。代码取自 Equation 的测试套件:ack.v

【讨论】:

    【解决方案2】:

    您收到此错误是因为您在定义它时引用了ack 函数。自引用只允许在Fixpoints(即递归函数)中使用,但问题是,您可能知道,Ackermann 函数不是原始递归函数。

    有关更多信息,请参阅Coq'Art section 4.3.2.2

    因此,另一种定义它的方法是内联第二个递归函数,该函数在结构上对第二个参数是递归的;所以像

    Fixpoint ack (n m : nat) : nat :=
      match n with
      | O => S m
      | S p => let fix ackn (m : nat) :=
                   match m with
                   | O => ack p 1
                   | S q => ack p (ackn q)
                   end
               in ackn m
      end.
    

    【讨论】:

    • 我使用的不是Fixpoint,而是Function。这应该适用于具有递减参数的总函数,我应该能够使用度量或比较来做到这一点,然后是递归调用中的参数具有较小度量或小于原始参数的定理参数,根据比较器。我知道 Ackermann 是二阶 PR,但显然该函数的 PR 状态并没有阻止您以某种方式对其进行编码。我想知道的是我给出的编码有什么问题,这似乎遵循手册中的描述。
    【解决方案3】:

    我刚刚用 Coq 8.4 试了一下你的函数,报错略有不同:

    Error: Nested recursive function are not allowed with Function
    

    我猜对 ack 的内部调用是问题所在,但我不知道为什么。

    希望这会有所帮助, 五、

    PS:我定义 Ack 的通常方式是用线写的内容,带有一个内部固定点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多