From Undecidability.HOU Require Import std.std.
From Undecidability.HOU Require Export unscoped.

Set Default Proof Using "Type".

Section Terms.

  Inductive type : Type :=
  | typevar : type
  | arr : type type type .

  Structure Const :=
  {
    const_type:> Type;
    const_dis: Dis const_type;
    ctype: const_type type
  }.

  Context {X: Const}.

Lemma congr_typevar { s0 : } { t0 : } : = typevar = typevar .
Proof. congruence. Qed.


Lemma congr_arr { s0 : type } { s1 : type } { t0 : type } { t1 : type } : = = arr = arr .
Proof. congruence. Qed.

Inductive exp : Type :=
  | var_exp : fin exp
  | const : X exp
  | lam : exp exp
  | app : exp exp exp .

Lemma congr_const { s0 : X } { t0 : X } : = const = const .
Proof. congruence. Qed.

Lemma congr_lam { s0 : exp } { t0 : exp } : = lam = lam .
Proof. congruence. Qed.

Lemma congr_app { s0 : exp } { s1 : exp } { t0 : exp } { t1 : exp } : = = app = app .
Proof. congruence. Qed.

Definition upRen_exp_exp (xi : fin fin ) : _ :=
  up_ren .

Fixpoint ren_exp (xiexp : fin fin ) (s : exp ) : _ :=
    match s with
    | var_exp s (var_exp ) (xiexp s)
    | const const
    | lam lam (ren_exp (upRen_exp_exp xiexp) )
    | app app (ren_exp xiexp ) (ren_exp xiexp )
    end.

Definition up_exp_exp (sigma : fin exp ) : _ :=
  scons ((var_exp ) var_zero) (funcomp (ren_exp shift) ).

Fixpoint subst_exp (sigmaexp : fin exp ) (s : exp ) : _ :=
    match s with
    | var_exp s sigmaexp s
    | const const
    | lam lam (subst_exp (up_exp_exp sigmaexp) )
    | app app (subst_exp sigmaexp ) (subst_exp sigmaexp )
    end.

Definition upId_exp_exp (sigma : fin exp ) (Eq : x, x = (var_exp ) x) : x, (up_exp_exp ) x = (var_exp ) x :=
   n match n with
  | S n ap (ren_exp shift) (Eq n)
  | 0 eq_refl
  end.

Fixpoint idSubst_exp (sigmaexp : fin exp ) (Eqexp : x, sigmaexp x = (var_exp ) x) (s : exp ) : subst_exp sigmaexp s = s :=
    match s with
    | var_exp s Eqexp s
    | const congr_const (eq_refl )
    | lam congr_lam (idSubst_exp (up_exp_exp sigmaexp) (upId_exp_exp (_) Eqexp) )
    | app congr_app (idSubst_exp sigmaexp Eqexp ) (idSubst_exp sigmaexp Eqexp )
    end.

Definition upExtRen_exp_exp (xi : fin fin ) (zeta : fin fin ) (Eq : x, x = x) : x, (upRen_exp_exp ) x = (upRen_exp_exp ) x :=
   n match n with
  | S n ap shift (Eq n)
  | 0 eq_refl
  end.

Fixpoint extRen_exp (xiexp : fin fin ) (zetaexp : fin fin ) (Eqexp : x, xiexp x = zetaexp x) (s : exp ) : ren_exp xiexp s = ren_exp zetaexp s :=
    match s with
    | var_exp s ap (var_exp ) (Eqexp s)
    | const congr_const (eq_refl )
    | lam congr_lam (extRen_exp (upRen_exp_exp xiexp) (upRen_exp_exp zetaexp) (upExtRen_exp_exp (_) (_) Eqexp) )
    | app congr_app (extRen_exp xiexp zetaexp Eqexp ) (extRen_exp xiexp zetaexp Eqexp )
    end.

Definition upExt_exp_exp (sigma : fin exp ) (tau : fin exp ) (Eq : x, x = x) : x, (up_exp_exp ) x = (up_exp_exp ) x :=
   n match n with
  | S n ap (ren_exp shift) (Eq n)
  | 0 eq_refl
  end.

Fixpoint ext_exp (sigmaexp : fin exp ) (tauexp : fin exp ) (Eqexp : x, sigmaexp x = tauexp x) (s : exp ) : subst_exp sigmaexp s = subst_exp tauexp s :=
    match s with
    | var_exp s Eqexp s
    | const congr_const (eq_refl )
    | lam congr_lam (ext_exp (up_exp_exp sigmaexp) (up_exp_exp tauexp) (upExt_exp_exp (_) (_) Eqexp) )
    | app congr_app (ext_exp sigmaexp tauexp Eqexp ) (ext_exp sigmaexp tauexp Eqexp )
    end.

Fixpoint compRenRen_exp (xiexp : fin fin ) (zetaexp : fin fin ) (rhoexp : fin fin ) (Eqexp : x, (funcomp zetaexp xiexp) x = rhoexp x) (s : exp ) : ren_exp zetaexp (ren_exp xiexp s) = ren_exp rhoexp s :=
    match s with
    | var_exp s ap (var_exp ) (Eqexp s)
    | const congr_const (eq_refl )
    | lam congr_lam (compRenRen_exp (upRen_exp_exp xiexp) (upRen_exp_exp zetaexp) (upRen_exp_exp rhoexp) (up_ren_ren (_) (_) (_) Eqexp) )
    | app congr_app (compRenRen_exp xiexp zetaexp rhoexp Eqexp ) (compRenRen_exp xiexp zetaexp rhoexp Eqexp )
    end.

Definition up_ren_subst_exp_exp (xi : fin fin ) (tau : fin exp ) (theta : fin exp ) (Eq : x, (funcomp ) x = x) : x, (funcomp (up_exp_exp ) (upRen_exp_exp )) x = (up_exp_exp ) x :=
   n match n with
  | S n ap (ren_exp shift) (Eq n)
  | 0 eq_refl
  end.

Fixpoint compRenSubst_exp (xiexp : fin fin ) (tauexp : fin exp ) (thetaexp : fin exp ) (Eqexp : x, (funcomp tauexp xiexp) x = thetaexp x) (s : exp ) : subst_exp tauexp (ren_exp xiexp s) = subst_exp thetaexp s :=
    match s with
    | var_exp s Eqexp s
    | const congr_const (eq_refl )
    | lam congr_lam (compRenSubst_exp (upRen_exp_exp xiexp) (up_exp_exp tauexp) (up_exp_exp thetaexp) (up_ren_subst_exp_exp (_) (_) (_) Eqexp) )
    | app congr_app (compRenSubst_exp xiexp tauexp thetaexp Eqexp ) (compRenSubst_exp xiexp tauexp thetaexp Eqexp )
    end.

Definition up_subst_ren_exp_exp (sigma : fin exp ) (zetaexp : fin fin ) (theta : fin exp ) (Eq : x, (funcomp (ren_exp zetaexp) ) x = x) : x, (funcomp (ren_exp (upRen_exp_exp zetaexp)) (up_exp_exp )) x = (up_exp_exp ) x :=
   n match n with
  | S n eq_trans (compRenRen_exp shift (upRen_exp_exp zetaexp) (funcomp shift zetaexp) ( x eq_refl) ( n)) (eq_trans (eq_sym (compRenRen_exp zetaexp shift (funcomp shift zetaexp) ( x eq_refl) ( n))) (ap (ren_exp shift) (Eq n)))
  | 0 eq_refl
  end.

Fixpoint compSubstRen__exp (sigmaexp : fin exp ) (zetaexp : fin fin ) (thetaexp : fin exp ) (Eqexp : x, (funcomp (ren_exp zetaexp) sigmaexp) x = thetaexp x) (s : exp ) : ren_exp zetaexp (subst_exp sigmaexp s) = subst_exp thetaexp s :=
    match s with
    | var_exp s Eqexp s
    | const congr_const (eq_refl )
    | lam congr_lam (compSubstRen__exp (up_exp_exp sigmaexp) (upRen_exp_exp zetaexp) (up_exp_exp thetaexp) (up_subst_ren_exp_exp (_) (_) (_) Eqexp) )
    | app congr_app (compSubstRen__exp sigmaexp zetaexp thetaexp Eqexp ) (compSubstRen__exp sigmaexp zetaexp thetaexp Eqexp )
    end.

Definition up_subst_subst_exp_exp (sigma : fin exp ) (tauexp : fin exp ) (theta : fin exp ) (Eq : x, (funcomp (subst_exp tauexp) ) x = x) : x, (funcomp (subst_exp (up_exp_exp tauexp)) (up_exp_exp )) x = (up_exp_exp ) x :=
   n match n with
  | S n eq_trans (compRenSubst_exp shift (up_exp_exp tauexp) (funcomp (up_exp_exp tauexp) shift) ( x eq_refl) ( n)) (eq_trans (eq_sym (compSubstRen__exp tauexp shift (funcomp (ren_exp shift) tauexp) ( x eq_refl) ( n))) (ap (ren_exp shift) (Eq n)))
  | 0 eq_refl
  end.

Fixpoint compSubstSubst_exp (sigmaexp : fin exp ) (tauexp : fin exp ) (thetaexp : fin exp ) (Eqexp : x, (funcomp (subst_exp tauexp) sigmaexp) x = thetaexp x) (s : exp ) : subst_exp tauexp (subst_exp sigmaexp s) = subst_exp thetaexp s :=
    match s with
    | var_exp s Eqexp s
    | const congr_const (eq_refl )
    | lam congr_lam (compSubstSubst_exp (up_exp_exp sigmaexp) (up_exp_exp tauexp) (up_exp_exp thetaexp) (up_subst_subst_exp_exp (_) (_) (_) Eqexp) )
    | app congr_app (compSubstSubst_exp sigmaexp tauexp thetaexp Eqexp ) (compSubstSubst_exp sigmaexp tauexp thetaexp Eqexp )
    end.

Definition rinstInst_up_exp_exp (xi : fin fin ) (sigma : fin exp ) (Eq : x, (funcomp (var_exp ) ) x = x) : x, (funcomp (var_exp ) (upRen_exp_exp )) x = (up_exp_exp ) x :=
   n match n with
  | S n ap (ren_exp shift) (Eq n)
  | 0 eq_refl
  end.

Fixpoint rinst_inst_exp (xiexp : fin fin ) (sigmaexp : fin exp ) (Eqexp : x, (funcomp (var_exp ) xiexp) x = sigmaexp x) (s : exp ) : ren_exp xiexp s = subst_exp sigmaexp s :=
    match s with
    | var_exp s Eqexp s
    | const congr_const (eq_refl )
    | lam congr_lam (rinst_inst_exp (upRen_exp_exp xiexp) (up_exp_exp sigmaexp) (rinstInst_up_exp_exp (_) (_) Eqexp) )
    | app congr_app (rinst_inst_exp xiexp sigmaexp Eqexp ) (rinst_inst_exp xiexp sigmaexp Eqexp )
    end.

Lemma instId_exp : subst_exp (var_exp ) = id .
Proof. exact (FunctionalExtensionality.functional_extensionality _ _ ( x idSubst_exp (var_exp ) ( n eq_refl) (id x))). Qed.

Lemma varL_exp (sigmaexp : fin exp ) : funcomp (subst_exp sigmaexp) (var_exp ) = sigmaexp .
Proof. exact (FunctionalExtensionality.functional_extensionality _ _ ( x eq_refl)). Qed.

Lemma rinstInst_exp (xiexp : fin fin ) : ren_exp xiexp = subst_exp (funcomp (var_exp ) xiexp) .
Proof. exact (FunctionalExtensionality.functional_extensionality _ _ ( x rinst_inst_exp xiexp (_) ( n eq_refl) x)). Qed.

Lemma compComp_exp (sigmaexp : fin exp ) (tauexp : fin exp ) (s : exp ) : subst_exp tauexp (subst_exp sigmaexp s) = subst_exp (funcomp (subst_exp tauexp) sigmaexp) s .
Proof. exact (compSubstSubst_exp sigmaexp tauexp (_) ( n eq_refl) s). Qed.

Lemma compComp'_exp (sigmaexp : fin exp ) (tauexp : fin exp ) : funcomp (subst_exp tauexp) (subst_exp sigmaexp) = subst_exp (funcomp (subst_exp tauexp) sigmaexp) .
Proof. exact (FunctionalExtensionality.functional_extensionality _ _ ( n compComp_exp sigmaexp tauexp n)). Qed.

End Terms.

Definition {X} (s: exp) (t: exp) := @subst_exp X (t .: var_exp) s.
Global Hint Rewrite @instId_exp @rinstInst_exp @compComp_exp @compComp'_exp @varL_exp : asimpl.
#[export] Hint Unfold upRen_exp_exp up_exp_exp : asimpl.

Ltac asimpl := autounfold with asimpl; autorewrite with asimpl using (cbn [subst_exp ren_exp]; fsimpl).
Tactic Notation "asimpl" "in" hyp(J) :=
  autounfold with asimpl in J; autorewrite with asimpl in J using (cbn [subst_exp ren_exp] in J; fsimplin J).