GL.Interpolation.UIGL_UIThree

(* Uniform interpolation *)

Require Import List.
Export ListNotations.
Require Import PeanoNat Arith.
Require Import Lia.

Require Import general_export.

Require Import GLS_export.

Require Import UIGL_Def_measure.
Require Import UIGL_Canopy.
Require Import UIGL_irred_short.
Require Import UIGL_braga.
Require Import UIGL_LexSeq.
Require Import UIGL_nodupseq.
Require Import UIGL_PermutationT.
Require Import UIGL_PermutationTS.
Require Import UIGL_And_Or_rules.
Require Import UIGL_UI_prelims.
Require Import UIGL_UI_inter.
Require Import UIGL_UIDiam_N.

  Section UIPThree.

  Theorem UI_Three : forall s p X0 Y0,
                                    (In (Var p) (propvar_subform_list (X0 ++ Y0)) -> False) ->
                                    GLS_prv (fst s ++ X0, snd s ++ Y0) ->
                                    GLS_prv (X0, (UI p s) :: Y0).
  Proof.
  (* Setting up the strong induction on the height of the derivation (PIH) and
      on the measure of the sequent using LexSeq (SIH). *)

  intros s p X0 Y0 NotVar D. generalize dependent NotVar. remember (fst s ++ X0, snd s ++ Y0) as scomp.
  generalize dependent Heqscomp. remember (derrec_height D) as n. generalize dependent Heqn.
  generalize dependent Y0. generalize dependent X0. generalize dependent D.
  generalize dependent scomp. generalize dependent s. generalize dependent n.
  induction n as [n PIH] using (well_founded_induction_type lt_wf).
  pose (d:=LexSeq_ind (fun (s:Seq) => forall (scomp : list MPropF * list MPropF) (D : GLS_prv scomp) (X0 Y0 : list MPropF),
                n = derrec_height D ->
                scomp = (fst s ++ X0, snd s ++ Y0) -> (In # p (propvar_subform_list (X0 ++ Y0)) -> False) -> GLS_prv (X0, UI p s :: Y0))).
  apply d. clear d. intros k SIH.

  (* Now we do the actual proof-theoretical work. *)
  intros s0 D0. remember D0 as D0'. destruct D0.
  (* D0 is a leaf *)
  - inversion f.
  (* D0 ends with an application of rule *)
  - intros X0 Y0 hei idseq propvar. destruct (empty_seq_dec k) as [ EE | NE].
    { subst ; simpl in *.
       assert (J1: GLS_prv (X0, Y0)). apply derI with ps ; auto. apply GLS_prv_wkn_R with (X0, Y0) (UI p ([], [])) ; auto.
       apply (wkn_RI _ _ []). }
    { inversion g ; subst.
    (* IdP *)
    * inversion H ; subst.
      assert (InT (# P) (fst k ++ X0)). rewrite <- H2. apply InT_or_app ; right ; apply InT_eq.
      apply InT_app_or in H0.
      assert (InT (# P) (snd k ++ Y0)). rewrite <- H3. apply InT_or_app ; right ; apply InT_eq.
      apply InT_app_or in H1. destruct H0 ; destruct H1.
      + assert ((X0, UI p k :: Y0) = (X0, [] ++ UI p k :: Y0)). auto. rewrite H0. apply is_init_UI.
         left ; left. destruct k. simpl in i ; simpl in i0. apply InT_split in i. destruct i. destruct s ; subst.
         apply InT_split in i0. destruct i0. destruct s ; subst. apply IdPRule_I.
      + destruct (critical_Seq_dec k).
         -- destruct (dec_init_rules k).
            ** assert (is_init k) ; auto. assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
                pose (@GUI_inv_critic_init p k _ J0 c X). rewrite <- e.
                assert ((X0, Top :: Y0) = (X0, [] ++ Top :: Y0)). auto. rewrite H0. apply TopR.
            ** assert ((is_init k) -> False) ; auto. assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
                assert (J1: Gimap (GUI p) (GLR_prems (nodupseq k)) (map (UI p) (GLR_prems (nodupseq k)))). apply Gimap_map. intros.
                apply UI_GUI ; auto.
                assert (J2: (Gimap (GN p (GUI p) k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), [])))
                (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), [])))))). apply Gimap_map. intros.
                apply (N_spec p k x).
                assert (J40: fst k <> []). intro. rewrite H1 in i ; inversion i.
                pose (@GUI_inv_critic_not_init p k _ _ _ J0 c NE H0 J1 J2). rewrite <- e.
                pose (OrR (X0,Y0)). simpl in g0. apply g0.
                apply (@GLS_adm_list_exch_R (X0,
                Or (list_disj (map Neg (restr_list_prop p (fst k))))
                   (Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k)))))
                      (Diam
                         (list_conj
                            (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list)))))))
                 :: list_disj (restr_list_prop p (snd k)) :: Y0)).
                2: epose (list_exch_RI _ [] [Or (list_disj (map Neg (restr_list_prop p (fst k)))) (Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k)))))
                (Diam (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list)))))))] [] [list_disj (restr_list_prop p (snd k))] Y0) ; simpl in l ; apply l.
                pose (OrR (X0,list_disj (restr_list_prop p (snd k)) :: Y0)). simpl in g1. apply g1.
                assert (J3: InT (Neg # P) (map Neg (restr_list_prop p (fst k)))). unfold restr_list_prop. apply InT_map_iff.
                exists (# P) ; split ; auto. apply In_InT. apply in_not_touched_remove. apply In_list_In_list_prop_LF ; apply InT_In ; auto.
                intro. apply propvar. rewrite <- H1. rewrite propvar_subform_list_app. apply in_or_app ; right.
                apply In_list_In_propvar_subform_list ; apply InT_In ; auto.
                remember (Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam (list_conj
                       (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
                 :: list_disj (restr_list_prop p (snd k)) :: Y0) as Y.
                pose (list_disj_wkn_R (map Neg (restr_list_prop p (fst k))) (X0, Y) (Neg # P) J3). apply g2. simpl.
                unfold Neg. apply derI with (ps:=[([] ++ # P :: X0, [] ++ ⊥ :: Y)]). apply ImpR. assert ((X0, # P --> ⊥ :: Y) = ([] ++ X0, [] ++ # P --> ⊥ :: Y)).
                auto. rewrite H1. apply ImpRRule_I. apply dlCons. 2: apply dlNil.
                assert (InT (# P) ([] ++ ⊥ :: Y)). simpl. apply InT_cons. rewrite HeqY. repeat apply InT_cons ; auto.
                apply InT_split in H1. destruct H1. destruct s. rewrite e0. apply derI with (ps:=[]). apply IdP. apply IdPRule_I.
                apply dlNil.
         -- assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
            assert (J1: Gimap (GUI p) (Canopy (nodupseq k)) (map (UI p) (Canopy (nodupseq k)))). apply Gimap_map. intros.
            apply UI_GUI ; auto.
            pose (@GUI_inv_not_critic p k _ _ J0 f J1). rewrite <- e.
            pose (list_conj_R (map (UI p) (Canopy (nodupseq k))) (X0,Y0)). simpl in g0. apply g0. intros.
            apply InT_map_iff in H0. destruct H0. destruct p0. subst.
            assert (LexSeq x k). pose (Canopy_LexSeq _ _ i1). destruct s ; subst ; auto. exfalso.
            apply f ; apply Canopy_critical in i1 ; auto. apply critical_nodupseq ; auto. apply LexSeq_nodupseq in l ; auto.
            simpl in SIH.
            assert (J2: GLS_rules [] (fst x ++ X0, snd x ++ Y0)).
            apply IdP. assert (InT (# P) (snd x ++ Y0)). apply InT_or_app ; auto. apply InT_split in H1.
            destruct H1. destruct s. rewrite e0. assert (InT (# P) (fst x ++ X0)). apply InT_or_app ; left.
            apply Canopy_neg_var with (q:=P) in i1 ; auto. apply In_InT. destruct k ; simpl. apply nodup_In ; simpl in i ; apply InT_In in i ; auto.
            apply InT_split in H1. destruct H1. destruct s. rewrite e1.
            apply IdPRule_I. pose (derI _ J2 d).
            assert (J3: S (dersrec_height d) = derrec_height d0). simpl. lia.
            assert (J4: (fst x ++ X0, snd x ++ Y0) = (fst x ++ X0, snd x ++ Y0)). auto.
            pose (SIH _ H0 _ _ _ _ J3 J4 propvar). auto.
      + destruct (critical_Seq_dec k).
         -- destruct (dec_init_rules k).
            ** assert (is_init k) ; auto. assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
                pose (@GUI_inv_critic_init p k _ J0 c X). rewrite <- e.
                assert ((X0, Top :: Y0) = (X0, [] ++ Top :: Y0)). auto. rewrite H0. apply TopR.
            ** assert ((is_init k) -> False) ; auto. assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
                assert (J1: Gimap (GUI p) (GLR_prems (nodupseq k)) (map (UI p) (GLR_prems (nodupseq k)))). apply Gimap_map. intros.
                apply UI_GUI ; auto.
                assert (J2: (Gimap (GN p (GUI p) k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), [])))
                (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), [])))))). apply Gimap_map. intros.
                apply (N_spec p k x).
                pose (@GUI_inv_critic_not_init p k _ _ _ J0 c NE H0 J1 J2). rewrite <- e.
                pose (OrR (X0,Y0)). simpl in g0. apply g0.
                assert (J3: InT (# P) (restr_list_prop p (snd k))). unfold restr_list_prop. apply In_InT.
                apply in_not_touched_remove. apply In_list_In_list_prop_LF ; apply InT_In ; auto.
                intro. apply propvar. rewrite <- H1. rewrite propvar_subform_list_app. apply in_or_app ; left.
                apply In_list_In_propvar_subform_list ; apply InT_In ; auto.
                remember (Or (list_disj (map Neg (restr_list_prop p (fst k)))) (Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
                (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))) :: Y0) as Y.
                pose (list_disj_wkn_R (restr_list_prop p (snd k)) (X0, Y) (# P) J3). apply g1. simpl.
                apply InT_split in i. destruct i. destruct s. rewrite e0. apply derI with (ps:=[]). apply IdP. 2: apply dlNil.
                assert ((x ++ # P :: x0, # P :: Y) = (x ++ # P :: x0, [] ++ # P :: Y)). auto. rewrite H1 ; apply IdPRule_I.
         -- assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
            assert (J1: Gimap (GUI p) (Canopy (nodupseq k)) (map (UI p) (Canopy (nodupseq k)))). apply Gimap_map. intros.
            apply UI_GUI ; auto.
            pose (@GUI_inv_not_critic p k _ _ J0 f J1). rewrite <- e.
            pose (list_conj_R (map (UI p) (Canopy (nodupseq k))) (X0,Y0)). simpl in g0. apply g0. intros.
            apply InT_map_iff in H0. destruct H0. destruct p0. subst.
            assert (LexSeq x k). pose (Canopy_LexSeq _ _ i1). destruct s ; subst ; auto. exfalso.
            apply f ; apply Canopy_critical in i1 ; auto. apply critical_nodupseq ; auto. apply LexSeq_nodupseq in l ; auto. simpl in SIH.
            assert (J2: GLS_rules [] (fst x ++ X0, snd x ++ Y0)).
            apply IdP. assert (InT (# P) (fst x ++ X0)). apply InT_or_app ; auto. apply InT_split in H1.
            destruct H1. destruct s. rewrite e0. assert (InT (# P) (snd x ++ Y0)). apply InT_or_app ; left.
            apply Canopy_pos_var with (q:=P) in i1 ; auto. auto. apply In_InT. destruct k ; simpl. apply nodup_In ; simpl in i0 ; apply InT_In in i0 ; auto.
            apply InT_split in H1. destruct H1. destruct s. rewrite e1.
            apply IdPRule_I. pose (derI _ J2 d).
            assert (J3: S (dersrec_height d) = derrec_height d0). simpl. lia.
            assert (J4: (fst x ++ X0, snd x ++ Y0) = (fst x ++ X0, snd x ++ Y0)). auto.
            pose (SIH _ H0 _ _ _ _ J3 J4 propvar). auto.
      + apply derI with (ps:=[]). 2: apply dlNil. apply IdP. apply InT_split in i. destruct i. destruct s ; subst.
         apply InT_split in i0. destruct i0. destruct s ; subst. assert (UI p k :: x1 ++ # P :: x2 = (UI p k :: x1) ++ # P :: x2).
         auto. rewrite H0. apply IdPRule_I.

    (* BotL *)
    * inversion H ; subst.
      assert (InT ⊥ (fst k ++ X0)). rewrite <- H2. apply InT_or_app ; right ; apply InT_eq.
      apply InT_app_or in H0. destruct H0.
      + assert ((X0, UI p k :: Y0) = (X0, [] ++ UI p k :: Y0)). auto. rewrite H0. apply is_init_UI.
         right. destruct k. simpl in i. apply InT_split in i. destruct i. destruct s ; subst. apply BotLRule_I.
      + apply derI with (ps:=[]). 2: apply dlNil. apply BotL. apply InT_split in i. destruct i. destruct s ; subst.
         apply BotLRule_I.

    (* ImpR *)
    * destruct (critical_Seq_dec k).
      (* If critical, then the rule ImpR was applied on a formula in X0 or Y0.
          So, apply PIH omn the premise and then the rule. *)

      + inversion H ; subst. assert (J0: dersrec_height d = dersrec_height d) ; auto.
         apply dersrec_derrec_height in J0. destruct J0.
         assert (J1: derrec_height x = derrec_height x). auto.
         assert (J2: list_exch_L (Γ0 ++ A :: Γ1, Δ0 ++ B :: Δ1) (A :: fst k ++ X0, Δ0 ++ B :: Δ1)).
         assert ((Γ0 ++ A :: Γ1, Δ0 ++ B :: Δ1) = ([] ++ [] ++ Γ0 ++ [A] ++ Γ1, Δ0 ++ B :: Δ1)). auto.
         rewrite H0.
         assert ((A :: fst k ++ X0, Δ0 ++ B :: Δ1) = ([] ++ [A] ++ Γ0 ++ [] ++ Γ1, Δ0 ++ B :: Δ1)).
         simpl. rewrite H2. auto. rewrite H1. apply list_exch_LI.
         pose (GLS_hpadm_list_exch_L x J1 J2). destruct s.
         assert (J3: derrec_height x0 = derrec_height x0). auto.
         assert (J4: list_exch_L (A :: fst k ++ X0, Δ0 ++ B :: Δ1) (fst k ++ A :: X0, Δ0 ++ B :: Δ1)).
         assert ((fst k ++ A :: X0, Δ0 ++ B :: Δ1) = ([] ++ [] ++ fst k ++ [A] ++ X0, Δ0 ++ B :: Δ1)). auto.
         rewrite H0.
         assert ((A :: fst k ++ X0, Δ0 ++ B :: Δ1) = ([] ++ [A] ++ fst k ++ [] ++ X0, Δ0 ++ B :: Δ1)).
         auto. rewrite H1. apply list_exch_LI.
         pose (GLS_hpadm_list_exch_L x0 J3 J4). destruct s. simpl in PIH.
         apply app2_find_hole in H3. destruct H3.
         repeat destruct s ; destruct p0 ; subst.
         assert (J5: derrec_height x1 < S (dersrec_height d)). lia.
         assert (J6: derrec_height x1 = derrec_height x1). auto.
         assert (J7: (fst k ++ A :: X0, snd k ++ B :: Δ1) = (fst k ++ A:: X0, snd k ++ B :: Δ1)). auto.
         assert (J8: (In # p (propvar_subform_list ((A :: X0) ++ B :: Δ1)) -> False)).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc in H0.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         left ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         left ; apply in_or_app ; auto. apply in_or_app ; right ; apply in_or_app ; auto.
         pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
         apply derI with (ps:=[([] ++ A :: X0, [UI p k] ++ B :: Δ1)]). apply ImpR.
         assert ((X0, UI p k :: A --> B :: Δ1) = ([] ++ X0, [UI p k] ++ A --> B :: Δ1)). auto. rewrite H0.
         apply ImpRRule_I. apply dlCons ; [ simpl ; auto | apply dlNil].
         destruct x2 ; simpl in e1 ; subst. rewrite app_nil_r in e0 ; subst.
         assert (J5: derrec_height x1 < S (dersrec_height d)). lia.
         assert (J6: derrec_height x1 = derrec_height x1). auto.
         assert (J7: (fst k ++ A :: X0, snd k ++ B :: Δ1) = (fst k ++ A:: X0, snd k ++ B :: Δ1)). auto.
         assert (J8: (In # p (propvar_subform_list ((A :: X0) ++ B :: Δ1)) -> False)).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc in H0.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         left ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         left ; apply in_or_app ; auto. apply in_or_app ; right ; apply in_or_app ; auto.
         pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
         apply derI with (ps:=[([] ++ A :: X0, [UI p k] ++ B :: Δ1)]). apply ImpR.
         assert ((X0, UI p k :: A --> B :: Δ1) = ([] ++ X0, [UI p k] ++ A --> B :: Δ1)). auto. rewrite H0.
         apply ImpRRule_I. apply dlCons ; [ simpl ; auto | apply dlNil].
         exfalso. destruct k ; simpl in e0 ; subst. unfold critical_Seq in c ; unfold is_Prime in c ; simpl in c.
         assert (In m (l1 ++ Δ0 ++ m :: x2)). apply in_or_app ; right ; apply in_or_app ; right ; apply in_eq.
         apply c in H0. inversion e1 ; subst. destruct H0 ; destruct H0 ; inversion H0 ; inversion H1.
         assert (J5: derrec_height x1 < S (dersrec_height d)). lia.
         assert (J6: derrec_height x1 = derrec_height x1). auto.
         assert (J7: (fst k ++ A :: X0, (snd k ++ x2) ++ B :: Δ1) = (fst k ++ A:: X0, snd k ++ x2 ++ B :: Δ1)).
         repeat rewrite <- app_assoc. auto.
         assert (J8: (In # p (propvar_subform_list ((A :: X0) ++ (x2 ++ B :: Δ1))) -> False)).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc in H0.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; left ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; left ; apply in_or_app ; auto.
         apply in_or_app ; right ; apply in_or_app ; right ; apply in_or_app ; auto.
         pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
         apply derI with (ps:=[([] ++ A :: X0, (UI p k :: x2) ++ B :: Δ1)]). apply ImpR.
         assert ((X0, UI p k :: x2 ++ A --> B :: Δ1) = ([] ++ X0, (UI p k :: x2) ++ A --> B :: Δ1)). auto. rewrite H0.
         apply ImpRRule_I. apply dlCons ; [ simpl ; auto | apply dlNil].
      (*  If not critical, consider the conjunction that UI p k is. *)
      + assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
         assert (J1: Gimap (GUI p) (Canopy (nodupseq k)) (map (UI p) (Canopy (nodupseq k)))). apply Gimap_map. intros.
         apply UI_GUI ; auto.
         pose (@GUI_inv_not_critic p k (UI p k) (map (UI p) (Canopy (nodupseq k))) J0 f J1). rewrite <- e.

         assert (J2: forall s1, InT s1 (Canopy (nodupseq k)) -> GLS_prv (X0, UI p s1 :: Y0)).
         intros. pose (fold_Canopy _ _ H0). destruct s ; subst.
         exfalso. apply f. apply Canopy_critical in H0 ; auto. apply critical_nodupseq in H0 ; auto.
         destruct s. destruct p0. unfold inv_prems in i.
         apply InT_flatten_list_InT_elem in i. destruct i. destruct p0. simpl in PIH. simpl in SIH.
         pose (derI _ g d).
         assert (existsT2 (d1: GLS_prv (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)), derrec_height d1 <= derrec_height d0).
         destruct (nodupseq_id k). destruct p0. destruct s. destruct s. destruct p1. destruct p1.
         pose (PermutationTS_prv_hpadm _ d0 (x2 ++ fst x1 ++ X0, x3 ++ snd x1 ++ Y0)). destruct s.
         split ; simpl ; apply Permutation_PermutationT. destruct p1.
         pose (@Permutation_app _ (fst k) X0 (x2 ++ fst x1) X0). rewrite <- app_assoc in p3 ; apply p3 ; auto.
         apply Permutation_PermutationT ; auto. destruct p1.
         pose (@Permutation_app _ (snd k) Y0 (x3 ++ snd x1) Y0). rewrite <- app_assoc in p3 ; apply p3 ; auto.
         apply Permutation_PermutationT ; auto.
         epose (incl_ctr_R_hpadm _ x3 _ x4). destruct s. intros A HA ; apply in_or_app ; left ; auto.
         epose (incl_ctr_L_hpadm x2 _ _ x5). destruct s. intros A HA ; apply in_or_app ; left ; auto.
         pose (PermutationTS_prv_hpadm _ x6 (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)). destruct s.
         split ; simpl ; apply Permutation_PermutationT. destruct p0. apply Permutation_app ; auto.
         unfold nodupseq in p0. apply Permutation_PermutationT ; auto. destruct p0.
         apply Permutation_app ; auto. unfold nodupseq in p2. apply Permutation_PermutationT ; auto.
         exists x7. lia. destruct X.
         assert (J2: derrec_height x1 = derrec_height x1). auto.
         assert (J3: (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0) = (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)). auto.
         pose (Canopy_hp_inv_ctx (nodupseq k) _ _ x1 X0 Y0 J2 J3 _ H0). destruct s.
         destruct (Compare_dec.lt_dec (derrec_height x2) (S (dersrec_height d))).
         (* Use PIH. *)
         pose (fold_Canopy _ _ H0). destruct s ; subst.
         exfalso. apply f. apply Canopy_critical in H0 ; auto. apply critical_nodupseq in H0 ; auto.
         destruct s. destruct p0. unfold inv_prems in i2.
         apply InT_flatten_list_InT_elem in i2. destruct i2. destruct p0.
         assert (J4: derrec_height x2 = derrec_height x2). auto.
         assert (J5: (fst s1 ++ X0, snd s1 ++ Y0) = (fst s1 ++ X0, snd s1 ++ Y0)). auto.
         pose (PIH _ l1 s1 _ x2 X0 Y0 J4 J5). apply g0 ; auto.
         (* Use SIH. *)
         assert (derrec_height x2 = S (dersrec_height d)). assert (derrec_height d0 = S (dersrec_height d)). simpl. auto. lia.
         assert (J4: LexSeq s1 k). pose (Canopy_LexSeq _ _ H0).
         destruct s ; subst ; auto. exfalso. apply f. apply Canopy_critical in H0 ; apply critical_nodupseq in H0 ; auto.
         apply LexSeq_nodupseq in l1 ; auto. symmetry in H1.
         assert (J5: (fst s1 ++ X0, snd s1 ++ Y0) = (fst s1 ++ X0, snd s1 ++ Y0)). auto.
         pose (SIH _ J4 _ _ _ _ H1 J5 propvar). auto.

         assert (J3: (forall A : MPropF, InT A (map (UI p) (Canopy (nodupseq k))) -> GLS_prv (fst (X0, Y0), A :: snd (X0, Y0)))).
         intros. simpl. apply InT_map_iff in H0. destruct H0. destruct p0 ; subst. apply J2 in i ; auto.
         pose (list_conj_R _ _ J3). simpl in g0. auto.

    (* ImpL *)
    * destruct (critical_Seq_dec k).
      (* If critical, then the rule ImpL was applied on a formula in X0 or Y0.
          So, apply PIH on the premises and then the rule. *)

      + inversion H ; subst. assert (J0: dersrec_height d = dersrec_height d) ; auto.
         apply dersrec_derrec2_height in J0. destruct J0. destruct s. simpl in PIH.
         assert (J1: derrec_height x = derrec_height x). auto.
         assert (J2: list_exch_R (Γ0 ++ Γ1, Δ0 ++ A :: Δ1) (Γ0 ++ Γ1, A :: snd k ++ Y0)).
         assert ((Γ0 ++ Γ1, Δ0 ++ A :: Δ1) = (Γ0 ++ Γ1, [] ++ [] ++ Δ0 ++ [A] ++ Δ1)). auto.
         rewrite H0.
         assert ((Γ0 ++ Γ1, A :: snd k ++ Y0) = (Γ0 ++ Γ1, [] ++ [A] ++ Δ0 ++ [] ++ Δ1)).
         simpl. rewrite H3. auto. rewrite H1. apply list_exch_RI.
         pose (GLS_hpadm_list_exch_R x J1 J2). destruct s.
         assert (J3: derrec_height x1 = derrec_height x1). auto.
         assert (J4: list_exch_R (Γ0 ++ Γ1, A :: snd k ++ Y0) (Γ0 ++ Γ1, snd k ++ A :: Y0)).
         assert ((Γ0 ++ Γ1, snd k ++ A :: Y0) = (Γ0 ++ Γ1, [] ++ [] ++ snd k ++ [A] ++ Y0)). auto.
         rewrite H0.
         assert ((Γ0 ++ Γ1, A :: snd k ++ Y0) = (Γ0 ++ Γ1, [] ++ [A] ++ snd k ++ [] ++ Y0)).
         auto. rewrite H1. apply list_exch_RI.
         pose (GLS_hpadm_list_exch_R x1 J3 J4). destruct s.
         apply app2_find_hole in H2. destruct H2.
         repeat destruct s ; destruct p0 ; subst.
         assert (J5: derrec_height x2 < S (dersrec_height d)). lia.
         assert (J6: derrec_height x2 = derrec_height x2). auto.
         assert (J7: (fst k ++ Γ1, snd k ++ A :: Y0) = (fst k ++ Γ1, snd k ++ A :: Y0)). auto.
         assert (J8: In # p (propvar_subform_list (Γ1 ++ A :: Y0)) -> False).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; auto. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto.
         pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
         assert (J9: derrec_height x0 < S (dersrec_height d)). lia.
         assert (J10: derrec_height x0 = derrec_height x0). auto.
         assert (J11: (fst k ++ B :: Γ1, Δ0 ++ Δ1) = (fst k ++ B :: Γ1, snd k ++ Y0)). rewrite H3 ; auto.
         assert (J12: In # p (propvar_subform_list ((B :: Γ1) ++ Y0)) -> False).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc. repeat rewrite <- app_assoc in H0.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto.
         pose (PIH _ J9 _ _ _ _ _ J10 J11 J12).
         apply derI with (ps:=[([] ++ Γ1, [UI p k] ++ A :: Y0);([] ++ B :: Γ1, [UI p k] ++ Y0)]). apply ImpL.
         assert ((A --> B :: Γ1, UI p k :: Y0) = ([] ++ A --> B :: Γ1, [UI p k] ++ Y0)). auto. rewrite H0.
         apply ImpLRule_I. apply dlCons. auto. apply dlCons. auto. apply dlNil.
         destruct x3 ; simpl in e1 ; subst. rewrite app_nil_r in e0 ; subst.
         assert (J5: derrec_height x2 < S (dersrec_height d)). lia.
         assert (J6: derrec_height x2 = derrec_height x2). auto.
         assert (J7: (fst k ++ Γ1, snd k ++ A :: Y0) = (fst k ++ Γ1, snd k ++ A :: Y0)). auto.
         assert (J8: In # p (propvar_subform_list (Γ1 ++ A :: Y0)) -> False).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; auto. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto.
         pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
         assert (J9: derrec_height x0 < S (dersrec_height d)). lia.
         assert (J10: derrec_height x0 = derrec_height x0). auto.
         assert (J11: (fst k ++ B :: Γ1, Δ0 ++ Δ1) = (fst k ++ B :: Γ1, snd k ++ Y0)). rewrite H3 ; auto.
         assert (J12: In # p (propvar_subform_list ((B :: Γ1) ++ Y0)) -> False).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc. repeat rewrite <- app_assoc in H0.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto. apply in_or_app ; right ; apply in_or_app ;
         right ; apply in_or_app ; auto.
         pose (PIH _ J9 _ _ _ _ _ J10 J11 J12).
         apply derI with (ps:=[([] ++ Γ1, [UI p k] ++ A :: Y0);([] ++ B :: Γ1, [UI p k] ++ Y0)]). apply ImpL.
         assert ((A --> B :: Γ1, UI p k :: Y0) = ([] ++ A --> B :: Γ1, [UI p k] ++ Y0)). auto. rewrite H0.
         apply ImpLRule_I. apply dlCons. auto. apply dlCons. auto. apply dlNil.
         exfalso. destruct k ; simpl in e0 ; subst. unfold critical_Seq in c ; unfold is_Prime in c ; simpl in c.
         assert (In m ((Γ0 ++ m :: x3) ++ l2)). repeat rewrite <- app_assoc. apply in_or_app ; right ; apply in_or_app ; left ; apply in_eq.
         apply c in H0. inversion e1 ; subst. destruct H0 ; destruct H0 ; inversion H0 ; inversion H1.
         assert (J5: derrec_height x2 < S (dersrec_height d)). lia.
         assert (J6: derrec_height x2 = derrec_height x2). auto.
         assert (J7: ((fst k ++ x3) ++ Γ1, snd k ++ A :: Y0) = (fst k ++ x3 ++ Γ1, snd k ++ A :: Y0)).
         rewrite <- app_assoc ; auto.
         assert (J8: In # p (propvar_subform_list ((x3 ++ Γ1) ++ A :: Y0)) -> False).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc. repeat rewrite <- app_assoc in H0.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; auto. apply in_app_or in H0 ; destruct H0.
         apply in_or_app ; right ; apply in_or_app ; right ; apply in_or_app ; right ; apply in_or_app ; auto.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; right ; apply in_or_app ; auto.
         apply in_or_app ; right ; apply in_or_app ; right ; apply in_or_app ; right ; apply in_or_app ; auto.
         pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
         assert (J9: derrec_height x0 < S (dersrec_height d)). lia.
         assert (J10: derrec_height x0 = derrec_height x0). auto.
         assert (J11: ((fst k ++ x3) ++ B :: Γ1, Δ0 ++ Δ1) = (fst k ++ x3 ++ B :: Γ1, snd k ++ Y0)).
         rewrite H3 ; rewrite <- app_assoc ; auto.
         assert (J12: In # p (propvar_subform_list ((x3 ++ B :: Γ1) ++ Y0)) -> False).
         intro. apply propvar. repeat rewrite propvar_subform_list_app.
         repeat rewrite propvar_subform_list_app in H0. simpl in H0. simpl.
         repeat rewrite <- app_assoc. repeat rewrite <- app_assoc in H0.
         apply in_app_or in H0 ; destruct H0. apply in_or_app ; auto. apply in_or_app ; right ; apply in_or_app ; auto.
         pose (PIH _ J9 _ _ _ _ _ J10 J11 J12).
         apply derI with (ps:=[(x3 ++ Γ1, [UI p k] ++ A :: Y0);(x3 ++ B :: Γ1, [UI p k] ++ Y0)]). apply ImpL.
         assert ((x3 ++ A --> B :: Γ1, UI p k :: Y0) = (x3 ++ A --> B :: Γ1, [UI p k] ++ Y0)). auto. rewrite H0.
         apply ImpLRule_I. apply dlCons. auto. apply dlCons. auto. apply dlNil.
      (*  If not critical, consider the conjunction that UI p k is. *)
      + assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
         assert (J1: Gimap (GUI p) (Canopy (nodupseq k)) (map (UI p) (Canopy (nodupseq k)))). apply Gimap_map. intros.
         apply UI_GUI ; auto.
         pose (@GUI_inv_not_critic p k (UI p k) (map (UI p) (Canopy (nodupseq k))) J0 f J1). rewrite <- e.

         assert (J2: forall s1, InT s1 (Canopy (nodupseq k)) -> GLS_prv (X0, UI p s1 :: Y0)).
         intros. pose (fold_Canopy _ _ H0). destruct s ; subst.
         exfalso. apply f. apply Canopy_critical in H0 ; auto. apply critical_nodupseq in H0 ; auto.
         destruct s. destruct p0. unfold inv_prems in i.
         apply InT_flatten_list_InT_elem in i. destruct i. destruct p0. simpl in PIH. simpl in SIH.
         pose (derI _ g d).

         assert (existsT2 (d1: GLS_prv (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)), derrec_height d1 <= derrec_height d0).
         destruct (nodupseq_id k). destruct p0. destruct s. destruct s. destruct p1. destruct p1.
         pose (PermutationTS_prv_hpadm _ d0 (x2 ++ fst x1 ++ X0, x3 ++ snd x1 ++ Y0)). destruct s.
         split ; simpl ; apply Permutation_PermutationT. destruct p1.
         pose (@Permutation_app _ (fst k) X0 (x2 ++ fst x1) X0). rewrite <- app_assoc in p3 ; apply p3 ; auto.
         apply Permutation_PermutationT ; auto. destruct p1.
         pose (@Permutation_app _ (snd k) Y0 (x3 ++ snd x1) Y0). rewrite <- app_assoc in p3 ; apply p3 ; auto.
         apply Permutation_PermutationT ; auto.
         epose (incl_ctr_R_hpadm _ x3 _ x4). destruct s. intros A HA ; apply in_or_app ; left ; auto.
         epose (incl_ctr_L_hpadm x2 _ _ x5). destruct s. intros A HA ; apply in_or_app ; left ; auto.
         pose (PermutationTS_prv_hpadm _ x6 (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)). destruct s.
         split ; simpl ; apply Permutation_PermutationT. destruct p0. apply Permutation_app ; auto.
         unfold nodupseq in p0. apply Permutation_PermutationT ; auto. destruct p0.
         apply Permutation_app ; auto. unfold nodupseq in p2. apply Permutation_PermutationT ; auto.
         exists x7. lia. destruct X.
         assert (J2: derrec_height x1 = derrec_height x1). auto.
         assert (J3: (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0) = (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)). auto.
         pose (Canopy_hp_inv_ctx (nodupseq k) _ _ x1 X0 Y0 J2 J3 _ H0). destruct s.
         destruct (Compare_dec.lt_dec (derrec_height x2) (S (dersrec_height d))).
         (* Use PIH. *)
         pose (fold_Canopy _ _ H0). destruct s ; subst.
         exfalso. apply f. apply Canopy_critical in H0 ; auto. apply critical_nodupseq in H0 ; auto.
         destruct s. destruct p0. unfold inv_prems in i2.
         apply InT_flatten_list_InT_elem in i2. destruct i2. destruct p0.
         assert (J4: derrec_height x2 = derrec_height x2). auto.
         assert (J5: (fst s1 ++ X0, snd s1 ++ Y0) = (fst s1 ++ X0, snd s1 ++ Y0)). auto.
         pose (PIH _ l1 s1 _ x2 X0 Y0 J4 J5). apply g0 ; auto.
         (* Use SIH. *)
         assert (derrec_height x2 = S (dersrec_height d)). assert (derrec_height d0 = S (dersrec_height d)). simpl. auto. lia.
         assert (J4: LexSeq s1 k). pose (Canopy_LexSeq _ _ H0).
         destruct s ; subst ; auto. exfalso. apply f. apply Canopy_critical in H0 ; apply critical_nodupseq in H0 ; auto.
         apply LexSeq_nodupseq in l1 ; auto. symmetry in H1.
         assert (J5: (fst s1 ++ X0, snd s1 ++ Y0) = (fst s1 ++ X0, snd s1 ++ Y0)). auto.
         pose (SIH _ J4 _ _ _ _ H1 J5 propvar). auto.

         assert (J3: (forall A : MPropF, InT A (map (UI p) (Canopy (nodupseq k))) -> GLS_prv (fst (X0, Y0), A :: snd (X0, Y0)))).
         intros. simpl. apply InT_map_iff in H0. destruct H0. destruct p0 ; subst. apply J2 in i ; auto.
         pose (list_conj_R _ _ J3). simpl in g0. auto.

    (* GLR *)
    * destruct (critical_Seq_dec k).
      (* If critical. *)
      + inversion X ; subst. (* Not sure the two lines below are useful. *)
         assert (J0: dersrec_height d = dersrec_height d) ; auto.
         apply dersrec_derrec_height in J0. destruct J0. simpl in PIH. simpl in SIH.
         destruct (dec_init_rules k).
         (* If initial. *)
        ** assert (is_init k) ; auto. assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
         pose (@GUI_inv_critic_init p k _ J0 c X2). rewrite <- e0.
         assert ((X0, Top :: Y0) = (X0, [] ++ Top :: Y0)). auto. rewrite H. apply TopR.
         (* If not initial. *)
        ** apply univ_gen_ext_splitR in X1. destruct X1. destruct s. destruct p0. destruct p0.
         apply app2_find_hole in H2. destruct H2.
         assert ((is_init k) -> False) ; auto.
         assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
         assert (J1: Gimap (GUI p) (GLR_prems (nodupseq k)) (map (UI p) (GLR_prems (nodupseq k)))). apply Gimap_map. intros.
         apply UI_GUI ; auto.
         assert (J2: (Gimap (GN p (GUI p) k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), [])))
         (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), [])))))). apply Gimap_map. intros.
         apply (N_spec p k x3).
         pose (@GUI_inv_critic_not_init p k _ _ _ J0 c NE H J1 J2). rewrite <- e1. clear e1.
         repeat destruct s ; destruct p0 ; subst.
         (* If Box A is in Y0. *)
         -- pose (OrR (X0,Box A :: Δ1)). simpl in g0. apply g0. clear g0.
            apply GLS_prv_wkn_R with (A:=list_disj (restr_list_prop p (snd k))) (s:=(X0,
            Or (list_disj (map Neg (restr_list_prop p (fst k))))(Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
            (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list)))))))
            :: Box A :: Δ1)).
            2: epose (wkn_RI (list_disj (restr_list_prop p (snd k))) _ [] _) ; simpl in w ; apply w.
            pose (OrR (X0,Box A :: Δ1)). simpl in g0. apply g0. clear g0.
            apply GLS_prv_wkn_R with (A:=list_disj (map Neg (restr_list_prop p (fst k)))) (s:=(X0,
            Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
            (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
            :: Box A :: Δ1)).
            2: epose (wkn_RI (list_disj (map Neg (restr_list_prop p (fst k)))) _ [] _) ; simpl in w ; apply w.
            pose (OrR (X0,Box A :: Δ1)). simpl in g0. apply g0. clear g0.
            apply GLS_prv_wkn_R with (A:=list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (s:=(X0,
            (Diam (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
            :: Box A :: Δ1)).
            2: epose (wkn_RI (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) _ [] _) ; simpl in w ; apply w.
            apply Diam_rec_UI ; auto.
            assert (J5: derrec_height x < S (dersrec_height d)). lia.
            assert (J6: derrec_height x = derrec_height x). auto.
            assert (J7: (XBoxed_list (x0 ++ x1) ++ [Box A], [A]) = (fst (XBoxed_list x0, @nil MPropF) ++ XBoxed_list x1 ++ [Box A], snd (XBoxed_list x0, []) ++ [A])).
            simpl ; rewrite XBox_app_distrib. repeat rewrite <- app_assoc ; auto.
            assert (J8: (In # p (propvar_subform_list ((XBoxed_list x1 ++ [Box A]) ++ [A])) -> False)).
            intro. apply propvar. repeat rewrite propvar_subform_list_app.
            repeat rewrite propvar_subform_list_app in H0. simpl in H0. repeat rewrite app_nil_r in H0. simpl.
            repeat rewrite <- app_assoc in H0. apply in_app_or in H0 ; destruct H0.
            apply in_or_app ; left. apply propvar_subform_list_XBoxed_list in H0.
            apply propvar_subform_list_nobox_gen_ext with (l0:=x1); auto.
            apply in_or_app ; right ; apply in_or_app ; left. apply in_app_or in H0 ; destruct H0 ; auto.
            pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
            apply derI with (ps:=[(X0 ++ Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))) :: [], [] ++ Bot :: Box A :: Δ1)]).
            apply ImpR. assert ((X0, Diam (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: Box A :: Δ1) =
            (X0 ++ [], [] ++ Diam (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: Box A :: Δ1)). rewrite app_nil_r. auto. rewrite H0.
            apply ImpRRule_I. apply dlCons. 2: apply dlNil.
            apply derI with (ps:=[(XBoxed_list (x1 ++ [Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))]) ++ [Box A], [A])]).
            apply GLR. assert (([] ++ ⊥ :: Box A :: Δ1) = [⊥] ++ Box A :: Δ1). auto. rewrite H0. apply GLRRule_I ; auto.
            intro. intros. apply in_app_or in H2 ; destruct H2. apply H1 ; apply in_or_app ; auto. exists (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))).
            inversion H2 ; subst ; auto. inversion H3. apply univ_gen_ext_combine ; auto. apply univ_gen_ext_cons. apply univ_gen_ext_nil.
            apply dlCons. 2: apply dlNil. rewrite XBox_app_distrib. simpl. repeat rewrite <- app_assoc. simpl.
            apply GLS_prv_wkn_L with (A:=Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))) (s:=(XBoxed_list x1 ++
            [Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)); Box A], [A])).
            2: epose (wkn_LI (Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))) (XBoxed_list x1 ++ [Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))]) [Box A] _) ;
            simpl in w ; repeat rewrite <- app_assoc in w ; simpl in w ; apply w.
            apply derI with (ps:=[(XBoxed_list x1 ++ [Box A], [] ++ (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: [A]);
            (XBoxed_list x1 ++ Bot :: [Box A], [] ++ [A])]). apply ImpL. apply ImpLRule_I. apply dlCons. 2: apply dlCons.
            3: apply dlNil. 2: apply derI with (ps:=[]) ; [apply BotL ; apply BotLRule_I | apply dlNil].
            simpl. assert ((top_boxes (fst k)) = x0). symmetry. apply nobox_gen_ext_top_boxes_identity ; auto.
            intro. intros. apply H1 ; apply in_or_app ; auto. rewrite H0. auto.
        -- destruct x2 ; simpl in e2 ; subst.
            (* If Box A is in Y0 (bis). *)
            +++ rewrite app_nil_r in e1 ; subst.
                pose (OrR (X0,Box A :: Δ1)). simpl in g0. apply g0. clear g0.
                apply GLS_prv_wkn_R with (A:=list_disj (restr_list_prop p (snd k))) (s:=(X0,
                Or (list_disj (map Neg (restr_list_prop p (fst k))))(Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
                (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list)))))))
                :: Box A :: Δ1)).
                2: epose (wkn_RI (list_disj (restr_list_prop p (snd k))) _ [] _) ; simpl in w ; apply w.
                pose (OrR (X0,Box A :: Δ1)). simpl in g0. apply g0. clear g0.
                apply GLS_prv_wkn_R with (A:=list_disj (map Neg (restr_list_prop p (fst k)))) (s:=(X0,
                Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
                (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
                :: Box A :: Δ1)).
                2: epose (wkn_RI (list_disj (map Neg (restr_list_prop p (fst k)))) _ [] _) ; simpl in w ; apply w.
                pose (OrR (X0,Box A :: Δ1)). simpl in g0. apply g0. clear g0.
                apply GLS_prv_wkn_R with (A:=list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (s:=(X0,
                (Diam (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
                :: Box A :: Δ1)).
                2: epose (wkn_RI (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) _ [] _) ; simpl in w ; apply w.
                apply Diam_rec_UI ; auto.
                assert (J5: derrec_height x < S (dersrec_height d)). lia.
                assert (J6: derrec_height x = derrec_height x). auto.
                assert (J7: (XBoxed_list (x0 ++ x1) ++ [Box A], [A]) = (fst (XBoxed_list x0, @nil MPropF) ++ XBoxed_list x1 ++ [Box A], snd (XBoxed_list x0, []) ++ [A])).
                simpl ; rewrite XBox_app_distrib. repeat rewrite <- app_assoc ; auto.
                assert (J8: (In # p (propvar_subform_list ((XBoxed_list x1 ++ [Box A]) ++ [A])) -> False)).
                intro. apply propvar. repeat rewrite propvar_subform_list_app.
                repeat rewrite propvar_subform_list_app in H0. simpl in H0. repeat rewrite app_nil_r in H0. simpl.
                repeat rewrite <- app_assoc in H0. apply in_app_or in H0 ; destruct H0.
                apply in_or_app ; left. apply propvar_subform_list_XBoxed_list in H0.
                apply propvar_subform_list_nobox_gen_ext with (l0:=x1); auto.
                apply in_or_app ; right ; apply in_or_app ; left. apply in_app_or in H0 ; destruct H0 ; auto.
                pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
                apply derI with (ps:=[(X0 ++ Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))) :: [], [] ++ Bot :: Box A :: Δ1)]).
                apply ImpR. assert ((X0, Diam (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: Box A :: Δ1) =
                (X0 ++ [], [] ++ Diam (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: Box A :: Δ1)). rewrite app_nil_r. auto. rewrite H0.
                apply ImpRRule_I. apply dlCons. 2: apply dlNil.
                apply derI with (ps:=[(XBoxed_list (x1 ++ [Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))]) ++ [Box A], [A])]).
                apply GLR. assert (([] ++ ⊥ :: Box A :: Δ1) = [⊥] ++ Box A :: Δ1). auto. rewrite H0. apply GLRRule_I ; auto.
                intro. intros. apply in_app_or in H2 ; destruct H2. apply H1 ; apply in_or_app ; auto. exists (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))).
                inversion H2 ; subst ; auto. inversion H3. apply univ_gen_ext_combine ; auto. apply univ_gen_ext_cons. apply univ_gen_ext_nil.
                apply dlCons. 2: apply dlNil. rewrite XBox_app_distrib. simpl. repeat rewrite <- app_assoc. simpl.
                apply GLS_prv_wkn_L with (A:=Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))) (s:=(XBoxed_list x1 ++
                [Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)); Box A], [A])).
                2: epose (wkn_LI (Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))) (XBoxed_list x1 ++ [Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))]) [Box A] _) ;
                simpl in w ; repeat rewrite <- app_assoc in w ; simpl in w ; apply w.
                apply derI with (ps:=[(XBoxed_list x1 ++ [Box A], [] ++ (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: [A]);
                (XBoxed_list x1 ++ Bot :: [Box A], [] ++ [A])]). apply ImpL. apply ImpLRule_I. apply dlCons. 2: apply dlCons.
                3: apply dlNil. 2: apply derI with (ps:=[]) ; [apply BotL ; apply BotLRule_I | apply dlNil].
                simpl. assert ((top_boxes (fst k)) = x0). symmetry. apply nobox_gen_ext_top_boxes_identity ; auto.
                intro. intros. apply H1 ; apply in_or_app ; auto. rewrite H0. auto.
           (* If Box A is in (snd k). *)
           +++ inversion e2 ; subst.
                assert (J10:derrec_height x = derrec_height x) ; auto.
                assert (J11: list_exch_L (XBoxed_list (x0 ++ x1) ++ [Box A], [A]) ((XBoxed_list x0 ++ [Box A]) ++ XBoxed_list x1, [A])).
                assert (XBoxed_list (x0 ++ x1) ++ [Box A] = XBoxed_list x0 ++ [] ++ XBoxed_list x1 ++ [Box A] ++ []). rewrite XBox_app_distrib.
                repeat rewrite <- app_assoc. auto. rewrite H0.
                assert ((XBoxed_list x0 ++ [Box A]) ++ XBoxed_list x1 = XBoxed_list x0 ++ [Box A] ++ XBoxed_list x1 ++ [] ++ []).
                repeat rewrite <- app_assoc. auto. repeat rewrite app_nil_r. auto. rewrite H2. apply list_exch_LI.
                pose (GLS_hpadm_list_exch_L _ J10 J11). destruct s.
                pose (incl_hpadm_prv _ ((XBoxed_list (top_boxes (fst (nodupseq k))) ++ [Box A]) ++ XBoxed_list x1, [A]) x3). simpl in s. destruct s.
                intros B HB. apply in_app_or in HB ; destruct HB. apply in_app_or in H0 ; destruct H0.
                apply in_or_app ; left. apply in_or_app ; left. destruct (In_XBoxed_list_gen _ _ H0).
                apply list_preserv_XBoxed_list. apply is_box_in_top_boxes. apply nodup_In.
                apply (univ_gen_ext_In _ u) ; auto. apply H1. apply in_or_app ; auto. destruct H2. destruct H2 ; subst.
                apply XBoxed_list_In. apply is_box_in_top_boxes. apply nodup_In. apply (univ_gen_ext_In _ u) ; auto.
                apply H1. apply in_or_app ; auto. inversion H0 ; subst. apply in_or_app ; left ; apply in_or_app ; auto. inversion H2.
                apply in_or_app ; auto. intros B HB ; auto.
                assert (J5: derrec_height x4 < S (dersrec_height d)). lia.
                assert (J6: derrec_height x4 = derrec_height x4). auto.
                assert (J7: ((XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A]) ++ XBoxed_list x1, [A]) = (fst (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++[Box A], [A]) ++ XBoxed_list x1, snd (XBoxed_list x0 ++[Box A], [A]) ++ [])).
                simpl. repeat rewrite <- app_assoc ; auto.
                assert (J8: (In # p (propvar_subform_list ((XBoxed_list x1 ++ [])))) -> False).
                intro. apply propvar. repeat rewrite propvar_subform_list_app.
                repeat rewrite propvar_subform_list_app in H0. simpl in H0. repeat rewrite app_nil_r in H0. simpl.
                repeat rewrite <- app_assoc in H0. apply in_or_app ; left. apply propvar_subform_list_XBoxed_list in H0.
                apply propvar_subform_list_nobox_gen_ext with (l0:=x1); auto.
                pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
                apply GLS_prv_wkn_L with (A:=Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])))
                (sw:=(XBoxed_list x1 ++ [Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A]))] , [UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])])) in g0.
                2: epose (wkn_LI (Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A]))) _ [] _) ; rewrite app_nil_r in w ; simpl in w ; apply w.
                assert (J20: GLS_rules [(XBoxed_list x1 ++ [Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A]))], [UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])])]
                (X0, Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])) :: Y0)). apply GLR.
                assert (Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])) :: Y0 = [] ++ Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])) :: Y0).
                auto. rewrite H0. apply GLRRule_I ;auto. intro. intros. apply H1. apply in_or_app ;auto.
                pose (dlNil GLS_rules (fun _ : Seq => False)).
                pose (dlCons g0 d0). pose (derI _ J20 d1).
                pose (OrR (X0,Y0)). simpl in g1. apply g1. clear g1.
                apply GLS_prv_wkn_R with (A:=list_disj (restr_list_prop p (snd k))) (s:=(X0,
                Or (list_disj (map Neg (restr_list_prop p (fst k))))(Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
                (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list)))))))
                :: Y0)).
                2: epose (wkn_RI (list_disj (restr_list_prop p (snd k))) _ [] _) ; simpl in w ; apply w.
                pose (OrR (X0,Y0)). simpl in g1. apply g1. clear g1.
                apply GLS_prv_wkn_R with (A:=list_disj (map Neg (restr_list_prop p (fst k)))) (s:=(X0,
                Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
                (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
                :: Y0)).
                2: epose (wkn_RI (list_disj (map Neg (restr_list_prop p (fst k)))) _ [] _) ; simpl in w ; apply w.
                pose (OrR (X0,Y0)). simpl in g1. apply g1. clear g1.
                pose (list_disj_wkn_R (map Box (map (UI p) (GLR_prems (nodupseq k)))) (X0, Diam
                 (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))) :: Y0)).
                (* The next UI does not have the correct LHS, which we expect to use x0, to link up with d1. *)
                apply g1 with (A:=Box (UI p (XBoxed_list (top_boxes (fst (nodupseq k))) ++ [Box A], [A]))) ; clear g1 ; simpl ; auto.
                apply InT_map_iff.
                exists (UI p (XBoxed_list (top_boxes (fst (nodupseq k))) ++ [Box A], [A])) ; split ; auto. apply InT_map_iff.
                exists (XBoxed_list (top_boxes (fst (nodupseq k))) ++ [Box A], [A]) ; split ; auto. unfold GLR_prems.
                apply InT_trans_flatten_list with (bs:=[(XBoxed_list (top_boxes (fst (nodupseq k))) ++ [Box A], [A])]) ; auto. apply InT_eq.
                destruct (finite_GLR_premises_of_S (nodupseq k)) ; subst. simpl. apply p0. assert (k = (fst k,Δ0 ++ Box A :: x2)).
                rewrite <- e1. destruct k ; auto. rewrite H0. unfold nodupseq ; simpl.
                assert (InT (Box A) (nodup eq_dec_form (Δ0 ++ Box A :: x2))). apply In_InT ; apply nodup_In ; apply in_or_app ; right ; simpl ; auto.
                apply InT_split in H2 ; destruct H2. destruct s. rewrite e0.
                apply GLRRule_I ; auto. intro. intros. apply in_top_boxes in H2 ; destruct H2. destruct s ; destruct s. destruct p1.
                eexists ; subst ; auto. apply nobox_top_boxes.
                apply GLS_prv_wkn_R with (A:=Diam (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
                (s:=(X0, Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])) :: Y0)) ; auto.
                assert ((X0, Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A])) :: Y0) = (X0, [Box (UI p (XBoxed_list (top_boxes (nodup eq_dec_form (fst k))) ++ [Box A], [A]))] ++ Y0)).
                repeat rewrite <- app_assoc ; auto. rewrite H0. apply wkn_RI.
         (* If Box A is in Y0 (ter). *)
         -- pose (OrR (X0,x2 ++ Box A :: Δ1)). simpl in g0. apply g0. clear g0.
            apply GLS_prv_wkn_R with (A:=list_disj (restr_list_prop p (snd k))) (s:=(X0,
            Or (list_disj (map Neg (restr_list_prop p (fst k))))(Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
            (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list)))))))
            :: x2 ++ Box A :: Δ1)).
            2: epose (wkn_RI (list_disj (restr_list_prop p (snd k))) _ [] _) ; simpl in w ; apply w.
            pose (OrR (X0,x2 ++ Box A :: Δ1)). simpl in g0. apply g0. clear g0.
            apply GLS_prv_wkn_R with (A:=list_disj (map Neg (restr_list_prop p (fst k)))) (s:=(X0,
            Or (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (Diam
            (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
            :: x2 ++ Box A :: Δ1)).
            2: epose (wkn_RI (list_disj (map Neg (restr_list_prop p (fst k)))) _ [] _) ; simpl in w ; apply w.
            pose (OrR (X0,x2 ++ Box A :: Δ1)). simpl in g0. apply g0. clear g0.
            apply GLS_prv_wkn_R with (A:=list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) (s:=(X0,
            (Diam (list_conj (map (N p k) (Canopy (nodupseq (XBoxed_list (top_boxes (fst k)), []%list))))))
            :: x2 ++ Box A :: Δ1)).
            2: epose (wkn_RI (list_disj (map Box (map (UI p) (GLR_prems (nodupseq k))))) _ [] _) ; simpl in w ; apply w.
            apply Diam_rec_UI ; auto.
            assert (J5: derrec_height x < S (dersrec_height d)). lia.
            assert (J6: derrec_height x = derrec_height x). auto.
            assert (J7: (XBoxed_list (x0 ++ x1) ++ [Box A], [A]) = (fst (XBoxed_list x0, @nil MPropF) ++ XBoxed_list x1 ++ [Box A], snd (XBoxed_list x0, []) ++ [A])).
            simpl ; rewrite XBox_app_distrib. repeat rewrite <- app_assoc ; auto.
            assert (J8: (In # p (propvar_subform_list ((XBoxed_list x1 ++ [Box A]) ++ [A])) -> False)).
            intro. apply propvar. repeat rewrite propvar_subform_list_app.
            repeat rewrite propvar_subform_list_app in H0. simpl in H0. repeat rewrite app_nil_r in H0. simpl.
            repeat rewrite <- app_assoc in H0. apply in_app_or in H0 ; destruct H0.
            apply in_or_app ; left. apply propvar_subform_list_XBoxed_list in H0.
            apply propvar_subform_list_nobox_gen_ext with (l0:=x1); auto.
            apply in_or_app ; right ; apply in_or_app ; right ; apply in_or_app ; left. apply in_app_or in H0 ; destruct H0 ; auto.
            pose (PIH _ J5 _ _ _ _ _ J6 J7 J8).
            apply derI with (ps:=[(X0 ++ Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))) :: [], [] ++ Bot :: x2 ++ Box A :: Δ1)]).
            apply ImpR. assert ((X0, Diam (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: x2 ++ Box A :: Δ1) =
            (X0 ++ [], [] ++ Diam (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: x2 ++ Box A :: Δ1)). rewrite app_nil_r. auto. rewrite H0.
            apply ImpRRule_I. apply dlCons. 2: apply dlNil.
            apply derI with (ps:=[(XBoxed_list (x1 ++ [Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))]) ++ [Box A], [A])]).
            apply GLR. assert (([] ++ ⊥ :: x2 ++ Box A :: Δ1) = (⊥ :: x2) ++ Box A :: Δ1). auto. rewrite H0. apply GLRRule_I ; auto.
            intro. intros. apply in_app_or in H2 ; destruct H2. apply H1 ; apply in_or_app ; auto. exists (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))).
            inversion H2 ; subst ; auto. inversion H3. apply univ_gen_ext_combine ; auto. apply univ_gen_ext_cons. apply univ_gen_ext_nil.
            apply dlCons. 2: apply dlNil. rewrite XBox_app_distrib. simpl. repeat rewrite <- app_assoc. simpl.
            apply GLS_prv_wkn_L with (A:=Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))) (s:=(XBoxed_list x1 ++
            [Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)); Box A], [A])).
            2: epose (wkn_LI (Box (Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list)))) (XBoxed_list x1 ++ [Neg (UI p (XBoxed_list (top_boxes (fst k)), []%list))]) [Box A] _) ;
            simpl in w ; repeat rewrite <- app_assoc in w ; simpl in w ; apply w.
            apply derI with (ps:=[(XBoxed_list x1 ++ [Box A], [] ++ (UI p (XBoxed_list (top_boxes (fst k)), []%list)) :: [A]);
            (XBoxed_list x1 ++ Bot :: [Box A], [] ++ [A])]). apply ImpL. apply ImpLRule_I. apply dlCons. 2: apply dlCons.
            3: apply dlNil. 2: apply derI with (ps:=[]) ; [apply BotL ; apply BotLRule_I | apply dlNil].
            simpl. assert ((top_boxes (fst k)) = x0). symmetry. apply nobox_gen_ext_top_boxes_identity ; auto.
            intro. intros. apply H1 ; apply in_or_app ; auto. rewrite H0. auto.
      (*  If not critical, consider the conjunction that UI p k is. *)
      + assert (J0: GUI p k (UI p k)). apply UI_GUI ; auto.
         assert (J1: Gimap (GUI p) (Canopy (nodupseq k)) (map (UI p) (Canopy (nodupseq k)))). apply Gimap_map. intros.
         apply UI_GUI ; auto.
         pose (@GUI_inv_not_critic p k (UI p k) (map (UI p) (Canopy (nodupseq k))) J0 f J1). rewrite <- e.

         assert (J2: forall s1, InT s1 (Canopy (nodupseq k)) -> GLS_prv (X0, UI p s1 :: Y0)).
         intros. pose (fold_Canopy _ _ H). destruct s ; subst.
         exfalso. apply f. apply Canopy_critical in H ; auto. apply critical_nodupseq in H ; auto.
         destruct s. destruct p0. unfold inv_prems in i.
         apply InT_flatten_list_InT_elem in i. destruct i. destruct p0. simpl in PIH. simpl in SIH.
         pose (derI _ g d).

         assert (existsT2 (d1: GLS_prv (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)), derrec_height d1 <= derrec_height d0).
         destruct (nodupseq_id k). destruct p0. destruct s. destruct s. destruct p1. destruct p1.
         pose (PermutationTS_prv_hpadm _ d0 (x2 ++ fst x1 ++ X0, x3 ++ snd x1 ++ Y0)). destruct s.
         split ; simpl ; apply Permutation_PermutationT. destruct p1.
         pose (@Permutation_app _ (fst k) X0 (x2 ++ fst x1) X0). rewrite <- app_assoc in p3 ; apply p3 ; auto.
         apply Permutation_PermutationT ; auto. destruct p1.
         pose (@Permutation_app _ (snd k) Y0 (x3 ++ snd x1) Y0). rewrite <- app_assoc in p3 ; apply p3 ; auto.
         apply Permutation_PermutationT ; auto.
         epose (incl_ctr_R_hpadm _ x3 _ x4). destruct s. intros A HA ; apply in_or_app ; left ; auto.
         epose (incl_ctr_L_hpadm x2 _ _ x5). destruct s. intros A HA ; apply in_or_app ; left ; auto.
         pose (PermutationTS_prv_hpadm _ x6 (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)). destruct s.
         split ; simpl ; apply Permutation_PermutationT. destruct p0. apply Permutation_app ; auto.
         unfold nodupseq in p0. apply Permutation_PermutationT ; auto. destruct p0.
         apply Permutation_app ; auto. unfold nodupseq in p2. apply Permutation_PermutationT ; auto.
         exists x7. lia. destruct X1.
         assert (J2: derrec_height x1 = derrec_height x1). auto.
         assert (J3: (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0) = (fst (nodupseq k) ++ X0, snd (nodupseq k) ++ Y0)). auto.
         pose (Canopy_hp_inv_ctx (nodupseq k) _ _ x1 X0 Y0 J2 J3 _ H). destruct s.
         destruct (Compare_dec.lt_dec (derrec_height x2) (S (dersrec_height d))).
         (* Use PIH. *)
         pose (fold_Canopy _ _ H). destruct s ; subst.
         exfalso. apply f. apply Canopy_critical in H ; auto. apply critical_nodupseq in H ; auto.
         destruct s. destruct p0. unfold inv_prems in i2.
         apply InT_flatten_list_InT_elem in i2. destruct i2. destruct p0.
         assert (J4: derrec_height x2 = derrec_height x2). auto.
         assert (J5: (fst s1 ++ X0, snd s1 ++ Y0) = (fst s1 ++ X0, snd s1 ++ Y0)). auto.
         pose (PIH _ l1 s1 _ x2 X0 Y0 J4 J5). apply g0 ; auto.
         (* Use SIH. *)
         assert (derrec_height x2 = S (dersrec_height d)). assert (derrec_height d0 = S (dersrec_height d)). simpl. auto. lia.
         assert (J4: LexSeq s1 k). pose (Canopy_LexSeq _ _ H).
         destruct s ; subst ; auto. exfalso. apply f. apply Canopy_critical in H ; apply critical_nodupseq in H ; auto.
         apply LexSeq_nodupseq in l1 ; auto. symmetry in H0.
         assert (J5: (fst s1 ++ X0, snd s1 ++ Y0) = (fst s1 ++ X0, snd s1 ++ Y0)). auto.
         pose (SIH _ J4 _ _ _ _ H0 J5 propvar). auto.

         assert (J3: (forall A : MPropF, InT A (map (UI p) (Canopy (nodupseq k))) -> GLS_prv (fst (X0, Y0), A :: snd (X0, Y0)))).
         intros. simpl. apply InT_map_iff in H. destruct H. destruct p0 ; subst. apply J2 in i ; auto.
         pose (list_conj_R _ _ J3). simpl in g0. auto. }
  Qed.

  End UIPThree.