(* Multiple inputs and outputs, blocking reads *)
Require Import Merges.Tactics.
Require Import Merges.Map.

Require Import Merges.List.List.
Require Import Coq.Lists.List.
Import ListNotations.
Set Implicit Arguments.
Require Import Coq.Logic.FunctionalExtensionality.

Module Base.
Section Machine.
  Variable Label : Set.

  Definition Value := nat.

  Variable ChanV : Set.
  Variable ChanVEqDec : EqDec ChanV.

  Variable ScalarV : Set.
  Variable ScalarVEqDec : EqDec ScalarV.

  Definition StreamHeap := Map ChanV (list Value).
  Definition ScalarHeap := Map ScalarV Value.
  Definition Pred := StreamHeap -> ScalarHeap -> Prop.

  Let streamUpdate := Map.update ChanV (list Value) ChanVEqDec.
  Let scalarUpdate := Map.update ScalarV Value ScalarVEqDec.

  Inductive StreamTypeT :=
   | Input | Output | Ignore.
  Variable StreamType : ChanV -> StreamTypeT.

  Inductive Block : Type :=
   (* Blocking pull, wait forever until we get something *)
   | BlockPull : ScalarV -> ChanV -> Label -> Block
   (* Release the thing we just pulled.
      When two machines are pulling from same thing, this
      signals to other machine that it can now pull if it wants *)
   | BlockRelease : ChanV -> Label -> Block

   (* Push a value *)
   | BlockPush : ChanV -> (ScalarHeap -> Value) -> Label -> Block

   (* Update a variable *)
   | BlockUpdate : ScalarV -> (ScalarHeap -> Value) -> Label -> Block

   (* If non-zero *)
   | BlockIf : (ScalarHeap -> Value) -> Label -> Label -> Block

   (* Jump to another label without doing anything *)
   | BlockJump   : Label -> Block
   .

  Variable Blocks : Label -> Block.
  Variable LabelPre  : Label -> Pred.

  Inductive EvalB : StreamHeap -> ScalarHeap -> Label
                 -> StreamHeap -> ScalarHeap -> Label -> Prop :=
   | EvalBPullOk l v c lok i h sh
      : Blocks l = BlockPull v c lok
     -> StreamType c = Input
     -> EvalB h sh l
              (streamUpdate c (i :: h c) h) (scalarUpdate v i sh) lok

   (* Release does nothing *)
   | EvalBRelease l v l' h sh
      : Blocks l = BlockRelease v l'
     -> StreamType v = Input
     -> EvalB h sh l
              h sh l'

   | EvalBPush l v push l' h sh
      : Blocks l = BlockPush v push l'
     -> StreamType v = Output
     -> EvalB h sh l
              (streamUpdate v (push sh :: h v) h) sh l'

   | EvalBUpdate l v f l' h sh
      : Blocks l = BlockUpdate v f l'
     -> EvalB h sh l
              h (scalarUpdate v (f sh) sh) l'

   | EvalBIfZ l f lz lnz h sh
      : Blocks l = BlockIf f lz lnz
     -> f sh = 0
     -> EvalB h sh l
              h sh lz

   | EvalBIfS l f lz lnz h sh n
      : Blocks l = BlockIf f lz lnz
     -> f sh = S n
     -> EvalB h sh l
              h sh lnz

   | EvalBJump l l' h sh
      : Blocks l = BlockJump l'
     -> EvalB h sh l
              h sh l'

   | EvalBIgnore l v i h sh
      : StreamType v = Ignore
     -> EvalB h sh l
              (streamUpdate v (i :: h v) h) sh l
   .
  Hint Constructors EvalB.

  Variable Init : Label.
  Variable InitPre : LabelPre Init (fun _ => []) (fun _ => 0).

  Inductive EvalBs : StreamHeap -> ScalarHeap -> Label -> Prop :=
   | EvalBs0
      : EvalBs (fun _ => []) (fun _ => 0) Init
   | EvalBs1 l l' h h' sh sh'
      : EvalBs h sh l
     -> EvalB  h sh l h' sh' l'
     -> EvalBs h' sh' l'
   .
  Hint Constructors EvalBs.

  Definition BlocksPreT :=
    forall h h' sh sh' l l',
    EvalBs h sh l ->
    LabelPre l h sh ->
    EvalB  h sh l h' sh' l' ->
    LabelPre l' h' sh'.

  Hypothesis BlocksPre: BlocksPreT.

  Theorem EvalBs_Hoare l h sh
   (hEvB : EvalBs h sh l)
         : LabelPre l h sh.
  Proof.
   !induction hEvB.
  Qed.
End Machine.

End Base.

  Ltac destruct_apps FUN :=
  repeat match goal with
  | [ _ : context [ FUN ?a ] |- _ ]
  => let x := fresh "destruct_" FUN in remember (FUN a) as x
     ; destruct x
     ; tryfalse
     ; repeat match goal with
       | [ H : _ = FUN a |- _ ] => gen H
       end
  end;
   intros.

  Ltac matchmaker Heq :=
   match goal with
  | [ Heq : _ = match ?A with | _ => _ end |- _ ]
  => let x    := fresh "scrut_" Heq
  in let Heqx := fresh "Heq_" x
  in remember A as x eqn:Heqx; destruct x; try rewrite <- Heqx in *; tryfalse
   ; try matchmaker Heqx
  | [ Heq : match ?A with | _ => _ end = _ |- _ ]
  => let x    := fresh "scrut_" Heq
  in let Heqx := fresh "Heq_" x
  in remember A as x eqn:Heqx; destruct x; try rewrite <- Heqx in *; tryfalse
   ; try matchmaker Heqx
  end.

  Ltac matchmaker_goal := repeat
   match goal with
  | [ |- context [match ?A with | _ => _ end] ]
  => let x    := fresh "scrut_"
  in let Heqx := fresh "Heq_" x
  in remember A as x eqn:Heqx; destruct x; substs; try rewrite <- Heqx in *; tryfalse
   ; try matchmaker Heqx
  end.

 Ltac matchmaker_goal' :=
            !repeat
           match goal with
          | [ |- context [match ?A with | _ => _ end] ]
          => let x    := fresh "scrut_"
          in let Heqx := fresh "Heq_" x
          in remember A as x eqn:Heqx; destruct x
           ; try matchmaker Heqx
           ; try rewrite <- Heqx in *; tryfalse
          end.

Module Program.
 Module B := Base.

 Record Program (Label : Set) (ChanVar : Set) (ScalarVar : Set) : Type
  := mkProgram
   { Init     : Label
   ; Blocks   : Label -> B.Block Label ChanVar ScalarVar

   ; ChanVarEqDec : EqDec ChanVar
   ; ScalarVarEqDec : EqDec ScalarVar
   ; StreamType : ChanVar -> B.StreamTypeT

   ; LabelPre : Label -> B.Pred ChanVar ScalarVar
   ; BlocksPre: B.BlocksPreT ChanVarEqDec ScalarVarEqDec StreamType Blocks LabelPre Init
   ; InitPre  : LabelPre Init (fun _ => []) (fun _ => 0)
   }.

  Definition EvalBs (Label : Set) (ChanVar : Set) (ScalarVar : Set) (P : Program Label ChanVar ScalarVar)
   := B.EvalBs (ChanVarEqDec P) (ScalarVarEqDec P) (StreamType P) (Blocks P) (Init P).

End Program.

Module Fuse.
  Module B := Base.
  Module P := Program.

Section Fuse.
  Variable C : Set.
  Variable V1 : Set.
  Variable L1 : Set.
  Variable P1 : P.Program L1 C V1.

  Variable V2 : Set.
  Variable L2 : Set.
  Variable P2 : P.Program L2 C V2.

  Variable EqDec_C : EqDec C.

  Inductive V :=
    | V'V1 : V1 -> V
    | V'V2 : V2 -> V
    | V'C : C -> V.

  (* Figure out what the fused StreamType will be *)
  Definition StreamType (c : C) : B.StreamTypeT :=
  match P.StreamType P1 c, P.StreamType P2 c with
  (* If left ignores, take whatever right does *)
  | B.Ignore, t
  => t
  (* Vice versa *)
  | t, B.Ignore
  => t
  (* If either is an output, it will be an output in the fused *)
  | B.Output, _
  => B.Output
  | _, B.Output
  => B.Output
  (* If both are inputs, end result is an input *)
  | B.Input, B.Input
  => B.Input
  end.

  Inductive State :=
    | NoValue         (* Input, Output, Ignore *)
    | AvailableToPull (* Input *)
    | HaveValue       (* Input *)
    | ReadyToPush     (* Output *)
    .

  Inductive IsValid :=
    | Valid
    | INVALID
    .

  Inductive L' :=
    | LX (l1 : L1) (l2 : L2) (s1 : C -> State) (s2 : C -> State) (v : IsValid).

  Definition stateUpdate := Map.update C State (P.ChanVarEqDec P1).

  Inductive BlockOption :=
    | BlockOk (b : B.Block L' C V)
    | BlockTryOther
    | BlockINVALID
    .

  Definition makeBlock
    (LA VA : Set)
    (mkV : VA -> V)
    (mkLabel : LA -> (C -> State) -> (C -> State) -> L')
    (lblThis : LA)
    (block : B.Block LA C VA)
    (sThis sOther : C -> State)
    (typeThis : C -> B.StreamTypeT)
    (typeOther : C -> B.StreamTypeT)
           : BlockOption :=
   match block with
    (* Jumps are very easy *)
    | B.BlockJump _ _ l'
    => BlockOk (B.BlockJump _ _ (mkLabel l' sThis sOther))

    (* Releases are fairly simple, so let's start with them *)
    | B.BlockRelease _ sv l'
    => match typeThis sv, typeOther sv, sThis sv, sOther sv with
       (* If the other machine ignores this, we can just release with no synchronisation *)
       (* We require sThis and sOther to be 'NoValue' even though there is something: *)
       (* it doesn't need to be tracked because it's ignored *)
       | B.Input, B.Ignore, NoValue, NoValue
       => BlockOk (B.BlockRelease _ sv (mkLabel l' sThis sOther))

       (* Both machines want to pull from this, so let's see.
          This machine must have a value for sv in its state now:
          sThis sv = HaveValue
          But it depends whether the other machine has it
       *)
       | B.Input, B.Input, HaveValue, HaveValue
       | B.Input, B.Input, HaveValue, AvailableToPull
       (* If other machine still has one, we only pretend to release *)
       => BlockOk (B.BlockJump _ _ (mkLabel l' (stateUpdate sv NoValue sThis) sOther))

       (* Other machine has already pretended to release *)
       | B.Input, B.Input, HaveValue, NoValue
       => BlockOk (B.BlockRelease _ sv (mkLabel l' (stateUpdate sv NoValue sThis) sOther))

       (* The other machine has already pushed this, so only pretend release *)
       (* sOther = NoValue because the push has already happened *)
       | B.Input, B.Output, HaveValue, NoValue
       => BlockOk (B.BlockJump _ _ (mkLabel l' (stateUpdate sv NoValue sThis) sOther))

       (* Otherwise sThis sv is invalid *)
       | _, _, _, _
       => BlockINVALID
       end

    (* Pulls are a bit more interesting *)
    | B.BlockPull v c l'
    => match typeThis c, typeOther c, sThis c, sOther c with
       (* Ignore is easy *)
       | B.Input, B.Ignore, NoValue, NoValue
       => BlockOk (B.BlockPull (mkV v) c (mkLabel l' sThis sOther))

       (* Both machines want to pull from this, so let's see. *)
       (* We already have a fake one ready to go, so use it *)
       | B.Input, B.Input, AvailableToPull, NoValue
       | B.Input, B.Input, AvailableToPull, HaveValue
       | B.Input, B.Input, AvailableToPull, AvailableToPull
       => BlockOk (B.BlockUpdate _
                    (mkV v) (fun sh => sh (V'C c))
                    (mkLabel l' (stateUpdate c HaveValue sThis) sOther))

       | B.Input, B.Input, NoValue, HaveValue
       | B.Input, B.Input, NoValue, AvailableToPull
       (* If other machine has one but we don't, that means
          we have already pulled and released, but they haven't released yet.
          They need to run a bit and hopefully release.
        *)
       => BlockTryOther

       | B.Input, B.Input, NoValue, NoValue
       (* Neither machine has it, but we both want it.
          Both now have the value available and the next step will use it *)
       => BlockOk (B.BlockPull (V'C c) c
                  (mkLabel lblThis
                      (stateUpdate c AvailableToPull sThis)
                      (stateUpdate c AvailableToPull sOther)))

       (* The other machine must push. Have they given us anything yet? *)
       (* Yes, they have given us something *)
       | B.Input, B.Output, AvailableToPull, NoValue
       => BlockOk (B.BlockUpdate _ (mkV v) (fun sh => sh (V'C c)) (mkLabel l'  (stateUpdate c HaveValue sThis) sOther))

       (* No, we have to wait. Try to let the other machine run *)
       | B.Input, B.Output, NoValue, NoValue
       | B.Input, B.Output, NoValue, ReadyToPush
       => BlockTryOther

       (* Otherwise sThis sv is invalid *)
       | _, _, _, _
       => BlockINVALID
       end

    (* Pushes are pretty similar *)
    | B.BlockPush sv f l'
    => match typeThis sv, typeOther sv, sThis sv, sOther sv with
       (* It's pretty easy if the other machine ignores this channel *)
       | B.Output, B.Ignore, NoValue, NoValue
       => BlockOk (B.BlockPush sv (fun sh => f (fun v => sh (mkV v))) (mkLabel l' sThis sOther))

       (* Other machine reads: *)
       (* Check if it is ready to scoop a new one *)
       | B.Output, B.Input, NoValue, HaveValue
       | B.Output, B.Input, NoValue, AvailableToPull
       (* No. The other machine has a value it hasn't already used *)
       => BlockTryOther

       (* Other machine is empty and ready to receive.
          Save the output value to the local V'C buffer so the pull can use it
           And next step will do the actual push *)
       | B.Output, B.Input, NoValue, NoValue
       => BlockOk
         (B.BlockUpdate _ (V'C sv)
             (fun sh => f (fun v => sh (mkV v)))
             (mkLabel lblThis (stateUpdate sv ReadyToPush sThis) sOther))

       (* We have already saved the output in V'C *)
       | B.Output, B.Input, ReadyToPush, NoValue
       => BlockOk
          (B.BlockPush sv
            (fun sh => sh (V'C sv))
            (mkLabel l' (stateUpdate sv NoValue sThis) (stateUpdate sv AvailableToPull sOther)))

       (* All other cases are invalid *)
       | _, _, _, _
       => BlockINVALID
       end
    | B.BlockUpdate _ v f l'
    => BlockOk (B.BlockUpdate _ (mkV v) (fun sh => f (fun v => sh (mkV v))) (mkLabel l' sThis sOther))
    | B.BlockIf _ f lz lnz
    => BlockOk (B.BlockIf _ (fun sh => f (fun v => sh (mkV v)))
                    (mkLabel lz sThis sOther)
                    (mkLabel lnz sThis sOther)
                )
   end.

  Definition Blocks (l : L') : B.Block L' C V :=
   match l with
   | LX l1 l2 s1 s2 v
   => let invalid := B.BlockJump _ _ (LX l1 l2 s1 s2 INVALID) in
      match v
    , makeBlock V'V1 (fun l1' s1' s2' => LX l1' l2 s1' s2' Valid) l1 (P.Blocks P1 l1) s1 s2 (P.StreamType P1) (P.StreamType P2)
    , makeBlock V'V2 (fun l2' s2' s1' => LX l1 l2' s1' s2' Valid) l2 (P.Blocks P2 l2) s2 s1 (P.StreamType P2) (P.StreamType P1)
      with
      | Valid, BlockINVALID, _
      => invalid
      | Valid, _, BlockINVALID
      => invalid
      | Valid, BlockOk block, _
      => block
      | Valid, _, BlockOk block
      => block
      | _, _, _
      => invalid
      end
    end.

  Definition Evalish (LA VA : Set) (mkV : VA -> V) (P : P.Program LA C VA) (s : C -> State) (iss : B.StreamHeap C) (h : B.ScalarHeap V) (l : LA) : Prop :=
   let iss' :=
    fun sv =>
     match s sv with
      | AvailableToPull => tail (iss sv)
      | HaveValue       => iss sv
      | NoValue         => iss sv
      | ReadyToPush     => iss sv
     end
   in P.EvalBs P iss' (fun v => h (mkV v)) l /\
    (forall sv,
     match s sv with
      | AvailableToPull
      => match iss sv with
         | [] => False
         | x :: _ => x = h (V'C sv)
         end
      | HaveValue => True
      | NoValue   => True
      | ReadyToPush
      => match P.Blocks P l with
         | B.BlockPush sv' f _
         => sv = sv' /\ h (V'C sv) = f (fun v => h (mkV v))
         | _ => False
         end
     end /\
     (P.StreamType P sv = B.Ignore -> s sv = NoValue)
     ).

  Definition LabelPre (l : L') : B.Pred C V :=
   match l with
   | LX l1 l2 s1 s2 INVALID
   => fun _ _ => True
   | LX l1 l2 s1 s2 Valid
   => fun iss h
   => Evalish V'V1 P1 s1 iss h l1
   /\ Evalish V'V2 P2 s2 iss h l2
   end.
  Hint Unfold LabelPre.

  Theorem ScalarVarEqDec_V: EqDec V.
  Proof.
    hint (P.ScalarVarEqDec P1).
    hint (P.ScalarVarEqDec P2).
    hint EqDec_C.
    decides_equality.
  Qed.

  Theorem ScalarHeap_update_sub
      (V' : Set)
      (Eq_V' : EqDec V')
      (mkV' : V' -> V)
      (mkV'inj : forall a b, mkV' a = mkV' b -> a = b)
      (sh : B.ScalarHeap V)
      (i : B.Value) (v0 : V'):
  (fun v : V' => update V P.B.Value ScalarVarEqDec_V (mkV' v0) i sh (mkV' v)) =
    update V' B.Value Eq_V' v0 i (fun v : V' => sh (mkV' v)).
  Proof.
    extensionality n.
    unfolds.
    !destruct (ScalarVarEqDec_V); destruct (Eq_V').
    !destruct n0.
    !destruct n0. !rewrite e.
  Qed.
  Program Definition ScalarHeap_update_sub_V1
    := ScalarHeap_update_sub (P.ScalarVarEqDec P1) V'V1 _.
  Program Definition ScalarHeap_update_sub_V2
    := ScalarHeap_update_sub (P.ScalarVarEqDec P2) V'V2 _.

  Theorem ScalarHeap_update_V1_as_V2 i sh v0:
    (fun v : V2 => update V P.B.Value ScalarVarEqDec_V (V'V1 v0) i sh (V'V2 v)) =
    (fun v : V2 => sh (V'V2 v)).
  Proof.
    extensionality v.
    unfolds.
    !destruct ScalarVarEqDec_V.
    tryfalse.
  Qed.

  Theorem ScalarHeap_update_V2_as_V1 i sh v0:
    (fun v : V1 => update V P.B.Value ScalarVarEqDec_V (V'V2 v0) i sh (V'V1 v)) =
    (fun v : V1 => sh (V'V1 v)).
  Proof.
    extensionality v.
    unfolds.
    !destruct ScalarVarEqDec_V.
    tryfalse.
  Qed.

  Theorem ScalarHeap_update_VC_as_V1 i sh c0:
    (fun v : V1 => update V P.B.Value ScalarVarEqDec_V (V'C c0) i sh (V'V1 v)) =
    (fun v : V1 => sh (V'V1 v)).
  Proof.
    extensionality v.
    unfolds update.
    !destruct (ScalarVarEqDec_V); tryfalse.
  Qed.

  Theorem ScalarHeap_update_VC_as_V2 i sh c0:
    (fun v : V2 => update V P.B.Value ScalarVarEqDec_V (V'C c0) i sh (V'V2 v)) =
    (fun v : V2 => sh (V'V2 v)).
  Proof.
    extensionality v.
    unfolds update.
    !destruct (ScalarVarEqDec_V); tryfalse.
  Qed.

  Ltac doit X := try solve [(!eapply B.EvalBs1); (!eapply X)].

  Ltac rewrite_Heaps :=
      try rewrite ScalarHeap_update_sub_V1;
      try rewrite ScalarHeap_update_sub_V2;
      try rewrite ScalarHeap_update_V1_as_V2;
      try rewrite ScalarHeap_update_V2_as_V1;
      try rewrite ScalarHeap_update_VC_as_V2;
      try rewrite ScalarHeap_update_VC_as_V1.

  Program Definition r
  := {| P.Blocks := Blocks
      ; P.LabelPre := LabelPre
      ; P.Init := LX (P.Init P1) (P.Init P2) (fun _ => NoValue) (fun _ => NoValue) Valid
      ; P.StreamType := StreamType
      ; P.ChanVarEqDec := P.ChanVarEqDec P1
      ; P.ScalarVarEqDec := ScalarVarEqDec_V
      |}.

  Next Obligation.

   unfolds B.BlocksPreT.
   introv hEvBs hLbl hEvB.
   clear hEvBs.
   destruct l; destruct l'.
   !destruct v0; destruct v; try solve [inverts hEvB; tryfalse].

   simpls; unfolds Evalish; unfolds Blocks; unfolds makeBlock.

  inverts hEvB.
  - (* BlockPull *)

    matchmaker H.
    all: inject_all.
    all: rewrite_Heaps.
    all: !jauto_set.

    all: try solve [
      match goal with
      | [ |- context [P.EvalBs P1] ] => applys_eq H 0
      | [ |- context [P.EvalBs P2] ] => applys_eq H1 0
      end; fequals;
      extensionality sv;
      unfolds stateUpdate;
      unfolds update;
      !destruct (P.ChanVarEqDec);
      subst; simpl;
      !destruct (s1 sv); destruct (s2 sv); tryfalse ].

    all: try solve
      [
   (!eapply B.EvalBs1);
    (!applys_eq B.EvalBIgnore 0; fequals);
    extensionality n;
    unfolds update;
    (!repeat destruct P.ChanVarEqDec; subst; destruct (s1 n); destruct (s2 n); tryfalse)
      ].

    all: try solve
      [
   (!eapply B.EvalBs1);
    (!applys_eq B.EvalBPullOk 0; fequals);
    extensionality n;
    unfolds update;
    (!repeat destruct P.ChanVarEqDec; subst; destruct (s1 n); destruct (s2 n); tryfalse)
      ].

    all: intros sv; unfolds stateUpdate; forwards: H0 sv; forwards: H2 sv.

    all: unfolds update.
    all: matchmaker_goal'.
    all: !jauto_set.

    all: substs.
    all: !inject_all.
    all: intros; tryfalse.

  - (* BlockRelease *)
    matchmaker H.
    all: inject_all.
    all: !jauto_set.
    all: doit B.EvalBRelease
       ; try assumption
      .

    all: try solve
      [
   (!eapply B.EvalBs1);
    (!applys_eq B.EvalBRelease 0; fequals);
    extensionality n;
    unfolds stateUpdate; unfolds update;
    (!repeat destruct P.ChanVarEqDec; subst; destruct (s1 n); destruct (s2 n); tryfalse)
      ].

    all: intros sv.
    all: unfolds stateUpdate; unfolds update; forwards: H0 sv; forwards: H2 sv.

    all: matchmaker_goal'.
    all: !inject_all.
    all: !jauto_set.
    all: tryfalse.

  - (* BlockPush *)

    matchmaker H.
    all: inject_all.
    all: !jauto_set.

    all: try solve
      [
       (!eapply B.EvalBs1);
        (!applys_eq B.EvalBPush 0; fequals);
        extensionality n;
        unfolds stateUpdate; unfolds update;
        (!repeat destruct P.ChanVarEqDec; subst);
        forwards: H0 n; forwards: H2 n;
        (!destruct (s1 n); destruct (s2 n); tryfalse);
        (!jauto_set); congruence
      ].

    all: unfolds stateUpdate; unfolds update.

    all: try solve [
      match goal with
      | [ |- context [P.EvalBs P1] ] => applys_eq H 0
      | [ |- context [P.EvalBs P2] ] => applys_eq H1 0
      end; fequals;
      extensionality sv;
      unfolds stateUpdate;
      unfolds update;
      !destruct (P.ChanVarEqDec);
      subst; simpl;
      !destruct (s1 sv); destruct (s2 sv); tryfalse ].

    all: try solve [
      (!eapply B.EvalBs1);
      (!applys_eq B.EvalBIgnore 0; fequals);
      extensionality sv;
      unfolds update;
      (!repeat destruct P.ChanVarEqDec; tryfalse; subst);
      simpl;
      (!destruct (s1 sv); destruct (s2 sv); tryfalse)
      ].

    all: intros sv.
    all: !jauto_set.
    all: !forwards: H0 sv; forwards: H2 sv; jauto_set.

    all: matchmaker_goal'.
    all: !inject_all.
    all: substs.
    all: !jauto_set; tryfalse.

  - (* BlockUpdate *)
    !jauto_set.
    + (* EvalBs P1 *)
      matchmaker H.
      all: inject_all.

      all: rewrite_Heaps.

      all: try solve [
        (!eapply B.EvalBs1); (!applys_eq B.EvalBPullOk 2 3);
        extensionality sv;
        forwards: H1 sv;
        unfolds stateUpdate; unfolds update;
        jauto_set;
        matchmaker_goal;
        (!destruct (h' sv); tryfalse);
        (!simpl; subst)
        ].

      all: try solve [
        (!applys_eq H0 2 3);
        extensionality sv;
        forwards: H1 sv;
        unfolds stateUpdate; unfolds update;
        matchmaker_goal;
        (!destruct (h' sv); tryfalse);
        (!simpl; subst)
        ].

      all: try solve [
        (!eapply B.EvalBs1); (!applys_eq B.EvalBUpdate 2 3);
        extensionality sv;
        forwards: H1 sv;
        unfolds stateUpdate; unfolds update;
        matchmaker_goal;
        (!destruct (h' sv); tryfalse);
        (!simpl; subst)
        ].

    + (* P1 invariant *)
        intros sv.
        forwards: H1 sv.
        unfolds stateUpdate; unfolds update.
        matchmaker H; inject_all.

  all: !repeat
   match goal with
  | [ |- context [match ?A with | _ => _ end] ]
  => let x    := fresh "scrut_"
  in let Heqx := fresh "Heq_" x
  in remember A as x eqn:Heqx; destruct x
   ; try matchmaker Heqx
   ; try rewrite <- Heqx in *; tryfalse
  end.
  all: inject_all.
  all: !jauto_set.

    all: try solve [
      fequals;
      extensionality v0;
      !matchmaker_goal ].
    all: substs.
    all: !jauto_set; tryfalse.

    + (* EvalBs P2 *)
      matchmaker H.
      all: inject_all.
      all: rewrite_Heaps.

      all: try solve [
        (!eapply B.EvalBs1); (!applys_eq B.EvalBPullOk 2 3);
        extensionality sv;
        forwards: H3 sv;
        jauto_set;
        unfolds stateUpdate; unfolds update;
        matchmaker_goal;
        (!destruct (h' sv); tryfalse);
        (!simpl; subst)
        ].

      all: try solve [
        (!applys_eq H2 2 3);
        extensionality sv;
        forwards: H3 sv;
        unfolds stateUpdate; unfolds update;
        matchmaker_goal;
        (!destruct (h' sv); tryfalse);
        (!simpl; subst)
        ].

      all: try solve [
        (!eapply B.EvalBs1); (!applys_eq B.EvalBUpdate 2 3);
        extensionality sv;
        forwards: H3 sv;
        unfolds stateUpdate; unfolds update;
        matchmaker_goal;
        (!destruct (h' sv); tryfalse);
        (!simpl; subst)
        ].

    + (* P2 invariant *)
        intros sv.
        forwards: H3 sv.
        unfolds stateUpdate; unfolds update.
        matchmaker H; inject_all.
          all: !repeat
           match goal with
          | [ |- context [match ?A with | _ => _ end] ]
          => let x    := fresh "scrut_"
          in let Heqx := fresh "Heq_" x
          in remember A as x eqn:Heqx; destruct x
           ; try matchmaker Heqx
           ; try rewrite <- Heqx in *; tryfalse
          end.
          all: inject_all.
          all: !jauto_set.

          all: try solve [
            fequals;
            extensionality vvvvv;
            !matchmaker_goal ].

          all: try solve [rewrite H4;
            fequals;
            extensionality vvvv;
            !matchmaker_goal].
    all: !jauto_set; tryfalse.

  - (* BlockIf - Z *)

    !jauto_set.
    + (* EvalBs P1 *)
      matchmaker H.
      all: inject_all.
      all: try doit B.EvalBIfZ.
      all: assumption.
    + (* Invariant P1 *)
      intros sv.
      matchmaker H; inject_all.
      all: forwards: H2 sv.
      all: !matchmaker_goal.
      all: !jauto_set.
      all: !inject_all.
      all: !jauto_set; tryfalse.

    + (* EvalBs P2 *)
      matchmaker H.
      all: inject_all.
      all: try doit B.EvalBIfZ.
      all: assumption.
    + (* Invariant P2 *)
      intros sv.
      matchmaker H; inject_all.
      all: forwards: H4 sv.
      all: !matchmaker_goal.
      all: !jauto_set.
      all: !inject_all.
      all: !jauto_set; tryfalse.

  - (* BlockIf - NZ *)

    !jauto_set.
    + (* EvalBs P1 *)
      matchmaker H.
      all: inject_all.
      all: try doit B.EvalBIfS.
      all: assumption.
    + (* Invariant P1 *)
      intros sv.
      matchmaker H; inject_all.
      all: forwards: H2 sv.
      all: !matchmaker_goal.
      all: !jauto_set.
      all: !inject_all.
      all: !jauto_set; tryfalse.

    + (* EvalBs P2 *)
      matchmaker H.
      all: inject_all.
      all: try doit B.EvalBIfS.
      all: assumption.
    + (* Invariant P2 *)
      intros sv.
      matchmaker H; inject_all.
      all: forwards: H4 sv.
      all: !matchmaker_goal.
      all: !jauto_set.
      all: !inject_all.
      all: !jauto_set; tryfalse.

  - (* BlockJump *)

    !jauto_set.
    + (* EvalBs P1 *)
      matchmaker H.
      all: inject_all.
      all: try doit B.EvalBJump.

      all: try solve [
          (!eapply B.EvalBs1);
          (!applys_eq B.EvalBRelease 2 3);
          extensionality sv;
          forwards: H1 sv;
          unfolds stateUpdate; unfolds update;
          matchmaker_goal;
          (!destruct (h' sv); tryfalse);
          (!simpl; subst)
        ].

      all: assumption.
    + (* Invariant P1 *)
      intros sv.
      matchmaker H; inject_all.
      all: unfolds stateUpdate; unfolds update.
      all: forwards: H1 sv.

      all: matchmaker_goal'.
      all: !jauto_set.
      all: !inject_all.
      all: !jauto_set; tryfalse.

    + (* EvalBs P2 *)
      matchmaker H.
      all: inject_all.
      all: try doit B.EvalBJump.
      all: try assumption.

      all: try solve [
          (!eapply B.EvalBs1);
          (!applys_eq B.EvalBRelease 2 3);
          extensionality sv;
          forwards: H3 sv;
          unfolds stateUpdate; unfolds update;
          matchmaker_goal;
          (!destruct (h' sv); tryfalse);
          (!simpl; subst)
        ].

    + (* Invariant P2 *)
      intros sv.
      matchmaker H; inject_all.
      all: unfolds stateUpdate; unfolds update.
      all: forwards: H3 sv.
      all: matchmaker_goal'.
      all: !jauto_set.
      all: !inject_all.
      all: !jauto_set; tryfalse.

  - (* Ignore *)
    unfolds StreamType.
    !destruct (P.StreamType P1 v) eqn:StreamType1; destruct (P.StreamType P2 v) eqn:StreamType2; tryfalse.
    jauto_set.
    assert (s0 v = NoValue).
      !forwards: H0 v.
    assert (s3 v = NoValue).
      !forwards: H2 v.
    + (* EvalBs P1 *)
          (!eapply B.EvalBs1);
          (!applys_eq B.EvalBIgnore 2 3).
          extensionality sv.
          unfolds update.
          forwards: H0 sv.

    !matchmaker_goal.

    + (* Invariant P1 *)
      unfolds update.
      intros sv.
      forwards: H0 sv.
      !matchmaker_goal; tryfalse.
      destruct (h sv); jauto_set; tryfalse.
      assert (AvailableToPull = NoValue).
        !jauto_set.
        apply H4. !substs.
      tryfalse.

      !destruct (h sv); jauto_set; tryfalse.
      substs. !inject_all.

    + (* EvalBs P2 *)
          (!eapply B.EvalBs1);
          (!applys_eq B.EvalBIgnore 2 3).
          extensionality sv.
          unfolds update.
          forwards: H2 sv.
          !matchmaker_goal.
          assert (AvailableToPull = NoValue).
            !jauto_set. tryfalse.

    + (* Invariant P2 *)
      unfolds update.
      intros sv.
      forwards: H2 sv.
      !matchmaker_goal; tryfalse.
      destruct (h sv); tryfalse.
      !destruct (h sv); tryfalse.

      assert (AvailableToPull = NoValue).
        !jauto_set.
        apply H4. !substs.
      tryfalse.

      !destruct (h sv); tryfalse.
      subst. !inject_all.
 Qed.
 Next Obligation.
  unfolds Evalish.
  jauto_set;
  try apply B.EvalBs0;
  !jauto_set.
 Qed.
End Fuse.
End Fuse.

Module Eg.
  Module Map.
    Module B := Base.
    Module P := Program.
  Section Map.
    Variable C : Set.
    Variable Cin : C.
    Variable Cout : C.
    Variable EqDec_C : EqDec C.

    Variable f : B.Value -> B.Value.
    Variable Cin_ne_Cout : Cin <> Cout.

    Inductive V :=
      | V0 : V.

    Inductive L :=
      | L'Pull : L
      | L'Push : L
      | L'Release : L.

    Definition Blocks (l : L) : B.Block L C V :=
      match l with
      | L'Pull => B.BlockPull V0 Cin L'Push
      | L'Push => B.BlockPush Cout (fun sh => f (sh V0)) L'Release
      | L'Release => B.BlockRelease V Cin L'Pull
      end.

    Definition LabelPre (l : L) : B.Pred C V :=
      match l with
      | L'Pull => fun iss h => iss Cout = map f (iss Cin)
      | L'Push => fun iss h => f (h V0) :: iss Cout = map f (iss Cin)
      | L'Release => fun iss h => iss Cout = map f (iss Cin)
      end.

    Definition StreamType (c : C) : B.StreamTypeT :=
      if EqDec_C c Cin
      then B.Input
      else if EqDec_C c Cout
      then B.Output
      else B.Ignore.

    Program Definition P : P.Program L C V :=
      {| P.Init := L'Pull
      ; P.Blocks := Blocks
      ; P.ChanVarEqDec := EqDec_C
      ; P.StreamType := StreamType
      ; P.LabelPre := LabelPre
      |}.
    Next Obligation.
      decides_equality.
    Qed.
    Next Obligation.
      unfolds B.BlocksPreT. unfolds LabelPre. unfolds Blocks.
      introv hEvBs hLbl hEvB.
      hint Cin_ne_Cout.

      !inverts hEvB; try destruct l; try destruct l'; inject_all; tryfalse.
      all: unfolds update; unfolds StreamType.

      all: try destruct v.
      all: matchmaker_goal'.
      !rewrite hLbl.
      !destruct n0.
    Qed.
  End Map. End Map.

  Module Eg1.
    Inductive C := C1 | C2 | C3.
    Theorem EqDec_C : EqDec C. decides_equality. Qed.

    Module M := Map.
    Check M.P.
    Definition P1 := Map.P C1 C2 EqDec_C.
    Check P1.
  End Eg1.

End Eg.


Require Export euclidean__axioms.
Require Export euclidean__defs.
Require Export euclidean__tactics.
Require Export lemma__3__6b.
Require Export lemma__NChelper.
Require Export lemma__NCorder.
Require Export lemma__Playfairhelper.
Require Export lemma__betweennotequal.
Require Export lemma__collinear4.
Require Export lemma__collinearbetween.
Require Export lemma__collinearorder.
Require Export lemma__collinearparallel.
Require Export lemma__crisscross.
Require Export lemma__extension.
Require Export lemma__inequalitysymmetric.
Require Export lemma__parallelNC.
Require Export lemma__parallelflip.
Require Export lemma__parallelsymmetric.
Require Export logic.
Definition lemma__Playfairhelper2 : forall A B C D E, (euclidean__defs.Par A B C D) -> ((euclidean__defs.Par A B C E) -> ((euclidean__defs.CR A D B C) -> (euclidean__axioms.Col C D E))).
Proof.
intro A.
intro B.
intro C.
intro D.
intro E.
intro H.
intro H0.
intro H1.
assert (* Cut *) (euclidean__axioms.neq A B) as H2.
- assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H2 by exact H0.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp by exact H2.
destruct __TmpHyp as [x H3].
destruct H3 as [x0 H4].
destruct H4 as [x1 H5].
destruct H5 as [x2 H6].
destruct H6 as [x3 H7].
destruct H7 as [H8 H9].
destruct H9 as [H10 H11].
destruct H11 as [H12 H13].
destruct H13 as [H14 H15].
destruct H15 as [H16 H17].
destruct H17 as [H18 H19].
destruct H19 as [H20 H21].
destruct H21 as [H22 H23].
destruct H23 as [H24 H25].
destruct H25 as [H26 H27].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H28 by exact H.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp0 by exact H28.
destruct __TmpHyp0 as [x4 H29].
destruct H29 as [x5 H30].
destruct H30 as [x6 H31].
destruct H31 as [x7 H32].
destruct H32 as [x8 H33].
destruct H33 as [H34 H35].
destruct H35 as [H36 H37].
destruct H37 as [H38 H39].
destruct H39 as [H40 H41].
destruct H41 as [H42 H43].
destruct H43 as [H44 H45].
destruct H45 as [H46 H47].
destruct H47 as [H48 H49].
destruct H49 as [H50 H51].
destruct H51 as [H52 H53].
exact H34.
- assert (* Cut *) (euclidean__axioms.neq C D) as H3.
-- assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H3 by exact H0.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp by exact H3.
destruct __TmpHyp as [x H4].
destruct H4 as [x0 H5].
destruct H5 as [x1 H6].
destruct H6 as [x2 H7].
destruct H7 as [x3 H8].
destruct H8 as [H9 H10].
destruct H10 as [H11 H12].
destruct H12 as [H13 H14].
destruct H14 as [H15 H16].
destruct H16 as [H17 H18].
destruct H18 as [H19 H20].
destruct H20 as [H21 H22].
destruct H22 as [H23 H24].
destruct H24 as [H25 H26].
destruct H26 as [H27 H28].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H29 by exact H.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp0 by exact H29.
destruct __TmpHyp0 as [x4 H30].
destruct H30 as [x5 H31].
destruct H31 as [x6 H32].
destruct H32 as [x7 H33].
destruct H33 as [x8 H34].
destruct H34 as [H35 H36].
destruct H36 as [H37 H38].
destruct H38 as [H39 H40].
destruct H40 as [H41 H42].
destruct H42 as [H43 H44].
destruct H44 as [H45 H46].
destruct H46 as [H47 H48].
destruct H48 as [H49 H50].
destruct H50 as [H51 H52].
destruct H52 as [H53 H54].
exact H37.
-- assert (* Cut *) (~(~((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)))) as H4.
--- intro H4.
assert (* Cut *) (euclidean__defs.Par A B E C) as H5.
---- assert (* Cut *) ((euclidean__defs.Par B A C E) /\ ((euclidean__defs.Par A B E C) /\ (euclidean__defs.Par B A E C))) as H5.
----- apply (@lemma__parallelflip.lemma__parallelflip A B C E H0).
----- destruct H5 as [H6 H7].
destruct H7 as [H8 H9].
exact H8.
---- assert (* Cut *) (euclidean__defs.CR A C E B) as H6.
----- apply (@lemma__crisscross.lemma__crisscross A E B C H5).
------intro H6.
apply (@H4).
-------left.
exact H6.

----- apply (@H4).
------right.
exact H6.

--- assert (exists M, (euclidean__axioms.BetS A M D) /\ (euclidean__axioms.BetS B M C)) as H5 by exact H1.
destruct H5 as [M H6].
destruct H6 as [H7 H8].
assert (* Cut *) (euclidean__axioms.Col C D E) as H9.
---- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H9.
----- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B))).
------intro H9.
assert (* Cut *) (False) as H10.
------- apply (@H4 H9).
------- assert (* Cut *) ((euclidean__defs.CR A E B C) -> False) as H11.
-------- intro H11.
apply (@H9).
---------left.
exact H11.

-------- assert (* Cut *) ((euclidean__defs.CR A C E B) -> False) as H12.
--------- intro H12.
apply (@H9).
----------right.
exact H12.

--------- contradiction H10.

----- assert ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H10 by exact H9.
assert ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as __TmpHyp by exact H10.
destruct __TmpHyp as [H11|H11].
------ assert (* Cut *) (euclidean__axioms.Col C D E) as H12.
------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H12.
-------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------- apply (@euclidean__tactics.not__nCol__Col C D E).
---------intro H13.
apply (@euclidean__tactics.Col__nCol__False C D E H13).
----------apply (@lemma__Playfairhelper.lemma__Playfairhelper A B C D E H H0 H1 H11).

------- exact H12.
------ assert (exists m, (euclidean__axioms.BetS A m C) /\ (euclidean__axioms.BetS E m B)) as H12 by exact H11.
destruct H12 as [m H13].
destruct H13 as [H14 H15].
assert (* Cut *) (euclidean__axioms.BetS B m E) as H16.
------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H16.
-------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------- apply (@euclidean__axioms.axiom__betweennesssymmetry E m B H15).
------- assert (* Cut *) (euclidean__axioms.neq C E) as H17.
-------- assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H17 by exact H0.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp0 by exact H17.
destruct __TmpHyp0 as [x H18].
destruct H18 as [x0 H19].
destruct H19 as [x1 H20].
destruct H20 as [x2 H21].
destruct H21 as [x3 H22].
destruct H22 as [H23 H24].
destruct H24 as [H25 H26].
destruct H26 as [H27 H28].
destruct H28 as [H29 H30].
destruct H30 as [H31 H32].
destruct H32 as [H33 H34].
destruct H34 as [H35 H36].
destruct H36 as [H37 H38].
destruct H38 as [H39 H40].
destruct H40 as [H41 H42].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H43 by exact H.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp1 by exact H43.
destruct __TmpHyp1 as [x4 H44].
destruct H44 as [x5 H45].
destruct H45 as [x6 H46].
destruct H46 as [x7 H47].
destruct H47 as [x8 H48].
destruct H48 as [H49 H50].
destruct H50 as [H51 H52].
destruct H52 as [H53 H54].
destruct H54 as [H55 H56].
destruct H56 as [H57 H58].
destruct H58 as [H59 H60].
destruct H60 as [H61 H62].
destruct H62 as [H63 H64].
destruct H64 as [H65 H66].
destruct H66 as [H67 H68].
exact H25.
-------- assert (* Cut *) (euclidean__axioms.neq E C) as H18.
--------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H18.
---------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
---------- apply (@lemma__inequalitysymmetric.lemma__inequalitysymmetric C E H17).
--------- assert (* Cut *) (exists e, (euclidean__axioms.BetS E C e) /\ (euclidean__axioms.Cong C e E C)) as H19.
---------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H19.
----------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
----------- apply (@lemma__extension.lemma__extension E C E C H18 H18).
---------- destruct H19 as [e H20].
destruct H20 as [H21 H22].
assert (* Cut *) (euclidean__axioms.Col E C e) as H23.
----------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H23.
------------ apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------ right.
right.
right.
right.
left.
exact H21.
----------- assert (* Cut *) (euclidean__axioms.neq C e) as H24.
------------ assert (* Cut *) ((euclidean__axioms.neq C e) /\ ((euclidean__axioms.neq E C) /\ (euclidean__axioms.neq E e))) as H24.
------------- apply (@lemma__betweennotequal.lemma__betweennotequal E C e H21).
------------- destruct H24 as [H25 H26].
destruct H26 as [H27 H28].
exact H25.
------------ assert (* Cut *) (euclidean__axioms.neq e C) as H25.
------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H25.
-------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------------- apply (@lemma__inequalitysymmetric.lemma__inequalitysymmetric C e H24).
------------- assert (* Cut *) (euclidean__defs.Par A B E C) as H26.
-------------- assert (* Cut *) ((euclidean__defs.Par B A C E) /\ ((euclidean__defs.Par A B E C) /\ (euclidean__defs.Par B A E C))) as H26.
--------------- apply (@lemma__parallelflip.lemma__parallelflip A B C E H0).
--------------- destruct H26 as [H27 H28].
destruct H28 as [H29 H30].
exact H29.
-------------- assert (* Cut *) (euclidean__defs.Par A B e C) as H27.
--------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H27.
---------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
---------------- apply (@lemma__collinearparallel.lemma__collinearparallel A B e E C H26 H23 H25).
--------------- assert (* Cut *) (euclidean__defs.Par A B C e) as H28.
---------------- assert (* Cut *) ((euclidean__defs.Par B A e C) /\ ((euclidean__defs.Par A B C e) /\ (euclidean__defs.Par B A C e))) as H28.
----------------- apply (@lemma__parallelflip.lemma__parallelflip A B e C H27).
----------------- destruct H28 as [H29 H30].
destruct H30 as [H31 H32].
exact H31.
---------------- assert (* Cut *) (euclidean__axioms.nCol A C D) as H29.
----------------- assert (* Cut *) ((euclidean__axioms.nCol A B C) /\ ((euclidean__axioms.nCol A C D) /\ ((euclidean__axioms.nCol B C D) /\ (euclidean__axioms.nCol A B D)))) as H29.
------------------ apply (@lemma__parallelNC.lemma__parallelNC A B C D H).
------------------ destruct H29 as [H30 H31].
destruct H31 as [H32 H33].
destruct H33 as [H34 H35].
exact H32.
----------------- assert (* Cut *) (euclidean__axioms.nCol A B C) as H30.
------------------ assert (* Cut *) ((euclidean__axioms.nCol A B C) /\ ((euclidean__axioms.nCol A C e) /\ ((euclidean__axioms.nCol B C e) /\ (euclidean__axioms.nCol A B e)))) as H30.
------------------- apply (@lemma__parallelNC.lemma__parallelNC A B C e H28).
------------------- destruct H30 as [H31 H32].
destruct H32 as [H33 H34].
destruct H34 as [H35 H36].
exact H31.
------------------ assert (* Cut *) (euclidean__axioms.nCol B C A) as H31.
------------------- assert (* Cut *) ((euclidean__axioms.nCol B A C) /\ ((euclidean__axioms.nCol B C A) /\ ((euclidean__axioms.nCol C A B) /\ ((euclidean__axioms.nCol A C B) /\ (euclidean__axioms.nCol C B A))))) as H31.
-------------------- apply (@lemma__NCorder.lemma__NCorder A B C H30).
-------------------- destruct H31 as [H32 H33].
destruct H33 as [H34 H35].
destruct H35 as [H36 H37].
destruct H37 as [H38 H39].
exact H34.
------------------- assert (* Cut *) (exists H32, (euclidean__axioms.BetS B H32 m) /\ (euclidean__axioms.BetS A H32 M)) as H32.
-------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H32.
--------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
--------------------- apply (@euclidean__axioms.postulate__Pasch__inner B A C M m H8 H14 H31).
-------------------- destruct H32 as [H33 H34].
destruct H34 as [H35 H36].
assert (* Cut *) (euclidean__axioms.nCol A E C) as H37.
--------------------- assert (* Cut *) ((euclidean__axioms.nCol A B E) /\ ((euclidean__axioms.nCol A E C) /\ ((euclidean__axioms.nCol B E C) /\ (euclidean__axioms.nCol A B C)))) as H37.
---------------------- apply (@lemma__parallelNC.lemma__parallelNC A B E C H26).
---------------------- destruct H37 as [H38 H39].
destruct H39 as [H40 H41].
destruct H41 as [H42 H43].
exact H40.
--------------------- assert (* Cut *) (euclidean__axioms.Col E C e) as H38.
---------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H38.
----------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
----------------------- exact H23.
---------------------- assert (* Cut *) (euclidean__axioms.Col C E e) as H39.
----------------------- assert (* Cut *) ((euclidean__axioms.Col C E e) /\ ((euclidean__axioms.Col C e E) /\ ((euclidean__axioms.Col e E C) /\ ((euclidean__axioms.Col E e C) /\ (euclidean__axioms.Col e C E))))) as H39.
------------------------ apply (@lemma__collinearorder.lemma__collinearorder E C e H38).
------------------------ destruct H39 as [H40 H41].
destruct H41 as [H42 H43].
destruct H43 as [H44 H45].
destruct H45 as [H46 H47].
exact H40.
----------------------- assert (* Cut *) (euclidean__axioms.neq C E) as H40.
------------------------ assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H40.
------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------- exact H17.
------------------------ assert (* Cut *) (euclidean__axioms.nCol C E A) as H41.
------------------------- assert (* Cut *) ((euclidean__axioms.nCol E A C) /\ ((euclidean__axioms.nCol E C A) /\ ((euclidean__axioms.nCol C A E) /\ ((euclidean__axioms.nCol A C E) /\ (euclidean__axioms.nCol C E A))))) as H41.
-------------------------- apply (@lemma__NCorder.lemma__NCorder A E C H37).
-------------------------- destruct H41 as [H42 H43].
destruct H43 as [H44 H45].
destruct H45 as [H46 H47].
destruct H47 as [H48 H49].
exact H49.
------------------------- assert (* Cut *) (E = E) as H42.
-------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H42.
--------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
--------------------------- apply (@logic.eq__refl Point E).
-------------------------- assert (* Cut *) (euclidean__axioms.Col C E E) as H43.
--------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H43.
---------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
---------------------------- right.
right.
left.
exact H42.
--------------------------- assert (* Cut *) (euclidean__axioms.neq E e) as H44.
---------------------------- assert (* Cut *) ((euclidean__axioms.neq C e) /\ ((euclidean__axioms.neq E C) /\ (euclidean__axioms.neq E e))) as H44.
----------------------------- apply (@lemma__betweennotequal.lemma__betweennotequal E C e H21).
----------------------------- destruct H44 as [H45 H46].
destruct H46 as [H47 H48].
exact H48.
---------------------------- assert (* Cut *) (euclidean__axioms.nCol E e A) as H45.
----------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H45.
------------------------------ apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------ apply (@euclidean__tactics.nCol__notCol E e A).
-------------------------------apply (@euclidean__tactics.nCol__not__Col E e A).
--------------------------------apply (@lemma__NChelper.lemma__NChelper C E A E e H41 H43 H39 H44).

----------------------------- assert (* Cut *) (exists F, (euclidean__axioms.BetS A F e) /\ (euclidean__axioms.BetS E m F)) as H46.
------------------------------ assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H46.
------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------- apply (@euclidean__axioms.postulate__Pasch__outer A E C m e H14 H21 H45).
------------------------------ destruct H46 as [F H47].
destruct H47 as [H48 H49].
assert (* Cut *) (euclidean__axioms.BetS e F A) as H50.
------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H50.
-------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------------------------------- apply (@euclidean__axioms.axiom__betweennesssymmetry A F e H48).
------------------------------- assert (* Cut *) (euclidean__axioms.Col E m F) as H51.
-------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H51.
--------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
--------------------------------- right.
right.
right.
right.
left.
exact H49.
-------------------------------- assert (* Cut *) (euclidean__axioms.Col E m B) as H52.
--------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H52.
---------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
---------------------------------- right.
right.
right.
right.
left.
exact H15.
--------------------------------- assert (* Cut *) (euclidean__axioms.Col m E F) as H53.
---------------------------------- assert (* Cut *) ((euclidean__axioms.Col m E F) /\ ((euclidean__axioms.Col m F E) /\ ((euclidean__axioms.Col F E m) /\ ((euclidean__axioms.Col E F m) /\ (euclidean__axioms.Col F m E))))) as H53.
----------------------------------- apply (@lemma__collinearorder.lemma__collinearorder E m F H51).
----------------------------------- destruct H53 as [H54 H55].
destruct H55 as [H56 H57].
destruct H57 as [H58 H59].
destruct H59 as [H60 H61].
exact H54.
---------------------------------- assert (* Cut *) (euclidean__axioms.Col m E B) as H54.
----------------------------------- assert (* Cut *) ((euclidean__axioms.Col m E B) /\ ((euclidean__axioms.Col m B E) /\ ((euclidean__axioms.Col B E m) /\ ((euclidean__axioms.Col E B m) /\ (euclidean__axioms.Col B m E))))) as H54.
------------------------------------ apply (@lemma__collinearorder.lemma__collinearorder E m B H52).
------------------------------------ destruct H54 as [H55 H56].
destruct H56 as [H57 H58].
destruct H58 as [H59 H60].
destruct H60 as [H61 H62].
exact H55.
----------------------------------- assert (* Cut *) (euclidean__axioms.neq E m) as H55.
------------------------------------ assert (* Cut *) ((euclidean__axioms.neq m F) /\ ((euclidean__axioms.neq E m) /\ (euclidean__axioms.neq E F))) as H55.
------------------------------------- apply (@lemma__betweennotequal.lemma__betweennotequal E m F H49).
------------------------------------- destruct H55 as [H56 H57].
destruct H57 as [H58 H59].
exact H58.
------------------------------------ assert (* Cut *) (euclidean__axioms.neq m E) as H56.
------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H56.
-------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------------------------------------- apply (@lemma__inequalitysymmetric.lemma__inequalitysymmetric E m H55).
------------------------------------- assert (* Cut *) (euclidean__axioms.Col E F B) as H57.
-------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H57.
--------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
--------------------------------------- apply (@euclidean__tactics.not__nCol__Col E F B).
----------------------------------------intro H58.
apply (@euclidean__tactics.Col__nCol__False E F B H58).
-----------------------------------------apply (@lemma__collinear4.lemma__collinear4 m E F B H53 H54 H56).

-------------------------------------- assert (* Cut *) (euclidean__axioms.Col E B F) as H58.
--------------------------------------- assert (* Cut *) ((euclidean__axioms.Col F E B) /\ ((euclidean__axioms.Col F B E) /\ ((euclidean__axioms.Col B E F) /\ ((euclidean__axioms.Col E B F) /\ (euclidean__axioms.Col B F E))))) as H58.
---------------------------------------- apply (@lemma__collinearorder.lemma__collinearorder E F B H57).
---------------------------------------- destruct H58 as [H59 H60].
destruct H60 as [H61 H62].
destruct H62 as [H63 H64].
destruct H64 as [H65 H66].
exact H65.
--------------------------------------- assert (* Cut *) (euclidean__axioms.neq e E) as H59.
---------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H59.
----------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
----------------------------------------- apply (@lemma__inequalitysymmetric.lemma__inequalitysymmetric E e H44).
---------------------------------------- assert (* Cut *) (E = E) as H60.
----------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H60.
------------------------------------------ apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------ exact H42.
----------------------------------------- assert (* Cut *) (euclidean__axioms.Col e E E) as H61.
------------------------------------------ assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H61.
------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------- right.
right.
left.
exact H60.
------------------------------------------ assert (* Cut *) (B = B) as H62.
------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H62.
-------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------------------------------------------- apply (@logic.eq__refl Point B).
------------------------------------------- assert (* Cut *) (euclidean__axioms.Col B B A) as H63.
-------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H63.
--------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
--------------------------------------------- left.
exact H62.
-------------------------------------------- assert (* Cut *) (euclidean__axioms.neq B A) as H64.
--------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H64.
---------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
---------------------------------------------- apply (@lemma__inequalitysymmetric.lemma__inequalitysymmetric A B H2).
--------------------------------------------- assert (* Cut *) (euclidean__defs.Par A B C E) as H65.
---------------------------------------------- assert (* Cut *) ((euclidean__defs.Par B A C e) /\ ((euclidean__defs.Par A B e C) /\ (euclidean__defs.Par B A e C))) as H65.
----------------------------------------------- apply (@lemma__parallelflip.lemma__parallelflip A B C e H28).
----------------------------------------------- destruct H65 as [H66 H67].
destruct H67 as [H68 H69].
exact H0.
---------------------------------------------- assert (* Cut *) (euclidean__axioms.Col C E e) as H66.
----------------------------------------------- assert (* Cut *) ((euclidean__axioms.Col B B A) /\ ((euclidean__axioms.Col B A B) /\ ((euclidean__axioms.Col A B B) /\ ((euclidean__axioms.Col B A B) /\ (euclidean__axioms.Col A B B))))) as H66.
------------------------------------------------ apply (@lemma__collinearorder.lemma__collinearorder B B A H63).
------------------------------------------------ destruct H66 as [H67 H68].
destruct H68 as [H69 H70].
destruct H70 as [H71 H72].
destruct H72 as [H73 H74].
exact H39.
----------------------------------------------- assert (* Cut *) (euclidean__defs.Par A B e E) as H67.
------------------------------------------------ assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H67.
------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------------- apply (@lemma__collinearparallel.lemma__collinearparallel A B e C E H65 H66 H59).
------------------------------------------------ assert (* Cut *) (euclidean__defs.Par e E A B) as H68.
------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H68.
-------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------------------------------------------------- apply (@lemma__parallelsymmetric.lemma__parallelsymmetric A B e E H67).
------------------------------------------------- assert (* Cut *) (euclidean__defs.Par e E B A) as H69.
-------------------------------------------------- assert (* Cut *) ((euclidean__defs.Par E e A B) /\ ((euclidean__defs.Par e E B A) /\ (euclidean__defs.Par E e B A))) as H69.
--------------------------------------------------- apply (@lemma__parallelflip.lemma__parallelflip e E A B H68).
--------------------------------------------------- destruct H69 as [H70 H71].
destruct H71 as [H72 H73].
exact H72.
-------------------------------------------------- assert (* Cut *) (~(euclidean__defs.Meet e E B A)) as H70.
--------------------------------------------------- assert (exists U V u v X, (euclidean__axioms.neq e E) /\ ((euclidean__axioms.neq B A) /\ ((euclidean__axioms.Col e E U) /\ ((euclidean__axioms.Col e E V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col B A u) /\ ((euclidean__axioms.Col B A v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet e E B A)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H70 by exact H69.
assert (exists U V u v X, (euclidean__axioms.neq e E) /\ ((euclidean__axioms.neq B A) /\ ((euclidean__axioms.Col e E U) /\ ((euclidean__axioms.Col e E V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col B A u) /\ ((euclidean__axioms.Col B A v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet e E B A)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp0 by exact H70.
destruct __TmpHyp0 as [x H71].
destruct H71 as [x0 H72].
destruct H72 as [x1 H73].
destruct H73 as [x2 H74].
destruct H74 as [x3 H75].
destruct H75 as [H76 H77].
destruct H77 as [H78 H79].
destruct H79 as [H80 H81].
destruct H81 as [H82 H83].
destruct H83 as [H84 H85].
destruct H85 as [H86 H87].
destruct H87 as [H88 H89].
destruct H89 as [H90 H91].
destruct H91 as [H92 H93].
destruct H93 as [H94 H95].
assert (exists U V u v X, (euclidean__axioms.neq e E) /\ ((euclidean__axioms.neq A B) /\ ((euclidean__axioms.Col e E U) /\ ((euclidean__axioms.Col e E V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col A B u) /\ ((euclidean__axioms.Col A B v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet e E A B)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H96 by exact H68.
assert (exists U V u v X, (euclidean__axioms.neq e E) /\ ((euclidean__axioms.neq A B) /\ ((euclidean__axioms.Col e E U) /\ ((euclidean__axioms.Col e E V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col A B u) /\ ((euclidean__axioms.Col A B v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet e E A B)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp1 by exact H96.
destruct __TmpHyp1 as [x4 H97].
destruct H97 as [x5 H98].
destruct H98 as [x6 H99].
destruct H99 as [x7 H100].
destruct H100 as [x8 H101].
destruct H101 as [H102 H103].
destruct H103 as [H104 H105].
destruct H105 as [H106 H107].
destruct H107 as [H108 H109].
destruct H109 as [H110 H111].
destruct H111 as [H112 H113].
destruct H113 as [H114 H115].
destruct H115 as [H116 H117].
destruct H117 as [H118 H119].
destruct H119 as [H120 H121].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq e E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col e E u) /\ ((euclidean__axioms.Col e E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B e E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H122 by exact H67.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq e E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col e E u) /\ ((euclidean__axioms.Col e E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B e E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp2 by exact H122.
destruct __TmpHyp2 as [x9 H123].
destruct H123 as [x10 H124].
destruct H124 as [x11 H125].
destruct H125 as [x12 H126].
destruct H126 as [x13 H127].
destruct H127 as [H128 H129].
destruct H129 as [H130 H131].
destruct H131 as [H132 H133].
destruct H133 as [H134 H135].
destruct H135 as [H136 H137].
destruct H137 as [H138 H139].
destruct H139 as [H140 H141].
destruct H141 as [H142 H143].
destruct H143 as [H144 H145].
destruct H145 as [H146 H147].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H148 by exact H65.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp3 by exact H148.
destruct __TmpHyp3 as [x14 H149].
destruct H149 as [x15 H150].
destruct H150 as [x16 H151].
destruct H151 as [x17 H152].
destruct H152 as [x18 H153].
destruct H153 as [H154 H155].
destruct H155 as [H156 H157].
destruct H157 as [H158 H159].
destruct H159 as [H160 H161].
destruct H161 as [H162 H163].
destruct H163 as [H164 H165].
destruct H165 as [H166 H167].
destruct H167 as [H168 H169].
destruct H169 as [H170 H171].
destruct H171 as [H172 H173].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C e) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C e u) /\ ((euclidean__axioms.Col C e v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C e)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H174 by exact H28.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C e) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C e u) /\ ((euclidean__axioms.Col C e v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C e)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp4 by exact H174.
destruct __TmpHyp4 as [x19 H175].
destruct H175 as [x20 H176].
destruct H176 as [x21 H177].
destruct H177 as [x22 H178].
destruct H178 as [x23 H179].
destruct H179 as [H180 H181].
destruct H181 as [H182 H183].
destruct H183 as [H184 H185].
destruct H185 as [H186 H187].
destruct H187 as [H188 H189].
destruct H189 as [H190 H191].
destruct H191 as [H192 H193].
destruct H193 as [H194 H195].
destruct H195 as [H196 H197].
destruct H197 as [H198 H199].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq e C) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col e C u) /\ ((euclidean__axioms.Col e C v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B e C)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H200 by exact H27.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq e C) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col e C u) /\ ((euclidean__axioms.Col e C v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B e C)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp5 by exact H200.
destruct __TmpHyp5 as [x24 H201].
destruct H201 as [x25 H202].
destruct H202 as [x26 H203].
destruct H203 as [x27 H204].
destruct H204 as [x28 H205].
destruct H205 as [H206 H207].
destruct H207 as [H208 H209].
destruct H209 as [H210 H211].
destruct H211 as [H212 H213].
destruct H213 as [H214 H215].
destruct H215 as [H216 H217].
destruct H217 as [H218 H219].
destruct H219 as [H220 H221].
destruct H221 as [H222 H223].
destruct H223 as [H224 H225].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq E C) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col E C u) /\ ((euclidean__axioms.Col E C v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B E C)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H226 by exact H26.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq E C) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col E C u) /\ ((euclidean__axioms.Col E C v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B E C)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp6 by exact H226.
destruct __TmpHyp6 as [x29 H227].
destruct H227 as [x30 H228].
destruct H228 as [x31 H229].
destruct H229 as [x32 H230].
destruct H230 as [x33 H231].
destruct H231 as [H232 H233].
destruct H233 as [H234 H235].
destruct H235 as [H236 H237].
destruct H237 as [H238 H239].
destruct H239 as [H240 H241].
destruct H241 as [H242 H243].
destruct H243 as [H244 H245].
destruct H245 as [H246 H247].
destruct H247 as [H248 H249].
destruct H249 as [H250 H251].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H252 by exact H0.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C E) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C E u) /\ ((euclidean__axioms.Col C E v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C E)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp7 by exact H252.
destruct __TmpHyp7 as [x34 H253].
destruct H253 as [x35 H254].
destruct H254 as [x36 H255].
destruct H255 as [x37 H256].
destruct H256 as [x38 H257].
destruct H257 as [H258 H259].
destruct H259 as [H260 H261].
destruct H261 as [H262 H263].
destruct H263 as [H264 H265].
destruct H265 as [H266 H267].
destruct H267 as [H268 H269].
destruct H269 as [H270 H271].
destruct H271 as [H272 H273].
destruct H273 as [H274 H275].
destruct H275 as [H276 H277].
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as H278 by exact H.
assert (exists U V u v X, (euclidean__axioms.neq A B) /\ ((euclidean__axioms.neq C D) /\ ((euclidean__axioms.Col A B U) /\ ((euclidean__axioms.Col A B V) /\ ((euclidean__axioms.neq U V) /\ ((euclidean__axioms.Col C D u) /\ ((euclidean__axioms.Col C D v) /\ ((euclidean__axioms.neq u v) /\ ((~(euclidean__defs.Meet A B C D)) /\ ((euclidean__axioms.BetS U X v) /\ (euclidean__axioms.BetS u X V))))))))))) as __TmpHyp8 by exact H278.
destruct __TmpHyp8 as [x39 H279].
destruct H279 as [x40 H280].
destruct H280 as [x41 H281].
destruct H281 as [x42 H282].
destruct H282 as [x43 H283].
destruct H283 as [H284 H285].
destruct H285 as [H286 H287].
destruct H287 as [H288 H289].
destruct H289 as [H290 H291].
destruct H291 as [H292 H293].
destruct H293 as [H294 H295].
destruct H295 as [H296 H297].
destruct H297 as [H298 H299].
destruct H299 as [H300 H301].
destruct H301 as [H302 H303].
exact H92.
--------------------------------------------------- assert (* Cut *) (euclidean__axioms.BetS E F B) as H71.
---------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H71.
----------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
----------------------------------------------------- apply (@lemma__collinearbetween.lemma__collinearbetween e E B A E B F H61 H63 H59 H64 H59 H64 H70 H50 H58).
---------------------------------------------------- assert (* Cut *) (euclidean__axioms.BetS B F E) as H72.
----------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H72.
------------------------------------------------------ apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------------------ apply (@euclidean__axioms.axiom__betweennesssymmetry E F B H71).
----------------------------------------------------- assert (* Cut *) (euclidean__axioms.BetS e C E) as H73.
------------------------------------------------------ assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H73.
------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------------------- apply (@euclidean__axioms.axiom__betweennesssymmetry E C e H21).
------------------------------------------------------ assert (* Cut *) (euclidean__axioms.nCol B E C) as H74.
------------------------------------------------------- assert (* Cut *) ((euclidean__axioms.nCol A B E) /\ ((euclidean__axioms.nCol A E C) /\ ((euclidean__axioms.nCol B E C) /\ (euclidean__axioms.nCol A B C)))) as H74.
-------------------------------------------------------- apply (@lemma__parallelNC.lemma__parallelNC A B E C H26).
-------------------------------------------------------- destruct H74 as [H75 H76].
destruct H76 as [H77 H78].
destruct H78 as [H79 H80].
exact H79.
------------------------------------------------------- assert (* Cut *) (euclidean__axioms.nCol E C B) as H75.
-------------------------------------------------------- assert (* Cut *) ((euclidean__axioms.nCol E B C) /\ ((euclidean__axioms.nCol E C B) /\ ((euclidean__axioms.nCol C B E) /\ ((euclidean__axioms.nCol B C E) /\ (euclidean__axioms.nCol C E B))))) as H75.
--------------------------------------------------------- apply (@lemma__NCorder.lemma__NCorder B E C H74).
--------------------------------------------------------- destruct H75 as [H76 H77].
destruct H77 as [H78 H79].
destruct H79 as [H80 H81].
destruct H81 as [H82 H83].
exact H78.
-------------------------------------------------------- assert (* Cut *) (euclidean__axioms.Col E C e) as H76.
--------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H76.
---------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
---------------------------------------------------------- exact H38.
--------------------------------------------------------- assert (* Cut *) (E = E) as H77.
---------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H77.
----------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
----------------------------------------------------------- exact H60.
---------------------------------------------------------- assert (* Cut *) (euclidean__axioms.Col E C E) as H78.
----------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H78.
------------------------------------------------------------ apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------------------------ right.
left.
exact H77.
----------------------------------------------------------- assert (* Cut *) (euclidean__axioms.nCol E e B) as H79.
------------------------------------------------------------ assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H79.
------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------------------------- apply (@euclidean__tactics.nCol__notCol E e B).
--------------------------------------------------------------apply (@euclidean__tactics.nCol__not__Col E e B).
---------------------------------------------------------------apply (@lemma__NChelper.lemma__NChelper E C B E e H75 H78 H76 H44).

------------------------------------------------------------ assert (* Cut *) (euclidean__axioms.nCol B E e) as H80.
------------------------------------------------------------- assert (* Cut *) ((euclidean__axioms.nCol e E B) /\ ((euclidean__axioms.nCol e B E) /\ ((euclidean__axioms.nCol B E e) /\ ((euclidean__axioms.nCol E B e) /\ (euclidean__axioms.nCol B e E))))) as H80.
-------------------------------------------------------------- apply (@lemma__NCorder.lemma__NCorder E e B H79).
-------------------------------------------------------------- destruct H80 as [H81 H82].
destruct H82 as [H83 H84].
destruct H84 as [H85 H86].
destruct H86 as [H87 H88].
exact H85.
------------------------------------------------------------- assert (* Cut *) (exists K, (euclidean__axioms.BetS B K C) /\ (euclidean__axioms.BetS e K F)) as H81.
-------------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H81.
--------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
--------------------------------------------------------------- apply (@euclidean__axioms.postulate__Pasch__inner B e E F C H72 H73 H80).
-------------------------------------------------------------- destruct H81 as [K H82].
destruct H82 as [H83 H84].
assert (* Cut *) (euclidean__axioms.BetS e F A) as H85.
--------------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H85.
---------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
---------------------------------------------------------------- exact H50.
--------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.BetS e K A) as H86.
---------------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H86.
----------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
----------------------------------------------------------------- apply (@lemma__3__6b.lemma__3__6b e K F A H84 H85).
---------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.BetS A K e) as H87.
----------------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H87.
------------------------------------------------------------------ apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------------------------------ apply (@euclidean__axioms.axiom__betweennesssymmetry e K A H86).
----------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.neq A e) as H88.
------------------------------------------------------------------ assert (* Cut *) ((euclidean__axioms.neq K e) /\ ((euclidean__axioms.neq A K) /\ (euclidean__axioms.neq A e))) as H88.
------------------------------------------------------------------- apply (@lemma__betweennotequal.lemma__betweennotequal A K e H87).
------------------------------------------------------------------- destruct H88 as [H89 H90].
destruct H90 as [H91 H92].
exact H92.
------------------------------------------------------------------ assert (* Cut *) (euclidean__defs.CR A e B C) as H89.
------------------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H89.
-------------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------------------------------------------------------------------- exists K.
split.
--------------------------------------------------------------------- exact H87.
--------------------------------------------------------------------- exact H83.
------------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.Col C D e) as H90.
-------------------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H90.
--------------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
--------------------------------------------------------------------- apply (@euclidean__tactics.not__nCol__Col C D e).
----------------------------------------------------------------------intro H91.
apply (@euclidean__tactics.Col__nCol__False C D e H91).
-----------------------------------------------------------------------apply (@lemma__Playfairhelper.lemma__Playfairhelper A B C D e H H28 H1 H89).

-------------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.Col e C D) as H91.
--------------------------------------------------------------------- assert (* Cut *) ((euclidean__axioms.Col D C e) /\ ((euclidean__axioms.Col D e C) /\ ((euclidean__axioms.Col e C D) /\ ((euclidean__axioms.Col C e D) /\ (euclidean__axioms.Col e D C))))) as H91.
---------------------------------------------------------------------- apply (@lemma__collinearorder.lemma__collinearorder C D e H90).
---------------------------------------------------------------------- destruct H91 as [H92 H93].
destruct H93 as [H94 H95].
destruct H95 as [H96 H97].
destruct H97 as [H98 H99].
exact H96.
--------------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.Col e C E) as H92.
---------------------------------------------------------------------- assert (* Cut *) ((euclidean__axioms.Col C E e) /\ ((euclidean__axioms.Col C e E) /\ ((euclidean__axioms.Col e E C) /\ ((euclidean__axioms.Col E e C) /\ (euclidean__axioms.Col e C E))))) as H92.
----------------------------------------------------------------------- apply (@lemma__collinearorder.lemma__collinearorder E C e H76).
----------------------------------------------------------------------- destruct H92 as [H93 H94].
destruct H94 as [H95 H96].
destruct H96 as [H97 H98].
destruct H98 as [H99 H100].
exact H100.
---------------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.neq C e) as H93.
----------------------------------------------------------------------- assert (* Cut *) ((euclidean__axioms.neq K e) /\ ((euclidean__axioms.neq A K) /\ (euclidean__axioms.neq A e))) as H93.
------------------------------------------------------------------------ apply (@lemma__betweennotequal.lemma__betweennotequal A K e H87).
------------------------------------------------------------------------ destruct H93 as [H94 H95].
destruct H95 as [H96 H97].
exact H24.
----------------------------------------------------------------------- assert (* Cut *) (euclidean__axioms.neq e C) as H94.
------------------------------------------------------------------------ assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H94.
------------------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
------------------------------------------------------------------------- exact H25.
------------------------------------------------------------------------ assert (* Cut *) (euclidean__axioms.Col C D E) as H95.
------------------------------------------------------------------------- assert (* Cut *) ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) as H95.
-------------------------------------------------------------------------- apply (@euclidean__tactics.NNPP ((euclidean__defs.CR A E B C) \/ (euclidean__defs.CR A C E B)) H4).
-------------------------------------------------------------------------- apply (@euclidean__tactics.not__nCol__Col C D E).
---------------------------------------------------------------------------intro H96.
apply (@euclidean__tactics.Col__nCol__False C D E H96).
----------------------------------------------------------------------------apply (@lemma__collinear4.lemma__collinear4 e C D E H91 H92 H94).

------------------------------------------------------------------------- exact H95.
---- exact H9.
Qed.