Error in defining Ackermann in Coq

前端 未结 3 1636
终归单人心
终归单人心 2020-12-31 09:37

I am trying to define the Ackermann-Peters function in Coq, and I\'m getting an error message that I don\'t understand. As you can see, I\'m packaging the arguments a,

相关标签:
3条回答
  • 2020-12-31 10:01

    I just tried your function with Coq 8.4, and the error is slightly different:

    Error: Nested recursive function are not allowed with Function
    

    I guess the inner call to ack is the problem, but I don't know why.

    Hope this helps a bit, V.

    PS: The usual way I define Ack is what wires wrote, with an inner fixpoint.

    0 讨论(0)
  • 2020-12-31 10:04

    It seems like Function can't solve this problem. However, its cousin Program Fixpoint can.

    Let's define some lemmas treating well-foundedness first:

    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.
    

    Now we can define the Ackermann-Péter function:

    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.
    

    Some simple tests demonstrating that we can compute with ack:

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

    Using the Equations plugin by M. Sozeau and C. Mangin it is possible to define the function this way:

    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)).
    

    Unfortunately, it's not possible to use the ( , ) notation for pairs due to issue #81. The code is taken from Equation's test suite: ack.v.

    0 讨论(0)
  • 2020-12-31 10:04

    You get this error because you are referencing the ack function while you are defining it. Self reference is only allowed in Fixpoints (ie. recursive functions) but the problem is, as you probably know, that the Ackermann function is not a primitive recursive function.

    See Coq'Art section 4.3.2.2 for some more information on this.

    So one alternative way to define it is by inlining a second recursive function that is structurally recursive for the second argument; so something like

    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.
    
    0 讨论(0)
提交回复
热议问题