Mcltt.Core.Soundness.NatCases

From Mcltt Require Import LibTactics.
From Mcltt.Core Require Import Base.
From Mcltt.Core.Completeness Require Import FundamentalTheorem.
From Mcltt.Core.Semantic Require Import Realizability.
From Mcltt.Core.Soundness Require Import
  ContextCases
  LogicalRelation
  SubstitutionCases
  SubtypingCases
  TermStructureCases
  UniverseCases.
Import Domain_Notations.

Lemma glu_rel_exp_nat : forall {Γ i},
    {{ Γ }} ->
    {{ Γ : Type@i }}.
Proof.
  intros * [Sb].
  assert {{ Γ }} by mauto.
  eapply glu_rel_exp_of_typ; mauto 3.
  intros.
  assert {{ Δ s σ : Γ }} by mauto 3.
  split; mauto 3.
  eexists; repeat split; mauto 3.
  - eexists; per_univ_elem_econstructor; reflexivity.
  - intros.
    match_by_head1 glu_univ_elem invert_glu_univ_elem.
    apply_predicate_equivalence.
    unfold nat_glu_typ_pred.
    mauto 3.
Qed.

#[export]
Hint Resolve glu_rel_exp_nat : mcltt.

Lemma glu_rel_exp_sub_nat : forall {Γ σ Δ M},
    {{ Γ s σ : Δ }} ->
    {{ Δ M : }} ->
    {{ Γ M[σ] : }}.
Proof.
  intros.
  assert {{ Γ s σ : Δ }} by mauto 3.
  assert {{ Γ [σ] }} by mautosolve 3.
  assert {{ Γ M[σ] : [σ] }} by mauto 3.
  mautosolve 4.
Qed.

#[export]
Hint Resolve glu_rel_exp_sub_nat : mcltt.

Lemma glu_rel_exp_clean_inversion2'' : forall {Γ Sb M},
    {{ EG Γ glu_ctx_env Sb }} ->
    {{ Γ M : }} ->
    glu_rel_exp_clean_inversion2_result 0 Sb M {{{ }}}.
Proof.
  intros * ? HM.
  assert {{ Γ : Type@0 }} by mauto 3.
  eapply glu_rel_exp_clean_inversion2 in HM; mauto 3.
Qed.

Ltac invert_glu_rel_exp H ::=
  (unshelve eapply (glu_rel_exp_clean_inversion2'' _) in H; shelve_unifiable; [eassumption |];
   unfold glu_rel_exp_clean_inversion2_result in H)
  + (unshelve eapply (glu_rel_exp_clean_inversion2' _) in H; shelve_unifiable; [eassumption |];
     unfold glu_rel_exp_clean_inversion2_result in H)
  + (unshelve eapply (glu_rel_exp_clean_inversion2 _ _) in H; shelve_unifiable; [eassumption | eassumption |];
     unfold glu_rel_exp_clean_inversion2_result in H)
  + (unshelve eapply (glu_rel_exp_clean_inversion1 _) in H; shelve_unifiable; [eassumption |];
     destruct H as [])
  + (inversion H; subst).

Lemma glu_rel_exp_of_nat : forall {Γ Sb M},
    {{ EG Γ glu_ctx_env Sb }} ->
    (forall Δ σ ρ, {{ Δ s σ ® ρ Sb }} -> exists m, {{ M ρ m }} /\ glu_nat Δ {{{ M[σ] }}} m) ->
    {{ Γ M : }}.
Proof.
  intros * ? Hbody.
  eexists; split; mauto 3.
  exists 0.
  intros.
  edestruct Hbody as [? []]; mauto 3.
  econstructor; mauto 3.
  - glu_univ_elem_econstructor; mauto 3; reflexivity.
  - simpl; split; mauto 3.
Qed.

Lemma glu_rel_exp_zero : forall {Γ},
    {{ Γ }} ->
    {{ Γ zero : }}.
Proof.
  intros * [Sb].
  eapply glu_rel_exp_of_nat; mauto 3.
  intros.
  eexists; split; mauto 4.
Qed.

#[export]
Hint Resolve glu_rel_exp_zero : mcltt.

Lemma glu_rel_exp_succ : forall {Γ M},
    {{ Γ M : }} ->
    {{ Γ succ M : }}.
Proof.
  intros * HM.
  assert {{ Γ }} as [SbΓ] by mauto 3.
  assert {{ Γ M : }} by mauto 3.
  invert_glu_rel_exp HM.
  eapply glu_rel_exp_of_nat; mauto.
  intros.
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  match_by_head1 glu_univ_elem invert_glu_univ_elem.
  apply_predicate_equivalence.
  inversion_clear_by_head nat_glu_exp_pred.
  eexists; split; mauto 3.
  econstructor; mauto.
Qed.

#[export]
Hint Resolve glu_rel_exp_succ : mcltt.

Lemma glu_rel_sub_extend_nat : forall {Γ σ Δ M},
    {{ Γ s σ : Δ }} ->
    {{ Γ M : }} ->
    {{ Γ s σ,,M : Δ, }}.
Proof.
  intros.
  assert {{ Δ }} by mauto 2.
  assert {{ Γ [σ] : Type@0 }} by mauto 3.
  assert {{ Γ s σ : Δ }} by mauto 3.
  assert {{ Γ [σ] }} by mautosolve 4.
  assert {{ Γ M : [σ] }}; mautosolve 3.
Qed.

#[export]
Hint Resolve glu_rel_sub_extend_nat : mcltt.

Lemma glu_rel_exp_natrec_zero_helper : forall {i Γ SbΓ A MZ MS Δ M σ ρ am P El},
    {{ EG Γ glu_ctx_env SbΓ }} ->
    {{ Γ, A : Type@i }} ->
    {{ Γ A[Id,,zero] : Type@i }} ->
    {{ Γ MZ : A[Id,,zero] }} ->
    {{ Γ, , A MS : A[WkWk,,succ #1] }} ->
    {{ Δ M zero : }} ->
    {{ Δ s σ ® ρ SbΓ }} ->
    {{ A ρ zero am }} ->
    {{ DG am glu_univ_elem i P El }} ->
    exists r,
      {{ rec zero return A | zero -> MZ | succ -> MS end ρ r }} /\
        {{ Δ rec M return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[σ,,M] ® r El }}.
Proof.
  intros * ? ? ? HMZ **.
  assert {{ Γ MZ : A[Id,,zero] }} by mauto 3.
  invert_glu_rel_exp HMZ.
  assert {{ Γ : Type@i }} as Hℕ by mauto 3.
  pose (SbΓℕ := cons_glu_sub_pred i Γ {{{ }}} SbΓ).
  assert {{ EG Γ, glu_ctx_env SbΓℕ }} by (invert_glu_rel_exp Hℕ; econstructor; mauto 3; reflexivity).
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  rename m into mz.
  eexists mz; split; mauto 3.
  handle_functional_glu_univ_elem.
  assert {{ Δ s σ : Γ }} by mauto 2.
  assert {{ Δ }} by mauto 2.
  assert {{ Δ, }} by mauto 3.
  assert {{ Δ, s q σ : Γ, }} by mauto 3.
  assert {{ Δ, , A[q σ] }} by mauto 3.
  assert {{ Δ s Id : Δ }} by mauto 2.
  assert {{ Δ s σ,,M σ,,zero : Γ, }} as -> by mauto 3.
  assert {{ Δ, s Wk : Δ }} by mauto 2.
  assert {{ Δ, , A[q σ] s Wk : Δ, }} by mauto 2.
  assert {{ Δ zero : }} by mauto 3.
  assert {{ Δ zero[σ] zero : }} by mauto 3.
  assert {{ Δ A[q σ][Id,,zero] A[σ,,zero] : Type@i }} by mauto 3.
  assert {{ Δ A[σ,,zero] A[σ,,zero[σ]] : Type@i }} by (symmetry; mauto 4).
  assert {{ Γ zero : }} by mauto 3.
  assert {{ Δ A[σ,,zero[σ]] A[Id,,zero][σ] : Type@i }} by mauto 3.
  assert {{ Δ A[q σ][Id,,zero] A[σ,,zero] : Type@i }} as <- by mauto 2.
  assert {{ Δ MZ[σ] : A[q σ][Id,,zero] }} by bulky_rewrite.
  assert {{ Δ, , A[q σ] s WkWk,,succ #1 : Δ, }} by mauto 4.
  assert {{ Δ, , A[q σ] MS[q (q σ)] : A[q σ][WkWk,,succ #1] }} by (rewrite @exp_eq_typ_q_sigma_then_weak_weak_extend_succ_var_1; mauto 3).
  pose (R := {{{ rec zero return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end }}}).
  assert
    {{ Δ R rec M return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[q σ][Id,,zero] }} as <-
      by (econstructor; try eapply exp_eq_refl; mauto 3).
  assert
    {{ Δ R MZ[σ] : A[q σ][Id,,zero] }} as ->
      by (econstructor; mauto 3).
  bulky_rewrite.
Qed.

Lemma cons_glu_sub_pred_nat_helper : forall {Γ SbΓ Δ σ ρ i M m},
    {{ EG Γ glu_ctx_env SbΓ }} ->
    {{ Δ s σ ® ρ SbΓ }} ->
    glu_nat Δ M m ->
    {{ Δ s σ,,M ® ρ m cons_glu_sub_pred i Γ {{{ }}} SbΓ }}.
Proof.
  intros * ? HM ?.
  assert {{ DG glu_univ_elem i nat_glu_typ_pred i nat_glu_exp_pred i }} by (glu_univ_elem_econstructor; reflexivity).
  eapply cons_glu_sub_pred_helper; mauto 3.
  econstructor; [unfold nat_glu_typ_pred |]; mauto 3.
Qed.

#[local]
Hint Resolve cons_glu_sub_pred_nat_helper : mcltt.

Lemma glu_rel_exp_natrec_succ_helper : forall {i Γ SbΓ A MZ MS Δ M M' m' σ ρ am P El},
    {{ EG Γ glu_ctx_env SbΓ }} ->
    {{ Γ, A : Type@i }} ->
    {{ Γ MZ : A[Id,,zero] }} ->
    {{ Γ, , A A[WkWk,,succ #1] : Type@i }} ->
    {{ Γ, , A MS : A[WkWk,,succ #1] }} ->
    {{ Δ M succ M' : }} ->
    glu_nat Δ M' m' ->
    (forall σ ρ am P El,
        {{ Δ s σ ® ρ SbΓ }} ->
        {{ A ρ m' am }} ->
        {{ DG am glu_univ_elem i P El }} ->
        exists r,
          {{ rec m' return A | zero -> MZ | succ -> MS end ρ r }} /\
            {{ Δ rec M' return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[σ,,M'] ® r El }}) ->
    {{ Δ s σ ® ρ SbΓ }} ->
    {{ A ρ succ m' am }} ->
    {{ DG am glu_univ_elem i P El }} ->
    exists r,
      {{ rec succ m' return A | zero -> MZ | succ -> MS end ρ r }} /\
        {{ Δ rec M return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[σ,,M] ® r El }}.
Proof.
  intros * ? HA ? ? HMS **.
  assert {{ Γ }} by (eexists; eassumption).
  assert {{ Γ : Type@i }} as Hℕ by mauto 3.
  pose (SbΓℕ := cons_glu_sub_pred i Γ {{{ }}} SbΓ).
  assert {{ EG Γ, glu_ctx_env SbΓℕ }} by (invert_glu_rel_exp Hℕ; econstructor; mauto 3; reflexivity).
  assert {{ Γ, A : Type@i }} by mauto 2.
  invert_glu_rel_exp HA.
  pose (SbΓℕA := cons_glu_sub_pred i {{{ Γ, }}} A SbΓℕ).
  assert {{ EG Γ, , A glu_ctx_env SbΓℕA }} by (econstructor; mauto 3; reflexivity).
  assert {{ Γ, , A MS : A[WkWk,,succ #1] }} by mauto 2.
  invert_glu_rel_exp HMS.
  assert {{ Δ s σ,,M' ® ρ m' SbΓℕ }} by (unfold SbΓℕ; mauto 3).
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
  apply_predicate_equivalence.
  unfold univ_glu_exp_pred' in *.
  destruct_conjs.
  match goal with
  | _: {{ A ρ m' ^?m }}, _: {{ DG ^?m glu_univ_elem i ?P ?El }} |- _ =>
      rename m into am';
      rename P into P';
      rename El into El'
  end.
  assert {{ Δ }} by mauto 2.
  assert {{ Δ, }} by mauto 3.
  assert {{ Δ s σ : Γ }} by mauto 3.
  assert {{ Δ, A[q σ] : Type@i }} by mauto 3.
  assert {{ Δ, , A[q σ] }} by mauto 2.
  assert {{ Δ M' : }} by mauto 3.
  assert {{ Δ : Type@0 }} by mauto 3.
  assert {{ Δ [σ] : Type@0 }} by mauto 3.
  assert {{ Δ M' : [σ] }} by mauto 3.
  assert {{ Δ zero : }} by mauto 3.
  assert {{ Δ zero : [σ] }} by mauto 3.
  assert {{ Δ zero[σ] zero : }} by mauto 3.
  assert {{ Δ, s q σ : Γ, }} by mauto 3.
  assert {{ Δ A[q σ][Id,,zero] A[σ,,zero] : Type@i }} by mauto 3.
  assert {{ Δ A[σ,,zero] A[σ,,zero[σ]] : Type@i }} by (symmetry; mauto 4).
  assert {{ Γ zero : }} by mauto 3.
  assert {{ Δ A[σ,,zero[σ]] A[Id,,zero][σ] : Type@i }} by mauto 4.
  assert {{ Δ MZ[σ] : A[q σ][Id,,zero] }} by bulky_rewrite.
  assert {{ Δ, , A[q σ] s WkWk,,succ #1 : Δ, }} by mauto 3.
  assert {{ Δ, , A[q σ] MS[q (q σ)] : A[q σ][WkWk,,succ #1] }} by (rewrite @exp_eq_typ_q_sigma_then_weak_weak_extend_succ_var_1; mauto 3).
  pose (R := {{{ rec M' return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end }}}).
  assert (exists r, {{ rec m' return A | zero -> MZ | succ -> MS end ρ r }} /\ {{ Δ R : A[σ,,M'] ® r El' }}) as [r' []] by mauto 3.
  assert {{ Δ R : A[σ,,M'] }} by (erewrite <- @exp_eq_elim_sub_rhs_typ; mauto 3).
  assert {{ Δ s σ,,M',,R ® ρ m' r' SbΓℕA }} by (unfold SbΓℕA; mauto 3).
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
  apply_predicate_equivalence.
  clear_dups.
  unfold univ_glu_exp_pred' in *.
  destruct_conjs.
  handle_functional_glu_univ_elem.
  match goal with
  | _: {{ MS ρ m' r' ^?m }} |- _ =>
      rename m into ms
  end.
  exists ms; split; mauto 3.
  assert {{ Δ s σ,,M σ,,succ M' : Γ, }} as -> by mauto 3.
  assert {{ Δ succ M' : }} by mauto 3.
  assert {{ Δ succ M' : [σ] }} by mauto 3.
  assert {{ Δ A[σ,,succ M'] A[q σ][Id,,succ M'] : Type@i }} as -> by mauto 3.
  assert {{ Δ rec succ M' return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end rec M return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[q σ][Id,,succ M'] }} as <- by (econstructor; mauto 3).
  assert {{ Δ rec succ M' return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end MS[q (q σ)][Id,,M',,R] : A[q σ][Id,,succ M'] }} as -> by mauto 2.
  assert {{ Δ R : A[q σ][Id,,M'] }} by bulky_rewrite.
  assert {{ Δ s Id,,M',,R : Δ, , A[q σ] }} by mauto 3.
  assert {{ Δ A[σ,,succ M'] A[q σ][Id,,succ M'] : Type@i }} as <- by mauto 3.
  assert {{ Δ A[WkWk,,succ #1][σ,,M',,R] A[σ,,succ M'] : Type@i }} as <- by mauto 3.
  assert {{ Δ MS[q (q σ)][Id,,M',,R] MS[σ,,M',,R] : A[WkWk,,succ #1][σ,,M',,R] }} as -> by mauto 4.
  eassumption.
Qed.

Lemma cons_glu_sub_pred_q_helper : forall {Γ SbΓ Δ σ ρ i A a},
    {{ EG Γ glu_ctx_env SbΓ }} ->
    {{ Δ s σ ® ρ SbΓ }} ->
    {{ Γ A : Type@i }} ->
    {{ A ρ a }} ->
    {{ Δ, A[σ] s q σ ® ρ ⇑! a (length Δ) cons_glu_sub_pred i Γ A SbΓ }}.
Proof.
  intros * ? ? HA ?.
  assert {{ Γ A : Type@i }} by mauto 2.
  invert_glu_rel_exp HA.
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
  apply_predicate_equivalence.
  unfold univ_glu_exp_pred' in *.
  destruct_conjs.
  assert {{ Δ s σ : Γ }} by mauto 2.
  assert {{ Δ, A[σ] }} by mauto 3.
  assert {{ Δ, A[σ] w Wk : Δ }} by mauto 2.
  eapply cons_glu_sub_pred_helper; mauto 2.
  - eapply glu_ctx_env_sub_monotone; eassumption.
  - assert {{ Δ, A[σ] s Wk : Δ }} by mauto 2.
    assert {{ Δ, A[σ] A[σWk] A[σ][Wk] : Type@i }} as -> by mauto 3.
    eapply var0_glu_elem; eassumption.
Qed.

#[local]
Hint Resolve cons_glu_sub_pred_q_helper : mcltt.

Lemma cons_glu_sub_pred_q_nat_helper : forall {Γ SbΓ Δ σ ρ i},
    {{ EG Γ glu_ctx_env SbΓ }} ->
    {{ Δ s σ ® ρ SbΓ }} ->
    {{ Δ, s q σ ® ρ ⇑! (length Δ) cons_glu_sub_pred i Γ {{{ }}} SbΓ }}.
Proof.
  intros.
  assert {{ Γ }} by (eexists; eassumption).
  assert {{ Γ : Type@i }} as Hℕ by mauto 3.
  assert {{ ρ }} by mauto 3.
  assert {{ Δ, [σ] s q σ ® ρ ⇑! (length Δ) cons_glu_sub_pred i Γ {{{ }}} SbΓ }} by mauto 3.
  assert {{ Δ [σ] : Type@i }} by mauto 4.
  assert {{ EG Γ, glu_ctx_env cons_glu_sub_pred i Γ {{{ }}} SbΓ }}
    by (invert_glu_rel_exp Hℕ; econstructor; mauto 3; reflexivity).
  assert {{ Δ }} by mauto 2.
  cbn.
  assert {{ Δ, [σ] Δ, }} as <- by mauto 3.
  eassumption.
Qed.

#[local]
Hint Resolve cons_glu_sub_pred_q_nat_helper : mcltt.

Lemma glu_rel_exp_natrec_neut_helper : forall {i Γ SbΓ A MZ MS Δ M a m σ ρ am P El},
    {{ EG Γ glu_ctx_env SbΓ }} ->
    {{ Γ, A : Type@i }} ->
    {{ Γ A[Id,,zero] : Type@i }} ->
    {{ Γ MZ : A[Id,,zero] }} ->
    {{ Γ, , A A[WkWk,,succ #1] : Type@i }} ->
    {{ Γ, , A MS : A[WkWk,,succ #1] }} ->
    {{ Dom m m per_bot }} ->
    (forall Δ' τ V, {{ Δ' w τ : Δ }} -> {{ Rne m in length Δ' V }} -> {{ Δ' M[τ] V : }}) ->
    {{ Δ s σ ® ρ SbΓ }} ->
    {{ A ρ a m am }} ->
    {{ DG am glu_univ_elem i P El }} ->
    exists r,
      {{ rec a m return A | zero -> MZ | succ -> MS end ρ r }} /\
        {{ Δ rec M return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[σ,,M] ® r El }}.
Proof.
  intros * ? HA ? HMZ ? HMS **.
  assert {{ Γ MZ : A[Id,,zero] }} by mauto 2.
  invert_glu_rel_exp HMZ.
  assert {{ Γ }} by (eexists; eassumption).
  assert {{ Γ : Type@i }} as Hℕ by mauto 3.
  pose (SbΓℕ := cons_glu_sub_pred i Γ {{{ }}} SbΓ).
  assert {{ EG Γ, glu_ctx_env SbΓℕ }} by (invert_glu_rel_exp Hℕ; econstructor; mauto 3; reflexivity).
  assert {{ Γ, A : Type@i }} by mauto 2.
  pose proof HA.
  invert_glu_rel_exp HA.
  pose (SbΓℕA := cons_glu_sub_pred i {{{ Γ, }}} A SbΓℕ).
  assert {{ EG Γ, , A glu_ctx_env SbΓℕA }} by (econstructor; mauto 3; reflexivity).
  assert {{ Δ s σ,,M ® ρ a m SbΓℕ }} by (unfold SbΓℕ; mauto 3).
  assert {{ Γ, , A MS : A[WkWk,,succ #1] }} by mauto 2.
  invert_glu_rel_exp HMS.
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
  apply_predicate_equivalence.
  unfold univ_glu_exp_pred' in *.
  destruct_conjs.
  handle_functional_glu_univ_elem.
  match goal with
  | _: {{ MZ ^?ρ0 ^?m }}, _: {{ A ^?ρ0 zero ^?a }} |- _ =>
      rename ρ0 into ρ;
      rename m into mz;
      rename a into az
  end.
  eexists; split; mauto 3.
  assert {{ Δ s σ : Γ }} by mauto 3.
  assert {{ Δ }} by mauto 2.
  assert {{ Δ, }} by mauto 3.
  assert {{ Δ, A[q σ] : Type@i }} by mauto 3.
  assert {{ Δ, , A[q σ] }} by mauto 2.
  assert {{ Δ M : }} by mautosolve 3.
  assert {{ Δ : Type@0 }} by mauto 3.
  assert {{ Δ [σ] : Type@0 }} by mauto 3.
  assert {{ Δ M : [σ] }} by mauto 3.
  assert {{ Δ zero : }} by mauto 3.
  assert {{ Δ zero[σ] zero : }} by mauto 3.
  assert {{ Δ, s q σ : Γ, }} by mauto 3.
  assert {{ Δ A[q σ][Id,,zero] A[σ,,zero] : Type@i }} by mauto 3.
  assert {{ Δ A[σ,,zero] A[σ,,zero[σ]] : Type@i }} by (symmetry; mauto 4).
  assert {{ Γ zero : }} by mauto 3.
  assert {{ Δ A[σ,,zero[σ]] A[Id,,zero][σ] : Type@i }} by mauto 4.
  assert {{ Δ MZ[σ] : A[q σ][Id,,zero] }} by bulky_rewrite.
  assert {{ Δ, , A[q σ] s WkWk,,succ #1 : Δ, }} by mauto 3.
  assert {{ Δ, , A[q σ] MS[q (q σ)] : A[q σ][WkWk,,succ #1] }} by (rewrite @exp_eq_typ_q_sigma_then_weak_weak_extend_succ_var_1; mauto 3).
  pose (R := {{{ rec M return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end }}}).
  enough {{ Δ R : A[σ,,M] ® rec m under ρ return A | zero -> mz | succ -> MS end glu_elem_bot i am }} by (eapply realize_glu_elem_bot; mauto 3).
  econstructor; mauto 3.
  - erewrite <- @exp_eq_elim_sub_rhs_typ; mauto 3.
  - assert {{ Δ MZ[σ] : A[Id,,zero][σ] ® mz glu_elem_top i az }} as [] by (eapply realize_glu_elem_top; eassumption).
    handle_functional_glu_univ_elem.
    assert {{ Γ }} as [env_relΓ] by mauto 3 using completeness_fundamental_ctx.
    assert {{ Γ, A : Type@i }} as [env_relΓℕ] by mauto 3 using completeness_fundamental_exp.
    assert {{ Γ, , A MS : A[WkWk,,succ #1] }} as [env_relΓℕA] by mauto 3 using completeness_fundamental_exp.
    destruct_conjs.
    pose env_relΓℕA.
    match_by_head (per_ctx_env env_relΓℕA) ltac:(fun H => invert_per_ctx_env H).
    match_by_head (per_ctx_env env_relΓℕ) ltac:(fun H => invert_per_ctx_env H).
    intros s.
    enough (exists r, {{ Rne rec m under ρ return A | zero -> mz | succ -> MS end in s r }}) as [] by (eexists; split; eassumption).
    assert {{ Dom ρ ρ env_relΓ }} by (eapply glu_ctx_env_per_env; revgoals; eassumption).
    destruct_rel_typ.
    invert_rel_typ_body.
    assert {{ Dom ! s ! s per_bot }} by mauto 3.
    assert {{ Dom ρ ⇑! s ρ ⇑! s env_relΓℕ }} by (apply_relation_equivalence; unshelve eexists; simpl; intuition).
    assert {{ Dom ρ succ ⇑! s ρ succ ⇑! s env_relΓℕ }} by (apply_relation_equivalence; unshelve eexists; simpl; intuition).
    destruct_rel_typ.
    invert_rel_typ_body.
    match goal with
    | _: {{ A ρ ⇑! s ^?a }}, _: {{ A ρ (succ ⇑! s) ^?a' }} |- _ =>
        rename a into as';
We cannot use as as a name
        rename a' into asucc
    end.
    assert {{ Dom ρ ⇑! s ⇑! as' (S s) ρ ⇑! s ⇑! as' (S s) env_relΓℕA }} as HΓℕA
        by (apply_relation_equivalence; unshelve eexists; simpl; intuition; eapply per_bot_then_per_elem; mauto 3).
    apply_relation_equivalence.
    (on_all_hyp_rev: fun H => destruct (H _ _ HΓℕA)).
    destruct_conjs.
    destruct_by_head rel_typ.
    invert_rel_typ_body.
    destruct_by_head rel_exp.
    functional_eval_rewrite_clear.
    match goal with
    | _: {{ MS ρ ⇑! s ⇑! as' (S s) ^?m }} |- _ =>
        rename m into ms
    end.
    assert {{ Dom as' as' per_top_typ }} as [? []]%(fun {a} (f : per_top_typ a a) => f (S s)) by mauto 3.
    assert {{ Dom asucc ms asucc ms per_top }} as [? []]%(fun {a} (f : per_top a a) => f (S (S s))) by mauto 3.
    match_by_head1 (per_top d{{{ az mz }}} d{{{ az mz }}}) ltac:(fun H => destruct (H s) as [? []]).
    match_by_head1 (per_bot m m) ltac:(fun H => destruct (H s) as [? []]).
    eexists.
    mauto.
  - intros Δ' τ w **.
    assert {{ Δ' }} by mauto 3.
    assert {{ Δ', }} by mauto 3.
    assert {{ Δ' s τ : Δ }} by mauto 3.
    assert {{ Δ' s στ : Γ }} by mauto 3.
    assert {{ Δ' s στ ® ρ SbΓ }} by (eapply glu_ctx_env_sub_monotone; eassumption).
    assert {{ Δ', s q (στ) ® ρ ⇑! (length Δ') SbΓℕ }} by (unfold SbΓℕ; mauto 3).
    destruct_glu_rel_exp_with_sub.
    simplify_evals.
    match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
    apply_predicate_equivalence.
    unfold univ_glu_exp_pred' in *.
    destruct_conjs.
    handle_functional_glu_univ_elem.
    match_by_head read_ne ltac:(fun H => directed inversion_clear H).
    handle_functional_glu_univ_elem.
    match goal with
    | _: {{ A ^?ρ' ⇑! (length Δ') ^?a }} |- _ =>
        rename ρ' into ρ;
        rename a into aΔ'
    end.
    assert {{ Δ', , A[q (στ)] s q (q (στ)) ® ρ ⇑! (length Δ') ⇑! aΔ' (length {{{ Δ', }}}) SbΓℕA }}
      by (unfold SbΓℕA; mauto 3).
    destruct_glu_rel_exp_with_sub.
    simplify_evals.
    match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
    apply_predicate_equivalence.
    unfold univ_glu_exp_pred' in *.
    destruct_conjs.
    clear_dups.
    handle_functional_glu_univ_elem.
    match goal with
    | _: {{ A ^?ρ' succ (⇑! (length Δ')) ^?a }},
        _: {{ Rtyp aΔ' in S (length Δ') ^?A }},
        _: {{ Rnf az mz in length Δ' ^?MZ }},
            _: {{ Rne m in length Δ' ^?M }} |- _ =>
        rename A into A';
        rename ρ' into ρ;
        rename a into asucc;
        rename MZ into MZ';
        rename M into M'
    end.
    assert {{ Δ', A[q (στ)] ® glu_typ_top i aΔ' }} as [] by (eapply realize_glu_typ_top; eassumption).
    assert {{ Δ MZ[σ] : A[Id,,zero][σ] ® mz glu_elem_top i az }} as [] by (eapply realize_glu_elem_top; eassumption).
    assert {{ Δ', , A[q (στ)] MS[q (q (στ))] : A[WkWk,,succ #1][q (q (στ))] ® ms glu_elem_top i asucc }} as []
        by (eapply realize_glu_elem_top; eassumption).
    assert {{ Δ s σ,,M : Γ, }} by mauto 4.
    assert {{ Δ' s στ,,M[τ] : Γ, }} by mauto 4.
    assert {{ Δ' A[σ,,M][τ] A[(σ,,M)τ] : Type@i }} as -> by mauto 3.
    assert {{ Δ' A[(σ,,M)τ] A[στ,,M[τ]] : Type@i }} as -> by mauto 3.
    assert {{ Δ' A[στ,,M[τ]] A[q σ][τ,,M[τ]] : Type@i }} as -> by (eapply sub_decompose_q_typ; mauto 2).
    assert {{ Δ' R[τ] rec M[τ] return A[q σ][q τ] | zero -> MZ[σ][τ] | succ -> MS[q (q σ)][q (q τ)] end : A[q σ][τ,,M[τ]] }} as -> by mauto 3.
    assert {{ Δ' A[q σ][q τ][Id,,M[τ]] A[q σ][τ,,M[τ]] : Type@i }} as <- by mauto 3.
    assert {{ Δ', w Id : Δ', }} by mauto 3.
    eapply wf_exp_eq_natrec_cong'; fold ne_to_exp nf_to_exp; [| | | mautosolve 3].
    + assert {{ Δ', s q σq τ : Γ, }} by mauto 3.
      assert {{ Δ', A[q σq τ] : Type@i }} by mauto 3.
      assert {{ Δ', A[q (στ)][Id] A' : Type@i }} as <- by mauto 3.
      transitivity {{{ A[q σq τ] }}}; mauto 3.
      transitivity {{{ A[q σq τ][Id] }}}; mauto 3.
      eapply exp_eq_sub_cong_typ1; mauto 3.
    + assert {{ Δ, A[q σ] : Type@i }} by mauto 3.
      assert {{ Δ', s q τ : Δ, }} by mauto 3.
      assert {{ Δ' zero : }} by mauto 3.
      assert {{ Δ' A[q σ][q τ][Id,,zero] A[q σ][τ,,zero] : Type@i }} as -> by mauto 3.
      assert {{ Δ' zero zero[τ] : }} by mauto 3.
      assert {{ Δ' zero zero[τ] : [τ] }} by mauto 4.
      assert {{ Δ' s τ,,zero τ,,zero[τ] : Δ, }} by mauto 3.
      assert {{ Δ' A[q σ][τ,,zero] A[q σ][τ,,zero[τ]] : Type@i }} by (symmetry; mauto 4).
      assert {{ Δ' A[q σ][τ,,zero] A[q σ][Id,,zero][τ] : Type@i }} as -> by mauto 4.
      assert {{ Δ A[q σ][Id,,zero] A[Id,,zero][σ] : Type@i }} by mauto 3.
      assert {{ Δ' A[q σ][Id,,zero][τ] A[Id,,zero][σ][τ] : Type@i }} as -> by mauto 3.
      mauto 3.
    + assert {{ Δ, A[q σ] : Type@i }} by mauto 3.
      assert {{ Δ', s q τ : Δ, }} by mauto 2.
      assert {{ Δ, , A[q σ] s q (q σ) : Γ, , A }} by mauto 2.
      assert {{ Δ', , A[q σ][q τ] s q (q τ) : Δ, , A[q σ] }} by mauto 2.
      assert {{ Δ', s q σq τ q (στ) : Γ, }} by mauto 4.
      assert {{ Δ', , A[q (στ)] }} by mauto 2.
      assert {{ Δ', A[q σ][q τ] A[q σq τ] : Type@i }} by mauto 2.
      assert {{ Δ', A[q σq τ] A[q (στ)] : Type@i }} by mauto 2.
      assert {{ Δ', , A[q σq τ] Δ', , A[q (στ)] }} by mauto 3.
      assert {{ Δ', , A[q σ][q τ] Δ', , A[q (στ)] }} by mauto 4.
      assert {{ Δ', , A[q σ][q τ] Δ', , A[q (στ)] }} as -> by eassumption.
      assert {{ Δ', , A[q (στ)] s WkWk,,succ #1 : Δ', }} by mauto 2.
      assert {{ Δ', , A[q (στ)] A[q σ][q τ][WkWk,,succ #1] A[q (στ)][WkWk,,succ #1] : Type@i }} as -> by mauto 3.
      assert {{ Δ', , A[q (στ)] A[q (στ)][WkWk,,succ #1] A[WkWk,,succ #1][q (q (στ))] : Type@i }} as -> by mauto 3 using exp_eq_typ_q_sigma_then_weak_weak_extend_succ_var_1.
      assert {{ Δ', s q (στ) : Γ, }} by mauto 2.
      assert {{ Δ', , A[q (στ)] s q (q (στ)) : Γ, , A }} by mauto 2.
      assert {{ Γ, , A s WkWk,,succ #1 : Γ, }} by mauto 2.
      assert {{ Δ', , A[q (στ)] s q (q τ) : Δ, , A[q σ] }} by mauto 2.
      assert {{ Δ', , A[q σ][q τ] MS[q (q σ)][q (q τ)] MS[q (q σ)q (q τ)] : A[WkWk,,succ #1][q (q σ)q (q τ)] }} by mauto 3.
      assert {{ Δ', , A[q σq τ] s q (q σ)q (q τ) q (q σq τ) : Γ, , A }} by mauto 2.
      assert {{ Δ', , A[q (στ)] s q (q σ)q (q τ) q (q σq τ) : Γ, , A }} by mauto 2.
      assert {{ Δ', , A[q (στ)] s q (q σq τ) q (q (στ)) : Γ, , A }} by mauto 3.
      assert {{ Δ', , A[q (στ)] s q (q σ)q (q τ) q (q (στ)) : Γ, , A }} by mauto 2.
      assert {{ Γ, , A A[WkWk,,succ #1] : Type@i }} by mauto 2.
      assert {{ Δ', , A[q (στ)] A[WkWk,,succ #1][q (q σ)q (q τ)] A[WkWk,,succ #1][q (q (στ))] : Type@i }} by mauto 3.
      assert {{ Δ', , A[q (στ)] MS[q (q σ)][q (q τ)] MS[q (q σ)q (q τ)] : A[WkWk,,succ #1][q (q σ)q (q τ)] }} by mauto 2.
      assert {{ Δ', , A[q (στ)] MS[q (q σ)][q (q τ)] MS[q (q σ)q (q τ)] : A[WkWk,,succ #1][q (q (στ))] }} as -> by mauto 2.
      assert {{ Δ', , A[q (στ)] MS[q (q σ)q (q τ)] MS[q (q (στ))] : A[WkWk,,succ #1][q (q σ)q (q τ)] }} by mauto 3.
      assert {{ Δ', , A[q (στ)] MS[q (q (στ))] MS[q (q σ)q (q τ)] : A[WkWk,,succ #1][q (q (στ))] }} as <- by mauto 3.
      assert {{ Δ', , A[q (στ)] MS[q (q (στ))][Id] MS[q (q (στ))] : A[WkWk,,succ #1][q (q (στ))] }} as <- by mauto 3.
      assert {{ Δ', , A[q (στ)] A[WkWk,,succ #1][q (q (στ))][Id] A[WkWk,,succ #1][q (q (στ))] : Type@i }} as <- by mauto 3.
      mauto 3.
Qed.

Lemma glu_rel_exp_natrec_helper : forall {i Γ SbΓ A MZ MS},
    {{ EG Γ glu_ctx_env SbΓ }} ->
    {{ Γ, A : Type@i }} ->
    {{ Γ MZ : A[Id,,zero] }} ->
    {{ Γ, , A MS : A[WkWk,,succ #1] }} ->
    forall {Δ M m},
      glu_nat Δ M m ->
      forall {σ ρ am P El},
        {{ Δ s σ ® ρ SbΓ }} ->
        {{ A ρ m am }} ->
        {{ DG am glu_univ_elem i P El }} ->
        exists r,
          {{ rec m return A | zero -> MZ | succ -> MS end ρ r }} /\
            {{ Δ rec M return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[σ,,M] ® r El }}.
Proof.
  intros * ? HA ? ?.
  assert {{ Γ }} by mauto 2.
  assert {{ Γ : Type@i }} as Hℕ by mauto 3.
  assert {{ Γ A[Id,,zero] : Type@i }}.
  {
    assert {{ Γ : Type@i }} by mauto 2.
    assert {{ Γ [Id] }} by mauto 4.
    mauto.
  }
  pose (SbΓℕ := cons_glu_sub_pred i Γ {{{ }}} SbΓ).
  assert {{ EG Γ, glu_ctx_env SbΓℕ }} by (invert_glu_rel_exp Hℕ; econstructor; mauto 3; reflexivity).
  pose proof HA.
  invert_glu_rel_exp HA.
  assert {{ Γ, , A A[WkWk,,succ #1] : Type@i }}.
  {
    assert {{ Γ, , A }} by mauto 3.
    assert {{ Γ, s Wk : Γ }} by mauto 3.
    assert {{ Γ, , A s Wk : Γ, }} by mauto 3.
    assert {{ Γ, s Wk : Γ }} by mauto 3.
    assert {{ Γ, , A s Wk : Γ, }} by mauto 3.
    assert {{ Γ, , A [Wk][Wk] : Type@0 }} by mauto 3.
    assert {{ Γ, , A #1 : [Wk][Wk] }} by mauto 3.
    assert {{ Γ, , A #1 : }} by mauto 3.
    mauto.
  }
  induction 1; intros; rename Γ0 into Δ.
  -
    mauto 4 using glu_rel_exp_natrec_zero_helper.
  -
    mauto 3 using glu_rel_exp_natrec_succ_helper.
  -
    mauto 3 using glu_rel_exp_natrec_neut_helper.
Qed.

Lemma glu_rel_exp_natrec : forall {Γ i A MZ MS M},
    {{ Γ, A : Type@i }} ->
    {{ Γ MZ : A[Id,,zero] }} ->
    {{ Γ, , A MS : A[WkWk,,succ #1] }} ->
    {{ Γ M : }} ->
    {{ Γ rec M return A | zero -> MZ | succ -> MS end : A[Id,,M] }}.
Proof.
  intros * HA HMZ HMS HM.
  assert {{ Γ }} as [SbΓ] by mauto 2.
  assert {{ Γ : Type@i }} as Hℕ by mauto 3.
  pose (SbΓℕ := cons_glu_sub_pred i Γ {{{ }}} SbΓ).
  assert {{ EG Γ, glu_ctx_env SbΓℕ }} by (invert_glu_rel_exp Hℕ; econstructor; mauto 3; try reflexivity).
  assert {{ Γ, Type@i : Type@(S i) }} by mauto 3.
  pose proof HM.
  invert_glu_rel_exp HM.
  pose proof HA.
  invert_glu_rel_exp HA.
  eexists; split; [eassumption |].
  eexists.
  intros.
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
  apply_predicate_equivalence.
  clear_dups.
  inversion_clear_by_head nat_glu_exp_pred.
  assert {{ Δ s σ,,M[σ] ® ρ m SbΓℕ }} by (unfold SbΓℕ; mauto 2).
  destruct_glu_rel_exp_with_sub.
  simplify_evals.
  match_by_head glu_univ_elem ltac:(fun H => directed invert_glu_univ_elem H).
  apply_predicate_equivalence.
  inversion_clear_by_head nat_glu_exp_pred.
  unfold univ_glu_exp_pred' in *.
  destruct_conjs.
  clear_dups.
  match_by_head nat_glu_typ_pred ltac:(fun H => clear H).
  match goal with
  | _: {{ A ρ m ^?a' }},
      _: {{ DG ^?a' glu_univ_elem i ?P' ?El' }} |- _ =>
      rename a' into a;
      rename P' into P;
      rename El' into El
  end.
  assert (exists r, {{ rec m return A | zero -> MZ | succ -> MS end ρ r }} /\ El Δ {{{ A[σ,, M[σ]] }}} {{{ rec M[σ] return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end }}} r) as [? []] by (eapply glu_rel_exp_natrec_helper; revgoals; mauto 4).
  econstructor; mauto 3.
  assert {{ Δ s σ : Γ }} by mauto 2.
  assert {{ Γ M : }} by mauto 2.
  assert {{ Γ, A : Type@i }} by mauto 3.
  assert {{ Δ A[σ,,M[σ]] A[Id,,M][σ] : Type@i }} as <- by (symmetry; mauto 2).
  assert {{ Δ rec M return A | zero -> MZ | succ -> MS end[σ] rec M[σ] return A[q σ] | zero -> MZ[σ] | succ -> MS[q (q σ)] end : A[σ,,M[σ]] }} as -> by (econstructor; mauto 3).
  eassumption.
Qed.

#[export]
Hint Resolve glu_rel_exp_natrec : mcltt.