Library hydras.Ackermann.primRec

Primitive Recursive functions Russel O'Connor

From Coq Require Import Arith Peano_dec Compare_dec List Eqdep_dec Utf8.
From hydras Require Import extEqualNat misc Compat815.
From Coq Require Vector Bool EqNat.
From Coq Require Import Lia.

Definitions

PrimRec n : data type of primitive recursive functions of arity n PrimRec n m : m-tuples of PrimRec n


Inductive PrimRec : nat Set :=
  | succFunc : PrimRec 1
  | zeroFunc : PrimRec 0
  | projFunc : n m : nat, m < n PrimRec n
  | composeFunc :
       (n m : nat) (g : PrimRecs n m) (h : PrimRec m),
        PrimRec n
  | primRecFunc :
       (n : nat) (g : PrimRec n) (h : PrimRec (S (S n))),
        PrimRec (S n)
with PrimRecs : nat nat Set :=
  | PRnil : n : nat, PrimRecs n 0
  | PRcons : n m : nat, PrimRec n PrimRecs n m
                               PrimRecs n (S m).


  Notation "f '=x=' g" := (extEqual _ f g) (at level 70, no associativity).


  Module PRNotations.
    Declare Scope pr_scope.
    Delimit Scope pr_scope with pr.
    Notation "h :: t" := (PRcons _ _ h t) (at level 60, right associativity)
        : pr_scope.
    Notation "[ x ]" := (PRcons _ _ x (PRnil _)) : pr_scope.

    Notation "[ x ; y ; .. ; z ]" :=
      (PRcons _ _ x (PRcons _ _ y .. (PRcons _ _ z (PRnil _)) ..)) : pr_scope.

    Notation PRcomp f v := (composeFunc _ _ v f).

    Notation PRrec f0 fS := (primRecFunc _ f0 fS).

Popular projections
    Notation pi1_1 := (projFunc 1 0 (le_n 1)).

    Notation pi1_2 := (projFunc 2 1 (le_n 2)).
    Notation pi2_2 := (projFunc 2 0 (le_S 1 1 (le_n 1))).

    Notation pi1_3 := (projFunc 3 2 (le_n 3)).
    Notation pi2_3 := (projFunc 3 1 (le_S 2 2 (le_n 2))).
    Notation pi3_3 := (projFunc 3 0 (le_S 1 2 (le_S 1 1 (le_n 1)))).

  End PRNotations.


Import PRNotations.

Scheme PrimRec_PrimRecs_rec := Induction for PrimRec Sort Set
  with PrimRecs_PrimRec_rec := Induction for PrimRecs Sort Set.

Arguments PrimRec_PrimRecs_rec P P0 : rename.
Arguments PrimRecs_PrimRec_rec P P0 : rename.


Scheme PrimRec_PrimRecs_ind := Induction for PrimRec Sort Prop
    with PrimRecs_PrimRec_ind := Induction for PrimRecs Sort Prop.

Arguments PrimRec_PrimRecs_ind P P0 : rename.
Arguments PrimRecs_PrimRec_ind P P0 : rename.

Check PrimRec_PrimRecs_ind.

Semantics

Constants


Fixpoint evalConstFunc (n m : nat) {struct n} : naryFunc n :=
  match n return (naryFunc n) with
  | Om
  | S n'fun _evalConstFunc n' m
  end.

Projections

The parameters are numbered in opposite order. So proj(2,0)(a,b) = b.

Fixpoint evalProjFunc (n : nat) :
   m : nat, m < n naryFunc n :=
  match n return ( m : nat, m < n naryFunc n) with
  | Ofun (m : nat) (l : m < 0) ⇒ False_rec _ (Nat.nlt_0_r _ l)
  | S n'
      fun (m : nat) (l : m < S n') ⇒
      match eq_nat_dec m n' with
      | left _fun a : natevalConstFunc _ a
      | right l1
          fun _
          evalProjFunc n' m
            match Compat815.le_lt_or_eq _ _
                    (Compat815.lt_n_Sm_le _ _ l) with
            | or_introl l2l2
            | or_intror l2False_ind _ (l1 l2)
            end
      end
  end.

Irrelevance of the proof that m < n

Lemma evalProjFuncInd :
  (n m : nat) (p1 p2 : m < n),
 evalProjFunc n m p1 = evalProjFunc n m p2.

Applies an m-ary function to the vector l


Fixpoint evalList (m : nat) (l : Vector.t nat m) {struct l} :
  naryFunc m nat :=
  match l in (Vector.t _ m) return (naryFunc m nat) with
  | Vector.nilfun x : naryFunc 0 ⇒ x
  | Vector.cons a n l'
    fun x : naryFunc (S n) ⇒ evalList n l' (x a)
  end.


Fixpoint evalOneParamList (n m a : nat) (l : Vector.t (naryFunc (S n)) m)
 {struct l} : Vector.t (naryFunc n) m :=
  match l in (Vector.t _ m) return (Vector.t (naryFunc n) m) with
  | Vector.nilVector.nil (naryFunc n)
  | Vector.cons f m' l'
      Vector.cons _ (f a) m' (evalOneParamList n m' a l')
  end.

Function composition


Fixpoint evalComposeFunc (n : nat) :
   m : nat,
    Vector.t (naryFunc n) m naryFunc m naryFunc n :=
  match
    n
    return
    ( m : nat,
        Vector.t (naryFunc n) m naryFunc m naryFunc n)
  with
  | OevalList
  | S n'
      fun (m : nat) (l : Vector.t (naryFunc (S n')) m)
          (f : naryFunc m) (a : nat) ⇒
        evalComposeFunc n' m (evalOneParamList _ _ a l) f
  end.

Fixpoint compose2 (n : nat) :
  naryFunc n naryFunc (S n) naryFunc n :=
  match n return (naryFunc n naryFunc (S n) naryFunc n) with
  | Ofun (a : nat) (g : nat nat) ⇒ g a
  | S n'
      fun (f : naryFunc (S n')) (g : naryFunc (S (S n'))) (a : nat) ⇒
        compose2 n' (f a) (fun x : natg x a)
  end.

Primitive recursion


Fixpoint evalPrimRecFunc (n : nat) (g : naryFunc n)
 (h : naryFunc (S (S n))) (a : nat) {struct a} : naryFunc n :=
  match a with
  | Og
  | S a'compose2 _ (evalPrimRecFunc n g h a') (h a')
  end.

The interpretation function


Fixpoint evalPrimRec (n : nat) (f : PrimRec n) {struct f} :
 naryFunc n :=
  match f in (PrimRec n) return (naryFunc n) with
  | succFuncS
  | zeroFunc ⇒ 0
  | projFunc n m pfevalProjFunc n m pf
  | composeFunc n m l f
      evalComposeFunc n m (evalPrimRecs _ _ l) (evalPrimRec _ f)
  | primRecFunc n g h
      evalPrimRecFunc n (evalPrimRec _ g) (evalPrimRec _ h)
  end
 
 with evalPrimRecs (n m : nat) (fs : PrimRecs n m) {struct fs} :
 Vector.t (naryFunc n) m :=
  match fs in (PrimRecs n m) return (Vector.t (naryFunc n) m) with
  | PRnil aVector.nil (naryFunc a)
  | PRcons a b g gs
    Vector.cons _ (evalPrimRec _ g) _ (evalPrimRecs _ _ gs)
  end.

Notation PReval f := (evalPrimRec _ f).
Notation PRevalN fs := (evalPrimRecs _ _ fs).

p is a correct implementation of f in PrimRec n

Definition PRcorrect {n:nat}(p:PrimRec n)(f: naryFunc n) :=
  PReval p =x= f.


Definition extEqualVectorGeneral (n m : nat) (l : Vector.t (naryFunc n) m) :
   (m' : nat) (l' : Vector.t (naryFunc n) m'), Prop.
Defined.

Every element of l is extensionally equal to the element of l' at the same position

Definition extEqualVector n:
   m (l l' : Vector.t (naryFunc n) m), Prop.

Lemma extEqualVectorRefl (n m: nat):
   (l : Vector.t (naryFunc n) m), extEqualVector n m l l.

Lemma extEqualOneParamList :
   (n m : nat) (l1 l2 : Vector.t (naryFunc (S n)) m) (c : nat),
    extEqualVector (S n) m l1 l2
    extEqualVector n m (evalOneParamList n m c l1)
      (evalOneParamList n m c l2).

Lemma extEqualCompose :
   (n m : nat) (l1 l2 : Vector.t (naryFunc n) m)
         (f1 f2 : naryFunc m),
    extEqualVector n m l1 l2
    f1 =x= f2
    evalComposeFunc n m l1 f1 =x= evalComposeFunc n m l2 f2.

Lemma extEqualCompose2 :
   (n : nat) (f1 f2 : naryFunc n),
     f1 =x= f2
     g1 g2 : naryFunc (S n),
       g1 =x= g2
       compose2 n f1 g1 =x= compose2 n f2 g2.

Lemma extEqualPrimRec :
   (n : nat) (g1 g2 : naryFunc n) (h1 h2 : naryFunc (S (S n))),
     g1 =x= g2 h1 =x= h2
       (evalPrimRecFunc n g1 h1: naryFunc (S n)) =x=
         evalPrimRecFunc n g2 h2.

Predicates "to be primitive recursive"


Class isPR (n : nat) (f : naryFunc n) : Set :=
  is_pr : {p : PrimRec n | extEqual n (PReval p) f}.

Definition fun2PR {n:nat}(f: naryFunc n)
  {p: isPR _ f}: PrimRec n := proj1_sig p.

Class isPRrel (n : nat) (R : naryRel n) : Set :=
  is_pr_rel: isPR n (charFunction n R).

#[export] Instance succIsPR : isPR 1 S.

#[export] Instance const0_NIsPR (n:nat): isPR 0 n.

#[export] Instance const1_NIsPR n: isPR 1 (fun _n).

Usual projections (in curried form) are primitive recursive


#[export] Instance idIsPR : isPR 1 (fun x : natx).

#[export] Instance pi1_2IsPR : isPR 2 (fun a b : nata).

#[export] Instance pi2_2IsPR : isPR 2 (fun a b : natb).

#[export] Instance pi1_3IsPR : isPR 3 (fun a b c : nata).

#[export] Instance pi2_3IsPR : isPR 3 (fun a b c : natb).

#[export] Instance pi3_3IsPR : isPR 3 (fun a b c : natc).

#[export] Instance pi1_4IsPR : isPR 4 (fun a b c d : nata).

#[export] Instance pi2_4IsPR : isPR 4 (fun a b c d : natb).

#[export] Instance pi3_4IsPR : isPR 4 (fun a b c d : natc).

#[export] Instance pi4_4IsPR : isPR 4 (fun a b c d : natd).

Composition lemmas


#[export] Instance filter01IsPR (g : nat nat) (H : isPR 1 g):
  isPR 2 (fun a b : natg b).

#[export] Instance filter10IsPR (g : nat nat) (H: isPR 1 g):
  isPR 2 (fun a b : natg a).

#[export] Instance filter100IsPR(g : nat nat)(H: isPR 1 g) :
  isPR 3 (fun a b c : natg a).

#[export] Instance filter010IsPR (g : nat nat)(H: isPR 1 g):
  isPR 3 (fun a b c : natg b).

#[export] Instance filter001IsPR (g:nat nat)(H: isPR 1 g) :
 isPR 3 (fun a b c : natg c).

#[export] Instance filter011IsPR (g: nat nat nat)(H: isPR 2 g):
   isPR 3 (fun a b c : natg b c).

#[export] Instance filter110IsPR(g : nat nat nat) :
  isPR 2 g isPR 3 (fun a b c : natg a b).

#[export] Instance filter101IsPR :
   g : nat nat nat, isPR 2 g
                                isPR 3 (fun a b c : natg a c).

#[export] Instance filter0011IsPR (g : nat nat nat) :
  isPR 2 g isPR 4 (fun a b c d : natg c d).

#[export] Instance filter1000IsPR (g : nat nat):
  isPR 1 g isPR 4 (fun a b c d : natg a).

#[export] Instance filter1011IsPR (g : nat nat nat nat) :
 isPR 3 g isPR 4 (fun a b c d : natg a c d).

#[export] Instance filter1100IsPR (g : nat nat nat) :
  isPR 2 g isPR 4 (fun a b c d : natg a b).

#[export] Instance compose1_1IsPR (f : nat nat):
  isPR 1 f
   g : nat nat, isPR 1 g isPR 1 (fun x : natg (f x)).

#[export] Instance compose1_2IsPR :
   f : nat nat,
    isPR 1 f
     f' : nat nat,
      isPR 1 f'
       g : nat nat nat,
        isPR 2 g isPR 1 (fun x : natg (f x) (f' x)).

#[export] Instance compose1_3IsPR :
  f1 : nat nat,
 isPR 1 f1
  f2 : nat nat,
 isPR 1 f2
  f3 : nat nat,
 isPR 1 f3
  g : nat nat nat nat,
 isPR 3 g isPR 1 (fun x : natg (f1 x) (f2 x) (f3 x)).

#[export] Instance compose2_1IsPR :
   f : nat nat nat,
    isPR 2 f
     g : nat nat, isPR 1 g
                           isPR 2 (fun x y : natg (f x y)).

#[export] Instance compose2_2IsPR :
  f : nat nat nat,
 isPR 2 f
  g : nat nat nat,
 isPR 2 g
  h : nat nat nat,
 isPR 2 h isPR 2 (fun x y : nath (f x y) (g x y)).

#[export] Instance compose2_3IsPR :
   f1 : nat nat nat,
    isPR 2 f1
     f2 : nat nat nat,
      isPR 2 f2
       f3 : nat nat nat,
        isPR 2 f3
         g : nat nat nat nat,
          isPR 3 g
          isPR 2 (fun x y : natg (f1 x y) (f2 x y) (f3 x y)).

#[export] Instance compose2_4IsPR :
  f1 : nat nat nat,
 isPR 2 f1
  f2 : nat nat nat,
 isPR 2 f2
  f3 : nat nat nat,
 isPR 2 f3
  f4 : nat nat nat,
 isPR 2 f4
  g : nat nat nat nat nat,
 isPR 4 g
 isPR 2 (fun x y : natg (f1 x y) (f2 x y) (f3 x y) (f4 x y)).

#[export] Instance compose3_1IsPR :
   f : nat nat nat nat,
    isPR 3 f
     g : nat nat, isPR 1 g
                           isPR 3 (fun x y z : natg (f x y z)).

#[export] Instance compose3_2IsPR :
   f1 : nat nat nat nat,
    isPR 3 f1
     f2 : nat nat nat nat,
      isPR 3 f2
       g : nat nat nat,
        isPR 2 g isPR 3 (fun x y z : natg (f1 x y z) (f2 x y z)).

#[export] Instance compose3_3IsPR :
  f1 : nat nat nat nat,
 isPR 3 f1
  f2 : nat nat nat nat,
 isPR 3 f2
  f3 : nat nat nat nat,
 isPR 3 f3
  g : nat nat nat nat,
 isPR 3 g isPR 3 (fun x y z : natg (f1 x y z) (f2 x y z) (f3 x y z)).

#[export] Instance compose4_2IsPR :
  f1 : nat nat nat nat nat,
 isPR 4 f1
  f2 : nat nat nat nat nat,
 isPR 4 f2
  g : nat nat nat,
 isPR 2 g isPR 4 (fun w x y z : natg (f1 w x y z) (f2 w x y z)).

#[export] Instance compose4_3IsPR :
  f1 : nat nat nat nat nat,
 isPR 4 f1
  f2 : nat nat nat nat nat,
 isPR 4 f2
  f3 : nat nat nat nat nat,
 isPR 4 f3
  g : nat nat nat nat,
 isPR 3 g
 isPR 4 (fun w x y z : natg (f1 w x y z) (f2 w x y z) (f3 w x y z)).

#[export] Instance swapIsPR :
   f : nat nat nat, isPR 2 f isPR 2 (fun x y : natf y x).

#[export] Instance indIsPR :
   f : nat nat nat,
    isPR 2 f
     g : nat,
      isPR 1
           (fun a : natnat_rec (fun _ : natnat) g
                             (fun x y : natf x y) a).

#[export] Instance ind1ParamIsPR :
   f : nat nat nat nat,
    isPR 3 f
     g : nat nat,
      isPR 1 g
      isPR 2
           (fun a b : nat
              nat_rec (fun n : natnat) (g b) (fun x y : natf x y b) a).

#[export] Instance ind2ParamIsPR :
   f : nat nat nat nat nat,
    isPR 4 f
     g : nat nat nat,
      isPR 2 g
      isPR 3
        (fun a b c : nat
           nat_rec (fun n : natnat) (g b c) (fun x y : natf x y b c) a).

#[export] Instance plusIndIsPR : isPR 3 (fun n fn b : natS fn).

#[export] Instance plusIsPR : isPR 2 plus.

#[export] Instance multIndIsPR : isPR 3 (fun n fn b : natfn + b).

#[export] Instance multIsPR : isPR 2 mult.

#[export] Instance predIsPR : isPR 1 pred.

#[export] Instance minusIndIsPR : isPR 3 (fun n fn b : natpred fn).

#[export] Instance minusIsPR : isPR 2 minus.

Definition notZero (a : nat) :=
  nat_rec (fun n : natnat) 0 (fun x y : nat ⇒ 1) a.

#[export] Instance notZeroIsPR : isPR 1 notZero.

Definition ltBool (a b : nat) : bool :=
  if le_lt_dec b a then false else true.

Lemma ltBoolTrue : a b : nat, ltBool a b = true a < b.

Lemma ltBoolFalse : a b : nat, ltBool a b = false ¬ a < b.

#[export] Instance ltIsPR : isPRrel 2 ltBool.

#[export] Instance maxIsPR : isPR 2 max.

#[export] Instance gtIsPR : isPRrel 2 (fun a b : natltBool b a).

Remark replaceCompose2 :
  (n : nat) (a b a' b' : naryFunc n) (c c' : naryFunc 2),
 extEqual n a a'
 extEqual n b b'
 extEqual 2 c c'
 extEqual
   n
   (evalComposeFunc _ _
                    (Vector.cons _ a _
                                 (Vector.cons _ b _
                                              (Vector.nil (naryFunc n)))) c)
   (evalComposeFunc _ _
                    (Vector.cons _ a' _
                                 (Vector.cons _ b' _
                                              (Vector.nil (naryFunc n)))) c').

Definition orRel (n : nat) (R S : naryRel n) : naryRel n.

Lemma orRelPR :
   (n : nat) (R R' : naryRel n),
    isPRrel n R isPRrel n R' isPRrel n (orRel n R R').

Definition andRel (n : nat) (R S : naryRel n) : naryRel n.

Lemma andRelPR :
   (n : nat) (R R' : naryRel n),
    isPRrel n R isPRrel n R' isPRrel n (andRel n R R').

Definition notRel (n : nat) (R : naryRel n) : naryRel n.

Lemma notRelPR (n : nat) (R : naryRel n):
  isPRrel n R isPRrel n (notRel n R).

Fixpoint bodd (n : nat) : bool :=
  match n with
  | Ofalse
  | S n'negb (bodd n')
  end.

#[export] Instance boddIsPR : isPRrel 1 bodd.

Lemma nat_eqb_false (a b: nat) : a b Nat.eqb a b = false.

#[local] Instance neqIsPR : isPRrel 2 (fun a b : natnegb (Nat.eqb a b)).

#[export] Instance eqIsPR : isPRrel 2 Nat.eqb.

Definition leBool (a b : nat) : bool :=
  if le_lt_dec a b then true else false.

#[export] Instance leIsPR : isPRrel 2 leBool.

Section Ignore_Params.

  Fixpoint ignoreParams (n m : nat) (f : naryFunc n) {struct m} :
    naryFunc (m + n) :=
    match m return (naryFunc (m + n)) with
    | Of
    | S xfun _ignoreParams n x f
    end.

  Definition projectionListPR (n m : nat) (p : m n) : PrimRecs n m.

  Definition projectionList (n m : nat) (p : m n) :
    Vector.t (naryFunc n) m := evalPrimRecs n m (projectionListPR n m p).

  Lemma projectionListInd :
     (n m : nat) (p1 p2 : m n),
      projectionList n m p1 = projectionList n m p2.

  Lemma projectionListApplyParam :
     (m n c : nat) (p1 : m n) (p2 : m S n),
      extEqualVector _ _ (projectionList n m p1)
                     (evalOneParamList n m c (projectionList (S n) m p2)).

  Lemma projectionListId :
     (n : nat) (f : naryFunc n) (p : n n),
      extEqual n f (evalComposeFunc n n (projectionList n n p) f).

  #[export] Instance ignoreParamsIsPR :
     (n m : nat) (f : naryFunc n),
      isPR _ f isPR _ (ignoreParams n m f).

End Ignore_Params.

Lemma reduce1stCompose :
   (c n m : nat) (v : Vector.t (naryFunc n) m) (g : naryFunc (S m)),
    extEqual n
      (evalComposeFunc n _ (Vector.cons (naryFunc n)
                              (evalConstFunc n c) _ v) g)
      (evalComposeFunc n _ v (g c)).

Lemma reduce2ndCompose :
   (c n m : nat) (v : Vector.t (naryFunc n) m) (n0 : naryFunc n)
         (g : naryFunc (S (S m))),
    extEqual n
      (evalComposeFunc n _
         (Vector.cons
            (naryFunc n) n0 _
            (Vector.cons (naryFunc n)
               (evalConstFunc n c) _ v))
         g)
      (evalComposeFunc n _ (Vector.cons (naryFunc n) n0 _ v)
         (fun x : natg x c)).

Lemma evalPrimRecParam :
   (n c d : nat) (g : naryFunc (S n)) (h : naryFunc (S (S (S n)))),
     evalPrimRecFunc n (g d) (fun x y : nath x y d) c =x=
      evalPrimRecFunc (S n) g h c d.

#[export] Instance compose2IsPR :
   (n : nat) (f : naryFunc n) (p : isPR n f) (g : naryFunc (S n))
         (q : isPR (S n) g), isPR n (compose2 n f g).

#[export] Instance compose1_NIsPR :
   (n : nat) (g : naryFunc (S n)),
    isPR (S n) g
     f : naryFunc 1, isPR 1 f
                           isPR (S n) (fun x : natg (f x)).

Definition switchPR : naryFunc 3 :=
  fun n x ymatch n with 0 ⇒ y | _x end.

#[export] Instance switchIsPR : isPR 3 switchPR.

Fixpoint boundedSearchHelp (P : naryRel 1) (b : nat) {struct b} : nat :=
  match b with
  | O ⇒ 0
  | S b'let q := boundedSearchHelp P b'
            in
      match eq_nat_dec q b' with
      | left _match P b' with
                  | trueb'
                  | falseS b'
                  end
      | right _q
      end
  end.

If there exists some x b such that (P b x), returns x Otherwise, returns b

Definition boundedSearch (P : naryRel 2) (b : nat) : nat :=
  boundedSearchHelp (P b) b.

Module Examples.

  Definition sqrtHelp (n: nat) :=
    boundedSearch (fun _ xNat.eqb (x × x) n) (S (n / 2)).

  Definition exact_sqrt (n: nat) :=
    let q := sqrtHelp n
    in if Nat.eqb (q × q) n then Some q else None.


  End Examples.

  Lemma boundedSearch1 :
     (P : naryRel 2) (b x : nat), x < boundedSearch P b
                                        P b x = false.

Lemma boundedSearch2 :
   (P : naryRel 2) (b : nat),
    boundedSearch P b = b P b (boundedSearch P b) = true.

#[export] Instance boundSearchIsPR :
   P : naryRel 2,
    isPRrel 2 P isPR 1 (boundedSearch P).

Definition iterate (g : nat nat) :=
  nat_rec (fun _nat nat) (fun x : natx)
          (fun (_ : nat) (rec : nat nat) (x : nat) ⇒ g (rec x)).

#[export] Instance iterateIsPR :
   g : nat nat, isPR 1 g
                          n : nat, isPR 1 (iterate g n).

#[export] Instance isPRTrans (n:nat) (f g : naryFunc n):
  f =x= g isPR n f isPR n g.

#[export] Instance isPRextEqual (n:nat) (f g : naryFunc n):
  isPR n f f =x= g isPR n g.