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

Require Import GLS_calcs.

Set Implicit Arguments.

(* First, as we want to mimick sequents based on multisets of formulae we need to
obtain exchange. *)


(* Definition of exchange with lists of formulae directly. It is more general and
makes the proofs easier to handle. *)


Inductive list_exch_L : relationT Seq :=
  | list_exch_LI Γ0 Γ1 Γ2 Γ3 Γ4 Δ : list_exch_L
      (Γ0 Γ1 Γ2 Γ3 Γ4, Δ) (Γ0 Γ3 Γ2 Γ1 Γ4, Δ).

Inductive list_exch_R : relationT Seq :=
  | list_exch_RI Γ Δ0 Δ1 Δ2 Δ3 Δ4 : list_exch_R
        (Γ, Δ0 Δ1 Δ2 Δ3 Δ4) (Γ, Δ0 Δ3 Δ2 Δ1 Δ4).

(* Some lemmas about In and exchange. *)

Lemma InT_list_exch_R : l0 l1 l2,
            (@list_exch_R (,) (,))
            ( x, (InT x InT x ) * (InT x InT x )).
Proof.
intros exch. inversion exch.
intro x. split.
- intro. apply InT_app_or in . destruct . apply InT_or_app. left. assumption.
  apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app. right.
  apply InT_or_app. right. apply InT_or_app. left. assumption. apply InT_app_or in i.
  destruct i. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. left.
  assumption. apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app.
  left. assumption. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right.
  assumption.
- intro. apply InT_app_or in . destruct . apply InT_or_app. left. assumption.
  apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app. right.
  apply InT_or_app. right. apply InT_or_app. left. assumption. apply InT_app_or in i.
  destruct i. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. left.
  assumption. apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app.
  left. assumption. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right.
  assumption.
Qed.


Lemma InT_list_exch_L : l0 l1 l2,
            (@list_exch_L (,) (,))
            ( x, (InT x InT x ) * (InT x InT x )).
Proof.
intros exch. inversion exch.
intro x. split.
- intro. apply InT_app_or in . destruct . apply InT_or_app. left. assumption.
  apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app. right.
  apply InT_or_app. right. apply InT_or_app. left. assumption. apply InT_app_or in i.
  destruct i. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. left.
  assumption. apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app.
  left. assumption. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right.
  assumption.
- intro. apply InT_app_or in . destruct . apply InT_or_app. left. assumption.
  apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app. right.
  apply InT_or_app. right. apply InT_or_app. left. assumption. apply InT_app_or in i.
  destruct i. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. left.
  assumption. apply InT_app_or in i. destruct i. apply InT_or_app. right. apply InT_or_app.
  left. assumption. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right. apply InT_or_app. right.
  assumption.
Qed.


(* Some useful lemmas about list exchange. *)

Lemma list_exch_R_id : s, (@list_exch_R s s).
Proof.
intros s. destruct s. pose (list_exch_RI l
[] [] [] []). simpl in . assert (H: [] = ).
apply app_nil_r. rewrite H in . assumption.
Qed.


Lemma list_exch_L_id : s, (@list_exch_L s s).
Proof.
intros s. destruct s. pose (list_exch_LI l
[] [] [] [] ). simpl in . assert (H: l [] = l).
apply app_nil_r. rewrite H in . assumption.
Qed.


Lemma list_exch_R_same_L: s se,
    (@list_exch_R s se)
    ( Γ Γe Δ Δe, (s = (Γ , Δ))
    (se = (Γe , Δe))
    (Γ = Γe)).
Proof.
intros s se exch. induction exch. intros Γ0 Γe Δ Δe .
inversion . inversion . rewrite in . assumption.
Qed.


Lemma list_exch_L_same_R : s se,
    (@list_exch_L s se)
    ( Γ Γe Δ Δe, (s = (Γ , Δ))
    (se = (Γe , Δe))
    (Δ = Δe)).
Proof.
intros s se exch. induction exch. intros Γ Γe Δ0 Δe .
inversion . inversion . rewrite in . assumption.
Qed.


Lemma list_exch_R_permL : s se,
    (@list_exch_R s se)
      ( Γ0 Γ1 Δ C, s = ((Γ0 C :: Γ1), Δ)
      ( , se = ((Γ0 C :: Γ1), ))).
Proof.
intros s se exch. induction exch. intros Γ0 Γ1 Δ C E.
inversion E. exists (Δ0 Δ3 Δ2 Δ1 Δ4). reflexivity.
Qed.


Lemma list_exch_R_permR : s se,
    (@list_exch_R s se)
      ( Γ Δ0 Δ1 C, s = (Γ, (Δ0 C :: Δ1))
      ( eΔ0 eΔ1, se = (Γ, (eΔ0 C :: eΔ1)))).
Proof.
intros s se exch. induction exch. intros Γ0 Δ5 Δ6 C E.
inversion E. apply partition_1_element in . destruct .
+ destruct s. destruct s. rewrite e. exists x. exists ( Δ3 Δ2 Δ1 Δ4).
  simpl.
  assert (: (x C :: ) Δ3 Δ2 Δ1 Δ4 = x C :: Δ3 Δ2 Δ1 Δ4).
  { symmetry. apply app_assoc with (l:=x) (m:=C :: ) (n:=Δ3 Δ2 Δ1 Δ4). }
  rewrite . reflexivity.
+ destruct s.
  * destruct s. destruct s. exists (Δ0 Δ3 Δ2 x). exists ( Δ4).
    rewrite e. assert (: Δ0 Δ3 Δ2 (x C :: ) Δ4 =
    (Δ0 Δ3 Δ2 x) C :: Δ4).
    pose (app_assoc x (C :: ) Δ4). rewrite . simpl.
    pose (app_assoc (Δ0 Δ3 Δ2) x (C :: Δ4)).
    pose (app_assoc (Δ0 Δ3) Δ2 x).
    pose (app_assoc Δ0 Δ3 Δ2).
    rewrite in . rewrite in .
    pose (app_assoc Δ0 Δ3 (Δ2 x)). rewrite in . rewrite .
    pose (app_assoc (Δ0 Δ3) Δ2 (x C :: Δ4)).
    rewrite in . rewrite .
    pose (app_assoc Δ0 Δ3 (Δ2 x C :: Δ4)). rewrite . reflexivity.
    rewrite . reflexivity.
  * destruct s.
    - destruct s. destruct s. exists (Δ0 Δ3 x). exists ( Δ1 Δ4).
      rewrite e. assert (: Δ0 Δ3 (x C :: ) Δ1 Δ4 =
      (Δ0 Δ3 x) C :: Δ1 Δ4).
      pose (app_assoc x (C :: ) (Δ1 Δ4)). rewrite . simpl.
      pose (app_assoc (Δ0 Δ3) x (C :: Δ1 Δ4)).
      pose (app_assoc Δ0 Δ3 x). rewrite in . rewrite .
      pose (app_assoc Δ0 Δ3 (x C :: Δ1 Δ4)). rewrite .
      reflexivity. rewrite . reflexivity.
    - destruct s.
      { destruct s. destruct s. rewrite e. exists (Δ0 x). exists ( Δ2 Δ1 Δ4).
        assert (: Δ0 (x C :: ) Δ2 Δ1 Δ4 =
        (Δ0 x) C :: Δ2 Δ1 Δ4).
        pose (app_assoc x (C :: ) (Δ2 Δ1 Δ4)). rewrite . simpl.
        pose (app_assoc Δ0 x (C :: Δ2 Δ1 Δ4)). rewrite .
        reflexivity. rewrite . reflexivity. }
      { destruct s. destruct s. rewrite e. exists (Δ0 Δ3 Δ2 Δ1 x).
        exists . assert (: Δ0 Δ3 Δ2 Δ1 x C :: =
        (Δ0 Δ3 Δ2 Δ1 x) C :: ).
        pose (app_assoc (Δ0 Δ3 Δ2 Δ1) x (C :: )).
        pose (app_assoc (Δ0 Δ3 Δ2) Δ1 x).
        pose (app_assoc (Δ0 Δ3) Δ2 Δ1).
        pose (app_assoc Δ0 Δ3 Δ2). rewrite in . rewrite in .
        pose (app_assoc Δ0 Δ3 (Δ2 Δ1)). rewrite in . rewrite in .
        pose (app_assoc (Δ0 Δ3) Δ2 (Δ1 x)). rewrite in .
        rewrite in .
        pose (app_assoc Δ0 Δ3 (Δ2 Δ1 x)). rewrite in .
        rewrite .
        pose (app_assoc (Δ0 Δ3 Δ2) Δ1 (x C :: )).
        rewrite in . rewrite in . rewrite .
        pose (app_assoc (Δ0 Δ3) Δ2 (Δ1 x C :: )).
        rewrite in . rewrite .
        pose (app_assoc Δ0 Δ3 (Δ2 Δ1 x C :: )).
        rewrite . reflexivity. rewrite . reflexivity. }
Qed.


Lemma list_exch_R_permLR : s se,
    (@list_exch_R s se)
      ( Γ0 Γ1 Δ0 Δ1 C D, s = ((Γ0 C :: Γ1), (Δ0 D :: Δ1))
      ( eΔ0 eΔ1, se = ((Γ0 C :: Γ1), (eΔ0 D :: eΔ1)))).
Proof.
intros s se exch. intros Γ0 Γ1 Δ0 Δ1 C D Eq.
pose (list_exch_R_permL exch). pose ( Γ0 Γ1 (Δ0 D :: Δ1) C).
pose ( Eq). destruct .
pose (list_exch_R_permR exch). pose ( (Γ0 C :: Γ1) Δ0 Δ1 D).
pose ( Eq). destruct . destruct . exists . exists . assumption.
Qed.


Lemma list_exch_L_permL : s se,
    (@list_exch_L s se)
      ( Γ0 Γ1 Δ C, s = ((Γ0 C :: Γ1), Δ)
      ( eΓ0 eΓ1, se = ((eΓ0 C :: eΓ1), Δ))).
Proof.
intros s se exch. induction exch. intros Γ5 Γ6 Δ0 C E.
inversion E. apply partition_1_element in . destruct .
+ destruct s. destruct s. rewrite e. exists x. exists ( Γ3 Γ2 Γ1 Γ4).
  simpl.
  assert (: (x C :: ) Γ3 Γ2 Γ1 Γ4 = x C :: Γ3 Γ2 Γ1 Γ4).
  { symmetry. apply app_assoc with (l:=x) (m:=C :: ) (n:=Γ3 Γ2 Γ1 Γ4). }
  rewrite . reflexivity.
+ destruct s.
  * destruct s. destruct s. exists (Γ0 Γ3 Γ2 x). exists ( Γ4).
    rewrite e. assert (: Γ0 Γ3 Γ2 (x C :: ) Γ4 =
    (Γ0 Γ3 Γ2 x) C :: Γ4).
    pose (app_assoc x (C :: ) Γ4). rewrite . simpl.
    pose (app_assoc (Γ0 Γ3 Γ2) x (C :: Γ4)).
    pose (app_assoc (Γ0 Γ3) Γ2 x).
    pose (app_assoc Γ0 Γ3 Γ2).
    rewrite in . rewrite in .
    pose (app_assoc Γ0 Γ3 (Γ2 x)). rewrite in . rewrite .
    pose (app_assoc (Γ0 Γ3) Γ2 (x C :: Γ4)).
    rewrite in . rewrite .
    pose (app_assoc Γ0 Γ3 (Γ2 x C :: Γ4)). rewrite . reflexivity.
    rewrite . reflexivity.
  * destruct s.
    - destruct s. destruct s. exists (Γ0 Γ3 x). exists ( Γ1 Γ4).
      rewrite e. assert (: Γ0 Γ3 (x C :: ) Γ1 Γ4 =
      (Γ0 Γ3 x) C :: Γ1 Γ4).
      pose (app_assoc x (C :: ) (Γ1 Γ4)). rewrite . simpl.
      pose (app_assoc (Γ0 Γ3) x (C :: Γ1 Γ4)).
      pose (app_assoc Γ0 Γ3 x). rewrite in . rewrite .
      pose (app_assoc Γ0 Γ3 (x C :: Γ1 Γ4)). rewrite .
      reflexivity. rewrite . reflexivity.
    - destruct s.
      { destruct s. destruct s. rewrite e. exists (Γ0 x). exists ( Γ2 Γ1 Γ4).
        assert (: Γ0 (x C :: ) Γ2 Γ1 Γ4 =
        (Γ0 x) C :: Γ2 Γ1 Γ4).
        pose (app_assoc x (C :: ) (Γ2 Γ1 Γ4)). rewrite . simpl.
        pose (app_assoc Γ0 x (C :: Γ2 Γ1 Γ4)). rewrite .
        reflexivity. rewrite . reflexivity. }
      { destruct s. destruct s. rewrite e. exists (Γ0 Γ3 Γ2 Γ1 x).
        exists . assert (: Γ0 Γ3 Γ2 Γ1 x C :: =
        (Γ0 Γ3 Γ2 Γ1 x) C :: ).
        pose (app_assoc (Γ0 Γ3 Γ2 Γ1) x (C :: )).
        pose (app_assoc (Γ0 Γ3 Γ2) Γ1 x).
        pose (app_assoc (Γ0 Γ3) Γ2 Γ1).
        pose (app_assoc Γ0 Γ3 Γ2). rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ3 (Γ2 Γ1)). rewrite in . rewrite in .
        pose (app_assoc (Γ0 Γ3) Γ2 (Γ1 x)). rewrite in .
        rewrite in .
        pose (app_assoc Γ0 Γ3 (Γ2 Γ1 x)). rewrite in .
        rewrite .
        pose (app_assoc (Γ0 Γ3 Γ2) Γ1 (x C :: )).
        rewrite in . rewrite in . rewrite .
        pose (app_assoc (Γ0 Γ3) Γ2 (Γ1 x C :: )).
        rewrite in . rewrite .
        pose (app_assoc Γ0 Γ3 (Γ2 Γ1 x C :: )).
        rewrite . reflexivity. rewrite . reflexivity. }
Qed.


Lemma list_exch_L_permR : s se,
    (@list_exch_L s se)
      ( Γ Δ0 Δ1 C, s = (Γ, (Δ0 C :: Δ1))
      ( , se = (, (Δ0 C :: Δ1)))).
Proof.
intros s se exch. induction exch. intros Γ Δ0 Δ1 C E.
inversion E. exists (Γ0 Γ3 Γ2 Γ1 Γ4). reflexivity.
Qed.


Lemma list_exch_L_permLR : s se,
    (@list_exch_L s se)
      ( Γ0 Γ1 Δ0 Δ1 C D, s = ((Γ0 C :: Γ1), (Δ0 D :: Δ1))
      ( eΓ0 eΓ1, se = ((eΓ0 C :: eΓ1), (Δ0 D :: Δ1)))).
Proof.
intros s se exch. intros Γ0 Γ1 Δ0 Δ1 C D Eq.
pose (list_exch_L_permR exch). pose ( (Γ0 C :: Γ1) Δ0 Δ1 D).
pose ( Eq). destruct .
pose (list_exch_L_permL exch). pose ( Γ0 Γ1 (Δ0 D :: Δ1) C).
pose ( Eq). destruct . destruct . exists . exists . assumption.
Qed.


(* Some lemmas about atomic generalized extensions of lists and exchange. *)

Lemma nobox_gen_ext_exch_R : Γ Γ' l0 l1 l2,
    (nobox_gen_ext ) (@list_exch_R (Γ,) (Γ,))
     l3, (nobox_gen_ext ) * (list_exch_R (Γ',) (Γ',)).
Proof.
intros Γ Γ' . induction .
+ intros gen. remember [] as . destruct gen.
  - intro exch. inversion exch. apply app_eq_nil in . destruct . apply app_eq_nil in . destruct .
    apply app_eq_nil in . destruct . apply app_eq_nil in . destruct .
    subst. simpl. exists []. split.
    * apply univ_gen_ext_nil.
    * apply list_exch_R_id.
  - intros exch. exists []. split.
    * inversion .
    * inversion .
  - intro exch. subst. exists []. split. apply all_P_univ_gen_ext_nil.
    intros. pose (InT_list_exch_R exch). pose (p ). destruct . pose (univ_gen_ext_nil_all_P gen).
    pose ( ). apply in H. inversion H. subst. apply f. assumption. subst. apply in .
    assumption. assumption.
    apply list_exch_R_id.
+ intros gen. induction gen.
  - intro exch. inversion exch. destruct Δ0.
    * rewrite app_nil_l in H. rewrite app_nil_l in . rewrite app_nil_l. destruct Δ1.
      { rewrite app_nil_l in . destruct Δ2.
        + rewrite app_nil_l in . destruct Δ3.
          - rewrite app_nil_l in . repeat rewrite app_nil_l in H. destruct Δ4.
            * simpl. exists []. split. apply univ_gen_ext_nil. apply list_exch_R_id.
            * inversion .
          - inversion .
        + inversion . }
      { inversion . }
    * inversion .
  - intro exch. inversion exch. destruct Δ0.
    * rewrite app_nil_l in H. rewrite app_nil_l in . rewrite app_nil_l. destruct Δ1.
      { rewrite app_nil_l in . destruct Δ2.
        + rewrite app_nil_l in . destruct Δ3.
          - rewrite app_nil_l in . repeat rewrite app_nil_l in H. destruct Δ4.
            * inversion .
            * inversion . simpl. subst. exists (x :: l).
              split. apply univ_gen_ext_cons. assumption. apply list_exch_R_id.
          - repeat rewrite app_nil_l in H. repeat rewrite app_nil_l. simpl. simpl in H. simpl in .
            inversion . subst. exists (x :: l). split. apply univ_gen_ext_cons. assumption. apply list_exch_R_id.
        + rewrite app_nil_l. rewrite app_nil_l in H. inversion . subst.
          pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct p.
          pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct p. subst.
          exists ( x :: ). split.
          - apply univ_gen_ext_cons with (x:=x) in u. pose (univ_gen_ext_combine u ).
            pose (univ_gen_ext_combine ). assumption.
          - pose (list_exch_RI Γ' [] [] (x :: ) ). repeat rewrite app_nil_l in l. assumption. }
      { inversion . subst. pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct p.
        pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
        repeat destruct s. repeat destruct p. subst. exists ( (x :: ) ).
        split.
        - apply univ_gen_ext_cons with (x:=x) in u. pose (univ_gen_ext_combine u ).
          pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ). assumption.
        - pose (list_exch_RI Γ' [] (x :: ) ). rewrite app_nil_l in l. assumption. }
    * inversion . subst. pose (univ_gen_ext_splitR _ _ gen).
      repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct p. subst. exists (x :: ).
      split.
      { apply univ_gen_ext_cons with (x:=x) in u. pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine u ). assumption. }
      { assert (: x :: = (x :: ) ).
        reflexivity. rewrite .
        assert (: x :: = (x :: ) ).
        reflexivity. rewrite . apply list_exch_RI. }
  - intro exch. inversion exch. destruct Δ0.
    * rewrite app_nil_l in H. rewrite app_nil_l in . rewrite app_nil_l. destruct Δ1.
      { rewrite app_nil_l in . destruct Δ2.
        + rewrite app_nil_l in . destruct Δ3.
          - rewrite app_nil_l in . repeat rewrite app_nil_l in H. destruct Δ4.
            * inversion .
            * inversion . simpl. subst. exists l.
              split. apply univ_gen_ext_extra. assumption. assumption. apply list_exch_R_id.
          - repeat rewrite app_nil_l in H. repeat rewrite app_nil_l. simpl. simpl in H. simpl in .
            inversion . subst. exists l. split. apply univ_gen_ext_extra. assumption. assumption. apply list_exch_R_id.
        + rewrite app_nil_l. rewrite app_nil_l in H. inversion . subst.
          pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct .
          pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct . subst.
          exists ( ). split.
          - apply univ_gen_ext_extra with (x:=x) in u. pose (univ_gen_ext_combine u ).
            pose (univ_gen_ext_combine ). assumption. assumption.
          - pose (list_exch_RI Γ' [] [] ). repeat rewrite app_nil_l in l. assumption. }
      { inversion . subst. pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct .
        pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
        repeat destruct s. repeat destruct . subst. exists ( ).
        split.
        - apply univ_gen_ext_extra with (x:=x) in u. pose (univ_gen_ext_combine u ).
          pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ). assumption. assumption.
        - pose (list_exch_RI Γ' [] ). rewrite app_nil_l in l. assumption. }
    * inversion . subst. pose (univ_gen_ext_splitR _ _ gen).
      repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct . subst. exists ( ).
      split.
      { apply univ_gen_ext_extra with (x:=x) in u. pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine u ). assumption. assumption. }
      { apply list_exch_RI. }
Qed.


Lemma nobox_gen_ext_exch_L : Δ Δ' l0 l1 l2,
    (nobox_gen_ext ) (@list_exch_L (,Δ) (,Δ))
     l3, (nobox_gen_ext ) * (list_exch_L (,Δ') (,Δ')).
Proof.
intros Δ Δ' . induction .
+ intros gen. inversion gen.
  - intro exch. inversion exch. apply app_eq_nil in . destruct . apply app_eq_nil in . destruct .
    apply app_eq_nil in . destruct . apply app_eq_nil in . destruct .
    subst. simpl. exists []. split.
    * apply univ_gen_ext_nil.
    * apply list_exch_L_id.
  - intros exch. exists []. split.
    * subst. apply all_P_univ_gen_ext_nil. intros. pose (InT_list_exch_L exch).
      pose (p ). destruct . apply in . inversion . subst. apply H.
      assumption. subst. pose (univ_gen_ext_nil_all_P gen). apply f in .
      assumption. assumption.
    * apply list_exch_L_id.
+ intros gen. induction gen.
  - intro exch. inversion exch. destruct Γ0.
    * rewrite app_nil_l in . rewrite app_nil_l in H. rewrite app_nil_l. destruct Γ1.
      { rewrite app_nil_l in . destruct Γ2.
        + rewrite app_nil_l in . destruct Γ3.
          - rewrite app_nil_l in . repeat rewrite app_nil_l in H. destruct Γ4.
            * simpl. exists []. split. apply univ_gen_ext_nil. apply list_exch_L_id.
            * inversion .
          - inversion .
        + inversion . }
      { inversion . }
    * inversion .
  - intro exch. inversion exch. destruct Γ0.
    * rewrite app_nil_l in H. rewrite app_nil_l in . rewrite app_nil_l. destruct Γ1.
      { rewrite app_nil_l in . destruct Γ2.
        + rewrite app_nil_l in . destruct Γ3.
          - rewrite app_nil_l in . repeat rewrite app_nil_l in H. destruct Γ4.
            * inversion .
            * inversion . simpl. subst. exists (x :: l).
              split. apply univ_gen_ext_cons. assumption. apply list_exch_L_id.
          - repeat rewrite app_nil_l in H. repeat rewrite app_nil_l. simpl. simpl in H. simpl in .
            inversion . subst. exists (x :: l). split. apply univ_gen_ext_cons. assumption. apply list_exch_L_id.
        + rewrite app_nil_l. rewrite app_nil_l in H. inversion . subst.
          pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct p.
          pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct p. subst.
          exists ( x :: ). split.
          - apply univ_gen_ext_cons with (x:=x) in u. pose (univ_gen_ext_combine u ).
            pose (univ_gen_ext_combine ). assumption.
          - pose (list_exch_LI [] [] (x :: ) Δ'). repeat rewrite app_nil_l in l. assumption. }
      { inversion . subst. pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct p.
        pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
        repeat destruct s. repeat destruct p. subst. exists ( (x :: ) ).
        split.
        - apply univ_gen_ext_cons with (x:=x) in u. pose (univ_gen_ext_combine u ).
          pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ). assumption.
        - pose (list_exch_LI [] (x :: ) Δ'). rewrite app_nil_l in l. assumption. }
    * inversion . subst. pose (univ_gen_ext_splitR _ _ gen).
      repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct p. pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct p. subst. exists (x :: ).
      split.
      { apply univ_gen_ext_cons with (x:=x) in u. pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine u ). assumption. }
      { assert (: x :: = (x :: ) ).
        reflexivity. rewrite .
        assert (: x :: = (x :: ) ).
        reflexivity. rewrite . apply list_exch_LI. }
  - intro exch. inversion exch. destruct Γ0.
    * rewrite app_nil_l in H. rewrite app_nil_l in . rewrite app_nil_l. destruct Γ1.
      { rewrite app_nil_l in . destruct Γ2.
        + rewrite app_nil_l in . destruct Γ3.
          - rewrite app_nil_l in . repeat rewrite app_nil_l in H. destruct Γ4.
            * inversion .
            * inversion . simpl. subst. exists l.
              split. apply univ_gen_ext_extra. assumption. assumption. apply list_exch_L_id.
          - repeat rewrite app_nil_l in H. repeat rewrite app_nil_l. simpl. simpl in H. simpl in .
            inversion . subst. exists l. split. apply univ_gen_ext_extra. assumption. assumption. apply list_exch_L_id.
        + rewrite app_nil_l. rewrite app_nil_l in H. inversion . subst.
          pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct .
          pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct . subst.
          exists ( ). split.
          - apply univ_gen_ext_extra with (x:=x) in u. pose (univ_gen_ext_combine u ).
            pose (univ_gen_ext_combine ). assumption. assumption.
          - pose (list_exch_LI [] [] Δ'). repeat rewrite app_nil_l in l. assumption. }
      { inversion . subst. pose (univ_gen_ext_splitR _ _ gen). repeat destruct s. repeat destruct .
        pose (univ_gen_ext_splitR _ _ ). repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
        repeat destruct s. repeat destruct . subst. exists ( ).
        split.
        - apply univ_gen_ext_extra with (x:=x) in u. pose (univ_gen_ext_combine u ).
          pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ). assumption. assumption.
        - pose (list_exch_LI [] Δ'). rewrite app_nil_l in l. assumption. }
    * inversion . subst. pose (univ_gen_ext_splitR _ _ gen).
      repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct . pose (univ_gen_ext_splitR _ _ ).
      repeat destruct s. repeat destruct . subst. exists ( ).
      split.
      { apply univ_gen_ext_extra with (x:=x) in u. pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine ). pose (univ_gen_ext_combine ).
        pose (univ_gen_ext_combine u ). assumption. assumption. }
      { apply list_exch_LI. }
Qed.


(* Interactions between exchange and rules. *)

Lemma list_exch_L_IdP_notapplic : s se,
    (@list_exch_L s se)
    ((IdPRule [] s) False)
    ((IdPRule [] se) False).
Proof.
intros s se exch. induction exch. intros RA RAe. apply RA.
inversion RAe. symmetry in H. apply partition_1_element in H.
destruct H.
- destruct s. destruct s. rewrite e.
  assert (E: (x # P :: ) Γ1 Γ2 Γ3 Γ4 =
  x # P :: Γ1 Γ2 Γ3 Γ4).
  pose (app_assoc x (# P :: ) (Γ1 Γ2 Γ3 Γ4)). rewrite .
  auto. rewrite E. apply IdPRule_I.
- destruct s.
  + destruct s. destruct s. rewrite e.
    assert (E: Γ0 Γ1 Γ2 (x # P :: ) Γ4 =
    Γ0 Γ1 Γ2 x # P :: Γ4).
    pose (app_assoc x (# P :: ) Γ4).
    simpl in . rewrite . reflexivity. rewrite E.
    assert (: Γ0 Γ1 Γ2 x # P :: Γ4 =
    (Γ0 Γ1 Γ2 x) # P :: Γ4).
    pose (app_assoc (Γ0 Γ1 Γ2) x (# P :: Γ4)).
    pose (app_assoc (Γ0 Γ1) Γ2 x).
    pose (app_assoc Γ0 Γ1 Γ2). rewrite in . rewrite in .
    pose (app_assoc Γ0 Γ1 (Γ2 x)). rewrite in . rewrite .
    pose (app_assoc (Γ0 Γ1) Γ2 (x # P :: Γ4)). rewrite in .
    rewrite .
    pose (app_assoc Γ0 Γ1 (Γ2 x # P :: Γ4)). rewrite . reflexivity.
    rewrite . apply IdPRule_I.
  + destruct s.
    * destruct s. destruct s. rewrite e.
      assert (E: Γ0 Γ1 (x # P :: ) Γ3 Γ4 =
      (Γ0 Γ1 x) # P :: Γ3 Γ4).
      pose (app_assoc x (# P :: ) (Γ3 Γ4)). rewrite . simpl.
      pose (app_assoc (Γ0 Γ1) x (# P :: Γ3 Γ4)).
      pose (app_assoc Γ0 Γ1 x). rewrite in . rewrite .
      pose (app_assoc Γ0 Γ1 (x # P :: Γ3 Γ4)). rewrite .
      reflexivity. rewrite E. apply IdPRule_I.
    * destruct s.
      { destruct s. destruct s. rewrite e.
        assert (E: Γ0 (x # P :: ) Γ2 Γ3 Γ4 =
        (Γ0 x) # P :: Γ2 Γ3 Γ4).
        pose (app_assoc x (# P :: ) (Γ2 Γ3 Γ4)).
        rewrite . simpl.
        pose (app_assoc Γ0 x (# P :: Γ2 Γ3 Γ4)).
        rewrite . reflexivity. rewrite E. apply IdPRule_I. }
      { destruct s. destruct s. rewrite e.
        assert (E: Γ0 Γ1 Γ2 Γ3 x # P :: =
        (Γ0 Γ1 Γ2 Γ3 x) # P :: ).
        pose (app_assoc (Γ0 Γ1 Γ2 Γ3) x (# P :: )).
        pose (app_assoc (Γ0 Γ1 Γ2) Γ3 x).
        pose (app_assoc (Γ0 Γ1) Γ2 Γ3).
        pose (app_assoc Γ0 Γ1 Γ2).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3)).
        rewrite in . rewrite in .
        pose (app_assoc (Γ0 Γ1) Γ2 (Γ3 x)).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3 x)).
        rewrite in . rewrite .
        pose (app_assoc (Γ0 Γ1 Γ2) Γ3 (x # P :: )).
        pose (app_assoc (Γ0 Γ1) Γ2 Γ3).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3)). rewrite in .
        rewrite .
        pose (app_assoc (Γ0 Γ1) Γ2 (Γ3 x # P :: )).
        rewrite in . rewrite .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3 x # P :: )).
        rewrite . reflexivity.
        rewrite E. apply IdPRule_I. }
Qed.


Lemma list_exch_L_IdB_notapplic : s se,
    (@list_exch_L s se)
    ((IdBRule [] s) False)
    ((IdBRule [] se) False).
Proof.
intros s se exch. induction exch. intros RA RAe. apply RA.
inversion RAe. symmetry in H. apply partition_1_element in H.
destruct H.
- destruct s. destruct s. rewrite e.
  assert (E: (x Box A :: ) Γ1 Γ2 Γ3 Γ4 =
  x Box A :: Γ1 Γ2 Γ3 Γ4).
  pose (app_assoc x (Box A :: ) (Γ1 Γ2 Γ3 Γ4)). rewrite .
  auto. rewrite E. apply IdBRule_I.
- destruct s.
  + destruct s. destruct s. rewrite e.
    assert (E: Γ0 Γ1 Γ2 (x Box A :: ) Γ4 =
    Γ0 Γ1 Γ2 x Box A :: Γ4).
    pose (app_assoc x (Box A :: ) Γ4).
    simpl in . rewrite . reflexivity. rewrite E.
    assert (: Γ0 Γ1 Γ2 x Box A :: Γ4 =
    (Γ0 Γ1 Γ2 x) Box A :: Γ4).
    pose (app_assoc (Γ0 Γ1 Γ2) x (Box A :: Γ4)).
    pose (app_assoc (Γ0 Γ1) Γ2 x).
    pose (app_assoc Γ0 Γ1 Γ2). rewrite in . rewrite in .
    pose (app_assoc Γ0 Γ1 (Γ2 x)). rewrite in . rewrite .
    pose (app_assoc (Γ0 Γ1) Γ2 (x Box A :: Γ4)). rewrite in .
    rewrite .
    pose (app_assoc Γ0 Γ1 (Γ2 x Box A :: Γ4)). rewrite . reflexivity.
    rewrite . apply IdBRule_I.
  + destruct s.
    * destruct s. destruct s. rewrite e.
      assert (E: Γ0 Γ1 (x Box A :: ) Γ3 Γ4 =
      (Γ0 Γ1 x) Box A :: Γ3 Γ4).
      pose (app_assoc x (Box A :: ) (Γ3 Γ4)). rewrite . simpl.
      pose (app_assoc (Γ0 Γ1) x (Box A :: Γ3 Γ4)).
      pose (app_assoc Γ0 Γ1 x). rewrite in . rewrite .
      pose (app_assoc Γ0 Γ1 (x Box A :: Γ3 Γ4)). rewrite .
      reflexivity. rewrite E. apply IdBRule_I.
    * destruct s.
      { destruct s. destruct s. rewrite e.
        assert (E: Γ0 (x Box A :: ) Γ2 Γ3 Γ4 =
        (Γ0 x) Box A :: Γ2 Γ3 Γ4).
        pose (app_assoc x (Box A :: ) (Γ2 Γ3 Γ4)).
        rewrite . simpl.
        pose (app_assoc Γ0 x (Box A :: Γ2 Γ3 Γ4)).
        rewrite . reflexivity. rewrite E. apply IdBRule_I. }
      { destruct s. destruct s. rewrite e.
        assert (E: Γ0 Γ1 Γ2 Γ3 x Box A :: =
        (Γ0 Γ1 Γ2 Γ3 x) Box A :: ).
        pose (app_assoc (Γ0 Γ1 Γ2 Γ3) x (Box A :: )).
        pose (app_assoc (Γ0 Γ1 Γ2) Γ3 x).
        pose (app_assoc (Γ0 Γ1) Γ2 Γ3).
        pose (app_assoc Γ0 Γ1 Γ2).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3)).
        rewrite in . rewrite in .
        pose (app_assoc (Γ0 Γ1) Γ2 (Γ3 x)).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3 x)).
        rewrite in . rewrite .
        pose (app_assoc (Γ0 Γ1 Γ2) Γ3 (x Box A :: )).
        pose (app_assoc (Γ0 Γ1) Γ2 Γ3).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3)). rewrite in .
        rewrite .
        pose (app_assoc (Γ0 Γ1) Γ2 (Γ3 x Box A :: )).
        rewrite in . rewrite .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3 x Box A :: )).
        rewrite . reflexivity.
        rewrite E. apply IdBRule_I. }
Qed.


Lemma list_exch_L_BotL_notapplic : s se,
    (@list_exch_L s se)
    ((BotLRule [] s) False)
    ((BotLRule [] se) False).
Proof.
intros s se exch. induction exch. intros RA RAe. apply RA.
inversion RAe. symmetry in H. apply partition_1_element in H.
destruct H.
- destruct s. destruct s. rewrite e.
  assert (E: (x :: ) Γ1 Γ2 Γ3 Γ4 =
  x :: Γ1 Γ2 Γ3 Γ4).
  pose (app_assoc x ( :: ) (Γ1 Γ2 Γ3 Γ4)). rewrite .
  auto. rewrite E. apply BotLRule_I.
- destruct s.
  + destruct s. destruct s. rewrite e.
    assert (E: Γ0 Γ1 Γ2 (x :: ) Γ4 =
    Γ0 Γ1 Γ2 x :: Γ4).
    pose (app_assoc x ( :: ) Γ4).
    simpl in . rewrite . reflexivity. rewrite E.
    assert (: Γ0 Γ1 Γ2 x :: Γ4 =
    (Γ0 Γ1 Γ2 x) :: Γ4).
    pose (app_assoc (Γ0 Γ1 Γ2) x ( :: Γ4)).
    pose (app_assoc (Γ0 Γ1) Γ2 x).
    pose (app_assoc Γ0 Γ1 Γ2). rewrite in . rewrite in .
    pose (app_assoc Γ0 Γ1 (Γ2 x)). rewrite in . rewrite .
    pose (app_assoc (Γ0 Γ1) Γ2 (x :: Γ4)). rewrite in .
    rewrite .
    pose (app_assoc Γ0 Γ1 (Γ2 x :: Γ4)). rewrite . reflexivity.
    rewrite . apply BotLRule_I.
  + destruct s.
    * destruct s. destruct s. rewrite e.
      assert (E: Γ0 Γ1 (x :: ) Γ3 Γ4 =
      (Γ0 Γ1 x) :: Γ3 Γ4).
      pose (app_assoc x ( :: ) (Γ3 Γ4)). rewrite . simpl.
      pose (app_assoc (Γ0 Γ1) x ( :: Γ3 Γ4)).
      pose (app_assoc Γ0 Γ1 x). rewrite in . rewrite .
      pose (app_assoc Γ0 Γ1 (x :: Γ3 Γ4)). rewrite .
      reflexivity. rewrite E. apply BotLRule_I.
    * destruct s.
      { destruct s. destruct s. rewrite e.
        assert (E: Γ0 (x :: ) Γ2 Γ3 Γ4 =
        (Γ0 x) :: Γ2 Γ3 Γ4).
        pose (app_assoc x ( :: ) (Γ2 Γ3 Γ4)).
        rewrite . simpl.
        pose (app_assoc Γ0 x ( :: Γ2 Γ3 Γ4)).
        rewrite . reflexivity. rewrite E. apply BotLRule_I. }
      { destruct s. destruct s. rewrite e.
        assert (E: Γ0 Γ1 Γ2 Γ3 x :: =
        (Γ0 Γ1 Γ2 Γ3 x) :: ).
        pose (app_assoc (Γ0 Γ1 Γ2 Γ3) x ( :: )).
        pose (app_assoc (Γ0 Γ1 Γ2) Γ3 x).
        pose (app_assoc (Γ0 Γ1) Γ2 Γ3).
        pose (app_assoc Γ0 Γ1 Γ2).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3)).
        rewrite in . rewrite in .
        pose (app_assoc (Γ0 Γ1) Γ2 (Γ3 x)).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3 x)).
        rewrite in . rewrite .
        pose (app_assoc (Γ0 Γ1 Γ2) Γ3 (x :: )).
        pose (app_assoc (Γ0 Γ1) Γ2 Γ3).
        rewrite in . rewrite in .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3)). rewrite in .
        rewrite .
        pose (app_assoc (Γ0 Γ1) Γ2 (Γ3 x :: )).
        rewrite in . rewrite .
        pose (app_assoc Γ0 Γ1 (Γ2 Γ3 x :: )).
        rewrite . reflexivity.
        rewrite E. apply BotLRule_I. }
Qed.


Lemma list_exch_R_IdP_notapplic : s se,
    (@list_exch_R s se)
    ((IdPRule [] s) False)
    ((IdPRule [] se) False).
Proof.
intros s se exch. induction exch. intros RA RAe. apply RA.
inversion RAe. symmetry in . apply partition_1_element in .
destruct .
- destruct s. destruct s. rewrite e.
  assert (E: (x # P :: ) Δ1 Δ2 Δ3 Δ4 =
  x # P :: Δ1 Δ2 Δ3 Δ4).
  pose (app_assoc x (# P :: ) (Δ1 Δ2 Δ3 Δ4)). rewrite .
  auto. rewrite E. apply IdPRule_I.
- destruct s.
  + destruct s. destruct s. rewrite e.
    assert (E: Δ0 Δ1 Δ2 (x # P :: ) Δ4 =
    Δ0 Δ1 Δ2 x # P :: Δ4).
    pose (app_assoc x (# P :: ) Δ4).
    simpl in . rewrite . reflexivity. rewrite E.
    assert (: Δ0 Δ1 Δ2 x # P :: Δ4 =
    (Δ0 Δ1 Δ2 x) # P :: Δ4).
    pose (app_assoc (Δ0 Δ1 Δ2) x (# P :: Δ4)).
    pose (app_assoc (Δ0 Δ1) Δ2 x).
    pose (app_assoc Δ0 Δ1 Δ2). rewrite in . rewrite in .
    pose (app_assoc Δ0 Δ1 (Δ2 x)). rewrite in . rewrite .
    pose (app_assoc (Δ0 Δ1) Δ2 (x # P :: Δ4)). rewrite in .
    rewrite .
    pose (app_assoc Δ0 Δ1 (Δ2 x # P :: Δ4)). rewrite . reflexivity.
    rewrite . apply IdPRule_I.
  + destruct s.
    * destruct s. destruct s. rewrite e.
      assert (E: Δ0 Δ1 (x # P :: ) Δ3 Δ4 =
      (Δ0 Δ1 x) # P :: Δ3 Δ4).
      pose (app_assoc x (# P :: ) (Δ3 Δ4)). rewrite . simpl.
      pose (app_assoc (Δ0 Δ1) x (# P :: Δ3 Δ4)).
      pose (app_assoc Δ0 Δ1 x). rewrite in . rewrite .
      pose (app_assoc Δ0 Δ1 (x # P :: Δ3 Δ4)). rewrite .
      reflexivity. rewrite E. apply IdPRule_I.
    * destruct s.
      { destruct s. destruct s. rewrite e.
        assert (E: Δ0 (x # P :: ) Δ2 Δ3 Δ4 =
        (Δ0 x) # P :: Δ2 Δ3 Δ4).
        pose (app_assoc x (# P :: ) (Δ2 Δ3 Δ4)).
        rewrite . simpl.
        pose (app_assoc Δ0 x (# P :: Δ2 Δ3 Δ4)).
        rewrite . reflexivity. rewrite E. apply IdPRule_I. }
      { destruct s. destruct s. rewrite e.
        assert (E: Δ0 Δ1 Δ2 Δ3 x # P :: =
        (Δ0 Δ1 Δ2 Δ3 x) # P :: ).
        pose (app_assoc (Δ0 Δ1 Δ2 Δ3) x (# P :: )).
        pose (app_assoc (Δ0 Δ1 Δ2) Δ3 x).
        pose (app_assoc (Δ0 Δ1) Δ2 Δ3).
        pose (app_assoc Δ0 Δ1 Δ2).
        rewrite in . rewrite in .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3)).
        rewrite in . rewrite in .
        pose (app_assoc (Δ0 Δ1) Δ2 (Δ3 x)).
        rewrite in . rewrite in .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3 x)).
        rewrite in . rewrite .
        pose (app_assoc (Δ0 Δ1 Δ2) Δ3 (x # P :: )).
        pose (app_assoc (Δ0 Δ1) Δ2 Δ3).
        rewrite in . rewrite in .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3)). rewrite in .
        rewrite .
        pose (app_assoc (Δ0 Δ1) Δ2 (Δ3 x # P :: )).
        rewrite in . rewrite .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3 x # P :: )).
        rewrite . reflexivity.
        rewrite E. apply IdPRule_I. }
Qed.


Lemma list_exch_R_IdB_notapplic : s se,
    (@list_exch_R s se)
    ((IdBRule [] s) False)
    ((IdBRule [] se) False).
Proof.
intros s se exch. induction exch. intros RA RAe. apply RA.
inversion RAe. symmetry in . apply partition_1_element in .
destruct .
- destruct s. destruct s. rewrite e.
  assert (E: (x Box A :: ) Δ1 Δ2 Δ3 Δ4 =
  x Box A :: Δ1 Δ2 Δ3 Δ4).
  pose (app_assoc x (Box A :: ) (Δ1 Δ2 Δ3 Δ4)). rewrite .
  auto. rewrite E. apply IdBRule_I.
- destruct s.
  + destruct s. destruct s. rewrite e.
    assert (E: Δ0 Δ1 Δ2 (x Box A :: ) Δ4 =
    Δ0 Δ1 Δ2 x Box A :: Δ4).
    pose (app_assoc x (Box A :: ) Δ4).
    simpl in . rewrite . reflexivity. rewrite E.
    assert (: Δ0 Δ1 Δ2 x Box A :: Δ4 =
    (Δ0 Δ1 Δ2 x) Box A :: Δ4).
    pose (app_assoc (Δ0 Δ1 Δ2) x (Box A :: Δ4)).
    pose (app_assoc (Δ0 Δ1) Δ2 x).
    pose (app_assoc Δ0 Δ1 Δ2). rewrite in . rewrite in .
    pose (app_assoc Δ0 Δ1 (Δ2 x)). rewrite in . rewrite .
    pose (app_assoc (Δ0 Δ1) Δ2 (x Box A :: Δ4)). rewrite in .
    rewrite .
    pose (app_assoc Δ0 Δ1 (Δ2 x Box A :: Δ4)). rewrite . reflexivity.
    rewrite . apply IdBRule_I.
  + destruct s.
    * destruct s. destruct s. rewrite e.
      assert (E: Δ0 Δ1 (x Box A :: ) Δ3 Δ4 =
      (Δ0 Δ1 x) Box A :: Δ3 Δ4).
      pose (app_assoc x (Box A :: ) (Δ3 Δ4)). rewrite . simpl.
      pose (app_assoc (Δ0 Δ1) x (Box A :: Δ3 Δ4)).
      pose (app_assoc Δ0 Δ1 x). rewrite in . rewrite .
      pose (app_assoc Δ0 Δ1 (x Box A :: Δ3 Δ4)). rewrite .
      reflexivity. rewrite E. apply IdBRule_I.
    * destruct s.
      { destruct s. destruct s. rewrite e.
        assert (E: Δ0 (x Box A :: ) Δ2 Δ3 Δ4 =
        (Δ0 x) Box A :: Δ2 Δ3 Δ4).
        pose (app_assoc x (Box A :: ) (Δ2 Δ3 Δ4)).
        rewrite . simpl.
        pose (app_assoc Δ0 x (Box A :: Δ2 Δ3 Δ4)).
        rewrite . reflexivity. rewrite E. apply IdBRule_I. }
      { destruct s. destruct s. rewrite e.
        assert (E: Δ0 Δ1 Δ2 Δ3 x Box A :: =
        (Δ0 Δ1 Δ2 Δ3 x) Box A :: ).
        pose (app_assoc (Δ0 Δ1 Δ2 Δ3) x (Box A :: )).
        pose (app_assoc (Δ0 Δ1 Δ2) Δ3 x).
        pose (app_assoc (Δ0 Δ1) Δ2 Δ3).
        pose (app_assoc Δ0 Δ1 Δ2).
        rewrite in . rewrite in .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3)).
        rewrite in . rewrite in .
        pose (app_assoc (Δ0 Δ1) Δ2 (Δ3 x)).
        rewrite in . rewrite in .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3 x)).
        rewrite in . rewrite .
        pose (app_assoc (Δ0 Δ1 Δ2) Δ3 (x Box A :: )).
        pose (app_assoc (Δ0 Δ1) Δ2 Δ3).
        rewrite in . rewrite in .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3)). rewrite in .
        rewrite .
        pose (app_assoc (Δ0 Δ1) Δ2 (Δ3 x Box A :: )).
        rewrite in . rewrite .
        pose (app_assoc Δ0 Δ1 (Δ2 Δ3 x Box A :: )).
        rewrite . reflexivity.
        rewrite E. apply IdBRule_I. }
Qed.


Lemma list_exch_R_BotL_notapplic : s se,
    (@list_exch_R s se)
    ((BotLRule [] s) False)
    ((BotLRule [] se) False).
Proof.
intros s se exch RA RAe. apply RA.
inversion RAe. destruct s.
apply list_exch_R_same_L with (Γ:=l) (Γe:=Γ0 :: Γ1) (Δ:=) (Δe:=Δ) in exch.
subst. apply BotLRule_I. reflexivity. symmetry. assumption.
Qed.


(* The following lemmas make sure that if a rule is applied on a sequent s with
premises ps, then the same rule is applicable on a sequent se which is an exchanged
version of s, with some premises pse that are such that they are exchanged versions
of ps. *)


Lemma ImpR_app_list_exchL : s se ps,
  (@list_exch_L s se)
  (ImpRRule [ps] s)
  ( pse,
    (ImpRRule [pse] se) *
    (@list_exch_L ps pse)).
Proof.
intros s se ps exch. intro RA. inversion RA. inversion exch. subst.
inversion H. apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
- exists (Γ2 A :: Γ5 Γ4 Γ3 Γ6, Δ0 B :: Δ1). split.
  apply ImpRRule_I. assert (Γ2 A :: Γ3 Γ4 Γ5 Γ6 = (Γ2 [A]) Γ3 Γ4 Γ5 Γ6).
  rewrite app_assoc. reflexivity. rewrite . clear .
  assert (Γ2 A :: Γ5 Γ4 Γ3 Γ6 = (Γ2 [A]) Γ5 Γ4 Γ3 Γ6).
  rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
- apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
  + exists ((Γ2 Γ5) A :: Γ4 Γ3 Γ6, Δ0 B :: Δ1). split.
    assert (Γ2 Γ5 Γ4 Γ3 Γ6 = (Γ2 Γ5) Γ4 Γ3 Γ6). rewrite app_assoc.
    reflexivity. rewrite . clear . apply ImpRRule_I. repeat rewrite app_assoc.
    assert (Γ2 Γ3 A :: Γ4 Γ5 Γ6 = Γ2 Γ3 (A :: Γ4) Γ5 Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 Γ5 A :: Γ4 Γ3 Γ6 = Γ2 Γ5 (A :: Γ4) Γ3 Γ6).
    reflexivity. rewrite . clear . apply list_exch_LI.
  + apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
    * exists ((Γ2 Γ5 Γ4) A :: Γ3 Γ6, Δ0 B :: Δ1). split.
      assert (Γ2 Γ5 Γ4 Γ3 Γ6 = (Γ2 Γ5 Γ4) Γ3 Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear . apply ImpRRule_I. repeat rewrite app_assoc.
      assert (Γ2 Γ3 Γ4 A :: Γ5 Γ6 = Γ2 Γ3 (Γ4 [A]) Γ5 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert (Γ2 Γ5 Γ4 A :: Γ3 Γ6 = Γ2 Γ5 (Γ4 [A]) Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    * apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
      { repeat rewrite app_assoc. exists (Γ2 Γ5 Γ4 Γ3 A :: Γ6, Δ0 B :: Δ1).
        split. repeat rewrite app_assoc. apply ImpRRule_I. apply list_exch_LI. }
      { repeat rewrite app_assoc. exists (Γ2 Γ5 Γ4 Γ3 A :: Γ1, Δ0 B :: Δ1).
        split. repeat rewrite app_assoc. apply ImpRRule_I. apply list_exch_LI. }
      { repeat rewrite app_assoc. exists (Γ2 (x A :: ) Γ4 Γ3 Γ6, Δ0 B :: Δ1).
        split. assert (Γ2 (x A :: ) Γ4 Γ3 Γ6 = (Γ2 x) A :: Γ4 Γ3 Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert (Γ2 x Γ4 Γ3 Γ6 = (Γ2 x) Γ4 Γ3 Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        apply ImpRRule_I.
        assert (Γ2 Γ3 Γ4 x A :: Γ6 = Γ2 Γ3 Γ4 (x A :: ) Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_LI. }
    * repeat rewrite app_assoc. exists (Γ2 Γ5 ( A :: x) Γ3 Γ6, Δ0 B :: Δ1).
      split. assert (Γ2 Γ5 ( A :: x) Γ3 Γ6 = (Γ2 Γ5 ) A :: x Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert (Γ2 Γ5 x Γ3 Γ6 = (Γ2 Γ5 ) x Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      apply ImpRRule_I.
      assert (Γ2 Γ3 A :: x Γ5 Γ6 = Γ2 Γ3 ( A :: x) Γ5 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_LI.
  + repeat rewrite app_assoc. exists (Γ2 Γ5 Γ4 (x A :: ) Γ6, Δ0 B :: Δ1).
    split. assert (Γ2 Γ5 Γ4 (x A :: ) Γ6 = (Γ2 Γ5 Γ4 x) A :: Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 Γ5 Γ4 x Γ6 = (Γ2 Γ5 Γ4 x) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    apply ImpRRule_I.
    assert (Γ2 x A :: Γ4 Γ5 Γ6 = Γ2 (x A :: ) Γ4 Γ5 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_LI.
- repeat rewrite app_assoc. exists (Γ0 A :: x Γ5 Γ4 Γ3 Γ6, Δ0 B :: Δ1).
  split. apply ImpRRule_I.
  assert (Γ0 A :: x Γ3 Γ4 Γ5 Γ6 = (Γ0 A :: x) Γ3 Γ4 Γ5 Γ6).
  repeat rewrite app_assoc. reflexivity. rewrite . clear .
  assert (Γ0 A :: x Γ5 Γ4 Γ3 Γ6 = (Γ0 A :: x) Γ5 Γ4 Γ3 Γ6).
  repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
Qed.


Lemma ImpL_app_list_exchL : s se ps1 ps2,
  (@list_exch_L s se)
  (ImpLRule [;] s)
  ( pse1 pse2,
    (ImpLRule [;] se) *
    (@list_exch_L ) *
    (@list_exch_L )).
Proof.
intros s se exch. intro RA. inversion RA. inversion exch. subst.
inversion H. apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
- destruct Γ3 ; destruct Γ4 ; destruct Γ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
  + exists (Γ2 Γ1, Δ0 A :: Δ1). exists (Γ2 B :: Γ1, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  + exists (Γ2 Γ5 Γ6, Δ0 A :: Δ1). exists (Γ2 B :: Γ5 Γ6, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  + exists (Γ2 Γ4 Γ6, Δ0 A :: Δ1). exists (Γ2 B :: Γ4 Γ6, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  + exists (Γ2 ( :: Γ5) Γ4 Γ6, Δ0 A :: Δ1).
    exists (Γ2 ( :: Γ5) B :: Γ4 Γ6, Δ0 Δ1). split. split.
    assert (Γ2 ( :: Γ5) B :: Γ4 Γ6 = (Γ2 :: Γ5) B :: Γ4 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 :: Γ5 A --> B :: Γ4 Γ6 = (Γ2 :: Γ5) A --> B :: Γ4 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 ( :: Γ5) Γ4 Γ6 = (Γ2 :: Γ5) Γ4 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    apply ImpLRule_I.
    assert (Γ2 Γ4 :: Γ5 Γ6 = Γ2 [] Γ4 ( :: Γ5) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 ( :: Γ5) Γ4 Γ6 = Γ2 ( :: Γ5) Γ4 [] Γ6).
    reflexivity. rewrite . clear . apply list_exch_LI.
    assert (Γ2 B :: Γ4 :: Γ5 Γ6 = Γ2 [] (B :: Γ4) ( :: Γ5) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 ( :: Γ5) B :: Γ4 Γ6 = Γ2 ( :: Γ5) (B :: Γ4) [] Γ6).
    reflexivity. rewrite . clear . apply list_exch_LI.
  + exists (Γ2 Γ3 Γ6, Δ0 A :: Δ1). exists (Γ2 B :: Γ3 Γ6, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  + exists (Γ2 ( :: Γ5) Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ2 ( :: Γ5) B :: Γ3 Γ6, Δ0 Δ1). split. split.
    assert (Γ2 :: Γ5 A --> B :: Γ3 Γ6 = (Γ2 :: Γ5) A --> B :: Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 ( :: Γ5) B :: Γ3 Γ6 = (Γ2 :: Γ5) B :: Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 ( :: Γ5) Γ3 Γ6 = (Γ2 :: Γ5) Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    apply ImpLRule_I.
    assert (Γ2 Γ3 :: Γ5 Γ6 = Γ2 Γ3 [] ( :: Γ5) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 ( :: Γ5) Γ3 Γ6 = Γ2 ( :: Γ5) [] Γ3 Γ6).
    reflexivity. rewrite . clear . apply list_exch_LI.
    assert (Γ2 B :: Γ3 :: Γ5 Γ6 = Γ2 (B :: Γ3) [] ( :: Γ5) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 ( :: Γ5) B :: Γ3 Γ6 = Γ2 ( :: Γ5) [] (B :: Γ3) Γ6).
    reflexivity. rewrite . clear . apply list_exch_LI.
  + exists (Γ2 :: Γ4 Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ2 :: Γ4 B :: Γ3 Γ6, Δ0 Δ1). split. split.
    assert (Γ2 :: Γ4 A --> B :: Γ3 Γ6 = (Γ2 :: Γ4) A --> B :: Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 :: Γ4 B :: Γ3 Γ6 = (Γ2 :: Γ4) B :: Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 :: Γ4 Γ3 Γ6 = (Γ2 :: Γ4) Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpLRule_I.
    assert (Γ2 Γ3 :: Γ4 Γ6 = Γ2 Γ3 [] ( :: Γ4) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 :: Γ4 Γ3 Γ6 = Γ2 ( :: Γ4) [] Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    assert (Γ2 B :: Γ3 :: Γ4 Γ6 = Γ2 (B :: Γ3) [] ( :: Γ4) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 :: Γ4 B :: Γ3 Γ6 = Γ2 ( :: Γ4) [] (B :: Γ3) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
  + exists (Γ2 :: Γ5 :: Γ4 Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ2 :: Γ5 :: Γ4 B :: Γ3 Γ6, Δ0 Δ1). split. split.
    assert (Γ2 :: Γ5 :: Γ4 A --> B :: Γ3 Γ6 = (Γ2 :: Γ5 :: Γ4) A --> B :: Γ3 Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 :: Γ5 :: Γ4 B :: Γ3 Γ6 = (Γ2 :: Γ5 :: Γ4) B :: Γ3 Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ2 :: Γ5 :: Γ4 Γ3 Γ6 = (Γ2 :: Γ5 :: Γ4) Γ3 Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear .
    apply ImpLRule_I.
    assert (Γ2 Γ3 :: Γ4 :: Γ5 Γ6 = Γ2 Γ3 ( :: Γ4) ( :: Γ5) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 :: Γ5 :: Γ4 Γ3 Γ6 = Γ2 ( :: Γ5) ( :: Γ4) Γ3 Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    assert (Γ2 B :: Γ3 :: Γ4 :: Γ5 Γ6 = Γ2 (B :: Γ3) ( :: Γ4) ( :: Γ5) Γ6).
    reflexivity. rewrite . clear .
    assert (Γ2 :: Γ5 :: Γ4 B :: Γ3 Γ6 = Γ2 ( :: Γ5) ( :: Γ4) (B :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
- apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
  + destruct Γ4 ; destruct Γ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
    * rewrite app_assoc. exists ((Γ2 Γ3) Γ1, Δ0 A :: Δ1).
      exists ((Γ2 Γ3) B :: Γ1, Δ0 Δ1). split. split ; try assumption. apply list_exch_L_id.
      apply list_exch_L_id.
    * exists (Γ2 Γ5 Γ3 Γ6, Δ0 A :: Δ1).
      exists (Γ2 B :: Γ5 Γ3 Γ6, Δ0 Δ1). split. split. apply ImpLRule_I.
      assert ((Γ2 Γ3) Γ5 Γ6 = Γ2 Γ3 [] Γ5 Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 Γ5 Γ3 Γ6 = Γ2 Γ5 [] Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
      assert ((Γ2 Γ3) B :: Γ5 Γ6 = Γ2 Γ3 [] (B :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 B :: Γ5 Γ3 Γ6 = Γ2 (B :: Γ5) [] Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    * exists (Γ2 Γ4 Γ3 Γ6, Δ0 A :: Δ1).
      exists (Γ2 B :: Γ4 Γ3 Γ6, Δ0 Δ1). split. split. apply ImpLRule_I.
      assert ((Γ2 Γ3) Γ4 Γ6 = Γ2 Γ3 [] Γ4 Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 Γ4 Γ3 Γ6 = Γ2 Γ4 [] Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
      assert ((Γ2 Γ3) B :: Γ4 Γ6 = Γ2 Γ3 [] (B :: Γ4) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 B :: Γ4 Γ3 Γ6 = Γ2 (B :: Γ4) [] Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    * exists ((Γ2 :: Γ5) Γ4 Γ3 Γ6, Δ0 A :: Δ1).
      exists ((Γ2 :: Γ5) B :: Γ4 Γ3 Γ6, Δ0 Δ1). split. split.
      assert (Γ2 :: Γ5 A --> B :: Γ4 Γ3 Γ6 = (Γ2 :: Γ5) A --> B :: Γ4 Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
      assert ((Γ2 Γ3) Γ4 :: Γ5 Γ6 = Γ2 Γ3 Γ4 ( :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5) Γ4 Γ3 Γ6 = Γ2 ( :: Γ5) Γ4 Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
      assert ((Γ2 Γ3) B :: Γ4 :: Γ5 Γ6 = Γ2 Γ3 (B :: Γ4) ( :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5) B :: Γ4 Γ3 Γ6 = Γ2 ( :: Γ5) (B :: Γ4) Γ3 Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
  + apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
    * destruct Γ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
      { exists ((Γ2 Γ4 Γ3) Γ1, Δ0 A :: Δ1).
        exists ((Γ2 Γ4 Γ3) B :: Γ1, Δ0 Δ1). split. split.
        assert (Γ2 Γ4 Γ3 A --> B :: Γ1 = (Γ2 Γ4 Γ3) A --> B :: Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
        assert ((Γ2 Γ3 Γ4) Γ1 = Γ2 Γ3 [] Γ4 Γ1). repeat rewrite app_assoc.
        reflexivity. rewrite . clear .
        assert ((Γ2 Γ4 Γ3) Γ1 = Γ2 Γ4 [] Γ3 Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
        assert ((Γ2 Γ3 Γ4) B :: Γ1 = Γ2 Γ3 [] Γ4 B :: Γ1). repeat rewrite app_assoc.
        reflexivity. rewrite . clear .
        assert ((Γ2 Γ4 Γ3) B :: Γ1 = Γ2 Γ4 [] Γ3 B :: Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI. }
      { exists (Γ2 Γ5 Γ4 Γ3 Γ6, Δ0 A :: Δ1).
        exists (Γ2 B :: Γ5 Γ4 Γ3 Γ6, Δ0 Δ1). split. split. apply ImpLRule_I.
        repeat rewrite app_assoc. apply list_exch_LI.
        assert ((Γ2 Γ3 Γ4) B :: Γ5 Γ6 = Γ2 Γ3 Γ4 (B :: Γ5) Γ6). repeat rewrite app_assoc.
        reflexivity. rewrite . clear .
        assert (Γ2 B :: Γ5 Γ4 Γ3 Γ6 = Γ2 (B :: Γ5) Γ4 Γ3 Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI. }
    * apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
      { exists ((Γ2 Γ5 Γ4 Γ3) Γ1, Δ0 A :: Δ1).
        exists ((Γ2 Γ5 Γ4 Γ3) B :: Γ1, Δ0 Δ1). split. split.
        assert (Γ2 Γ5 Γ4 Γ3 A --> B :: Γ1 = (Γ2 Γ5 Γ4 Γ3) A --> B :: Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
        repeat rewrite app_assoc. apply list_exch_LI. repeat rewrite app_assoc. apply list_exch_LI. }
      { exists ((Γ2 Γ5 Γ4 Γ3 ) Γ1, Δ0 A :: Δ1).
        exists ((Γ2 Γ5 Γ4 Γ3 ) B :: Γ1, Δ0 Δ1). split. split.
        assert (Γ2 Γ5 Γ4 Γ3 A --> B :: Γ1 = (Γ2 Γ5 Γ4 Γ3 ) A --> B :: Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
        repeat rewrite app_assoc. apply list_exch_LI. repeat rewrite app_assoc. apply list_exch_LI. }
      { destruct .
        - simpl in . subst. rewrite app_nil_r.
          exists ((Γ2 x Γ4 Γ3) Γ1, Δ0 A :: Δ1).
          exists ((Γ2 x Γ4 Γ3) B :: Γ1, Δ0 Δ1). split. split.
          assert (Γ2 x Γ4 Γ3 A --> B :: Γ1 = (Γ2 x Γ4 Γ3) A --> B :: Γ1).
          repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpLRule_I.
          repeat rewrite app_assoc. apply list_exch_LI. repeat rewrite app_assoc. apply list_exch_LI.
        - inversion . subst.
          exists ((Γ2 x) Γ4 Γ3 Γ6, Δ0 A :: Δ1).
          exists ((Γ2 x) B :: Γ4 Γ3 Γ6, Δ0 Δ1). split. split.
          assert (Γ2 (x A --> B :: ) Γ4 Γ3 Γ6 = (Γ2 x) A --> B :: Γ4 Γ3 Γ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpLRule_I.
          assert ((Γ2 Γ3 Γ4 x) Γ6 = Γ2 Γ3 Γ4 (x ) Γ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear .
          assert ((Γ2 x) Γ4 Γ3 Γ6 = Γ2 (x ) Γ4 Γ3 Γ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear .
          apply list_exch_LI.
          assert ((Γ2 Γ3 Γ4 x) B :: Γ6 = Γ2 Γ3 Γ4 (x B :: ) Γ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear .
          assert ((Γ2 x) B :: Γ4 Γ3 Γ6 = Γ2 (x B :: ) Γ4 Γ3 Γ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear .
          apply list_exch_LI. }
    * destruct x ; destruct Γ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
      { rewrite app_nil_r. exists ((Γ2 Γ3) Γ1, Δ0 A :: Δ1).
        exists ((Γ2 Γ3) B :: Γ1, Δ0 Δ1). split. split.
        assert (Γ2 Γ3 A --> B :: Γ1 = (Γ2 Γ3) A --> B :: Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpLRule_I.
        assert ((Γ2 Γ3 ) Γ1 = Γ2 Γ3 [] Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Γ2 Γ3) Γ1 = Γ2 [] Γ3 Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
        assert ((Γ2 Γ3 ) B :: Γ1 = Γ2 Γ3 [] B :: Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Γ2 Γ3) B :: Γ1 = Γ2 [] Γ3 B :: Γ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI. }
      { rewrite app_nil_r. exists (Γ2 Γ5 Γ3 Γ6, Δ0 A :: Δ1).
        exists (Γ2 B :: Γ5 Γ3 Γ6, Δ0 Δ1). split. split.
        apply ImpLRule_I. repeat rewrite app_assoc. apply list_exch_LI.
        assert ((Γ2 Γ3 ) B :: Γ5 Γ6 = Γ2 Γ3 (B :: Γ5) Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert (Γ2 B :: Γ5 Γ3 Γ6 = Γ2 (B :: Γ5) Γ3 Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI. }
      { exists ((Γ2 ) x Γ3 Γ6, Δ0 A :: Δ1).
        exists ((Γ2 ) B :: x Γ3 Γ6, Δ0 Δ1). split. split.
        assert (Γ2 ( A --> B :: x) Γ3 Γ6 = (Γ2 ) A --> B :: x Γ3 Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpLRule_I.
        assert ((Γ2 Γ3 ) x Γ6 = Γ2 Γ3 [] ( x) Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Γ2 ) x Γ3 Γ6 = Γ2 ( x) [] Γ3 Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
        assert ((Γ2 Γ3 ) B :: x Γ6 = Γ2 Γ3 [] ( B :: x) Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Γ2 ) B :: x Γ3 Γ6 = Γ2 ( B :: x) [] Γ3 Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI. }
      { exists ((Γ2 :: Γ5 ) x Γ3 Γ6, Δ0 A :: Δ1).
        exists ((Γ2 :: Γ5 ) B :: x Γ3 Γ6, Δ0 Δ1). split. split.
        assert (Γ2 :: Γ5 ( A --> B :: x) Γ3 Γ6 = (Γ2 :: Γ5 ) A --> B :: x Γ3 Γ6).
        repeat rewrite app_assoc. simpl. repeat rewrite app_assoc.
        reflexivity. rewrite . clear . apply ImpLRule_I.
        assert ((Γ2 Γ3 ) x :: Γ5 Γ6 = Γ2 Γ3 ( x) ( :: Γ5) Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Γ2 :: Γ5 ) x Γ3 Γ6 = Γ2 ( :: Γ5) ( x) Γ3 Γ6).
        repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear .
        apply list_exch_LI.
        assert ((Γ2 Γ3 ) B :: x :: Γ5 Γ6 = Γ2 Γ3 ( B :: x) ( :: Γ5) Γ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Γ2 :: Γ5 ) B :: x Γ3 Γ6 = Γ2 ( :: Γ5) ( B :: x) Γ3 Γ6).
        repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear .
        apply list_exch_LI. }
  + destruct ; destruct Γ4 ; destruct Γ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
    * rewrite app_nil_r. rewrite app_assoc. exists ((Γ2 x) Γ1, Δ0 A :: Δ1).
      exists ((Γ2 x) B :: Γ1, Δ0 Δ1). split. split ; try assumption. apply list_exch_L_id. apply list_exch_L_id.
    * rewrite app_nil_r. exists (Γ2 Γ5 x Γ6, Δ0 A :: Δ1).
      exists (Γ2 B :: Γ5 x Γ6, Δ0 Δ1). split. split. apply ImpLRule_I.
      assert ((Γ2 x) Γ5 Γ6 = Γ2 x [] Γ5 Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 Γ5 x Γ6 = Γ2 Γ5 [] x Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
      assert ((Γ2 x) B :: Γ5 Γ6 = Γ2 x [] (B :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 B :: Γ5 x Γ6 = Γ2 (B :: Γ5) [] x Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    * rewrite app_nil_r. exists (Γ2 Γ4 x Γ6, Δ0 A :: Δ1).
      exists (Γ2 B :: Γ4 x Γ6, Δ0 Δ1). split. split. apply ImpLRule_I.
      assert ((Γ2 x) Γ4 Γ6 = Γ2 x [] Γ4 Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 Γ4 x Γ6 = Γ2 Γ4 [] x Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
      assert ((Γ2 x) B :: Γ4 Γ6 = Γ2 x [] (B :: Γ4) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Γ2 B :: Γ4 x Γ6 = Γ2 (B :: Γ4) [] x Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    * rewrite app_nil_r. exists ((Γ2 :: Γ5) Γ4 x Γ6, Δ0 A :: Δ1).
      exists ((Γ2 :: Γ5) B :: Γ4 x Γ6, Δ0 Δ1). split. split.
      assert (Γ2 :: Γ5 A --> B :: Γ4 x Γ6 = (Γ2 :: Γ5) A --> B :: Γ4 x Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
      assert ((Γ2 x) Γ4 :: Γ5 Γ6 = Γ2 x Γ4 ( :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5) Γ4 x Γ6 = Γ2 ( :: Γ5) Γ4 x Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
      assert ((Γ2 x) B :: Γ4 :: Γ5 Γ6 = Γ2 x (B :: Γ4) ( :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5) B :: Γ4 x Γ6 = Γ2 ( :: Γ5) (B :: Γ4) x Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_LI.
    * exists ((Γ2 x) Γ6, Δ0 A :: Δ1).
      exists ((Γ2 x) B :: Γ6, Δ0 Δ1). split. split.
      assert (Γ2 (x A --> B :: ) Γ6 = (Γ2 x) A --> B :: Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
      apply list_exch_L_id. apply list_exch_L_id.
    * exists ((Γ2 :: Γ5 x) Γ6, Δ0 A :: Δ1).
      exists ((Γ2 :: Γ5 x) B :: Γ6, Δ0 Δ1). split. split.
      assert (Γ2 :: Γ5 (x A --> B :: ) Γ6 = (Γ2 :: Γ5 x) A --> B :: Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
      assert ((Γ2 x) :: Γ5 Γ6 = Γ2 [] (x ) ( :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5 x) Γ6 = Γ2 ( :: Γ5) (x ) [] Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_LI.
      assert ((Γ2 x) B :: :: Γ5 Γ6 = Γ2 [] (x B :: ) ( :: Γ5) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5 x) B :: Γ6 = Γ2 ( :: Γ5) (x B :: ) [] Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_LI.
    * exists ((Γ2 :: Γ4 x) Γ6, Δ0 A :: Δ1).
      exists ((Γ2 :: Γ4 x) B :: Γ6, Δ0 Δ1). split. split.
      assert (Γ2 :: Γ4 (x A --> B :: ) Γ6 = (Γ2 :: Γ4 x) A --> B :: Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
      assert ((Γ2 x) :: Γ4 Γ6 = Γ2 [] (x ) ( :: Γ4) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ4 x) Γ6 = Γ2 ( :: Γ4) (x ) [] Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_LI.
      assert ((Γ2 x) B :: :: Γ4 Γ6 = Γ2 [] (x B :: ) ( :: Γ4) Γ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ4 x) B :: Γ6 = Γ2 ( :: Γ4) (x B :: ) [] Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_LI.
    * exists ((Γ2 :: Γ5 :: Γ4 x) Γ6, Δ0 A :: Δ1).
      exists ((Γ2 :: Γ5 :: Γ4 x) B :: Γ6, Δ0 Δ1). split. split.
      assert (Γ2 :: Γ5 :: Γ4 (x A --> B :: ) Γ6 = (Γ2 :: Γ5 :: Γ4 x) A --> B :: Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. simpl.
      repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
      assert ((Γ2 x) :: Γ4 :: Γ5 Γ6 = Γ2 (x ) ( :: Γ4) ( :: Γ5) Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5 :: Γ4 x) Γ6 = Γ2 ( :: Γ5) ( :: Γ4) (x ) Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_LI.
      assert ((Γ2 x) B :: :: Γ4 :: Γ5 Γ6 = Γ2 (x B :: ) ( :: Γ4) ( :: Γ5) Γ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert ((Γ2 :: Γ5 :: Γ4 x) B :: Γ6 = Γ2 ( :: Γ5) ( :: Γ4) (x B :: ) Γ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_LI.
- destruct x ; destruct Γ3 ; destruct Γ4 ; destruct Γ5 ; simpl ; simpl in ; simpl in exch ;
  subst ; try inversion ; subst.
  * rewrite app_nil_r. exists (Γ0 Γ1, Δ0 A :: Δ1).
    exists (Γ0 B :: Γ1, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  * rewrite app_nil_r. exists (Γ0 Γ5 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: Γ5 Γ6, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  * rewrite app_nil_r. exists (Γ0 Γ4 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: Γ4 Γ6, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  * rewrite app_nil_r. exists ((Γ0 :: Γ5) Γ4 Γ6, Δ0 A :: Δ1).
    exists ((Γ0 :: Γ5) B :: Γ4 Γ6, Δ0 Δ1). split. split.
    assert (Γ0 :: Γ5 A --> B :: Γ4 Γ6 = (Γ0 :: Γ5) A --> B :: Γ4 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
    assert (Γ0 Γ4 :: Γ5 Γ6 = Γ0 [] Γ4 ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Γ0 :: Γ5) Γ4 Γ6 = Γ0 ( :: Γ5) Γ4 [] Γ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert (Γ0 B :: Γ4 :: Γ5 Γ6 = Γ0 [] (B :: Γ4) ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Γ0 :: Γ5) B :: Γ4 Γ6 = Γ0 ( :: Γ5) (B :: Γ4) [] Γ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
  * rewrite app_nil_r. exists (Γ0 Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: Γ3 Γ6, Δ0 Δ1). split. split ; try assumption.
    apply list_exch_L_id. apply list_exch_L_id.
  * rewrite app_nil_r. exists ((Γ0 :: Γ5) Γ3 Γ6, Δ0 A :: Δ1).
    exists ((Γ0 :: Γ5) B :: Γ3 Γ6, Δ0 Δ1). split. split.
    assert (Γ0 :: Γ5 A --> B :: Γ3 Γ6 = (Γ0 :: Γ5) A --> B :: Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
    assert (Γ0 Γ3 :: Γ5 Γ6 = Γ0 [] Γ3 ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Γ0 :: Γ5) Γ3 Γ6 = Γ0 ( :: Γ5) Γ3 [] Γ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert (Γ0 B :: Γ3 :: Γ5 Γ6 = Γ0 [] (B :: Γ3) ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Γ0 :: Γ5) B :: Γ3 Γ6 = Γ0 ( :: Γ5) (B :: Γ3) [] Γ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
  * rewrite app_nil_r. exists ((Γ0 :: Γ4) Γ3 Γ6, Δ0 A :: Δ1).
    exists ((Γ0 :: Γ4) B :: Γ3 Γ6, Δ0 Δ1). split. split.
    assert (Γ0 :: Γ4 A --> B :: Γ3 Γ6 = (Γ0 :: Γ4) A --> B :: Γ3 Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
    assert ((Γ0 :: Γ4) Γ3 Γ6 = Γ0 ( :: Γ4) Γ3 [] Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 Γ3 :: Γ4 Γ6 = Γ0 [] Γ3 ( :: Γ4) Γ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert ((Γ0 :: Γ4) B :: Γ3 Γ6 = Γ0 ( :: Γ4) (B :: Γ3) [] Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 B :: Γ3 :: Γ4 Γ6 = Γ0 [] (B :: Γ3) ( :: Γ4) Γ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
  * rewrite app_nil_r. exists ((Γ0 :: Γ5 :: Γ4) Γ3 Γ6, Δ0 A :: Δ1).
    exists ((Γ0 :: Γ5 :: Γ4) B :: Γ3 Γ6, Δ0 Δ1). split. split.
    assert (Γ0 :: Γ5 :: Γ4 A --> B :: Γ3 Γ6 = (Γ0 :: Γ5 :: Γ4) A --> B :: Γ3 Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . apply ImpLRule_I.
    assert (Γ0 Γ3 :: Γ4 :: Γ5 Γ6 = Γ0 Γ3 ( :: Γ4) ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Γ0 :: Γ5 :: Γ4) Γ3 Γ6 = Γ0 ( :: Γ5) ( :: Γ4) Γ3 Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert (Γ0 B :: Γ3 :: Γ4 :: Γ5 Γ6 = Γ0 (B :: Γ3) ( :: Γ4) ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Γ0 :: Γ5 :: Γ4) B :: Γ3 Γ6 = Γ0 ( :: Γ5) ( :: Γ4) (B :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
  * exists (Γ0 x Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x Γ6, Δ0 Δ1). split. split. repeat rewrite app_assoc. apply ImpLRule_I.
    apply list_exch_L_id. apply list_exch_L_id.
  * exists (Γ0 x :: Γ5 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x :: Γ5 Γ6, Δ0 Δ1). split. split. repeat rewrite app_assoc. apply ImpLRule_I.
    apply list_exch_L_id. apply list_exch_L_id.
  * exists (Γ0 x :: Γ4 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x :: Γ4 Γ6, Δ0 Δ1). split. split. repeat rewrite app_assoc. apply ImpLRule_I.
    apply list_exch_L_id. apply list_exch_L_id.
  * exists (Γ0 x :: Γ5 :: Γ4 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x :: Γ5 :: Γ4 Γ6, Δ0 Δ1). split. split.
    repeat rewrite app_assoc. apply ImpLRule_I.
    assert (Γ0 x :: Γ4 :: Γ5 Γ6 = (Γ0 x) ( :: Γ4) [] ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 x :: Γ5 :: Γ4 Γ6 = (Γ0 x) ( :: Γ5) [] ( :: Γ4) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert (Γ0 B :: x :: Γ4 :: Γ5 Γ6 = (Γ0 B :: x) ( :: Γ4) [] ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 B :: x :: Γ5 :: Γ4 Γ6 = (Γ0 B :: x) ( :: Γ5) [] ( :: Γ4) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
  * exists (Γ0 x :: Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x :: Γ3 Γ6, Δ0 Δ1). split. split. repeat rewrite app_assoc. apply ImpLRule_I.
    apply list_exch_L_id. apply list_exch_L_id.
  * exists (Γ0 x :: Γ5 :: Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x :: Γ5 :: Γ3 Γ6, Δ0 Δ1). split. split.
    repeat rewrite app_assoc. apply ImpLRule_I.
    assert (Γ0 x :: Γ3 :: Γ5 Γ6 = (Γ0 x) ( :: Γ3) [] ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 x :: Γ5 :: Γ3 Γ6 = (Γ0 x) ( :: Γ5) [] ( :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert (Γ0 B :: x :: Γ3 :: Γ5 Γ6 = (Γ0 B :: x) ( :: Γ3) [] ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 B :: x :: Γ5 :: Γ3 Γ6 = (Γ0 B :: x) ( :: Γ5) [] ( :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
  * exists (Γ0 x :: Γ4 :: Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x :: Γ4 :: Γ3 Γ6, Δ0 Δ1). split. split.
    repeat rewrite app_assoc. apply ImpLRule_I.
    assert (Γ0 x :: Γ3 :: Γ4 Γ6 = (Γ0 x) ( :: Γ3) [] ( :: Γ4) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 x :: Γ4 :: Γ3 Γ6 = (Γ0 x) ( :: Γ4) [] ( :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert (Γ0 B :: x :: Γ3 :: Γ4 Γ6 = (Γ0 B :: x) ( :: Γ3) [] ( :: Γ4) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 B :: x :: Γ4 :: Γ3 Γ6 = (Γ0 B :: x) ( :: Γ4) [] ( :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
  * exists (Γ0 x :: Γ5 :: Γ4 :: Γ3 Γ6, Δ0 A :: Δ1).
    exists (Γ0 B :: x :: Γ5 :: Γ4 :: Γ3 Γ6, Δ0 Δ1). split. split.
    repeat rewrite app_assoc. apply ImpLRule_I.
    assert (Γ0 x :: Γ3 :: Γ4 :: Γ5 Γ6 = (Γ0 x) ( :: Γ3) ( :: Γ4) ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 x :: Γ5 :: Γ4 :: Γ3 Γ6 = (Γ0 x) ( :: Γ5) ( :: Γ4) ( :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
    assert (Γ0 B :: x :: Γ3 :: Γ4 :: Γ5 Γ6 = (Γ0 B :: x) ( :: Γ3) ( :: Γ4) ( :: Γ5) Γ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Γ0 B :: x :: Γ5 :: Γ4 :: Γ3 Γ6 = (Γ0 B :: x) ( :: Γ5) ( :: Γ4) ( :: Γ3) Γ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_LI.
Qed.


Lemma GLR_app_list_exchL : s se ps,
  (@list_exch_L s se)
  (GLRRule [ps] s)
  ( pse,
    (GLRRule [pse] se) *
    (@list_exch_L ps pse)).
Proof.
intros s se ps exch RA. inversion RA. inversion exch. rewrite in .
inversion . subst.
pose (@nobox_gen_ext_exch_L (Δ0 Box A :: Δ1) [A] (Γ1 Γ2 Γ3 Γ4 Γ5) (Γ1 Γ4 Γ3 Γ2 Γ5) X exch).
destruct s. destruct p. inversion l.
exists (XBoxed_list (Γ0 Γ8 Γ7 Γ6 Γ9) [Box A], [A]). split.
- apply GLRRule_I.
  * unfold is_Boxed_list. intros. apply in_exch_list in . subst. apply in .
    assumption.
  * subst. assumption.
- repeat rewrite XBox_app_distrib. repeat rewrite app_assoc. apply list_exch_LI.
Qed.


Lemma ImpR_app_list_exchR : s se ps,
  (@list_exch_R s se)
  (ImpRRule [ps] s)
  ( pse,
    (ImpRRule [pse] se) *
    (@list_exch_R ps pse)).
Proof.
intros s se ps exch. intro RA. inversion RA. inversion exch. subst.
inversion H. apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
- destruct Δ3 ; destruct Δ4 ; destruct Δ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
  + exists (Γ0 A :: Γ1, Δ2 B :: Δ1). split ; try assumption. apply list_exch_R_id.
  + exists (Γ0 A :: Γ1, Δ2 B :: Δ5 Δ6). split ; try assumption. apply list_exch_R_id.
  + exists (Γ0 A :: Γ1, Δ2 B :: Δ4 Δ6). split ; try assumption. apply list_exch_R_id.
  + exists (Γ0 A :: Γ1, Δ2 ( :: Δ5) B :: Δ4 Δ6). split.
    assert (Δ2 ( :: Δ5) B :: Δ4 Δ6 = (Δ2 :: Δ5) B :: Δ4 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ2 :: Δ5 A --> B :: Δ4 Δ6 = (Δ2 :: Δ5) A --> B :: Δ4 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    apply ImpRRule_I. assert (Δ2 B :: Δ4 :: Δ5 Δ6 = Δ2 [] (B :: Δ4) ( :: Δ5) Δ6).
    reflexivity. rewrite . clear .
    assert (Δ2 ( :: Δ5) B :: Δ4 Δ6 = Δ2 ( :: Δ5) (B :: Δ4) [] Δ6).
    reflexivity. rewrite . clear . apply list_exch_RI.
  + exists (Γ0 A :: Γ1, Δ2 B :: Δ3 Δ6). split ; try assumption. apply list_exch_R_id.
  + exists (Γ0 A :: Γ1, Δ2 ( :: Δ5) B :: Δ3 Δ6). split.
    assert (Δ2 :: Δ5 A --> B :: Δ3 Δ6 = (Δ2 :: Δ5) A --> B :: Δ3 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ2 ( :: Δ5) B :: Δ3 Δ6 = (Δ2 :: Δ5) B :: Δ3 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    apply ImpRRule_I. assert (Δ2 B :: Δ3 :: Δ5 Δ6 = Δ2 (B :: Δ3) [] ( :: Δ5) Δ6).
    reflexivity. rewrite . clear .
    assert (Δ2 ( :: Δ5) B :: Δ3 Δ6 = Δ2 ( :: Δ5) [] (B :: Δ3) Δ6).
    reflexivity. rewrite . clear . apply list_exch_RI.
  + exists (Γ0 A :: Γ1, (Δ2 :: Δ4) B :: Δ3 Δ6). split.
    assert (Δ2 :: Δ4 A --> B :: Δ3 Δ6 = (Δ2 :: Δ4) A --> B :: Δ3 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
    assert (Δ2 B :: Δ3 :: Δ4 Δ6 = Δ2 (B :: Δ3) [] ( :: Δ4) Δ6).
    reflexivity. rewrite . clear .
    assert ((Δ2 :: Δ4) B :: Δ3 Δ6 = Δ2 ( :: Δ4) [] (B :: Δ3) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
  + exists (Γ0 A :: Γ1, (Δ2 :: Δ5 :: Δ4) B :: Δ3 Δ6). split.
    assert (Δ2 :: Δ5 :: Δ4 A --> B :: Δ3 Δ6 = (Δ2 :: Δ5 :: Δ4) A --> B :: Δ3 Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
    assert (Δ2 B :: Δ3 :: Δ4 :: Δ5 Δ6 = Δ2 (B :: Δ3) ( :: Δ4) ( :: Δ5) Δ6).
    reflexivity. rewrite . clear .
    assert ((Δ2 :: Δ5 :: Δ4) B :: Δ3 Δ6 = Δ2 ( :: Δ5) ( :: Δ4) (B :: Δ3) Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
- apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
  + destruct Δ4 ; destruct Δ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
    * rewrite app_assoc. exists (Γ0 A :: Γ1, (Δ2 Δ3) B :: Δ1). split ; try assumption. apply list_exch_R_id.
    * exists (Γ0 A :: Γ1, Δ2 B :: Δ5 Δ3 Δ6). split. apply ImpRRule_I.
      assert ((Δ2 Δ3) B :: Δ5 Δ6 = Δ2 Δ3 [] (B :: Δ5) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Δ2 B :: Δ5 Δ3 Δ6 = Δ2 (B :: Δ5) [] Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
    * exists (Γ0 A :: Γ1, Δ2 B :: Δ4 Δ3 Δ6). split. apply ImpRRule_I.
      assert ((Δ2 Δ3) B :: Δ4 Δ6 = Δ2 Δ3 [] (B :: Δ4) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Δ2 B :: Δ4 Δ3 Δ6 = Δ2 (B :: Δ4) [] Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
    * exists (Γ0 A :: Γ1, (Δ2 :: Δ5) B :: Δ4 Δ3 Δ6). split.
      assert (Δ2 :: Δ5 A --> B :: Δ4 Δ3 Δ6 = (Δ2 :: Δ5) A --> B :: Δ4 Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
      assert ((Δ2 Δ3) B :: Δ4 :: Δ5 Δ6 = Δ2 Δ3 (B :: Δ4) ( :: Δ5) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Δ2 :: Δ5) B :: Δ4 Δ3 Δ6 = Δ2 ( :: Δ5) (B :: Δ4) Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
  + apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
    * destruct Δ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
      { exists (Γ0 A :: Γ1, (Δ2 Δ4 Δ3) B :: Δ1). split.
        assert (Δ2 Δ4 Δ3 A --> B :: Δ1 = (Δ2 Δ4 Δ3) A --> B :: Δ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
        assert ((Δ2 Δ3 Δ4) B :: Δ1 = Δ2 Δ3 [] Δ4 B :: Δ1). repeat rewrite app_assoc.
        reflexivity. rewrite . clear .
        assert ((Δ2 Δ4 Δ3) B :: Δ1 = Δ2 Δ4 [] Δ3 B :: Δ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI. }
      { exists (Γ0 A :: Γ1, Δ2 B :: Δ5 Δ4 Δ3 Δ6). split. apply ImpRRule_I.
        assert ((Δ2 Δ3 Δ4) B :: Δ5 Δ6 = Δ2 Δ3 Δ4 (B :: Δ5) Δ6). repeat rewrite app_assoc.
        reflexivity. rewrite . clear .
        assert (Δ2 B :: Δ5 Δ4 Δ3 Δ6 = Δ2 (B :: Δ5) Δ4 Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI. }
    * apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
      { exists (Γ0 A :: Γ1, (Δ2 Δ5 Δ4 Δ3) B :: Δ1). split.
        assert (Δ2 Δ5 Δ4 Δ3 A --> B :: Δ1 = (Δ2 Δ5 Δ4 Δ3) A --> B :: Δ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
        repeat rewrite app_assoc. apply list_exch_RI. }
      { exists (Γ0 A :: Γ1, (Δ2 Δ5 Δ4 Δ3 ) B :: Δ1). split.
        assert (Δ2 Δ5 Δ4 Δ3 A --> B :: Δ1 = (Δ2 Δ5 Δ4 Δ3 ) A --> B :: Δ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
        repeat rewrite app_assoc. apply list_exch_RI. }
      { destruct .
        - simpl in . subst. rewrite app_nil_r.
          exists (Γ0 A :: Γ1, (Δ2 x Δ4 Δ3) B :: Δ1). split.
          assert (Δ2 x Δ4 Δ3 A --> B :: Δ1 = (Δ2 x Δ4 Δ3) A --> B :: Δ1).
          repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
          repeat rewrite app_assoc. apply list_exch_RI.
        - inversion . subst.
          exists (Γ0 A :: Γ1, (Δ2 x) B :: Δ4 Δ3 Δ6). split.
          assert (Δ2 (x A --> B :: ) Δ4 Δ3 Δ6 = (Δ2 x) A --> B :: Δ4 Δ3 Δ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
          assert ((Δ2 Δ3 Δ4 x) B :: Δ6 = Δ2 Δ3 Δ4 (x B :: ) Δ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear .
          assert ((Δ2 x) B :: Δ4 Δ3 Δ6 = Δ2 (x B :: ) Δ4 Δ3 Δ6).
          repeat rewrite app_assoc. reflexivity. rewrite . clear .
          apply list_exch_RI. }
    * destruct x ; destruct Δ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
      { rewrite app_nil_r. exists (Γ0 A :: Γ1, (Δ2 Δ3) B :: Δ1). split.
        assert (Δ2 Δ3 A --> B :: Δ1 = (Δ2 Δ3) A --> B :: Δ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
        assert ((Δ2 Δ3 ) B :: Δ1 = Δ2 Δ3 [] B :: Δ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Δ2 Δ3) B :: Δ1 = Δ2 [] Δ3 B :: Δ1).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI. }
      { rewrite app_nil_r. exists (Γ0 A :: Γ1, Δ2 B :: Δ5 Δ3 Δ6). split.
        apply ImpRRule_I.
        assert ((Δ2 Δ3 ) B :: Δ5 Δ6 = Δ2 Δ3 (B :: Δ5) Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert (Δ2 B :: Δ5 Δ3 Δ6 = Δ2 (B :: Δ5) Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI. }
      { exists (Γ0 A :: Γ1, (Δ2 ) B :: x Δ3 Δ6). split.
        assert (Δ2 ( A --> B :: x) Δ3 Δ6 = (Δ2 ) A --> B :: x Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply ImpRRule_I.
        assert ((Δ2 Δ3 ) B :: x Δ6 = Δ2 Δ3 [] ( B :: x) Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Δ2 ) B :: x Δ3 Δ6 = Δ2 ( B :: x) [] Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI. }
      { exists (Γ0 A :: Γ1, (Δ2 :: Δ5 ) B :: x Δ3 Δ6). split.
        assert (Δ2 :: Δ5 ( A --> B :: x) Δ3 Δ6 = (Δ2 :: Δ5 ) A --> B :: x Δ3 Δ6).
        repeat rewrite app_assoc. simpl. repeat rewrite app_assoc.
        reflexivity. rewrite . clear . apply ImpRRule_I.
        assert ((Δ2 Δ3 ) B :: x :: Δ5 Δ6 = Δ2 Δ3 ( B :: x) ( :: Δ5) Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert ((Δ2 :: Δ5 ) B :: x Δ3 Δ6 = Δ2 ( :: Δ5) ( B :: x) Δ3 Δ6).
        repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . clear .
        apply list_exch_RI. }
  + destruct ; destruct Δ4 ; destruct Δ5 ; simpl ; simpl in ; simpl in exch ; subst ; try inversion ; subst.
    * rewrite app_nil_r. rewrite app_assoc. exists (Γ0 A :: Γ1, (Δ2 x) B :: Δ1). split ; try assumption. apply list_exch_R_id.
    * rewrite app_nil_r. exists (Γ0 A :: Γ1, Δ2 B :: Δ5 x Δ6). split. apply ImpRRule_I.
      assert ((Δ2 x) B :: Δ5 Δ6 = Δ2 x [] (B :: Δ5) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Δ2 B :: Δ5 x Δ6 = Δ2 (B :: Δ5) [] x Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
    * rewrite app_nil_r. exists (Γ0 A :: Γ1, Δ2 B :: Δ4 x Δ6). split. apply ImpRRule_I.
      assert ((Δ2 x) B :: Δ4 Δ6 = Δ2 x [] (B :: Δ4) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert (Δ2 B :: Δ4 x Δ6 = Δ2 (B :: Δ4) [] x Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
    * rewrite app_nil_r. exists (Γ0 A :: Γ1, (Δ2 :: Δ5) B :: Δ4 x Δ6). split.
      assert (Δ2 :: Δ5 A --> B :: Δ4 x Δ6 = (Δ2 :: Δ5) A --> B :: Δ4 x Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
      assert ((Δ2 x) B :: Δ4 :: Δ5 Δ6 = Δ2 x (B :: Δ4) ( :: Δ5) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Δ2 :: Δ5) B :: Δ4 x Δ6 = Δ2 ( :: Δ5) (B :: Δ4) x Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
    * exists (Γ0 A :: Γ1, (Δ2 x) B :: Δ6). split.
      assert (Δ2 (x A --> B :: ) Δ6 = (Δ2 x) A --> B :: Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
      apply list_exch_R_id.
    * exists (Γ0 A :: Γ1, (Δ2 :: Δ5 x) B :: Δ6). split.
      assert (Δ2 :: Δ5 (x A --> B :: ) Δ6 = (Δ2 :: Δ5 x) A --> B :: Δ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
      assert ((Δ2 x) B :: :: Δ5 Δ6 = Δ2 [] (x B :: ) ( :: Δ5) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Δ2 :: Δ5 x) B :: Δ6 = Δ2 ( :: Δ5) (x B :: ) [] Δ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_RI.
    * exists (Γ0 A :: Γ1, (Δ2 :: Δ4 x) B :: Δ6). split.
      assert (Δ2 :: Δ4 (x A --> B :: ) Δ6 = (Δ2 :: Δ4 x) A --> B :: Δ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
      assert ((Δ2 x) B :: :: Δ4 Δ6 = Δ2 [] (x B :: ) ( :: Δ4) Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear .
      assert ((Δ2 :: Δ4 x) B :: Δ6 = Δ2 ( :: Δ4) (x B :: ) [] Δ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_RI.
    * exists (Γ0 A :: Γ1, (Δ2 :: Δ5 :: Δ4 x) B :: Δ6). split.
      assert (Δ2 :: Δ5 :: Δ4 (x A --> B :: ) Δ6 = (Δ2 :: Δ5 :: Δ4 x) A --> B :: Δ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. simpl.
      repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
      assert ((Δ2 x) B :: :: Δ4 :: Δ5 Δ6 = Δ2 (x B :: ) ( :: Δ4) ( :: Δ5) Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert ((Δ2 :: Δ5 :: Δ4 x) B :: Δ6 = Δ2 ( :: Δ5) ( :: Δ4) (x B :: ) Δ6).
      repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
      rewrite . clear . apply list_exch_RI.
- destruct x ; destruct Δ3 ; destruct Δ4 ; destruct Δ5 ; simpl ; simpl in ; simpl in exch ;
  subst ; try inversion ; subst.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, Δ0 B :: Δ1). split ; try assumption.
    apply list_exch_R_id.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, Δ0 B :: Δ5 Δ6). split ; try assumption.
    apply list_exch_R_id.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, Δ0 B :: Δ4 Δ6). split ; try assumption.
    apply list_exch_R_id.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, (Δ0 :: Δ5) B :: Δ4 Δ6). split.
    assert (Δ0 :: Δ5 A --> B :: Δ4 Δ6 = (Δ0 :: Δ5) A --> B :: Δ4 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
    assert (Δ0 B :: Δ4 :: Δ5 Δ6 = Δ0 [] (B :: Δ4) ( :: Δ5) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Δ0 :: Δ5) B :: Δ4 Δ6 = Δ0 ( :: Δ5) (B :: Δ4) [] Δ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, Δ0 B :: Δ3 Δ6). split ; try assumption.
    apply list_exch_R_id.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, (Δ0 :: Δ5) B :: Δ3 Δ6). split.
    assert (Δ0 :: Δ5 A --> B :: Δ3 Δ6 = (Δ0 :: Δ5) A --> B :: Δ3 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
    assert (Δ0 B :: Δ3 :: Δ5 Δ6 = Δ0 [] (B :: Δ3) ( :: Δ5) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Δ0 :: Δ5) B :: Δ3 Δ6 = Δ0 ( :: Δ5) (B :: Δ3) [] Δ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, (Δ0 :: Δ4) B :: Δ3 Δ6). split.
    assert (Δ0 :: Δ4 A --> B :: Δ3 Δ6 = (Δ0 :: Δ4) A --> B :: Δ3 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
    assert ((Δ0 :: Δ4) B :: Δ3 Δ6 = Δ0 ( :: Δ4) (B :: Δ3) [] Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ0 B :: Δ3 :: Δ4 Δ6 = Δ0 [] (B :: Δ3) ( :: Δ4) Δ6).
    repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
  * rewrite app_nil_r. exists (Γ0 A :: Γ1, (Δ0 :: Δ5 :: Δ4) B :: Δ3 Δ6). split.
    assert (Δ0 :: Δ5 :: Δ4 A --> B :: Δ3 Δ6 = (Δ0 :: Δ5 :: Δ4) A --> B :: Δ3 Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity. rewrite . apply ImpRRule_I.
    assert (Δ0 B :: Δ3 :: Δ4 :: Δ5 Δ6 = Δ0 (B :: Δ3) ( :: Δ4) ( :: Δ5) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert ((Δ0 :: Δ5 :: Δ4) B :: Δ3 Δ6 = Δ0 ( :: Δ5) ( :: Δ4) (B :: Δ3) Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
  * exists (Γ0 A :: Γ1, Δ0 B :: x Δ6). split. repeat rewrite app_assoc. apply ImpRRule_I.
    apply list_exch_R_id.
  * exists (Γ0 A :: Γ1, Δ0 B :: x :: Δ5 Δ6). split. repeat rewrite app_assoc. apply ImpRRule_I.
    apply list_exch_R_id.
  * exists (Γ0 A :: Γ1, Δ0 B :: x :: Δ4 Δ6). split. repeat rewrite app_assoc. apply ImpRRule_I.
    apply list_exch_R_id.
  * exists (Γ0 A :: Γ1, Δ0 B :: x :: Δ5 :: Δ4 Δ6). split.
    repeat rewrite app_assoc. apply ImpRRule_I.
    assert (Δ0 B :: x :: Δ4 :: Δ5 Δ6 = (Δ0 B :: x) ( :: Δ4) [] ( :: Δ5) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ0 B :: x :: Δ5 :: Δ4 Δ6 = (Δ0 B :: x) ( :: Δ5) [] ( :: Δ4) Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
  * exists (Γ0 A :: Γ1, Δ0 B :: x :: Δ3 Δ6). split. repeat rewrite app_assoc. apply ImpRRule_I.
    apply list_exch_R_id.
  * exists (Γ0 A :: Γ1, Δ0 B :: x :: Δ5 :: Δ3 Δ6). split.
    repeat rewrite app_assoc. apply ImpRRule_I.
    assert (Δ0 B :: x :: Δ3 :: Δ5 Δ6 = (Δ0 B :: x) ( :: Δ3) [] ( :: Δ5) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ0 B :: x :: Δ5 :: Δ3 Δ6 = (Δ0 B :: x) ( :: Δ5) [] ( :: Δ3) Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
  * exists (Γ0 A :: Γ1, Δ0 B :: x :: Δ4 :: Δ3 Δ6). split.
    repeat rewrite app_assoc. apply ImpRRule_I.
    assert (Δ0 B :: x :: Δ3 :: Δ4 Δ6 = (Δ0 B :: x) ( :: Δ3) [] ( :: Δ4) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ0 B :: x :: Δ4 :: Δ3 Δ6 = (Δ0 B :: x) ( :: Δ4) [] ( :: Δ3) Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
  * exists (Γ0 A :: Γ1, Δ0 B :: x :: Δ5 :: Δ4 :: Δ3 Δ6). split.
    repeat rewrite app_assoc. apply ImpRRule_I.
    assert (Δ0 B :: x :: Δ3 :: Δ4 :: Δ5 Δ6 = (Δ0 B :: x) ( :: Δ3) ( :: Δ4) ( :: Δ5) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ0 B :: x :: Δ5 :: Δ4 :: Δ3 Δ6 = (Δ0 B :: x) ( :: Δ5) ( :: Δ4) ( :: Δ3) Δ6).
    repeat rewrite app_assoc. simpl. repeat rewrite app_assoc. reflexivity.
    rewrite . clear . apply list_exch_RI.
Qed.


Lemma ImpL_app_list_exchR : s se ps1 ps2,
  (@list_exch_R s se)
  (ImpLRule [;] s)
  ( pse1 pse2,
    (ImpLRule [;] se) *
    (@list_exch_R ) *
    (@list_exch_R )).
Proof.
intros s se exch. intro RA. inversion RA. inversion exch. subst.
inversion H. apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
- exists (Γ0 Γ1, Δ2 A :: Δ5 Δ4 Δ3 Δ6).
  exists (Γ0 B :: Γ1, Δ2 Δ5 Δ4 Δ3 Δ6). split. split. apply ImpLRule_I.
  assert (Δ2 A :: Δ3 Δ4 Δ5 Δ6 = (Δ2 [A]) Δ3 Δ4 Δ5 Δ6).
  rewrite app_assoc. reflexivity. rewrite . clear .
  assert (Δ2 A :: Δ5 Δ4 Δ3 Δ6 = (Δ2 [A]) Δ5 Δ4 Δ3 Δ6).
  rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
  apply list_exch_RI.
- apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
  + exists (Γ0 Γ1, (Δ2 Δ5) A :: Δ4 Δ3 Δ6).
    exists (Γ0 B :: Γ1, Δ2 Δ5 Δ4 Δ3 Δ6).
    split. split.
    assert (Δ2 Δ5 Δ4 Δ3 Δ6 = (Δ2 Δ5) Δ4 Δ3 Δ6). rewrite app_assoc.
    reflexivity. rewrite . clear . apply ImpLRule_I.
    repeat rewrite app_assoc.
    assert (Δ2 Δ3 A :: Δ4 Δ5 Δ6 = Δ2 Δ3 (A :: Δ4) Δ5 Δ6).
    reflexivity. rewrite . clear .
    assert (Δ2 Δ5 A :: Δ4 Δ3 Δ6 = Δ2 Δ5 (A :: Δ4) Δ3 Δ6).
    reflexivity. rewrite . clear . apply list_exch_RI. apply list_exch_RI.
  + apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
    * exists (Γ0 Γ1, (Δ2 Δ5 Δ4) A :: Δ3 Δ6).
      exists (Γ0 B :: Γ1, Δ2 Δ5 Δ4 Δ3 Δ6). split. split.
      assert (Δ2 Δ5 Δ4 Δ3 Δ6 = (Δ2 Δ5 Δ4) Δ3 Δ6). repeat rewrite app_assoc.
      reflexivity. rewrite . clear . apply ImpLRule_I. repeat rewrite app_assoc.
      assert (Δ2 Δ3 Δ4 A :: Δ5 Δ6 = Δ2 Δ3 (Δ4 [A]) Δ5 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert (Δ2 Δ5 Δ4 A :: Δ3 Δ6 = Δ2 Δ5 (Δ4 [A]) Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI. apply list_exch_RI.
    * apply app2_find_hole in . destruct . repeat destruct s ; destruct p ; subst.
      { repeat rewrite app_assoc. exists (Γ0 Γ1, Δ2 Δ5 Δ4 Δ3 A :: Δ6).
        exists (Γ0 B :: Γ1, Δ2 Δ5 Δ4 Δ3 Δ6).
        split. split. repeat rewrite app_assoc. apply ImpLRule_I. apply list_exch_RI.
        apply list_exch_RI. }
      { repeat rewrite app_assoc. exists (Γ0 Γ1, Δ2 Δ5 Δ4 Δ3 A :: Δ1).
        exists (Γ0 B :: Γ1, Δ2 Δ5 Δ4 Δ3 Δ1). split. split. repeat rewrite app_assoc.
        apply ImpLRule_I. apply list_exch_RI. apply list_exch_RI. }
      { repeat rewrite app_assoc. exists (Γ0 Γ1, Δ2 (x A :: ) Δ4 Δ3 Δ6).
        exists (Γ0 B :: Γ1, Δ2 x Δ4 Δ3 Δ6). split. split.
        assert (Δ2 (x A :: ) Δ4 Δ3 Δ6 = (Δ2 x) A :: Δ4 Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert (Δ2 x Δ4 Δ3 Δ6 = (Δ2 x) Δ4 Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        apply ImpLRule_I.
        assert (Δ2 Δ3 Δ4 x A :: Δ6 = Δ2 Δ3 Δ4 (x A :: ) Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_RI.
        assert (Δ2 Δ3 Δ4 x Δ6 = Δ2 Δ3 Δ4 (x ) Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . clear .
        assert (Δ2 x Δ4 Δ3 Δ6 = Δ2 (x ) Δ4 Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_RI. }
    * repeat rewrite app_assoc. exists (Γ0 Γ1, Δ2 Δ5 ( A :: x) Δ3 Δ6).
      exists (Γ0 B :: Γ1, Δ2 Δ5 ( x) Δ3 Δ6). split. split.
      assert (Δ2 Δ5 ( A :: x) Δ3 Δ6 = (Δ2 Δ5 ) A :: x Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert (Δ2 Δ5 x Δ3 Δ6 = (Δ2 Δ5 ) x Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      assert (Δ2 Δ5 ( x) Δ3 Δ6 = (Δ2 Δ5 ) x Δ3 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . clear .
      apply ImpLRule_I.
      assert (Δ2 Δ3 A :: x Δ5 Δ6 = Δ2 Δ3 ( A :: x) Δ5 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_RI.
      assert (Δ2 Δ3 x Δ5 Δ6 = Δ2 Δ3 ( x) Δ5 Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_RI.
  + repeat rewrite app_assoc. exists (Γ0 Γ1, Δ2 Δ5 Δ4 (x A :: ) Δ6).
    exists (Γ0 B :: Γ1, Δ2 Δ5 Δ4 (x ) Δ6). split. split.
    assert (Δ2 Δ5 Δ4 (x A :: ) Δ6 = (Δ2 Δ5 Δ4 x) A :: Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ2 Δ5 Δ4 x Δ6 = (Δ2 Δ5 Δ4 x) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    assert (Δ2 Δ5 Δ4 (x ) Δ6 = (Δ2 Δ5 Δ4 x) Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . clear .
    apply ImpLRule_I.
    assert (Δ2 x A :: Δ4 Δ5 Δ6 = Δ2 (x A :: ) Δ4 Δ5 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_RI.
    assert (Δ2 x Δ4 Δ5 Δ6 = Δ2 (x ) Δ4 Δ5 Δ6).
    repeat rewrite app_assoc. reflexivity. rewrite . apply list_exch_RI.
- repeat rewrite app_assoc. exists (Γ0 Γ1, Δ0 A :: x Δ5 Δ4 Δ3 Δ6).
  exists (Γ0 B :: Γ1, Δ0 x Δ5 Δ4 Δ3 Δ6). split. split. apply ImpLRule_I.
  assert (Δ0 A :: x Δ3 Δ4 Δ5 Δ6 = (Δ0 A :: x) Δ3 Δ4 Δ5 Δ6).
  repeat rewrite app_assoc. reflexivity. rewrite . clear .
  assert (Δ0 A :: x Δ5 Δ4 Δ3 Δ6 = (Δ0 A :: x) Δ5 Δ4 Δ3 Δ6).
  repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
  assert (Δ0 x Δ3 Δ4 Δ5 Δ6 = (Δ0 x) Δ3 Δ4 Δ5 Δ6).
  repeat rewrite app_assoc. reflexivity. rewrite . clear .
  assert (Δ0 x Δ5 Δ4 Δ3 Δ6 = (Δ0 x) Δ5 Δ4 Δ3 Δ6).
  repeat rewrite app_assoc. reflexivity. rewrite . clear . apply list_exch_RI.
Qed.


Lemma GLR_app_list_exchR : s se ps,
  (@list_exch_R s se)
  (GLRRule [ps] s)
  ( pse,
    (GLRRule [pse] se) *
    (@list_exch_R ps pse)).
Proof.
intros s se ps exch RA. inversion RA. inversion exch. rewrite in .
inversion . exists (XBoxed_list [Box A], [A]). split.
- pose (partition_1_element2 Δ2 Δ3 Δ4 Δ5 Δ6 Δ0 Δ1 (Box A) ). destruct .
  + repeat destruct . repeat destruct p. subst. assert (E : (Δ0 Box A :: ) Δ5 Δ4 Δ3 Δ6 = Δ0 Box A :: ( Δ5 Δ4 Δ3 Δ6)).
    repeat rewrite app_assoc. reflexivity. rewrite E. apply GLRRule_I.
    * assumption.
    * assumption.
  + destruct .
    * repeat destruct . repeat destruct p. subst. assert (E: Δ2 Δ5 Δ4 (x Box A :: ) Δ6 = (Δ2 Δ5 Δ4 x) Box A :: Δ6).
      repeat rewrite app_assoc. reflexivity. rewrite E. apply GLRRule_I.
      { assumption. }
      { assumption. }
    * destruct .
      { repeat destruct . repeat destruct p. subst. assert (E: Δ2 Δ5 (x Box A :: ) Δ3 Δ6 = (Δ2 Δ5 x) Box A :: Δ3 Δ6).
        repeat rewrite app_assoc. reflexivity. rewrite E. apply GLRRule_I.
        - assumption.
        - assumption. }
      { destruct .
        - repeat destruct . repeat destruct p. subst. assert (E: Δ2 (x Box A :: ) Δ4 Δ3 Δ6 = (Δ2 x) Box A :: Δ4 Δ3 Δ6).
          repeat rewrite app_assoc. reflexivity. rewrite E. apply GLRRule_I.
          + assumption.
          + assumption.
        - repeat destruct . repeat destruct p. subst. assert (E: Δ2 Δ5 Δ4 Δ3 x Box A :: Δ1 = (Δ2 Δ5 Δ4 Δ3 x) Box A :: Δ1).
          repeat rewrite app_assoc. reflexivity. rewrite E. apply GLRRule_I.
          + assumption.
          + assumption. }
- apply list_exch_R_id.
Qed.


(* We can now prove the admissibility of list_exchange on the left. *)

Theorem GLS_adm_list_exch_L : s,
        (GLS_prv s)
        ( se, (@list_exch_L s se)
        (GLS_prv se)).
Proof.
intros s D. apply derrec_all_rect with
(Q:= fun x (se : Seq),
list_exch_L x se
derrec GLS_rules (fun _ : Seq False)
  se)
in D.
- exact D.
- intros concl F. inversion F.
- intros ps concl rule. induction rule.
  (* IdP *)
  * intros ders IH se exch. inversion i. apply derI with (ps:=[]).
    apply IdP.
    + assert (Permstose: eΓ0 eΓ1, se = (eΓ0 # P :: eΓ1, Δ0 # P :: Δ1)).
      { pose (list_exch_L_permLR exch). subst. destruct with (Γ0:=Γ0) (Γ1:=Γ1) (Δ0:=Δ0) (Δ1:=Δ1)
      (C:=# P) (D:=# P). auto. exists x. assumption. }
      destruct Permstose. repeat destruct . subst. apply IdPRule_I.
    + apply dersrec_all in ders. apply dersrec_all. subst. assumption.
  (* BotL *)
  * intros ders IH se exch. apply derI with (ps:=ps).
    + apply BotL. inversion b. symmetry in .
      assert (Permstose: eΓ0 eΓ1, se = ((eΓ0 Bot :: eΓ1), Δ)).
      { apply list_exch_L_permL with (s:=c) (Γ0:=Γ0) (Γ1:=Γ1) (Δ:=Δ). assumption.
        assumption. }
      destruct Permstose. destruct . subst. apply BotLRule_I.
    + apply dersrec_all in ders. apply dersrec_all. assumption.
  (* ImpR *)
  * intros ders IH se exch. inversion i. subst. pose (ImpR_app_list_exchL exch i).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply ImpR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
  (* ImpL *)
  * intros ders IH se exch. inversion i. subst. pose (ImpL_app_list_exchL exch i).
    destruct . destruct . destruct p. destruct p. apply derI with (ps:=[x;]).
    + apply ImpL. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_cons_inv in IH. destruct IH.
      apply ForallT_inv in f. apply ForallT_cons.
      { apply d. subst. assumption. }
      { apply ForallT_cons. apply f. subst. assumption. apply ForallT_nil. }
  (* GLR *)
  * intros ders IH se exch. inversion g. subst. pose (GLR_app_list_exchL exch g).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply GLR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion g. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
Qed.


Theorem GLS_adm_list_exch_R : s,
        (GLS_prv s)
        ( se, (@list_exch_R s se)
        (GLS_prv se)).
Proof.
intros s D. apply derrec_all_rect with
(Q:= fun x (se : Seq),
list_exch_R x se
derrec GLS_rules (fun _ : Seq False)
  se)
in D.
- exact D.
- intros concl F. inversion F.
- intros ps concl rule. induction rule.
  (* IdP *)
  * intros ders IH se exch. inversion i. apply derI with (ps:=[]).
    apply IdP.
    + assert (Permstose: eΔ0 eΔ1, se = (Γ0 # P :: Γ1, eΔ0 # P :: eΔ1)).
      { pose (list_exch_R_permLR exch). subst. destruct with (Γ0:=Γ0) (Γ1:=Γ1) (Δ0:=Δ0) (Δ1:=Δ1)
      (C:=# P) (D:=# P). auto. exists x. assumption. }
      destruct Permstose. repeat destruct . subst. apply IdPRule_I.
    + apply dersrec_all in ders. apply dersrec_all. subst. assumption.
  (* BotL *)
  * intros ders IH se exch. apply derI with (ps:=ps).
    + apply BotL. inversion b. symmetry in .
      assert (Permstose: , se = ((Γ0 Bot :: Γ1), )).
      { apply list_exch_R_permL with (s:=c) (Γ0:=Γ0) (Γ1:=Γ1) (Δ:=Δ). assumption.
        assumption. }
      destruct Permstose. subst. apply BotLRule_I.
    + apply dersrec_all in ders. apply dersrec_all. assumption.
  (* ImpR *)
  * intros ders IH se exch. inversion i. subst. pose (ImpR_app_list_exchR exch i).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply ImpR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
  (* ImpL *)
  * intros ders IH se exch. inversion i. subst. pose (ImpL_app_list_exchR exch i).
    destruct . destruct . destruct p. destruct p. apply derI with (ps:=[x;]).
    + apply ImpL. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_cons_inv in IH. destruct IH.
      apply ForallT_inv in f. apply ForallT_cons.
      { apply d. subst. assumption. }
      { apply ForallT_cons. apply f. subst. assumption. apply ForallT_nil. }
  (* GLR *)
  * intros ders IH se exch. inversion g. subst. pose (GLR_app_list_exchR exch g).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply GLR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion g. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
Qed.


(* Now we can turn to the derivability of list_exchange. *)

Inductive Closure {X: Type} (F : X Type) (P : X X Type) : X Type :=
  | InitClo : x, F x Closure F P x
  | IndClo : x y, Closure F P y (P y x) Closure F P x.

Inductive ExcClosure (hyps : Seq Type) : Seq Type :=
  | InitLExch : x, Closure hyps list_exch_L x ExcClosure hyps x
  | InitRExch : x, Closure hyps list_exch_R x ExcClosure hyps x
  | IndLExch : x y, ExcClosure hyps x list_exch_L x y ExcClosure hyps y
  | IndRExch : x y, ExcClosure hyps x list_exch_R x y ExcClosure hyps y.

Theorem GLS_der_list_exch_L : hyps s,
        (derrec GLS_rules hyps s)
        ( se, (@list_exch_L s se)
        (derrec GLS_rules (ExcClosure hyps) se)).
Proof.
intros hyps s D. apply derrec_all_rect with
(Q:= fun x (se : Seq),
list_exch_L x se
derrec GLS_rules (ExcClosure hyps) se) in D.
- exact D.
- intros concl se exch. apply dpI. apply InitLExch. apply IndClo with (y:=concl).
  apply InitClo. assumption. assumption.
- intros ps concl rule. induction rule.
  (* IdP *)
  * intros ders IH se exch. inversion i. apply derI with (ps:=[]).
    apply IdP.
    + assert (Permstose: eΓ0 eΓ1, se = (eΓ0 # P :: eΓ1, Δ0 # P :: Δ1)).
      { pose (list_exch_L_permLR exch). subst. destruct with (Γ0:=Γ0) (Γ1:=Γ1) (Δ0:=Δ0) (Δ1:=Δ1)
      (C:=# P) (D:=# P). auto. exists x. assumption. }
      destruct Permstose. repeat destruct . subst. apply IdPRule_I.
    + apply dersrec_all in ders. apply dersrec_nil.
  (* BotL *)
  * intros ders IH se exch. apply derI with (ps:=ps).
    + apply BotL. inversion b. symmetry in .
      assert (Permstose: eΓ0 eΓ1, se = ((eΓ0 Bot :: eΓ1), Δ)).
      { apply list_exch_L_permL with (s:=c) (Γ0:=Γ0) (Γ1:=Γ1) (Δ:=Δ). assumption.
        assumption. }
      destruct Permstose. repeat destruct . subst. apply BotLRule_I.
    + apply dersrec_all in ders. inversion b. apply dersrec_nil.
  (* ImpR *)
  * intros ders IH se exch. inversion i. subst. pose (ImpR_app_list_exchL exch i).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply ImpR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
  (* ImpL *)
  * intros ders IH se exch. inversion i. subst. pose (ImpL_app_list_exchL exch i).
    destruct . destruct . destruct p. destruct p. apply derI with (ps:=[x;]).
    + apply ImpL. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_cons_inv in IH. destruct IH.
      apply ForallT_inv in f. apply ForallT_cons.
      { apply d. subst. assumption. }
      { apply ForallT_cons. apply f. subst. assumption. apply ForallT_nil. }
  (* GLR *)
  * intros ders IH se exch. inversion g. subst. pose (GLR_app_list_exchL exch g).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply GLR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion g. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
Qed.


Theorem GLS_der_list_exch_R : hyps s,
        (derrec GLS_rules hyps s)
        ( se, (@list_exch_R s se)
        (derrec GLS_rules (ExcClosure hyps) se)).
Proof.
intros hyps s D. apply derrec_all_rect with
(Q:= fun x (se : Seq),
list_exch_R x se
derrec GLS_rules (ExcClosure hyps) se) in D.
- exact D.
- intros concl se exch. apply dpI. apply InitRExch. apply IndClo with (y:=concl).
  apply InitClo. assumption. assumption.
- intros ps concl rule. induction rule.
  (* IdP *)
  * intros ders IH se exch. inversion i. apply derI with (ps:=[]).
    apply IdP.
    + assert (Permstose: eΔ0 eΔ1, se = (Γ0 # P :: Γ1, eΔ0 # P :: eΔ1)).
      { pose (list_exch_R_permLR exch). subst. destruct with (Γ0:=Γ0) (Γ1:=Γ1) (Δ0:=Δ0) (Δ1:=Δ1)
      (C:=# P) (D:=# P). auto. exists x. assumption. }
      destruct Permstose. repeat destruct . subst. apply IdPRule_I.
    + apply dersrec_all in ders. apply dersrec_nil.
  (* BotL *)
  * intros ders IH se exch. apply derI with (ps:=ps).
    + apply BotL. inversion b. symmetry in .
      assert (Permstose: , se = ((Γ0 Bot :: Γ1), )).
      { apply list_exch_R_permL with (s:=c) (Γ0:=Γ0) (Γ1:=Γ1) (Δ:=Δ). assumption.
        assumption. }
      destruct Permstose. subst. apply BotLRule_I.
    + apply dersrec_all in ders. inversion b. apply dersrec_nil.
  (* ImpR *)
  * intros ders IH se exch. inversion i. subst. pose (ImpR_app_list_exchR exch i).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply ImpR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
  (* ImpL *)
  * intros ders IH se exch. inversion i. subst. pose (ImpL_app_list_exchR exch i).
    destruct . destruct . destruct p. destruct p. apply derI with (ps:=[x;]).
    + apply ImpL. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion i. apply ForallT_cons_inv in IH. destruct IH.
      apply ForallT_inv in f. apply ForallT_cons.
      { apply d. subst. assumption. }
      { apply ForallT_cons. apply f. subst. assumption. apply ForallT_nil. }
  (* GLR *)
  * intros ders IH se exch. inversion g. subst. pose (GLR_app_list_exchR exch g).
    destruct . destruct p. apply derI with (ps:=[x]).
    + apply GLR. assumption.
    + apply dersrec_all. apply dersrec_all in ders. inversion .
      inversion g. apply ForallT_inv in IH. apply ForallT_cons.
      { apply IH. subst. assumption. }
      { apply ForallT_nil. }
Qed.


(* In fact, we can prove that exchange is height-preserving admissible. *)

Theorem GLS_hpadm_list_exch_R : (k : ) s
                                  (D0: GLS_prv s),
        k = (derrec_height )
        ( se, (list_exch_R s se)
        ( (D1 : GLS_prv se),
          derrec_height k)).
Proof.
induction k as [n IH] using (well_founded_induction_type lt_wf).
intros . remember as . destruct .
(* D0 ip a leaf *)
- inversion f.
(* D0 is ends with an application of rule *)
- intros hei se exch. inversion exch.
  assert (DersNil: dersrec GLS_rules (fun _ : Seq False) []).
  apply dersrec_nil. inversion g.
  (* IdP *)
  * inversion . subst. inversion . subst. simpl.
    assert (In # P (Δ0 Δ3 Δ2 Δ1 Δ4)). assert (In # P (Δ0 Δ1 Δ2 Δ3 Δ4)).
    rewrite . apply in_or_app. right. apply in_eq. apply in_app_or in H. apply in_or_app.
    destruct H. auto. apply in_app_or in H. right. apply in_or_app. destruct H. right. apply in_or_app.
    right. apply in_or_app. auto. apply in_app_or in H. destruct H. right. apply in_or_app. auto.
    apply in_app_or in H. destruct H. auto. right. apply in_or_app. right. apply in_or_app. auto.
    apply in_splitT in H. destruct H. destruct s. rewrite e.
    assert (IdPRule [] (Γ0 # P :: Γ1, x # P :: )). apply IdPRule_I. apply IdP in H.
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[]) (Γ0 # P :: Γ1, x # P :: ) H DersNil). exists . simpl. rewrite dersrec_height_nil.
    lia. reflexivity.
  (* BotL *)
  * inversion . subst. inversion . subst. simpl.
    assert (BotLRule [] (Γ0 :: Γ1, Δ0 Δ3 Δ2 Δ1 Δ4)). apply BotLRule_I. apply BotL in H.
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[]) (Γ0 :: Γ1, Δ0 Δ3 Δ2 Δ1 Δ4) H DersNil). exists . simpl. rewrite dersrec_height_nil.
    lia. reflexivity.
  (* ImpR *)
  * inversion . subst. inversion . subst. simpl. simpl in IH.
    pose (ImpR_app_list_exchR exch ). destruct s. destruct p.
    apply ImpR in i. assert (: dersrec_height d = dersrec_height d). reflexivity.
    pose (dersrec_derrec_height d ). destruct s.
    assert (E: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) E (Γ0 A :: Γ1, Δ5 B :: Δ6) x l).
    destruct s. pose (dlCons DersNil).
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[x]) (Γ0 Γ1, Δ0 Δ3 Δ2 Δ1 Δ4) i ). exists . simpl.
    rewrite dersrec_height_nil. rewrite Nat.max_0_r. lia. reflexivity.
  (* ImpL *)
  * inversion . subst. inversion . subst. simpl. simpl in IH.
    pose (ImpL_app_list_exchR exch ). repeat destruct s. repeat destruct p.
    apply ImpL in i. assert (: dersrec_height d = dersrec_height d). reflexivity.
    pose (dersrec_derrec2_height d ). repeat destruct s.
    assert (E: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) E (Γ0 Γ1, Δ5 A :: Δ6) x ).
    destruct s.
    assert (: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) (Γ0 B :: Γ1, Δ5 Δ6) l).
    destruct s. pose (dlCons DersNil). pose (dlCons ).
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[x; ]) (Γ0 A --> B :: Γ1, Δ0 Δ3 Δ2 Δ1 Δ4) i ). exists . simpl.
    rewrite dersrec_height_nil. rewrite Nat.max_0_r. lia. reflexivity.
  (* GLR *)
  * inversion X. subst. inversion . subst. simpl. simpl in IH.
    pose (GLR_app_list_exchR exch X). destruct s. destruct p.
    apply GLR in . assert (: dersrec_height d = dersrec_height d). reflexivity.
    pose (dersrec_derrec_height d ). destruct s.
    assert (E: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) E (XBoxed_list [Box A], [A]) x l).
    destruct s. pose (dlCons DersNil).
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[x]) (Γ, Δ0 Δ3 Δ2 Δ1 Δ4) ). exists . simpl.
    rewrite dersrec_height_nil. rewrite Nat.max_0_r. lia. reflexivity.
Qed.


Theorem GLS_hpadm_list_exch_L : (k : ) s
                                  (D0: GLS_prv s),
        k = (derrec_height )
        ( se, (list_exch_L s se)
        ( (D1 : GLS_prv se),
          derrec_height k)).
Proof.
induction k as [n IH] using (well_founded_induction_type lt_wf).
intros . remember as . destruct .
(* D0 ip a leaf *)
- inversion f.
(* D0 is ends with an application of rule *)
- intros hei se exch. inversion exch.
  assert (DersNil: dersrec GLS_rules (fun _ : Seq False) []).
  apply dersrec_nil. inversion g.
  (* IdP *)
  * inversion . subst. inversion . subst. simpl.
    assert (In # P (Γ0 Γ3 Γ2 Γ1 Γ4)). assert (In # P (Γ0 Γ1 Γ2 Γ3 Γ4)).
    rewrite . apply in_or_app. right. apply in_eq. apply in_app_or in H. apply in_or_app.
    destruct H. auto. apply in_app_or in H. right. apply in_or_app. destruct H. right. apply in_or_app.
    right. apply in_or_app. auto. apply in_app_or in H. destruct H. right. apply in_or_app. auto.
    apply in_app_or in H. destruct H. auto. right. apply in_or_app. right. apply in_or_app. auto.
    apply in_splitT in H. destruct H. destruct s. rewrite e.
    assert (IdPRule [] (x # P :: , Δ0 # P :: Δ1)). apply IdPRule_I. apply IdP in H.
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[]) (x # P :: , Δ0 # P :: Δ1) H DersNil). exists . simpl. rewrite dersrec_height_nil.
    lia. reflexivity.
  (* BotL *)
  * inversion . subst. inversion . subst. simpl.
    assert (In () (Γ0 Γ3 Γ2 Γ1 Γ4)). assert (In () (Γ0 Γ1 Γ2 Γ3 Γ4)).
    rewrite . apply in_or_app. right. apply in_eq. apply in_app_or in H. apply in_or_app.
    destruct H. auto. apply in_app_or in H. right. apply in_or_app. destruct H. right. apply in_or_app.
    right. apply in_or_app. auto. apply in_app_or in H. destruct H. right. apply in_or_app. auto.
    apply in_app_or in H. destruct H. auto. right. apply in_or_app. right. apply in_or_app. auto.
    apply in_splitT in H. destruct H. destruct s. rewrite e.
    assert (BotLRule [] (x :: , Δ)). apply BotLRule_I. apply BotL in H.
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[]) (x :: , Δ) H DersNil). exists . simpl. rewrite dersrec_height_nil.
    lia. reflexivity.
  (* ImpR *)
  * inversion . subst. inversion . subst. simpl. simpl in IH.
    pose (ImpR_app_list_exchL exch ). destruct s. destruct p.
    apply ImpR in i. assert (: dersrec_height d = dersrec_height d). reflexivity.
    pose (dersrec_derrec_height d ). destruct s.
    assert (E: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) E (Γ5 A :: Γ6, Δ0 B :: Δ1) x l).
    destruct s. pose (dlCons DersNil).
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[x]) (Γ0 Γ3 Γ2 Γ1 Γ4, Δ0 A --> B :: Δ1) i ). exists . simpl.
    rewrite dersrec_height_nil. rewrite Nat.max_0_r. lia. reflexivity.
  (* ImpL *)
  * inversion . subst. inversion . subst. simpl. simpl in IH.
    pose (ImpL_app_list_exchL exch ). repeat destruct s. repeat destruct p.
    apply ImpL in i. assert (: dersrec_height d = dersrec_height d). reflexivity.
    pose (dersrec_derrec2_height d ). repeat destruct s.
    assert (E: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) E (Γ5 Γ6, Δ0 A :: Δ1) x ).
    destruct s.
    assert (: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) (Γ5 B :: Γ6, Δ0 Δ1) l).
    destruct s. pose (dlCons DersNil). pose (dlCons ).
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[x; ]) (Γ0 Γ3 Γ2 Γ1 Γ4, Δ0 Δ1) i ). exists . simpl.
    rewrite dersrec_height_nil. rewrite Nat.max_0_r. lia. reflexivity.
  (* GLR *)
  * inversion X. subst. inversion . subst. simpl. simpl in IH.
    pose (GLR_app_list_exchL exch X). destruct s. destruct p.
    apply GLR in . assert (: dersrec_height d = dersrec_height d). reflexivity.
    pose (dersrec_derrec_height d ). destruct s.
    assert (E: derrec_height < S (dersrec_height d)). lia.
    assert (: derrec_height = derrec_height ). auto.
    pose (IH (derrec_height ) E (XBoxed_list [Box A], [A]) x l).
    destruct s. pose (dlCons DersNil).
    pose (derI (rules:=GLS_rules) (prems:=fun _ : Seq False)
    (ps:=[x]) (Γ0 Γ3 Γ2 Γ1 Γ4, Δ0 Box A :: Δ1) ). exists . simpl.
    rewrite dersrec_height_nil. rewrite Nat.max_0_r. lia. reflexivity.
Qed.


Theorem GLS_adm_list_exch_LR : s (D0: GLS_prv s),
        ( se, ((list_exch_L s se) (GLS_prv se)) *
                        ((list_exch_R s se) (GLS_prv se))).
Proof.
intros. assert (: derrec_height = derrec_height ). auto. split ; intro.
- pose (@GLS_hpadm_list_exch_L (derrec_height ) s se H). destruct ; auto.
- pose (@GLS_hpadm_list_exch_R (derrec_height ) s se H). destruct ; auto.
Qed.