Register often used container types with helpful assumption and proof functions

Require Import helperGen.

Require Import MetaCoq.Template.All.

From MetaCoq.PCUIC Require Import
     PCUICAst PCUICAstUtils PCUICInduction
     PCUICLiftSubst PCUICEquality
     PCUICUnivSubst PCUICTyping PCUICGeneration.

From MetaCoq.PCUIC Require Import PCUICToTemplate.
From MetaCoq.PCUIC Require Import TemplateToPCUIC.

Require Import List String.
Import ListNotations MonadNotation Nat.
Require Import MetaCoq.Template.Pretty.
Require Import MetaCoq.PCUIC.PCUICPretty.

From Equations Require Import Equations.
Require Import nested_datatypes.

Open Scope string_scope.

Print prod.
Print VectorDef.t.

(* list satisfy *)
Inductive is_list A (PA:AType) : list A Type :=
| is_nil : is_list A PA nil
| is_cons a (pa: PA a) l (pl:is_list A PA l): is_list A PA (a::l).

Definition {X} (P:XType) (xs:list X) := is_list _ P xs.

Lemma is_list_in {X} (P:XProp) xs : is_list X P xs x, In x xs P x.
Proof.
  intros.
  induction .
  - now contradict H.
  - destruct H as [|H].
    + apply pa.
    + apply , H.
Qed.


Definition {X} (P:XType) (f: x, P x) (xs:list X) : P xs.
Proof.
  unfold .
  induction xs.
  - constructor.
  - constructor.
    + apply f.
    + apply IHxs.
Defined.


Fixpoint F (n : ) : := (fun _ O)(F n).
Compute (F 2).

Definition prodAssumption X (Px:XType) Y (Py:YType) (t:X*Y) : Type := let (x,y) := t in (Px x) * (Py y).
Definition prodProof X (Px:XType) (fx: x, Px x) Y (Py:YType) (fy: y, Py y) (t:X*Y) : prodAssumption _ Px _ Py t.
Proof.
  destruct t.
  cbn. split;[apply fx | apply fy].
Defined.


Compute ( T p pd t,prodAssumption T p pd t).

Definition listAssumption {X} (P:XProp) (xs:list X) := t, In t xs P t.

Definition listProof {X} (P:XProp) (f: x, P x) (xs:list X) : listAssumption P xs :=
(list_ind (fun : list X listAssumption P )
            (fun (t : X) ( : In t []) match return (P t) with
                                                  end)
            (fun (a : X) ( : list X) (IHxs : listAssumption P )
               (t : X) ( : In t (a :: ))
             match with
             | or_introl Coq.Init.Logic.eq_ind a (fun : X P ) (f a) t
             | or_intror IHxs t
             end) xs).

(* invalid f only for smaller instances *)
(* Goal forall X (P:X->Prop) (f:forall x, P x) (xs:list X) , listAssumption P xs. *)
(* Proof. *)
(*   unfold listAssumption. *)
(*   intros. *)
(*   apply f. *)
(* Qed. *)

Inductive is_prod X Y (Px : XType) (Py: Y Type) : X*YType :=
| is_pair x y (px:Px x) (py:Py y) : is_prod X Y Px Py (x,y).
Definition {X Y} (Px:XType) (Py:YType) (fx: x, Px x) (fy: y, Py y) (t:X*Y) : is_prod _ _ Px Py t.
Proof.
  destruct t.
  cbn. split;[apply fx | apply fy].
Defined.


Definition vec:=Vector.t.

Inductive is_vec {X:Type} (Px: XType) : n, vec X n Type :=
| is_nilV : is_vec Px 0 (@Vector.nil _)
| is_consV (x:X) (px:Px x) n (xs:Vector.t X n) (pxs:is_vec Px n xs): is_vec Px (S n) (Vector.cons X x n xs).

Definition vecProof {X} (P:XType) (f: x, P x) n (xs:vec X n) : is_vec P n xs.
Proof.
  induction xs.
  - constructor.
  - constructor.
    + apply f.
    + apply IHxs.
Defined.


Definition rtree_ind_MC_Test
     : (A : Type) (p : rtree A Type),
       ( a : A, p (Leaf A a))
       ( l : list (rtree A), is_list (rtree A) p l p (Node A l)) inst : rtree A, p inst :=
fun (A : Type) (p : rtree A Type) (H_Leaf : a : A, p (Leaf A a))
  (H_Node : l : list (rtree A), is_list (rtree A) p l p (Node A l))
fix f (inst : rtree A) : p inst :=
  match inst as return (p ) with
  | @Leaf _ a H_Leaf a
  | @Node _ l
      H_Node l
        ((fix F ( : list (rtree A)) : is_list (rtree A) p :=
            match as return (is_list (rtree A) p ) with
            | [] is_nil (rtree A) p
            | y :: is_cons (rtree A) p y (f y) (F )
            end) l)
  end.

Inductive is_rtree X (Px : X Type) : rtree X Type :=
| is_Leaf x (px: Px x) : is_rtree X Px (Leaf X x)
| is_Node xs (pxs: is_list (rtree X) (is_rtree X Px) xs) : is_rtree X Px (Node X xs).

Definition X (P:XType) (f: x, P x) (r:rtree X) : is_rtree X P r.
Proof.
  revert r.
  refine (fix IH r := _).
  destruct r.
  - constructor. apply f.
  - constructor.
    apply .
    apply IH.
Defined.


Definition rtreeProof X (P:XType) (f: x, P x) (r:rtree X) : is_rtree X P r.
Proof.
  induction r using rtree_ind_MC_Test.
  - constructor. apply f.
  - constructor. apply .
Defined.


Definition roseTreeO3_ind_MC :=
fun (X : Type) (p : X Prop)
  (H_treeO3 : (x : X) (xs : list X)
                (xxs : X),
              p xxs
               xsxs : list ( X),
              is_list ( X)
                (fun H : X p H) xsxs
              p (treeO3 X x xs xxs xsxs))
fix f (inst : X) : p inst :=
  match inst as return (p ) with
  | @ _ x xs xxs xsxs
      H_treeO3 x xs xxs (f xxs) xsxs
        ((fix F (l : list ( X)) :
            is_list ( X)
              (fun H : X p H) l :=
            match
              l as
              return
                (is_list ( X)
                   (fun H : X p H) )
            with
            | []
                is_nil ( X)
                  (fun H : X p H)
            | y ::
                is_cons ( X)
                  (fun H : X p H) y
                  (f y) (F )
            end) xsxs)
  end.

Inductive list (A : Type) (Aᵗ : A Type) : list A Type :=
    nil : list A A [] | cons : H : A, A H : list A, list A A list A A (H :: ).

Inductive (X : Type) (Xᵗ : X Type) : X Prop :=
    treeO3 : x : X,
               X x
                xs : list X,
               is_list X X xs
                xxs : X,
                X X xxs
                xsxs : list ( X),
               is_list ( X) ( X X) xsxs
                X X (treeO3 X x xs xxs xsxs).

Definition rtreeO3Proof X (P:XType) (f: x, P x) (r: X) : X P r.
Proof.
  induction r using roseTreeO3_ind_MC.
  - constructor.
    + apply f.
    + apply .
      apply f.
    + apply IHr.
    + apply . (* alternative: listProof2 & IH explizit with fix *)
Restart.
  revert r.
  refine (fix IH r := _).
  destruct r.
  - constructor.
    + apply f.
    + apply .
      apply f.
    + apply IH.
    + apply .
      apply IH.
Qed.


Inductive Acc (A : Type) (Aᵗ : A Type) (R : A A Prop)
(Rᵗ : H : A,
      A H : A, A R H Prop)
(x : A) (xᵗ : A x) : Acc R x Prop :=
    Acc_intro :
                   H : y : A, R y x Acc R y,
                 ( (y : A) (yᵗ : A y)
                    ( : R y x),
                  R y y x x
                  Acc A A R R y y (H y ))
                 Acc A A R R x x (Acc_intro x H).

Definition AccProof (A : Type) (Aᵗ : A Type) (R : A A Prop)
(Rᵗ : H : A,
      A H : A, A R H Prop)
(x : A) (xᵗ : A x) (r : Acc R x) : Acc A A R R x x r.
Proof.
  intros.
  revert x xr.
  refine (fix IH x xr := _).
  destruct r.
  constructor.
  intros.
  apply IH.
Defined.


Inductive bool : bool Set :=
  true : bool true | false : bool false.
Inductive : Set :=
    O : 0
  | S : H : , H (S H).

Inductive
(b : bool) (bᵗ : bool b)
(X : Type) (Xᵗ : X Type) (n : )
(nᵗ : n)
  : b X n Prop :=
  c4 : b b X X n n (c4 b X n).

Definition containerInd4Proof (b : bool) (bᵗ : bool b)
(X : Type) (Xᵗ : X Type) (n : )
(nᵗ : n) (a: b X n) :
   b b X X n n a.
Proof.
  destruct a.
  constructor.
Defined.


Inductive
vec (A : Type) (Aᵗ : A Type)
  : H : , H vec A H Type :=
    vecnil : vec A A 0 O (@Vector.nil A)
  | veccons : H : A,
               A H
                (n : ) (nᵗ : n)
                 ( : vec A n),
               vec A A n n
               vec A A (S n) (S n n)
                    (@Vector.cons A H n ).

Definition
           (A : Type) (Aᵗ : A Type) (fA: a, A a)
           (n : ) (H: n) (fn: n, n)
           (a:vec A n) :
  vec A A n H a.
Proof.
  induction a in H, fn |- *.
  - depelim H.
    constructor.
  - depelim H.
    constructor.
    + apply fA.
    + apply IHa.
      apply fn.
Qed.


Inductive
vecᵗ' (A : Type) (Aᵗ : A Type)
  : H : , vec A H Type :=
    vecnilᵗ' : vecᵗ' A A 0 (@Vector.nil A)
  | vecconsᵗ' : H : A,
               A H
                (n : )
               (* (nᵗ : natᵗ n) *)
                 ( : vec A n),
               vecᵗ' A A n
               vecᵗ' A A (S n)
                    (@Vector.cons A H n ).

Definition
           (A : Type) (Aᵗ : A Type) (fA: a, A a)
           (n : )
           (* (fn: forall n, natᵗ n) *)
           (a:vec A n) :
  vecᵗ' A A n a.
Proof.
  induction a.
  - constructor.
  - constructor.
    + apply fA.
    + apply IHa.
Qed.


Print mfixpoint.
Check list.

Print def.

Definition defAssumption {X} (P:XType) (x:def X) :=
  prod
    (P (dtype x))
    (P (dbody x)).
Definition defProof {X} (P:XType) (f: x, P x) (x:def X) : defAssumption P x.
  now constructor.
Defined.

Definition mfixpointAssumption {X} (P:XType) (x:mfixpoint X) := is_list _ (defAssumption P) x.
Definition mfixpointProof {X} (P:XType) (f: x, P x) (x:mfixpoint X) : mfixpointAssumption P x.
  now apply , defProof.
Defined.

Print All_Forall.All.
Print is_list.
Print .

Instance listInst : registered list :=
{|
    assumption := @listAssumption2;
    proof := @listProof2
|}.

Instance prodInst : registered prod :=
{|
    assumption := @prodAssumption;
    proof := @prodProof
|}.

Instance vecInst : registered VectorDef.t :=
{|
    assumption := @is_vec;
    proof := @vecProof
|}.

Instance rtreeInst : registered rtree :=
{|
    assumption := @is_rtree;
    proof := @rtreeProof
|}.

Instance containerInd4Inst : registered :=
{|
    assumption := @containerInd4ᵗ;
    proof := @containerInd4Proof
|}.

Instance defInst : registered def :=
{|
    assumption := @defAssumption;
    proof := @defProof
|}.

Instance mfixpointInst : registered mfixpoint :=
{|
    assumption := @mfixpointAssumption;
    proof := @mfixpointProof
|}.