Require Import Bool.
Require Import Arith.
Require Export String.
Require Import CR.
Require Import Meta.
Require Import SR.

Coercion Is_true : bool >-> Sortclass.

Fixpoint varlike (n : nat) (M : term n) {struct M} : bool :=
match M with
  var n x => true |
  srt n s => false |
  app n M N => varlike n M |
  pi n A B => false |
  lda n A M => varlike (S n) M
end.

Implicit Arguments varlike [n].

Lemma varlike_subvar : forall m M n (rho : fin m -> fin n),
  varlike M -> varlike (subvar M rho).
Proof.
 induction M; simpl; auto.
Qed.

Lemma varlike_subvar' : forall m M n (rho : fin m -> fin n),
  varlike (subvar M rho) -> varlike M.
Proof.
 induction M; simpl; auto.
 intros n0 rho.
 apply IHM2.
Qed.

Fixpoint sortlike (n : nat) (M : term n) {struct M} : bool :=
match M with
  var n x => false |
  srt n s => true |
  app n M N => sortlike n M |
  pi n A B => true |
  lda n A M => sortlike (S n) M
end.

Implicit Arguments sortlike [n].

Lemma sortlike_subvar : forall m M n (rho : fin m -> fin n),
  sortlike M -> sortlike (subvar M rho).
Proof.
 induction M; simpl; auto.
Qed.

Lemma sortlike_subvar' : forall m M n (rho : fin m -> fin n),
  sortlike (subvar M rho) -> sortlike M.
Proof.
 induction M; simpl; auto.
 intros n0 rho.
 apply IHM2.
Qed.

Lemma sortlike_liftterm : forall n (M : term n), sortlike M -> sortlike (liftterm M).
Proof.
intros.
unfold liftterm.
apply sortlike_subvar.
assumption.
Qed.

Lemma sortlike_liftterm' : forall n (M : term n), sortlike (liftterm M) -> sortlike M.
Proof.
unfold liftterm.
intros n M.
apply sortlike_subvar'.
Qed.

Lemma var_or_sort : forall n (M : term n), varlike M \/ sortlike M.
Proof.
 induction M; simpl; auto.
Qed.

Lemma var_not_sort : forall n (M : term n), varlike M -> sortlike M -> False.
Proof.
 induction M; simpl; auto.
Qed.

Lemma Unique_Type_varlike : forall n (M : term n), varlike M ->
  forall Gamma A B, Gamma |- M ; A -> Gamma |- M ; B -> A ~= B.
Proof.
 induction M; simpl.
  intros _ Gamma A B H H1.
    apply conv_trans with (typeof f Gamma).
     apply conv_sym.
       apply Gen_var.
       assumption.
     apply Gen_var.
       assumption.
  destruct 1.
  intros.
    elim Gen_app with n Gamma M1 M2 A.
     intro C.
       destruct 1.
       rename x into D.
       destruct H2.
       destruct H3.
       elim Gen_app with n Gamma M1 M2 B.
        intro C'.
	  destruct 1.
	  rename x into D'.
	  destruct H5.
	  destruct H6.
	  apply conv_trans with (subbot D M2).
	   assumption.
	   apply conv_trans with (subbot D' M2).
	    apply conv_subbot.
	     apply conv_pi_injr with C C'.
	       apply IHM1 with Gamma; assumption.
	     apply conv_ref.
	    apply conv_sym.
	      assumption.
	assumption.
     assumption.
  destruct 1.
  intros.
    elim Gen_lda with n Gamma M1 M2 A.
     intro C.
       destruct 1.
       rename x into s.
       destruct H2.
       destruct H3.
       elim Gen_lda with n Gamma M1 M2 B.
        intro C'.
	  destruct 1.
	  rename x into t.
	  destruct H5.
	  destruct H6.
	  apply conv_trans with (pi M1 C).
	   assumption.
	   apply conv_trans with (pi M1 C').
	    apply conv_pir.
	      apply IHM2 with (Gamma, M1); assumption.
	    apply conv_sym.
	      assumption.
	assumption.
    assumption.
Qed.

Lemma Typing_Lemma_sortlike : forall n (Gamma : context n) M A,
  Gamma |- M ; A -> sortlike M ->
  exists m, exists Delta : string m n, exists s,
  A ->> Pi Delta (srt s).
Proof.
 induction 1; simpl.
(* axioms *)
  split with O.
    split with (emp (m:=O)).
    split with t.
    apply red_ref.
(* start *)
  destruct 1.
(* weakening *)
  intro.
    elim IHPTS1.
     intro m.
       destruct 1.
       rename x into Delta.
       destruct H2.
       rename x into t.
       split with (S m).
       split with (liftstring Delta).
       split with t.
       unfold liftstring.
       change (srt (n:=S m) t) with (subvar (srt t) (subvar_lift (mtch_Sm_Sn m n Delta) (up (n:=n)))).
       rewrite <- Pi_subvar with (rho := up (n:=n)) (B := srt (n:=m) t) (e := mtch_Sm_Sn m n Delta) (Delta := Delta).
       apply red_liftterm with (N := Pi Delta (srt t)).
       assumption.
     apply sortlike_liftterm'.
       assumption.
(* product *)
  intros _.
    split with n.
    split with (emp (m:=n)).
    split with s3.
    apply red_ref.
(* application *)
  intro.
    elim IHPTS1.
     destruct x.
      destruct 1.
        induction x.
         destruct H2.
	   elim not_red_pi_srt with O A B x.
	   assumption.
	 elim le_Sn_O with n.
	   apply string_leq.
	   assumption.
        destruct 1.
	  destruct H2.
	  rename x1 into s.
          induction x0.
	   elim not_red_pi_srt with (S x) A B s.
	     assumption.
	   split with x.
	     split with (subbot_string x0 a).
	     split with s.
	     unfold subbot_string.
	     change (srt (n := x) s) with (subst (srt s) (subst_lift (mtch_Sm_Sn_inv _ _ x0)
	       (fun x : fin (S n) =>
		 match x with
		   Some y => var y |
		     None   => a
		 end))).
	     rewrite <- Pi_subst.
	     apply red_subbot with (M := B) (N := Pi x0 (srt s)) (P := a) (Q := a).
	      apply red_pi_injr with A t.
	        assumption.
	      apply red_ref.
     assumption.
(* abstraction *)
  intro.
    elim IHPTS1.
     intro m.
       destruct 1.
       rename x into Delta.
       destruct H4.
       rename x into s.
       split with m.
       split with (cons A Delta).
       split with s.
       simpl.
       apply red_pir.
       assumption.
     assumption.
(* conversion *)
  intro.
    elim IHPTS1.
     intro m.
       destruct 1.
       rename x into Delta.
       destruct H3.
       rename x into t.
       split with m.
       elim Church_Rosser with n B B'.
        intro B0.
	  destruct 1.
	  elim red_dmnd with n B (Pi Delta (srt t)) B0; auto.
	  intro B1.
	  destruct 1.
	  elim red_Pi_inv with m n Delta (srt (n:=m) t) B1.
	   intro Delta0.
	     destruct 1.
	     rename x into C.
	     destruct H8.
	     destruct H9.
	     split with Delta0.
	     split with t.
	     apply red_trans with B0.
	      assumption.
	      rewrite <- Gen_red_srt with m t C.
	       rewrite <- H10.
	         assumption.
	       assumption.
	   assumption.
	assumption.
     assumption.
Qed.

Definition Sigma : forall n : nat, (term n) -> (context n) -> sort -> Prop.
  induction 1.
  intros _ _.
    exact False.
  intros _.
    exact (axiom s).
  exact IHterm1.
  intros Gamma s3.
    exact (exists s1 : sort, exists s2 : sort, rule s1 s2 s3 /\
      ((varlike H /\ PTS Gamma H (srt s1)) \/ (sortlike H /\ IHterm1 Gamma s1)) /\
      ((varlike H0 /\ PTS (n := S n) (Gamma, H) H0 (srt s2)) \/ (sortlike H0 /\ IHterm2 (Gamma, H) s2))).
  intro Gamma.
    exact (IHterm2 (Gamma, H)).
Defined.

Implicit Arguments Sigma [n].

Theorem Sigma_ctxt_irrel : forall (m : nat) (a : term m) (n : nat) (A : term m) (Delta : context m) (Gamma : context n) (rho : fin m -> fin n),
  sortlike a -> Delta |- a ; A -> valid Gamma -> subctxt Delta Gamma rho ->
  forall s : sort, Sigma a Delta s <-> Sigma (subvar a rho) Gamma s.
Proof.
 induction a; simpl; intros.
(* var *)
  destruct H.
(* srt *)
  tauto.
(* app *)
  elim Gen_app with n Delta a1 a2 A.
   intro A0.
     destruct 1.
     rename x into B0.
     destruct H3.
     destruct H4.
     apply IHa1 with (pi A0 B0); assumption.
   assumption.
(* pi *)
  elim Gen_pi with n Delta a1 a2 A.
   intro t1.
     destruct 1.
     rename x into t2.
     destruct H3.
     rename x into t3.
     destruct H3.
     destruct H4.
     destruct H5.
     split.
      destruct 1.
        rename x into s1.
	destruct H7.
	rename x into s2.
	destruct H7.
	destruct H8.
	split with s1.
	split with s2.
	assert (Gamma |- subvar a1 rho ; srt t1).
	  apply Weakening with (Delta:=Delta) (rho:=rho) (A:=srt (n:=n) t1); assumption.
	split.
	 assumption.
	split.
	 destruct H8; destruct H8.
	  left.
	    split.
	     apply varlike_subvar.
	       assumption.
	     apply Weakening with (Delta:=Delta) (rho:=rho) (A:=srt (n:=n) s1); assumption.
	  right.
	    split.
	     apply sortlike_subvar.
	       assumption.
	     elim IHa1 with n0 (srt (n:=n) t1) Delta Gamma rho s1; auto.
	 destruct H9; destruct H9.
	  left.
	    split.
	     apply varlike_subvar.
	       assumption.
	     apply Weakening with (n:=S n) (Delta:=(Delta,a1)) (rho:=Sfun rho) (A:=srt (n:=S n) s2).
	      assumption.
	      split with t1.
	        assumption.
	      apply Weak_subctxt.
	        assumption.
          right.
	    split.
	     apply sortlike_subvar.
	       assumption.
	     elim IHa2 with (S n0) (srt (n:=S n) t2) (Delta, a1) (Gamma, subvar a1 rho) (Sfun rho) s2; auto.
	      split with t1.
	        assumption.
              apply Weak_subctxt.
	        assumption.
   destruct 1.
     rename x into s1.
     destruct H7.
     rename x into s2.
     destruct H7.
     destruct H8.
     split with s1.
     split with s2.
     split.
      assumption.
     split.
      destruct H8; destruct H8.
       left.
        split.
	 apply varlike_subvar' with n0 rho.
	   assumption.
	 replace s1 with t1.
	  assumption.
	  apply conv_srt_inj with n0.
	    apply Unique_Type_varlike with (subvar a1 rho) Gamma; try assumption.
	    apply Weakening with (Delta:=Delta) (A:=srt (n:=n) t1) (rho:=rho); assumption.
       right.
        assert (Is_true (sortlike a1)).
	  apply sortlike_subvar' with n0 rho.
	  assumption.
        split.
	 assumption.
	 elim IHa1 with n0 (srt (n:=n) t1) Delta Gamma rho s1; auto.
      destruct H9; destruct H9.
       left.
        split.
	 apply varlike_subvar' with (S n0) (Sfun rho).
	   assumption.
	 replace s2 with t2.
	  assumption.
	  apply conv_srt_inj with (S n0).
	    apply Unique_Type_varlike with (subvar a2 (Sfun rho)) (Gamma, subvar a1 rho); auto.
	    apply Weakening with (n:=S n) (Delta := (Delta, a1)) (A := srt (n:=S n) t2) (rho := Sfun rho).
	     assumption.
	     apply Context_Validity with (subvar a2 (Sfun rho)) (srt (n:=S n0) s2).
	       assumption.
	     apply Weak_subctxt.
	       assumption.
       right.
        assert (Is_true (sortlike a2)).
	  apply sortlike_subvar' with (S n0) (Sfun rho).
	  assumption.
        split.
	 assumption.
	 elim IHa2 with (S n0) (srt (n:=S n) t2) (Delta, a1) (Gamma, subvar a1 rho) (Sfun rho) s2; auto.
	  split with t1.
	    apply Weakening with (Delta:=Delta) (A:=srt (n:=n) t1) (rho:=rho); auto.
	    apply Weak_subctxt.
	    assumption.
   assumption.
(* lda *)
  elim Gen_lda with n Delta a1 a2 A.
   intro B.
     destruct 1.
     rename x into t.
     destruct H3.
     destruct H4.
     apply IHa2 with B; try assumption.
      elim (Context_Validity (S n) (Delta, a1) a2 B).
       intro t'.
	 split with t'.
	 apply Weakening with (Delta:=Delta) (A:=srt (n:=n) t') (rho:=rho); assumption.
       assumption.
      apply Weak_subctxt.
        assumption.
   assumption.
Qed.

Theorem pre_Sigma_typing : forall n (Gamma : context n) a A,
  Gamma |- a ; A ->
  forall m (Delta : string m n) s1 s,
  sortlike a -> red A (Pi Delta (srt s1)) -> Sigma a Gamma s ->
  exists Theta, exists a1 : term m,
  red a (Lda Theta a1) /\ PTS (concat Gamma Theta) a1 (srt s).
Proof.
 induction 1; simpl.
(* axioms *)
  destruct m.
   intro Delta.
     rewrite string_n_n with O Delta.
     intros s1 s' _ H0 H1.
     split with (emp (m:=O)).
     split with (srt (n:=O) s).
     simpl.
     split.
      apply red_ref.
      apply axioms.
        assumption.
   intro Delta.
     rewrite string_m_n with (S m) O Delta (lt_O_Sn m).
     simpl.
     intros s1 s' _ H0.
     elim not_red_srt_pi with O t (head Delta (lt_O_Sn m)) (Pi (tail Delta (lt_O_Sn m)) (srt s1)).
     assumption.
(* start *)
  destruct 1.
(* weak *)
  destruct m.
   intro Delta.
     elim le_Sn_O with n.
     apply string_leq.
     assumption.
   intros Delta s1 s2 H1 H2 H3.
     elim red_subvar_Pi with m (S m) n (S n) (mtch_Sm_Sn' _ _ Delta) B (up (n:=n)) Delta (srt (n := S m) s1).
      intro Delta'.
        destruct 1.
        rename x into C'.
        destruct H4.
        destruct H5.
	assert (Is_true (sortlike A)).
	  apply sortlike_liftterm'.
	  assumption.
        elim IHPTS1 with m Delta' s1 s2.
         intro Theta.
           destruct 1.
	   rename x into a1.
	   destruct H8.
	   split with (liftstring Theta).
	   split with (subvar a1 (subvar_lift (mtch_Sm_Sn _ _ Theta) (up (n:=n)))).
	   unfold liftstring.
	   split.
	    rewrite <- Lda_subvar with m (S m) n (S n) (mtch_Sm_Sn _ _ Theta) Theta a1 (up (n:=n)).
	      apply red_liftterm with (n:=n) (M:=A) (N:=Lda Theta a1).
	      assumption.
	    apply Weakening with (Delta := Gamma @ Theta) (A := srt (n:=m) s2) (rho := subvar_lift (mtch_Sm_Sn _ _ Theta) (up (n:=n))).
	     assumption.
	     apply valid_concat with Gamma.
	       split.
	        apply Context_Validity with a1 (srt (n:=m) s2).
	          assumption.
	        split with s.
	          assumption.
	     apply subctxt_concat.
	       unfold subctxt.
	       reflexivity.
         assumption.
         rewrite <- subvar_srt with m C' (S m) (subvar_lift (mtch_Sm_Sn' _ _ Delta) (up (n:=n))) s1; auto.
	 elim Sigma_ctxt_irrel with n A (S n) B Gamma (Gamma, C) (up (n:=n)) s2; try assumption.
          intros.
            apply H9.
	    assumption.
	  split with s.
            assumption.
          unfold subctxt.
            reflexivity.
      assumption.
(* product *)
  induction Delta.
   intros s4 s _ _.
     clear s4.
     destruct 1.
     rename x into t1.
     destruct H2.
     rename x into t2.
     destruct H2.
     destruct H3.
     split with (emp (m:=m)).
     destruct H3; destruct H3; destruct H4; destruct H4.
      split with (pi A B).
        split.
	 apply red_ref.
	 apply product with t1 t2; assumption.
      elim IHPTS2 with (m0 := S m) (Delta := emp (m:=S m)) (s1 := s2) (s := t2); auto.
        intro Theta.
        rewrite string_n_n with (S m) Theta.
	destruct 1.
	rename x into B1.
	destruct H7.
	split with (pi A B1).
	split.
	 apply red_pir with (A := A) (B' := B1).
	   assumption.
	 apply product with t1 t2; auto.
      elim (IHPTS1 m emp s1 t1); auto.
        intro x.
	rewrite string_n_n with m x.
	clear x.
	simpl.
	destruct 1.
	rename x into A0.
	destruct H7.
	split with (pi A0 B).
	split.
	 apply red_pil.
	   assumption.
	 apply product with t1 t2; try assumption.
	   apply Context_Conversion with (Gamma, A).
	    assumption.
	    apply conv_ctxt_build.
	     apply conv_ctxt_ref.
	     apply conv_red.
	       assumption.
	    split with t1.
	      assumption.
      simpl.
        elim IHPTS1 with m (emp (m:=m)) s1 t1; auto.
	intro x.
	rewrite string_n_n with m x.
	clear x.
	simpl.
	destruct 1.
	rename x into A0.
	destruct H7.
	elim IHPTS2 with (S m) (emp (m:=S m)) s2 t2; auto.
	intro x.
	rewrite string_n_n with (S m) x.
	clear x.
	simpl.
	destruct 1.
	rename x into B0.
	destruct H9.
	split with (pi A0 B0).
	split.
	 apply red_pi; assumption.
	 apply product with t1 t2; try assumption.
	  apply Context_Conversion with (Gamma, A).
	   assumption.
	   apply conv_ctxt_build.
	    apply conv_ctxt_ref.
	    apply conv_red.
	      assumption.
	   split with t1.
	     assumption.
(* abstraction *)
  intros s4 s _ H2.
    simpl in H2.
    elim not_red_srt_pi with n s3 t (Pi Delta (srt s4)).
    assumption.
(* application *)
  intros.
    elim Typing_Lemma_sortlike with n Gamma F (pi A B); try assumption.
    intro p.
    case (lt_eq_lt_dec p n).
    destruct 1.
     destruct 1.
       elim le_not_lt with n p.
        apply string_leq.
          assumption.
	assumption.
     rewrite e.
       clear p e.
       destruct 1.
       rewrite string_n_n with n x in H4.
       clear x.
       destruct H4.
       rename x into s'.
       elim not_red_pi_srt with n A B s'.
       assumption.
     case p.
      intro.
        elim lt_n_O with n.
	assumption.
      clear p.
        intros p n_lt_Sp.
	destruct 1.
	rename x into Theta.
	destruct H4.
	rename x into s1'.
	rewrite string_m_n with (S p) n Theta n_lt_Sp in H4.
	simpl in H4.
	assert (m = p).
	  apply conv_Pi_srt with n Delta (subbot_string (tail Theta n_lt_Sp) a) s1 s1'.
	  apply conv_trans with (subbot B a).
	   apply conv_sym.
	     apply conv_red.
	     assumption.
	   apply conv_red.
	     change (srt (n:=p) s1') with (subst (srt (n:=S p) s1') (subst_lift (mtch_Sm_Sn_inv _ _ (tail Theta n_lt_Sp))
	       (botsub a))).
	     unfold subbot_string.
	     rewrite <- Pi_subst.
	     unfold subbot.
	     apply red_substl.
	     apply red_pi_injr with A (head Theta n_lt_Sp).
	     assumption.
        generalize H2.
	clear H2.
	generalize Delta.
	clear Delta.
	rewrite H5.
	clear m H5.
	intros.
	elim IHPTS1 with (S p) Theta s1' s; try assumption.
         intro Phi.
	   destruct 1.
	   rename x into a1.
 	   destruct H5.
	   split with (subbot_string (tail Phi n_lt_Sp) a).
	   split with (subst a1 (subst_lift (mtch_Sm_Sn_inv _ _ (tail Phi n_lt_Sp)) (botsub a))).
	   split.
	    unfold subbot_string.
	      rewrite <- Lda_subst.
	      apply red_trans with (app (Lda Phi a1) a).
	       apply red_appl.
	         assumption.
	       rewrite string_m_n with (S p) n Phi n_lt_Sp.
	         simpl.
	         apply red_beta with (n:=n) (A:=head Phi n_lt_Sp) (M:=Lda (tail Phi n_lt_Sp) a1) (N:=a).
	    change (srt (n:=p) s) with (subst (srt s) (subst_lift (mtch_Sm_Sn_inv _ _ (tail Phi n_lt_Sp)) (botsub a))).
	      elim Gen_lda' with n Gamma (head Phi n_lt_Sp) (Lda (tail Phi n_lt_Sp) a1) (pi A B); auto.
               intro C.
	         destruct 1.
		 rename x into t1.
		 destruct H7.
		 rename x into t2.
		 destruct H7.
		 rename x into t3.
		 destruct H7.
		 destruct H8.
		 destruct H9.
		 destruct H10.
		 assert (Gamma |= botsub a ; (Gamma, head Phi n_lt_Sp)).
		   apply satisfy_botsub.
		   apply conversion with A t1; try assumption.
		   apply conv_pi_injl with B C.
		   assumption.
		 assert (valid (((Gamma, head Phi n_lt_Sp) : context (S n)) @ tail Phi n_lt_Sp)).
		   rewrite string_m_n with (S p) n Phi n_lt_Sp in H6.
		   apply Context_Validity with a1 (srt (n:=S p) s).
		   assumption.
		 assert (valid Gamma).
		   apply Context_Validity with a A.
		   assumption.
                 apply Substitution with (concat Gamma Phi); auto.
		  unfold subbot_string.
		    apply valid_concat' with (Gamma, head Phi n_lt_Sp); assumption.
		  unfold subbot_string.
		    rewrite string_m_n with (S p) n Phi n_lt_Sp.
		    simpl.
		    apply satisfy_concat; assumption.
               rewrite string_m_n with (S p) n Phi n_lt_Sp in H5.
	         simpl in H5.
		 apply Subject_Reduction with F; assumption.
         rewrite string_m_n with (S p) n Theta n_lt_Sp.
	   exact H4.
(* abstraction *)
  intro m.
    case (lt_eq_lt_dec m n).
    destruct 1.
     intro Delta.
       elim lt_not_le with m n.
        assumption.
	apply string_leq.
	  assumption.
     rewrite e.
       clear m e.
       intro Delta.
       rewrite string_n_n with n Delta.
       clear Delta.
       simpl.
       intros s4 s H3 H4.
       elim not_red_pi_srt with n A B s4.
       assumption.
     intros.
       rewrite string_m_n with m n Delta l in H4.
       simpl in H4.
       elim IHPTS1 with m (tail Delta l) s0 s; try assumption.
        intro Theta.
          destruct 1.
	  rename x into b1.
	  destruct H6.
	  split with (cons A Theta).
	  split with b1.
	  simpl.
	  split.
           apply red_ldar.
	     assumption.
	   assumption.
	apply red_pi_injr with A (head Delta l).
	  assumption.
(* conversion *)
  intros.
    elim Church_Rosser with n B (Pi Delta (srt s1)).
     intro B0.
       destruct 1.
       elim red_Pi_inv with m n Delta (srt (n:=m) s1) B0.
        intro Delta0.
          destruct 1.
	  rename x into C.
	  destruct H7.
	  destruct H8.
	  apply IHPTS1 with Delta0 s1; try assumption.
	  rewrite <- Gen_red_srt with m s1 C.
	   rewrite <- H9.
	     assumption.
	   assumption.
	assumption.
     apply conv_trans with B'.
      assumption.
      apply conv_red.
        assumption.
Qed.

Theorem Sigma_typing : forall n (Gamma : context n) A s1 s2,
  sortlike A -> Gamma |- A ; srt s1 -> Sigma A Gamma s2 ->
  exists A', A ->> A' /\ Gamma |- A' ; srt s2.
Proof.
 intros.
 elim pre_Sigma_typing with n Gamma A (srt (n:=n) s1) n (emp (m:=n)) s1 s2; auto.
 intro Delta.
 rewrite string_n_n with n Delta.
 trivial.
Qed.

Lemma pre_Sigma_gen : forall n (Gamma : context n) M A, Gamma |- M ; A ->
  forall m (Theta : string m n) s, sortlike M -> A ->> Pi Theta (srt s) ->
  Sigma M Gamma s.
Proof.
 induction 1; simpl.
(* axioms *)
  destruct m; intro Theta.
   rewrite string_n_n with O Theta.
     intros s' _ H0.
     rewrite srt_inj with O s' t.
      assumption.
      apply Gen_red_srt.
        assumption.
   rewrite string_m_n with (S m) O Theta (lt_O_Sn m).
     simpl.
     intros s' _ H0.
     elim not_red_srt_pi with O t (head Theta (lt_O_Sn m)) (Pi (tail Theta (lt_O_Sn m)) (srt s')).
     assumption.
(* start *)
  destruct 1.
(* weakening *)
  destruct m.
   intro Theta.
     elim lt_not_le with O (S n).
      apply lt_O_Sn.
      apply string_leq.
        assumption.
   intros Theta s' H1 H2.
     assert (Is_true (sortlike A)).
       apply sortlike_liftterm'.
       assumption.
     elim Sigma_ctxt_irrel with n A (S n) B Gamma (Gamma, C) (up (n:=n)) s'; try assumption.
      intros.
        apply H4.
	unfold liftterm in H3.
	elim red_subvar_Pi with m (S m) n (S n) (mtch_Sm_Sn' _ _ Theta) B (up (n:=n)) Theta (srt (n:=S m) s').
	 intro Theta0.
	   destruct 1.
	   rename x into M.
	   destruct H6.
	   destruct H7.
	   apply IHPTS1 with m Theta0.
	    assumption.
	    rewrite <- subvar_srt with m M (S m) (subvar_lift (mtch_Sm_Sn' m n Theta) (up (n:=n))) s'.
	     assumption.
	     symmetry.
	       assumption.
	 assumption.
      split with s.
        assumption.
      apply Weak_subctxtr with (rho := id (fin n)).
        apply Triv_subctxt.
(* product *)
  intro m.
    case (lt_eq_lt_dec m n).
    destruct 1.
     intro Theta.
       elim lt_not_le with m n.
        assumption.
        apply string_leq.
          assumption.
     rewrite e.
       clear m e.
       intro Theta.
       rewrite string_n_n with n Theta.
       clear Theta.
       simpl.
       intros s _ H2.
       rewrite <- red_srt_inj with n s3 s.
        clear s H2.
	  split with s1.
	  split with s2.
	  split.
	   assumption.
	  split.
	   elim var_or_sort with n A.
	    auto.
	    right.
	      split.
	       assumption.
	       apply IHPTS1 with n (emp (m:=n)); auto.
	   elim var_or_sort with (S n) B.
	    auto.
	    right.
	      split.
	       assumption.
	       apply IHPTS2 with (S n) (emp (m:=S n)); auto.
        assumption.
     intros n_lt_m Theta.
       rewrite string_m_n with m n Theta n_lt_m.
       simpl.
       intros s _ H2.
       elim not_red_srt_pi with n s3 (head Theta n_lt_m) (Pi (tail Theta n_lt_m) (srt s)).
       assumption.
(* application *)
  intros.
    elim Typing_Lemma_sortlike with n Gamma F (pi A B); try assumption.
    destruct x.
     destruct 1.
       rename x into Phi.
       case (lt_eq_lt_dec O n).
       destruct 1.
	elim lt_not_le with O n.
	 assumption.
	 apply string_leq.
	   assumption.
	generalize H3.
	  generalize B.
	  generalize A.
	  generalize Phi.
	  rewrite e.
	  intro Phi'.
	  rewrite string_n_n with n Phi'.
	  destruct 1.
	  elim not_red_pi_srt with n A0 B0 x.
	  assumption.
	intro.
	  elim lt_n_O with n.
	  assumption.
    rename x into p.
      destruct 1.
      rename x into Delta.
      destruct H3.
      rename x into t.
      elim (lt_eq_lt_dec (S p) n).
      destruct 1.
       elim lt_not_le with (S p) n.
        assumption.
	apply string_leq.
	  assumption.
       generalize H3.
	 generalize B.
	 generalize A.
	 generalize Delta.
	 rewrite e.
	 intro Delta'.
	 rewrite string_n_n with n Delta'.
	 intros.
	 elim not_red_pi_srt with n A0 B0 t.
	 assumption.
       intro n_lt_Sp.
	 apply IHPTS1 with (S p) Delta.
	  assumption.
	  rewrite conv_Pi_srt' with m n Theta p (subbot_string (tail Delta n_lt_Sp) a) s t.
	   assumption.
	   apply conv_trans with (subbot B a).
	    apply conv_red'.
	      assumption.
	    apply conv_red.
	      rewrite <- Pi_subbot_srt.
	      apply red_subbotl.
	      rewrite string_m_n with (S p) n Delta n_lt_Sp in H3.
	      apply red_pi_injr with A (head Delta n_lt_Sp).
	      assumption.
(* abstraction *)
  intro m.
    case (lt_eq_lt_dec m n).
    destruct 1.
     intro Theta.
       elim (lt_not_le m n).
        assumption.
	apply string_leq.
          assumption.
     rewrite e.
       clear m e.
       intro Theta.
       rewrite string_n_n with n Theta.
       clear Theta.
       intros.
       elim not_red_pi_srt with n A B s.
       assumption.
     intros n_lt_m Theta.
       rewrite string_m_n with m n Theta n_lt_m.
       intros.
       apply IHPTS1 with m (tail Theta n_lt_m).
        assumption.
	apply red_pi_injr with A (head Theta n_lt_m).
	  assumption.
(* conversion *)
  intros.
    elim Church_Rosser with n B (Pi Theta (srt s0)).
     intro B0.
       destruct 1.
       elim red_Pi_inv with m n Theta (srt (n:=m) s0) B0.
        intro Theta0.
          destruct 1.
	  rename x into A'.
	  destruct H6.
	  destruct H7.
	  apply IHPTS1 with m Theta0; try assumption.
	  rewrite H8 in H4.
	  rewrite <- Gen_red_srt with m s0 A'; assumption.
	assumption.
     apply conv_trans with B'.
      assumption.
      apply conv_red.
        assumption.
Qed.

Theorem Sigma_gen : forall n (Gamma : context n) a s,
  sortlike a -> Gamma |- a ; srt s -> Sigma a Gamma s.
Proof.
  intros.
  apply pre_Sigma_gen with (srt (n := n) s) n (emp (m:=n)); auto.
Qed.

Lemma pre_Strengthening : forall n b (Gamma : context n) B,
  Gamma |- b ; B ->
  forall m (Delta : context m) rho b0,
  valid Delta ->
  injective rho ->
  subctxt Delta Gamma rho ->
  b = subvar b0 rho ->
  exists B', B ->> subvar B' rho /\ Delta |- b0 ; B'.
Proof.
  induction b; intros.
(* var *)
   elim subvar_var with m b0 n rho f.
    intro x.
      destruct 1.
      rewrite H4.
      clear b0 H3 H4.
      rewrite H5 in H.
      clear f H5.
      assert (typeof (rho x) Gamma ~= B).
        apply Gen_var.
        assumption.
      elim Church_Rosser with n (typeof (rho x) Gamma) B.
       intro B'.
         destruct 1.
	 rewrite H2 in H4.
	 elim red_subvar_inv with m n (typeof x Delta) rho B'.
	  intro B1.
	    destruct 1.
	    rewrite H7 in H5.
	    clear H7.
	    split with B1.
	    split.
	     assumption.
	     apply Predicate_Reduction with (typeof x Delta).
	      apply Start_var.
	        assumption.
	      assumption.
	  assumption.
       assumption.
    symmetry.
      assumption.
(* srt *)
   rewrite subvar_srt with m b0 n rho s.
    elim Gen_srt with n Gamma s B.
     intro t.
       destruct 1.
       split with (srt (n:=m) t); simpl.
       split.
        assumption.
	apply Start_ax; assumption.
     assumption.
    symmetry.
      assumption.
(* app *)
   elim subvar_app with m b0 n rho b1 b2; auto.
   clear H3.
   intro M.
   destruct 1.
   rename x into N.
   destruct H3.
   destruct H4.
   rewrite H3.
   clear b0 H3.
   elim Gen_app with n Gamma b1 b2 B; auto.
   intro A.
   destruct 1.
   rename x into C.
   destruct H3.
   destruct H6.
   elim IHb1 with Gamma (pi A C) m Delta rho M; auto.
   intro X.
   destruct 1.
   elim IHb2 with Gamma A m Delta rho N; auto.
   intro A'.
   destruct 1.
   elim Gen_red_pi with n A C (subvar X rho); auto.
   intro A0.
   destruct 1.
   rename x into C0.
   destruct H12.
   destruct H13.
   elim subvar_pi with m X n rho A0 C0; auto.
   intro A1.
   destruct 1.
   rename x into B1.
   destruct H15.
   destruct H16.
   assert (A1 ~= A').
     apply conv_subvar_inj with n rho.
      assumption.
      apply conv_trans with A.
       apply conv_red'.
         rewrite H16.
	 assumption.
       apply conv_red.
         assumption.
   elim Church_Rosser with m A1 A'; auto.
   intro A00.
   destruct 1.
   assert (Delta |- app M N ; subbot B1 N).
     apply application with A00.
      apply Predicate_Reduction with X.
       assumption.
       rewrite H15.
         apply red_pil.
	 assumption.
      apply Predicate_Reduction with A'; assumption.
   elim Church_Rosser with n (subvar (subbot B1 N) rho) B.
    intro Y.
      destruct 1.
      elim red_subvar_inv with m n (subbot B1 N) rho Y; auto.
      intro B'.
      destruct 1.
      split with B'.
      split.
       rewrite <- H25.
         assumption.
       apply Predicate_Reduction with (subbot B1 N); assumption.
    rewrite subvar_subbot.
      rewrite H17.
      rewrite H5.
      apply conv_trans with (subbot C b2).
       apply conv_subbotl.
         apply conv_red'.
	 assumption.
       apply conv_sym.
         assumption.
(* pi *)
   elim Gen_pi with n Gamma b1 b2 B; auto.
   intro s1.
   destruct 1.
   rename x into s2.
   destruct H4.
   rename x into s3.
   destruct H4.
   destruct H5.
   destruct H6.
   split with (srt (n:=m) s3).
   split; auto.
   elim subvar_pi with m b0 n rho b1 b2; auto.
   intro A.
   destruct 1.
   rename x into C.
   destruct H8.
   destruct H9.
   rewrite H8.
   clear b0 H8 H3.
   elim IHb1 with Gamma (srt (n:=n) s1) m Delta rho A; auto.
   intro X.
   destruct 1.
   replace X with (srt (n:=m) s1) in H8.
    elim IHb2 with (Gamma, b1) (srt (n:=S n) s2) (S m) (Delta, A) (Sfun rho) C; auto.
     intro Y.
       destruct 1.
       replace Y with (srt (n:=S m) s2) in H12.
        apply product with s1 s2; assumption.
        symmetry.
	  apply subvar_srt with (S n) (Sfun rho).
	  apply Gen_red_srt.
	  assumption.
     split with s1.
       assumption.
     apply Sfun_inj.
       assumption.
     rewrite <- H9.
       apply Weak_subctxt.
       assumption.
    symmetry.
      apply subvar_srt with n rho.
      apply Gen_red_srt.
      assumption.
(* lda *)
   rename b1 into B'.
   rename b2 into c.
   rename b0 into L.
   rename B into P.
   elim Gen_lda' with n Gamma B' c P; auto.
   intro C.
   destruct 1.
   rename x into s1.
   destruct H4.
   rename x into s2.
   destruct H4.
   rename x into s3.
   destruct H4.
   destruct H5.
   destruct H6.
   destruct H7.
   elim Gen_conv_pi with n B' C P; try (apply conv_sym; assumption).
   intro B'0.
   destruct 1.
   rename x into C0.
   destruct H9.
   destruct H10.
   elim subvar_lda with m L n rho B' c; auto.
   intro B'low.
   destruct 1.
   rename x into clow.
   destruct H12.
   destruct H13.
   elim IHb1 with Gamma (srt (n:=n) s1) m Delta rho B'low; auto.
   intro s1low.
   destruct 1.
   rewrite subvar_srt with m s1low n rho s1 in H16.
    clear H15 s1low.
      elim IHb2 with (Gamma, B') C0 (S m) (Delta, B'low) (Sfun rho) clow; auto.
       intro C'low.
         destruct 1.
	 elim red_subvar_inv with m n B'low rho B'0.
	  intro B'0low.
	    destruct 1.
	    elim Type_Validity with (S m) (Delta, B'low) clow C'low; auto; destruct 1.
	    (* Case One: C'low is a sort *)
	     rename x into s2'.
	     rewrite H20 in H15.
	     split with (pi B'0low (srt s2')).
	     split.
	      apply red_trans with (pi B'0 C0).
	       assumption.
	       rewrite H19.
	         simpl.
		 apply red_pir.
		 assumption.
	      rewrite H12.
	        apply Predicate_Reduction with (pi B'low (srt s2')).
		 apply abstraction with s1 s2 s3; auto.
		  rewrite <- H20.
		    assumption.
		  apply Start_ax.
		   apply Gen_srt' with (S n) (Gamma, B').
		     apply Subject_Reduction with C.
		      assumption.
		      apply red_trans with C0; assumption.
		 split with s1.
		   assumption.
		 apply red_pil.
		   assumption.
	   (* Case two : C'low : s2 *)
           rename x into s2'.
	   elim var_or_sort with (S m) C'low.
	   (* Case 2.1 : C'low is varlike *)
	    split with (pi B'0low C'low).
	    split.
	     apply red_trans with (pi B'0 C0).
	      assumption.
	      rewrite H19.
	        simpl.
	        apply red_pir.
	        assumption.
	     rewrite H12.
	       apply Predicate_Reduction with (pi B'low C'low).
	        apply abstraction with s1 s2 s3; auto.
		  replace s2 with s2'.
		   assumption.
		   apply conv_srt_inj with (S n).
		     apply Unique_Type_varlike with (subvar C'low (Sfun rho)) (Gamma, B').
		      apply varlike_subvar.
		        assumption.
		      apply Weakening with (n:=S m) (Delta:=(Delta, B'low)) (M:=C'low) (A:=srt (n:=S m) s2') (m:=S n) (Gamma:=(Gamma,B')) (rho:=Sfun rho); auto.
		       apply Context_Validity with c C.
		         assumption.
		       rewrite <- H13.
		         apply Weak_subctxt.
			 assumption.
		      apply Subject_Reduction with C.
		       assumption.
		       apply red_trans with C0; auto.
	        apply red_pil.
		  assumption.
	   (* Case 2.2 : C'low is sortlike *)
            intro.
	    elim Sigma_typing with (S m) (Delta, B'low) C'low s2' s2; auto.
	     intro C''low.
	       destruct 1.
	       split with (pi B'0low C''low).
	       split.
	        apply red_trans with (pi B'0 C0).
		 assumption.
		 simpl.
	           rewrite H19.
		   apply red_pir.
		   apply red_trans with (subvar C'low (Sfun rho)).
		    assumption.
		    apply red_subvar.
		      assumption.
		rewrite H12.
		  apply Predicate_Reduction with (pi B'low C''low).
		   apply abstraction with s1 s2 s3; auto.
		     apply Predicate_Reduction with C'low; auto.
		   apply red_pil.
		     assumption.
	     elim Sigma_ctxt_irrel with (S m) C'low (S n) (srt (n:=S m) s2') (Delta, B'low) (Gamma, B') (Sfun rho) s2; auto.
	      intros.
	        apply H23.
		apply Sigma_gen.
	         apply sortlike_subvar.
		   assumption.
		 apply Subject_Reduction with C; auto.
		   apply red_trans with C0; auto.
	      split with s1.
	        assumption.
              rewrite <- H13.
	        apply Weak_subctxt.
		assumption.
	  rewrite H13.
	    assumption.
      apply Predicate_Reduction with C; auto.
      split with s1.
        assumption.
      apply Sfun_inj.
        assumption.
      rewrite <- H13.
        apply Weak_subctxt.
	assumption.
    apply Gen_red_srt.
      assumption.
Qed.

Theorem Strengthening : forall m n Delta Gamma M A (rho : fin m -> fin n),
  Gamma |- subvar M rho ; subvar A rho ->
  subctxt Delta Gamma rho ->
  injective rho ->
  valid Delta ->
  Delta |- M ; A.
Proof.
  intros.
  elim pre_Strengthening with n (subvar M rho) Gamma (subvar A rho) m Delta rho M; auto.
  intro A'.
  destruct 1.
  elim Type_Validity with n Gamma (subvar M rho) (subvar A rho); auto; destruct 1; rename x into s.
  (* Case One - A is a sort *)
   replace A with (srt (n:=m) s).
    replace A' with (srt (n:=m) s) in H4.
     assumption.
     symmetry.
       apply subvar_srt with n rho.
       apply Gen_red_srt.
       rewrite <- H5.
       assumption.
    symmetry.
      apply subvar_srt with n rho.
      assumption.
  (* Case Two - A : s *)
   elim pre_Strengthening with n (subvar A rho) Gamma (srt (n:=n) s) m Delta rho A; auto.
     intro X.
     destruct 1.
     apply conversion with A' s; auto.
      apply conv_red'.
        apply red_subvar_inj with n rho; assumption.
      replace (srt (n:=m) s) with X.
       assumption.
       apply subvar_srt with n rho.
         apply Gen_red_srt.
	 assumption.
Qed.


Require Export GeoCoq.Elements.OriginalProofs.proposition_23C.

Section Euclid.

Context `{Ax:euclidean_neutral_ruler_compass}.

Lemma lemma_angletrichotomy2 :
   forall A B C D E F,
   nCol A B C -> nCol D E F -> ~ CongA A B C D E F -> ~ LtA D E F A B C ->
   LtA A B C D E F.
Proof.
intros.
assert (~ eq B A).
 {
 intro.
 assert (eq A B) by (conclude lemma_equalitysymmetric).
 assert (Col A B C) by (conclude_def Col ).
 contradict.
 }
assert (~ eq B C).
 {
 intro.
 assert (Col A B C) by (conclude_def Col ).
 contradict.
 }
assert (~ Col B A C).
 {
 intro.
 assert (Col A B C) by (forward_using lemma_collinearorder).
 contradict.
 }
let Tf:=fresh in
assert (Tf:exists G J, (Out B A J /\ CongA G B J D E F /\ OS G C B A)) by (conclude proposition_23C);destruct Tf as [G[J]];spliter.
assert (nCol B A G) by (conclude_def OS ).
assert (~ eq B G).
 {
 intro.
 assert (Col B A G) by (conclude_def Col ).
 contradict.
 }
assert (~ eq A G).
 {
 intro.
 assert (Col B A G) by (conclude_def Col ).
 contradict.
 }
assert (CongA D E F G B J) by (conclude lemma_equalanglessymmetric).
assert (Out B J A) by (conclude lemma_ray5).
assert (eq G G) by (conclude cn_equalityreflexive).
assert (Out B G G) by (conclude lemma_ray4).
assert (CongA D E F G B A) by (conclude lemma_equalangleshelper).
assert (nCol G B A) by (conclude lemma_equalanglesNC).
assert (~ Col A B G).
 {
 intro.
 assert (Col B A G) by (forward_using lemma_collinearorder).
 contradict.
 }
assert (CongA G B A D E F) by (conclude lemma_equalanglessymmetric).
assert (CongA A B G G B A) by (conclude lemma_ABCequalsCBA).
assert (CongA A B G D E F) by (conclude lemma_equalanglestransitive).
assert (~ Col A B G).
 {
 intro.
 assert (Col G B A) by (forward_using lemma_collinearorder).
 contradict.
 }
assert (~ eq G A).
 {
 intro.
 assert (eq A G) by (conclude lemma_equalitysymmetric).
 assert (Col A B G) by (conclude_def Col ).
 contradict.
 }
let Tf:=fresh in
assert (Tf:exists P, (BetS G A P /\ Cong A P G A)) by (conclude lemma_extension);destruct Tf as [P];spliter.
assert (eq A A) by (conclude cn_equalityreflexive).
assert (Col B A A) by (conclude_def Col ).
assert (~ Col B A G).
 {
 intro.
 assert (Col G B A) by (forward_using lemma_collinearorder).
 contradict.
 }
assert (OS C G B A) by (forward_using lemma_samesidesymmetric).
assert (TS G B A P) by (conclude_def TS ).
assert (TS C B A P) by (conclude lemma_planeseparation).
let Tf:=fresh in
assert (Tf:exists R, (BetS C R P /\ Col B A R /\ nCol B A C)) by (conclude_def TS );destruct Tf as [R];spliter.
assert (BetS P R C) by (conclude axiom_betweennesssymmetry).
assert (LtA A B C D E F).
by cases on (TS G B C A \/ ~ TS G B C A).
{
 rename_H H;let Tf:=fresh in
 assert (Tf:exists H, (BetS G H A /\ Col B C H /\ nCol B C G)) by (conclude_def TS );destruct Tf as [H];spliter.
 assert (BetS A H G) by (conclude axiom_betweennesssymmetry).
 assert (Out B A A) by (conclude lemma_ray4).
 assert (~ Col A B H).
  {
  intro.
  assert (~ eq B H).
   {
   intro.
   assert (BetS A B G) by (conclude cn_equalitysub).
   assert (Col A B G) by (conclude_def Col ).
   assert (Col G B A) by (forward_using lemma_collinearorder).
   contradict.
   }
  assert (neq H B) by (conclude lemma_inequalitysymmetric).
  assert (Col H B A) by (forward_using lemma_collinearorder).
  assert (Col H B C) by (forward_using lemma_collinearorder).
  assert (Col B A C) by (conclude lemma_collinear4).
  assert (Col A B C) by (forward_using lemma_collinearorder).
  contradict.
  }
 assert (CongA A B H A B H) by (conclude lemma_equalanglesreflexive).
 assert (LtA A B H A B G) by (conclude_def LtA ).
 assert (CongA G B A A B G) by (conclude lemma_ABCequalsCBA).
 assert (LtA A B H G B A) by (conclude lemma_angleorderrespectscongruence).
 assert (~ Col H B A).
  {
  intro.
  assert (Col A B H) by (forward_using lemma_collinearorder).
  contradict.
  }
 assert (CongA H B A A B H) by (conclude lemma_ABCequalsCBA).
 assert (LtA H B A G B A) by (conclude lemma_angleorderrespectscongruence2).
 assert (LtA H B A D E F) by (conclude lemma_angleorderrespectscongruence).
 assert (CongA A B H H B A) by (conclude lemma_ABCequalsCBA).
 assert (LtA A B H D E F) by (conclude lemma_angleorderrespectscongruence2).
 assert (Out B A A) by (conclude lemma_ray4).
 assert (OS C G B A) by (forward_using lemma_samesidesymmetric).
 assert (Out A G H) by (conclude lemma_ray4).
 assert (eq A A) by (conclude cn_equalityreflexive).
 assert (Col B A A) by (conclude_def Col ).
 assert (OS C H B A) by (conclude lemma_sameside2).
 assert (~ BetS C B H).
  {
  intro.
  assert (eq B B) by (conclude cn_equalityreflexive).
  assert (Col B A B) by (conclude_def Col ).
  assert (TS C B A H) by (conclude_def TS ).
  assert (TS H B A C) by (conclude lemma_oppositesidesymmetric).
  assert (TS C B A C) by (conclude lemma_planeseparation).
  let Tf:=fresh in
  assert (Tf:exists M, (BetS C M C /\ Col B A M /\ nCol B A C)) by (conclude_def TS );destruct Tf as [M];spliter.
  assert (~ BetS C M C) by (conclude axiom_betweennessidentity).
  contradict.
  }
 assert ((eq B C \/ eq B H \/ eq C H \/ BetS C B H \/ BetS B C H \/ BetS B H C)) by (conclude_def Col ).
 assert (Out B C H).
 by cases on (eq B C \/ eq B H \/ eq C H \/ BetS C B H \/ BetS B C H \/ BetS B H C).
 {
  assert (Col A B C) by (conclude_def Col ).
  assert (~ ~ Out B C H).
   {
   intro.
   contradict.
   }
  close.
  }
 {
  assert (Col B H A) by (conclude_def Col ).
  assert (~ ~ Out B C H).
   {
   intro.
   assert (~ Col B H A).
    {
    intro.
    assert (Col H B A) by (forward_using lemma_collinearorder).
    contradict.
    }
   contradict.
   }
  close.
  }
 {
  assert (eq H H) by (conclude cn_equalityreflexive).
  assert (Out B C H).
  by cases on (eq B H \/ neq B H).
  {
   assert (Col B H A) by (conclude_def Col ).
   assert (~ ~ Out B C H).
    {
    intro.
    assert (~ Col B H A).
     {
     intro.
     assert (Col H B A) by (forward_using lemma_collinearorder).
     contradict.
     }
    contradict.
    }
   close.
   }
  {
   assert (Out B H H) by (conclude lemma_ray4).
   assert (Out B C H) by (conclude cn_equalitysub).
   close.
   }
(** cases *)
  close.
  }
 {
  assert (~ ~ Out B C H).
   {
   intro.
   contradict.
   }
  close.
  }
 {
  assert (neq B C) by (forward_using lemma_betweennotequal).
  assert (Out B C H) by (conclude lemma_ray4).
  close.
  }
 {
  assert (neq B C) by (forward_using lemma_betweennotequal).
  assert (Out B C H) by (conclude lemma_ray4).
  close.
  }
(** cases *)
 assert (CongA A B C A B C) by (conclude lemma_equalanglesreflexive).
 assert (CongA A B C A B H) by (conclude lemma_equalangleshelper).
 assert (LtA A B C D E F) by (conclude lemma_angleorderrespectscongruence2).
 close.
 }
{
 assert ((eq B A \/ eq B R \/ eq A R \/ BetS A B R \/ BetS B A R \/ BetS B R A)) by (conclude_def Col ).
 assert (LtA A B C D E F).
 by cases on (eq B A \/ eq B R \/ eq A R \/ BetS A B R \/ BetS B A R \/ BetS B R A).
 {
  assert (~ ~ LtA A B C D E F).
   {
   intro.
   contradict.
   }
  close.
  }
 {
  assert (eq R B) by (conclude lemma_equalitysymmetric).
  assert (BetS C R P) by (conclude axiom_betweennesssymmetry).
  assert (~ Col C P G).
   {
   intro.
   assert (Col C R P) by (conclude_def Col ).
   assert (Col C B P) by (conclude cn_equalitysub).
   assert (Col G A P) by (conclude_def Col ).
   assert (Col G P A) by (forward_using lemma_collinearorder).
   assert (Col G P C) by (forward_using lemma_collinearorder).
   assert (neq G P) by (forward_using lemma_betweennotequal).
   assert (Col P C A) by (conclude lemma_collinear4).
   assert (Col P C B) by (forward_using lemma_collinearorder).
   assert (neq C P) by (forward_using lemma_betweennotequal).
   assert (neq P C) by (conclude lemma_inequalitysymmetric).
   assert (Col C A B) by (conclude lemma_collinear4).
   assert (Col A B C) by (forward_using lemma_collinearorder).
   contradict.
   }
  let Tf:=fresh in
  assert (Tf:exists Q, (BetS C Q A /\ BetS G Q R)) by (conclude postulate_Pasch_inner);destruct Tf as [Q];spliter.
  assert (BetS G Q B) by (conclude cn_equalitysub).
  assert (BetS B Q G) by (conclude axiom_betweennesssymmetry).
  assert (neq B Q) by (forward_using lemma_betweennotequal).
  assert (neq B G) by (forward_using lemma_betweennotequal).
  assert (Out B Q G) by (conclude lemma_ray4).
  assert (Out B G Q) by (conclude lemma_ray5).
  assert (eq Q Q) by (conclude cn_equalityreflexive).
  assert (eq A A) by (conclude cn_equalityreflexive).
  assert (eq C C) by (conclude cn_equalityreflexive).
  assert (Out B A A) by (conclude lemma_ray4).
  assert (Out B C C) by (conclude lemma_ray4).
  assert (Out B G G) by (conclude lemma_ray4).
  assert (Out B Q Q) by (conclude lemma_ray4).
  assert (Cong A Q A Q) by (conclude cn_congruencereflexive).
  assert (Cong B Q B Q) by (conclude cn_congruencereflexive).
  assert (Cong B A B A) by (conclude cn_congruencereflexive).
  assert (CongA A B G A B Q) by (conclude_def CongA ).
  assert (BetS A Q C) by (conclude axiom_betweennesssymmetry).
  assert (LtA A B G A B C) by (conclude_def LtA ).
  assert (CongA D E F A B G) by (conclude lemma_equalanglessymmetric).
  assert (LtA D E F A B C) by (conclude lemma_angleorderrespectscongruence2).
  assert (~ ~ LtA A B C D E F).
   {
   intro.
   contradict.
   }
  close.
  }
 {
  assert (~ ~ LtA A B C D E F).
   {
   intro.
   assert (BetS P A G) by (conclude axiom_betweennesssymmetry).
   assert (BetS P A C) by (conclude cn_equalitysub).
   assert (eq G G) by (conclude cn_equalityreflexive).
   assert (Out B G G) by (conclude lemma_ray4).
   assert (eq A A) by (conclude cn_equalityreflexive).
   assert (Out B A A) by (conclude lemma_ray4).
   assert (eq C C) by (conclude cn_equalityreflexive).
   assert (Out B C C) by (conclude lemma_ray4).
   assert (CongA D E F A B G) by (conclude lemma_equalanglessymmetric).
   assert (~ BetS A G C).
    {
    intro.
    assert (CongA A B G A B G) by (conclude lemma_equalanglesreflexive).
    assert (LtA A B G A B C) by (conclude_def LtA ).
    assert (LtA D E F A B C) by (conclude lemma_angleorderrespectscongruence2).
    contradict.
    }
   assert (~ BetS A C G).
    {
    intro.
    assert (CongA A B C A B C) by (conclude lemma_equalanglesreflexive).
    assert (LtA A B C A B G) by (conclude_def LtA ).
    assert (LtA A B C D E F) by (conclude lemma_angleorderrespectscongruence).
    contradict.
    }
   assert (eq C G) by (conclude lemma_outerconnectivity).
   assert (CongA A B C A B C) by (conclude lemma_equalanglesreflexive).
   assert (CongA A B G A B C) by (conclude cn_equalitysub).
   assert (CongA A B C A B G) by (conclude lemma_equalanglessymmetric).
   assert (CongA A B C D E F) by (conclude lemma_equalanglestransitive).
   contradict.
   }
  close.
  }
 {
  assert (BetS R B A) by (conclude axiom_betweennesssymmetry).
  assert (BetS A B R) by (conclude axiom_betweennesssymmetry).
  assert (~ Col C P A).
   {
   intro.
   assert (Col C R P) by (conclude_def Col ).
   assert (Col C P R) by (forward_using lemma_collinearorder).
   assert (neq C P) by (forward_using lemma_betweennotequal).
   assert (Col P A R) by (conclude lemma_collinear4).
   assert (Col R B A) by (conclude_def Col ).
   assert (Col R A B) by (forward_using lemma_collinearorder).
   assert (Col R A P) by (forward_using lemma_collinearorder).
   assert (neq R A) by (forward_using lemma_betweennotequal).
   assert (Col A B P) by (conclude lemma_collinear4).
   assert (Col P A B) by (forward_using lemma_collinearorder).
   assert (Col G A P) by (conclude_def Col ).
   assert (Col P A G) by (forward_using lemma_collinearorder).
   assert (neq A P) by (forward_using lemma_betweennotequal).
   assert (neq P A) by (conclude lemma_inequalitysymmetric).
   assert (Col A B G) by (conclude lemma_collinear4).
   contradict.
   }
  let Tf:=fresh in
  assert (Tf:exists M, (BetS A M P /\ BetS C B M)) by (conclude postulate_Pasch_outer);destruct Tf as [M];spliter.
  assert (BetS P A G) by (conclude axiom_betweennesssymmetry).
  assert (BetS P M A) by (conclude axiom_betweennesssymmetry).
  assert (BetS M A G) by (conclude lemma_3_6a).
  assert (BetS G A M) by (conclude axiom_betweennesssymmetry).
  assert (~ Col C M G).
   {
   intro.
   assert (BetS P M A) by (conclude axiom_betweennesssymmetry).
   assert (BetS P A G) by (conclude axiom_betweennesssymmetry).
   assert (BetS P M G) by (conclude lemma_3_6b).
   assert (Col P M G) by (conclude_def Col ).
   assert (Col M G P) by (forward_using lemma_collinearorder).
   assert (Col M G C) by (forward_using lemma_collinearorder).
   assert (neq M G) by (forward_using lemma_betweennotequal).
   assert (Col G P C) by (conclude lemma_collinear4).
   assert (Col P A G) by (conclude_def Col ).
   assert (Col G P A) by (forward_using lemma_collinearorder).
   assert (neq P G) by (forward_using lemma_betweennotequal).
   assert (neq G P) by (conclude lemma_inequalitysymmetric).
   assert (Col P C A) by (conclude lemma_collinear4).
   assert (Col C P A) by (forward_using lemma_collinearorder).
   contradict.
   }
  let Tf:=fresh in
  assert (Tf:exists Q, (BetS C Q A /\ BetS G Q B)) by (conclude postulate_Pasch_inner);destruct Tf as [Q];spliter.
  assert (BetS B Q G) by (conclude axiom_betweennesssymmetry).
  assert (neq B Q) by (forward_using lemma_betweennotequal).
  assert (neq B G) by (forward_using lemma_betweennotequal).
  assert (Out B Q G) by (conclude lemma_ray4).
  assert (Out B G Q) by (conclude lemma_ray5).
  assert (eq Q Q) by (conclude cn_equalityreflexive).
  assert (eq A A) by (conclude cn_equalityreflexive).
  assert (eq C C) by (conclude cn_equalityreflexive).
  assert (Out B A A) by (conclude lemma_ray4).
  assert (Out B C C) by (conclude lemma_ray4).
  assert (Out B G G) by (conclude lemma_ray4).
  assert (Out B Q Q) by (conclude lemma_ray4).
  assert (Cong A Q A Q) by (conclude cn_congruencereflexive).
  assert (Cong B Q B Q) by (conclude cn_congruencereflexive).
  assert (Cong B A B A) by (conclude cn_congruencereflexive).
  assert (CongA A B G A B Q) by (conclude_def CongA ).
  assert (BetS A Q C) by (conclude axiom_betweennesssymmetry).
  assert (LtA A B G A B C) by (conclude_def LtA ).
  assert (CongA D E F A B G) by (conclude lemma_equalanglessymmetric).
  assert (LtA D E F A B C) by (conclude lemma_angleorderrespectscongruence2).
  assert (~ ~ LtA A B C D E F).
   {
   intro.
   contradict.
   }
  close.
  }
 {
  assert (~ Col P C B).
   {
   intro.
   assert (Col B A R) by (conclude_def Col ).
   assert (Col P R C) by (conclude_def Col ).
   assert (Col P C R) by (forward_using lemma_collinearorder).
   assert (neq P C) by (forward_using lemma_betweennotequal).
   assert (Col C B R) by (conclude lemma_collinear4).
   assert (Col R B C) by (forward_using lemma_collinearorder).
   assert (Col R B A) by (forward_using lemma_collinearorder).
   assert (neq B R) by (forward_using lemma_betweennotequal).
   assert (neq R B) by (conclude lemma_inequalitysymmetric).
   assert (Col B C A) by (conclude lemma_collinear4).
   assert (Col A B C) by (forward_using lemma_collinearorder).
   contradict.
   }
  let Tf:=fresh in
  assert (Tf:exists Q, (BetS B Q C /\ BetS P A Q)) by (conclude postulate_Pasch_outer);destruct Tf as [Q];spliter.
  assert (Col B C Q) by (conclude_def Col ).
  assert (~ eq G Q).
   {
   intro.
   assert (BetS B G C) by (conclude cn_equalitysub).
   assert (Out B C G) by (conclude lemma_ray4).
   assert (Out B A A) by (conclude lemma_ray4).
   assert (Out B G G) by (conclude lemma_ray4).
   assert (Cong A G A G) by (conclude cn_congruencereflexive).
   assert (Cong B G B G) by (conclude cn_congruencereflexive).
   assert (Cong B A B A) by (conclude cn_congruencereflexive).
   assert (CongA A B G A B C) by (conclude_def CongA ).
   assert (CongA A B C A B G) by (conclude lemma_equalanglessymmetric).
   assert (CongA A B C D E F) by (conclude lemma_equalanglestransitive).
   contradict.
   }
  assert (~ Col B C G).
   {
   intro.
   assert (BetS P A G) by (conclude axiom_betweennesssymmetry).
   assert (Out A G Q) by (conclude_def Out ).
   assert (Col A G Q) by (conclude lemma_rayimpliescollinear).
   assert (Col Q C B) by (forward_using lemma_collinearorder).
   assert (Col C B G) by (forward_using lemma_collinearorder).
   assert (Col C B Q) by (forward_using lemma_collinearorder).
   assert (neq B C) by (forward_using lemma_betweennotequal).
   assert (neq C B) by (conclude lemma_inequalitysymmetric).
   assert (eq B B) by (conclude cn_equalityreflexive).
   assert (Col C B B) by (conclude_def Col ).
   assert (Col G Q B) by (conclude lemma_collinear5).
   assert (Col Q G B) by (forward_using lemma_collinearorder).
   assert (Col Q G A) by (forward_using lemma_collinearorder).
   assert (neq Q G) by (conclude lemma_inequalitysymmetric).
   assert (Col G B A) by (conclude lemma_collinear4).
   assert (Col A B G) by (forward_using lemma_collinearorder).
   contradict.
   }
  assert (~ BetS A Q G).
   {
   intro.
   assert (BetS G Q A) by (conclude axiom_betweennesssymmetry).
   assert (TS G B C A) by (conclude_def TS ).
   contradict.
   }
  assert (Out B C Q) by (conclude lemma_ray4).
  assert (Out B A A) by (conclude lemma_ray4).
  assert (~ BetS A G Q).
   {
   intro.
   assert (CongA A B G A B G) by (conclude lemma_equalanglesreflexive).
   assert (LtA A B G A B C) by (conclude_def LtA ).
   assert (CongA D E F A B G) by (conclude lemma_equalanglessymmetric).
   assert (LtA D E F A B C) by (conclude lemma_angleorderrespectscongruence2).
   contradict.
   }
  assert (BetS P A G) by (conclude axiom_betweennesssymmetry).
  assert (eq G Q) by (conclude lemma_outerconnectivity).
  assert (~ ~ LtA A B C D E F).
   {
   intro.
   contradict.
   }
  close.
  }
 {
  assert (~ ~ LtA A B C D E F).
   {
   intro.
   assert (BetS P A G) by (conclude axiom_betweennesssymmetry).
   assert (~ Col P G B).
    {
    intro.
    assert (Col P A G) by (conclude_def Col ).
    assert (Col P G A) by (forward_using lemma_collinearorder).
    assert (neq P G) by (forward_using lemma_betweennotequal).
    assert (Col G B A) by (conclude lemma_collinear4).
    assert (Col A B G) by (forward_using lemma_collinearorder).
    contradict.
    }
   let Tf:=fresh in
   assert (Tf:exists Q, (BetS B Q G /\ BetS P R Q)) by (conclude postulate_Pasch_outer);destruct Tf as [Q];spliter.
   assert (neq Q G) by (forward_using lemma_betweennotequal).
   assert (neq B Q) by (forward_using lemma_betweennotequal).
   assert (Out B A A) by (conclude lemma_ray4).
   assert (Out B G Q) by (conclude lemma_ray4).
   assert (Out B Q G) by (conclude lemma_ray4).
   assert (~ BetS R C Q).
    {
    intro.
    assert (Out B A R) by (conclude lemma_ray4).
    assert (Out B G Q) by (conclude lemma_ray4).
    assert (CongA A B C A B C) by (conclude lemma_equalanglesreflexive).
    assert (LtA A B C A B G) by (conclude_def LtA ).
    assert (CongA D E F A B G) by (conclude lemma_equalanglessymmetric).
    assert (LtA A B C D E F) by (conclude lemma_angleorderrespectscongruence).
    contradict.
    }
   assert (~ BetS R Q C).
    {
    intro.
    assert (eq A A) by (conclude cn_equalityreflexive).
    assert (Out B A A) by (conclude lemma_ray4).
    assert (Out B Q G) by (conclude lemma_ray4).
    assert (eq G G) by (conclude cn_equalityreflexive).
    assert (Out B G G) by (conclude lemma_ray4).
    assert (Cong B A B A) by (conclude cn_congruencereflexive).
    assert (Cong B G B G) by (conclude cn_congruencereflexive).
    assert (Cong A G A G) by (conclude cn_congruencereflexive).
    assert (CongA A B G A B Q) by (conclude_def CongA ).
    assert (Out B A R) by (conclude lemma_ray4).
    assert (eq C C) by (conclude cn_equalityreflexive).
    assert (Out B C C) by (conclude lemma_ray4).
    assert (LtA A B G A B C) by (conclude_def LtA ).
    assert (CongA D E F A B G) by (conclude lemma_equalanglessymmetric).
    assert (LtA D E F A B C) by (conclude lemma_angleorderrespectscongruence2).
    contradict.
    }
   assert (eq Q C) by (conclude lemma_outerconnectivity).
   assert (eq C C) by (conclude cn_equalityreflexive).
   assert (Out B C C) by (conclude lemma_ray4).
   assert (Out B C G) by (conclude cn_equalitysub).
   assert (eq A A) by (conclude cn_equalityreflexive).
   assert (Out B A A) by (conclude lemma_ray4).
   assert (Out B Q G) by (conclude lemma_ray4).
   assert (eq G G) by (conclude cn_equalityreflexive).
   assert (Out B G G) by (conclude lemma_ray4).
   assert (Cong B A B A) by (conclude cn_congruencereflexive).
   assert (Cong B G B G) by (conclude cn_congruencereflexive).
   assert (Cong A G A G) by (conclude cn_congruencereflexive).
   assert (CongA A B G A B Q) by (conclude_def CongA ).
   assert (CongA A B C A B G) by (conclude_def CongA ).
   assert (CongA A B C D E F) by (conclude lemma_equalanglestransitive).
   contradict.
   }
  close.
  }
(** cases *)
 close.
 }
(** cases *)
close.
Qed.

End Euclid.