import Euclid.tarski_3
open classical set
namespace Euclidean_plane
variables {point : Type} [Euclidean_plane point]

local attribute [instance] prop_decidable

-- Planes and Half-planes

def Bl (a : point) (A : set point) (b : point) : Prop := line A ∧ a ∉ A ∧ b ∉ A ∧ ∃ t, t ∈ A ∧ B a t b

theorem nine1 {a p : point} {A : set point} : line A → a ∈ A → p ∉ A → Bl p A (S a p) :=
λ h h1 h2, ⟨h, h2, (λ h_2, h2 ((seven24 h h1).2 h_2)), a, h1, (seven5 a p).1⟩

theorem nine2 {a b : point} {A : set point} : Bl a A b → a ≠ b :=
begin
intros h h1,
subst h1,
unfold Bl at h,
apply h.2.1,
cases h.2.2.2 with x hx,
suffices : a = x,
  rw this,
  exact hx.1,
exact bet_same hx.2
end

theorem Bl.symm {a b : point} {A : set point} : Bl a A b → Bl b A a :=
begin
unfold Bl,
intro h,
split,
  exact h.1,
split,
  exact h.2.2.1,
split,
  exact h.2.1,
cases h.2.2.2 with t ht,
constructor,
split,
  exact ht.1,
exact ht.2.symm
end

lemma nine3 {a c m r : point} {A : set point} : Bl a A c → m ∈ A → M a m c → r ∈ A →
∀ {b}, sided r a b → Bl b A c :=
begin
unfold Bl,
intros h h1 h2 h3 b hb,
cases hb.2.2,
  have h4 := (seven15 m).1 h_1,
  have h5 := (seven6 h2).symm,
  rw h5 at h4,
  have h6 := seven5 m b,
  cases pasch h6.1 h4 with t ht,
  split,
    exact h.1,
  split,
    intro h_2,
    apply h.2.1,
    exact six27 h.1 h3 h_2 h_1,
  split,
    exact h.2.2.1,
  existsi t,
  split,
    have h_2 := (seven24 h.1 h1).1 h3,
    exact six27 h.1 h1 h_2 ht.1,
  exact ht.2.symm,
cases pasch h_1 h2.1.symm with t ht,
split,
  exact h.1,
split,
  intro h_2,
  apply h.2.1,
  have h_3 := six18 h.1 hb.2.1.symm h3 h_2,
  rw h_3,
  left,
  exact h_1,
split,
  exact h.2.2.1,
existsi t,
split,
  exact six27 h.1 h1 h3 ht.2,
exact ht.1
end

lemma nine4a {a c m r s t : point} {A : set point} (h3 : r ∈ A) (h4 : A ⊥ l a r) (h5 : s ∈ A) (h6 : A ⊥ l c s)
(h2 : Bl a A c) (ht : t ∈ A ∧ B a t c) (h_1 : ¬r = s) (h_2 : distle s c r a) :
M r m s → ∀ {u}, (sided r u a ↔ sided s (S m u) c) :=
begin
unfold Bl at h2,
have g2 := six18 h2.1 (ne.symm h_1) h5 h3,
have g3 : (l s r) ⊥ (l c s),
  rwa g2 at h6,
have g4 : (l s r) ⊥ (l a r),
  rwa g2 at h4,
have g5 : col s r t,
  rw g2 at ht,
  exact ht.1,
cases h_2 with b gb,
cases eight24 g3.symm g4.symm g5 ht.2.symm gb.1 gb.2 with m' hm,
intro h_2,
have h_3 : m' = m,
  exact unique_of_exists_unique (eight22 r s) hm.1.symm h_2,
subst m',
intro u,
have h_3 : sided r a b,
    split,
      exact six13 (eight14e h4).2,
    split,
      intro h_4,
      subst b,
      apply six13 (eight14e h6).2,
      exact id_eqd (two4 gb.2),
    right,
    exact gb.1,
split,
  intro h_4,
  have h_5 := sided.trans h_4 h_3,
  split,
    intro h_6,
    have h_7 := seven5 m u,
    rw h_6 at h_7,
    apply h_4.1,
    exact unique_of_exists_unique (seven4 m s) h_7.symm hm.1,
  split,
    exact six13 (eight14e h6).2,
  have h_6 := seven6 h_2,
  rw h_6,
  have h_7 := seven6 hm.2.symm,
  rw h_7,
  cases h_5.2.2,
    left,
    exact (seven15 m).1 h,
  right,
  exact (seven15 m).1 h,
intro h_4,
suffices : sided r u b,
  exact sided.trans this h_3.symm,
have h_5 := seven6 h_2,
have h_6 := seven6 hm.2.symm,
rw [h_5, h_6] at h_4,
split,
  intro h_7,
  subst u,
  apply h_4.1,
  refl,
split,
  exact h_3.2.1,
cases h_4.2.2,
  left,
  exact (seven15 m).2 h,
right,
exact (seven15 m).2 h
end

lemma nine4b {a c r s t : point} {A : set point} (h3 : r ∈ A) (h4 : A ⊥ l a r) (h5 : s ∈ A) (h6 : A ⊥ l c s)
(h2 : Bl a A c) (ht : t ∈ A ∧ B a t c) (h_1 : ¬r = s) (h_2 : distle s c r a) :
∀ {u v}, sided r u a → sided s v c → Bl u A v :=
begin
have g2 := six18 h2.1 (ne.symm h_1) h5 h3,
have g3 : (l s r) ⊥ (l c s),
  rwa g2 at h6,
have g4 : (l s r) ⊥ (l a r),
  rwa g2 at h4,
have g5 : col s r t,
  rw g2 at ht,
  exact ht.1,
cases h_2 with b gb,
cases eight24 g3.symm g4.symm g5 ht.2.symm gb.1 gb.2 with m hm,
unfold Bl at h2,
intros u v hu hv,
have h7 := nine4a h3 h4 h5 h6 h2 ht h_1 ⟨b, gb⟩ hm.1.symm,
have h8 := (h7).1 hu,
have h9 := sided.trans h8 hv.symm,
have h10 : u ∉ A,
  intro h_2,
  have h_3 := six18 h2.1 hu.1 h_2 h3,
  apply h2.2.1,
  rw h_3,
  cases hu.2.2 with,
    right, right,
    exact h.symm,
  right, left,
  exact h,
have h11 : m ∈ A,
  rw g2,
  right, left,
  exact hm.1.1.symm,
have h12 : Bl (S m u) A u,
  unfold Bl,
  split,
    exact h2.1,
  split,
    intro h_2,
    apply h10,
    exact (seven24 h2.1 h11).2 h_2,
  split,
    exact h10,
  existsi m,
  split,
    exact h11,
  exact (seven5 m u).1.symm,
apply Bl.symm,
exact nine3 h12 h11 (seven5 m u).symm h5 h9
end

theorem nine4 {a c m r s : point} {A : set point} : Bl a A c → r ∈ A → perp A (l a r) → s ∈ A → perp A (l c s) →
(M r m s → ∀ {u}, (sided r u a ↔ sided s (S m u) c)) ∧ ∀ {u v}, sided r u a → sided s v c → Bl u A v :=
begin
intros h2 h3 h4 h5 h6,
cases h2.2.2.2 with t ht,
cases em (r = s),
  have h_2 : xperp r (l a r) A,
    apply eight14c.2,
    split,
      exact h4.symm,
    split,
      exact (eight14e h4).2,
    split,
      exact h2.1,
    split,
      exact eight14a h4.symm,
    simp,
    exact h3,
  have h_3 : xperp s (l c s) A,
    apply eight14c.2,
    split,
      exact h6.symm,
    split,
      exact (eight14e h6).2,
    split,
      exact h2.1,
    split,
      exact eight14a h6.symm,
    simp,
    exact h5,
  have h_4 := h_2.2.2.2.2 (six17a a r) ht.1,
  have h_5 := h_3.2.2.2.2 (six17a c s) ht.1,
  subst h,
  have h_6 : r = t,
    exact eight6 h_4 h_5 ht.2,
  subst h_6,
  split,
    intros h7 u,
    have h_7 : m = r,
      exact (bet_same h7.1).symm,
    rw h_7,
    have h8 := seven5 r u,
    apply iff.intro,
      intro hu,
      unfold sided,
      split,
        intro h_9,
        apply hu.1,
        exact seven9 (eq.trans h_9 (seven11 r).symm),
      split,
        exact (six13 (eight14e h6).2),
      cases hu.2.2,
        have h7 : B u r c,
          exact three6a h.symm ht.2,
        exact five2 hu.1 h8.1 h7,
      have h7 : B u r c,
        exact three7a h.symm ht.2 (six13 (eight14e h4).2),
      exact five2 hu.1 h8.1 h7,
    intro hu,
    unfold sided,
    split,
      intro h_8,
      apply hu.1,
      simp [h_8],
    split,
      exact (six13 (eight14e h4).2),
    cases hu.2.2,
      have h7 : B (S r u) r a,
        exact three6a h.symm ht.2.symm,
      exact five2 hu.1 h8.1.symm h7,
    have h7 : B (S r u) r a,
      exact three7a h.symm ht.2.symm (six13 (eight14e h6).2),
    exact five2 hu.1 h8.1.symm h7,
  intros u v hu hv,
  unfold Bl,
  split,
    exact h2.1,
  split,
    intro h_6,
    have h_7 := six18 h2.1 hu.1 h_6 ht.1,
    rw h_7 at h2,
    exact h2.2.1 (six4.1 hu).1,
  split,
    intro h_6,
    have h_7 := six18 h2.1 hv.1 h_6 ht.1,
    rw h_7 at h2,
    exact h2.2.2.1 (six4.1 hv).1,
  existsi r,
  split,
    exact ht.1,
  exact six8 hu hv ht.2,
cases five10 s c r a,
  split,
    apply nine4a;
    assumption,
  apply nine4b;
  assumption,
have g2 := six18 h2.1 h h3 h5,
have g3 : (l r s) ⊥ (l c s),
  rwa g2 at h6,
have g4 : (l r s) ⊥ (l a r),
  rwa g2 at h4,
have g5 : col r s t,
  rw g2 at ht,
  exact ht.1,
cases h_1 with b gb,
cases eight24 g4.symm g3.symm g5 ht.2 gb.1 gb.2 with m' hm,
split,
  intro h_2,
  have h_3 := unique_of_exists_unique (eight22 r s) hm.1 h_2,
    subst m',
  intro u,
  suffices : sided r (S m (S m u)) a ↔ sided s (S m u) c,
    simp at this,
    exact this,
  exact (nine4a h5 h6 h3 h4 h2.symm ⟨ht.1, ht.2.symm⟩ (ne.symm h) ⟨b, gb⟩ hm.1.symm).symm,
intros u v hu hv,
apply Bl.symm,
apply nine4b h5 h6 h3 h4 h2.symm ⟨ht.1, ht.2.symm⟩ (ne.symm h) ⟨b, gb⟩ hv hu
end

theorem nine5 {a b c r : point} {A : set point} : Bl a A c → r ∈ A → sided r a b → Bl b A c :=
begin
intros h h1 h2,
have h3 : b ∉ A,
  intro h_1,
  have h_2 := six18 h.1 h2.2.1.symm h1 h_1,
  apply h.2.1,
  rw h_2,
  exact (four11 (six4.1 h2).1).2.2.1,
cases eight17 h.1 h.2.1 with x hx,
cases eight17 h.1 h3 with y hy,
cases eight17 h.1 h.2.2.1 with z hz,
cases eight22 x z with m hm,
have h4 := six27 h.1 hx.1.1 hz.1.1 hm.1.1,
have h5 : a ≠ x,
  intro h_1,
  apply h.2.1,
  rw h_1,
  exact hx.1.1,
have h6 : b ≠ y,
  intro h_1,
  apply h3,
  rw h_1,
  exact hy.1.1,
have h7 : c ≠ z,
  intro h_1,
  apply h.2.2.1,
  rw h_1,
  exact hz.1.1,
have h8 := nine4 h hx.1.1 hx.1.2 hz.1.1 hz.1.2,
have h9 := (h8.1 hm.1).1 (six5 h5),
have h10 := h8.2 (six5 h5) h9,
have h11 := nine3 h10 h4 (seven5 m a) h1 h2,
have h12 : (S m a) ≠ z,
  intro h_1,
  apply h5,
  apply unique_of_exists_unique (seven8 m z) h_1,
  exact (seven6 hm.1).symm,
have h13 : l c z = l (S m a) z,
  apply six18 (six14 h7),
      exact h12,
    exact (four11 (six4.1 h9).1).2.2.2.2,
  simp,
have h14 := hz.1,
rw h13 at h14,
have h15 := (nine4 h11 hy.1.1 hy.1.2 h14.1 h14.2).2 (six5 h6) h9.symm,
exact h15,
exact a
end

theorem nine6 {a b c p q : point} : B a c p → B b q c → ∃ x, B a x b ∧ B p q x :=
begin
intros h h1,
cases em (col p q c),
  cases em (B p q c),
    have h_3 := three6b h_2 h.symm,
    constructor,
    split,
      exact three3 a b,
    exact h_3,
  have h_3 : sided q p c,
    exact six4.2 ⟨h_1, h_2⟩,
  constructor,
  split,
    exact three1 a b,
  exact (six6 h1 h_3.symm).symm,
cases em (b ∈ l p q),
  suffices : b = q,
    constructor,
    split,
      exact three1 a b,
    rw this,
    exact three1 p q,
  by_contradiction h_3,
  apply h_1,
  suffices : c ∈ l p q,
    exact this,
  suffices : l p q = l b q,
    rw this,
    left,
    exact h1,
  exact six18 (six14 (six26 h_1).1) h_3 h_2 (six17b p q),
have h3 : Bl c (l p q) b,
  split,
    exact six14 (six26 h_1).1,
  split,
    exact h_1,
  split,
    exact h_2,
  constructor,
  split,
    exact (six17b p q),
  exact h1.symm,
have h4 : sided p c a,
  split,
    exact (six26 h_1).2.2.symm,
  split,
    intro h_1,
    subst h_1,
    apply (six26 h_1).2.2,
    exact bet_same h,
  left,
  exact h.symm,
have h5 := nine5 h3 (six17a p q) h4,
cases h5.2.2.2 with x hx,
constructor,
split,
  exact hx.2,
cases pasch h.symm hx.2.symm with t ht,
suffices : t = q,
  subst t,
  exact ht.2.symm,
apply six21a (six14 (nine2 h3.symm)) (six14 (six26 h_1).1) _ (or.inr (or.inl ht.1)) _ (or.inr (or.inl h1.symm)) (six17b p q),
  intro h_1,
  exact absurd (six17a b c) (h_1.symm ▸ h_2),
exact (six27 (six14 (six26 h_1).1) (six17a p q) hx.1 ht.2.symm)
end

def side (A : set point) (a b : point) : Prop := ∃ c, Bl a A c ∧ Bl b A c

theorem nine8 {a b c : point} {A : set point} : Bl a A c → (Bl b A c ↔ side A a b) :=
begin
intro h,
split,
  intro h1,
  constructor,
  exact ⟨h, h1⟩,
intro h1,
cases h1 with d hd,
cases hd.1.2.2.2 with x hx,
cases hd.2.2.2.2 with y hy,
cases pasch hx.2 hy.2 with z hz,
cases em (x = y),
  subst y,
  suffices : sided x a b,
    exact nine5 h hx.1 this,
  split,
    intro h_1,
    subst x,
    apply hd.1.2.1,
    exact hx.1,
  split,
    intro h_1,
    subst x,
    apply hd.2.2.1,
    exact hx.1,
  suffices : d ≠ x,
    exact five2 this hx.2.symm hy.2.symm,
  intro h_1,
  subst d,
  apply hd.1.2.2.1,
  exact hx.1,
have h1 : A = l x y,
  exact six18 h.1 h_1 hx.1 hy.1,
have h2 : z ≠ x,
  intro h_1,
  subst h1,
  subst h_1,
  apply hd.1.2.1,
  right, right,
  exact hz.2.symm,
have h3 : z ≠ y,
  intro h_1,
  subst h1,
  subst h_1,
  apply hd.2.2.1,
  left,
  exact hz.1,
have h4 := nine5 h hy.1 (six7 hz.2 h3).symm,
exact nine5 h4 hx.1 (six7 hz.1 h2)
end

theorem nine9 {a b : point} {A : set point} : Bl a A b → ¬side A a b :=
begin
intros h h1,
suffices : Bl b A b,
  apply nine2 this,
  refl,
exact (nine8 h).2 h1
end

theorem nine10 {a : point} {A : set point} : line A → a ∉ A → ∃ b, Bl a A b :=
begin
intros h h1,
rcases h with ⟨p, q, h⟩,
cases three14 a p with b hb,
existsi b,
split,
  rw h.2,
  exact six14 h.1,
split,
  exact h1,
split,
  intro h_1,
  apply h1,
  rw h.2 at *,
  suffices : l p q = l p b,
    rw this,
    right, right,
    exact hb.1,
  exact six18 (six14 h.1) hb.2 (six17a p q) h_1,
existsi p,
split,
  rw h.2,
  simp,
exact hb.1
end

theorem nine11 {p q : point} {A : set point} : side A p q → line A ∧ p ∉ A ∧ q ∉ A :=
begin
intro h,
cases h with x hx,
split,
  exact hx.1.1,
split,
  exact hx.1.2.1,
exact hx.2.2.1
end

theorem nine12 {a b p : point} {A : set point} : line A → p ∈ A → sided p a b → a ∉ A → side A a b :=
λ h h1 h2 h3, let ⟨c, hc⟩ := nine10 h h3 in ⟨c, hc, nine5 hc h1 h2⟩

theorem side.refl {a : point} {A : set point} : line A → a ∉ A → side A a a :=
begin
intros h h1,
cases nine10 h h1 with b hb,
existsi b,
split;
assumption
end

theorem side.refla {a b c : point} : ¬col a b c → side (l a b) c c :=
λ h, side.refl (six14 (six26 h).1) h

theorem side.symm {a b : point} {A : set point} : side A a b → side A b a :=
begin
intro h,
cases h with c hc,
constructor,
exact ⟨hc.2, hc.1⟩
end

theorem side.trans {a b c : point} {A : set point} : side A a b → side A b c → side A a c :=
begin
intros h h1,
cases h with d hd,
constructor,
split,
  exact hd.1,
exact (nine8 hd.2).2 h1
end

def hp (A : set point) (a : point) : set point := {x | side A x a}

theorem nine14 {a b : point} {A : set point} : b ∈ hp A a → hp A a = hp A b :=
begin
intro h,
ext,
split,
  intro h1,
  exact side.trans h1 h.symm,
intro h1,
exact side.trans h1 h
end

theorem nine17 {a b c : point} {A : set point} : side A a b → B a c b → side A c a :=
begin
intros h h1,
cases h with d hd,
cases hd.1.2.2.2 with x hx,
cases hd.2.2.2.2 with y hy,
cases three17 hx.2 hy.2 h1 with t ht,
have h2 : t ∈ A,
  exact six27 hd.1.1 hx.1 hy.1 ht.2,
have h3 : Bl c A d,
  split,
    exact hd.1.1,
  split,
    intro h_1,
    suffices : Bl b A b,
      apply nine2 this,
      refl,
    suffices : Bl a A b,
      apply (nine8 this).2,
      existsi d,
      exact hd,
    split,
      exact hd.1.1,
    split,
      exact hd.1.2.1,
    split,
      exact hd.2.2.1,
    existsi c,
    split,
      exact h_1,
    exact h1,
  split,
    exact hd.1.2.2.1,
  constructor,
  split,
    exact h2,
  exact ht.1,
existsi d,
split,
  exact h3,
exact hd.1
end

theorem nine17a {a b c p : point} {A : set point} : side A p a → side A p c → B a b c → side A p b :=
λ h h1 h2, h.trans (nine17 (h.symm.trans h1) h2).symm

theorem nine18 {a b p : point} {A : set point} : line A → p ∈ A → col a b p →
(Bl a A b ↔ B a p b ∧ a ∉ A ∧ b ∉ A) :=
begin
intros h h1 h2,
split,
  intro h3,
  split,
    cases h3.2.2.2 with q hq,
    suffices : p = q,
      rw this,
      exact hq.2,
    apply six21a h (six14 (nine2 h3)) _ h1 h2 hq.1 (or.inr (or.inl hq.2.symm)),
    intro h_1,
    apply h3.2.1,
    simpa [h_1] using (six17a a b),
  split,
    exact h3.2.1,
  exact h3.2.2.1,
intro h3,
split,
  exact h,
split,
  exact h3.2.1,
split,
  exact h3.2.2,
existsi p,
split,
  exact h1,
exact h3.1
end

theorem nine19 {a b p : point} {A : set point} : line A → p ∈ A → col a b p →
side A a b → sided p a b ∧ a ∉ A :=
begin
intros h h1 h2 h3,
  split,
    apply six4.2,
    split,
      exact (four11 h2).1,
    intro h,
    cases nine17 h3 h with x hx,
    exact hx.1.2.1 h1,
  cases h3 with d hd,
exact hd.1.2.1
end

theorem nine19a {a b c p : point} {A : set point} : side A a b → p ∈ A → sided p b c → side A a c :=
λ h h1 h2, h.trans (nine12 (nine11 h).1 h1 h2 (nine11 h).2.2)

theorem nine15 {a b x y p : point} : ¬col a b p → B a p x → B b p y → side (l a b) x y :=
λ h h1 h2, nine19a (nine12 (six14 (six26 h).1) (six17a a b) (six7 h1 (six26 h).2.2.symm) h).symm (six17b a b) (six7 h2 (six26 h).2.1.symm)

def pl (A : set point) (a : point) : set point := {x | side A x a ∨ x ∈ A ∨ Bl a A x}

def plane (P : set point) : Prop := ∃ p q r, ¬col p q r ∧ P = pl (l p q) r

theorem nine20 {a : point} {A : set point} : line A → a ∉ A → plane (pl A a) :=
begin
intros h h1,
rcases h with ⟨p, q, h⟩,
rw h.2 at *,
repeat {constructor},
exact h1
end

theorem nine21a {a b : point} {A : set point} : b ∈ pl A a → b ∉ A → line A ∧ a ∉ A :=
begin
intros h h1,
cases h,
  cases h with x hx,
  split,
    exact hx.1.1,
  exact hx.2.2.1,
cases h,
  contradiction,
split,
  exact h.1,
exact h.2.1
end

theorem nine21b {a b : point} {A : set point} : b ∈ pl A a → b ∉ A → pl A a = pl A b :=
begin
intros h h1,
ext,
cases h,
  split,
    intro h2,
    cases h2,
      left,
      exact side.trans h2 h.symm,
    cases h2,
      right, left,
      exact h2,
    right, right,
    exact (nine8 h2).2 h.symm,
  intro h2,
  cases h2,
    left,
    exact side.trans h2 h,
  cases h2,
    right, left,
    exact h2,
  right, right,
  exact (nine8 h2).2 h,
cases h,
  contradiction,
split,
  intro h2,
  cases h2,
    right, right,
    exact ((nine8 h).2 h2.symm).symm,
  cases h2,
    right, left,
    exact h2,
  left,
  existsi a,
  split,
    exact h2.symm,
  exact h.symm,
intro h2,
cases h2,
  right, right,
  exact ((nine8 h.symm).2 h2.symm).symm,
cases h2,
  right, left,
  exact h2,
left,
existsi b,
split,
  exact h2.symm,
exact h
end

theorem nine22 {a x : point} {A A' : set point} : is x A A' → a ∈ A' → a ≠ x → A' ⊆ pl A a :=
begin
intros h h1 h2,
intros p hp,
have h3 : a ∉ A,
  intro h_1,
  apply h.2.2.1,
  exact six21 h2 h.1 h.2.1 h_1 h1 h.2.2.2.1 h.2.2.2.2,
have h4 : A' = l a x,
  exact six18 h.2.1 h2 h1 h.2.2.2.2,
cases em (p = x),
  rw h_1,
  right, left,
  exact h.2.2.2.1,
have h5 : p ∉ A,
  intro h_2,
  apply h.2.2.1,
  exact six21 h_1 h.1 h.2.1 h_2 hp h.2.2.2.1 h.2.2.2.2,
rw h4 at hp,
have h6 : col a x p,
  exact hp,
cases hp,
  right, right,
  split,
    exact h.1,
  split,
    exact h3,
  split,
    exact h5,
  existsi x,
  split,
    exact h.2.2.2.1,
  exact hp,
left,
apply nine12 h.1 h.2.2.2.1 _ h5,
split,
  exact h_1,
split,
  exact h2,
cases hp,
  left,
  exact hp,
right,
exact hp.symm
end

def planeof (p q s : point) : set point := pl (l p q) s

theorem nine23 (a b c p : point) : a ≠ c → ¬col a b p → col a c p → planeof a b c = planeof a b p :=
begin
intros h_1 h h1,
unfold planeof,
apply nine21b,
  suffices : l a c ⊆ pl (l a b) c,
    exact this h1,
  apply nine22,
    split,
      exact (six14 (six26 h).1),
    split,
      exact six14 h_1,
    split,
      intro h_2,
      apply h,
      suffices : p ∈ l a c,
        rw ←h_2 at this,
        exact this,
      exact h1,
    split,
      exact (six17a a b),
    simp,
    simp,
  exact h_1.symm,
exact h
end

theorem nine24b {a b c x : point} : ¬col a b c → side (l a b) x c → x ∈ planeof a c b :=
begin
intros h hx,
have h1 := seven5 a c,
have h2 := seven5 a b,
have h3 : Bl c (l a b) (S a c),
  split,
    exact six14 (six26 h).1,
  split,
    exact h,
  split,
    intro h_1,
    apply h,
    exact (seven24 (six14 (six26 h).1) (six17a a b)).2 h_1,
  constructor,
  split,
    exact (six17a a b),
  exact h1.1,
have h4 : Bl b (l a c) (S a b),
  split,
    exact six14 (six26 h).2.2,
  split,
    exact (four10 h).1,
  split,
    intro h_1,
    apply (four10 h).1,
    exact (seven24 (six14 (six26 h).2.2) (six17a a c)).2 h_1,
  constructor,
  split,
    exact (six17a a c),
  exact h2.1,
have h5 : l a c = l a (S a c),
  apply six18 (six14 (six26 h).2.2),
    exact seven12a (six26 h).2.2,
    simp,
  right, right,
  exact h1.1.symm,
unfold planeof,
have h6 := (nine8 h3).2 hx.symm,
cases h6.2.2.2 with t ht,
cases em (t = a),
  subst t,
  right, left,
  rw h5,
  right, right,
  exact ht.2,
have h7 : sided (S a c) t x,
  split,
    intro h_2,
    apply h3.2.2.1,
    rw ←h_2,
    exact ht.1,
  split,
    intro h_2,
    suffices : t = S a c,
      apply h3.2.2.1,
      rw ←this,
      exact ht.1,
    subst x,
    exact (bet_same ht.2).symm,
  left,
  exact ht.2.symm,
cases ht.1,
  left,
  have h_3 : B t a (S a b),
    exact three7a h_2.symm h2.1 (six26 h).1.symm,
  apply side.symm,
  suffices : Bl t (l a c) (S a b),
    have h8 : side (l a c) b t,
      constructor,
      split,
        exact h4,
      exact this,
    apply side.trans h8,
    apply (nine8 this).1,
    apply nine5 this,
      right, right,
      exact h1.1.symm,
    exact h7,
  split,
    exact six14 (six26 h).2.2,
  split,
    intro h_4,
    suffices : l a b = l a c,
      have h_5 : c ∈ l a b,
        rw this,
        simp,
      exact h h_5,
    exact six21 h_1 (six14 (six26 h).1) (six14 (six26 h).2.2) ht.1 h_4 (six17a a b) (six17a a c),
  split,
    intro h_4,
    apply (four10 h).1,
    exact (seven24 (six14 (six26 h).2.2) (six17a a c)).2 h_4,
  constructor,
  split,
    exact (six17a a c),
  exact h_3,
cases h_2,
  left,
  have h_3 : B t a (S a b),
    exact three6a h_2 h2.1,
  apply side.symm,
  suffices : Bl t (l a c) (S a b),
    have h8 : side (l a c) b t,
      constructor,
      split,
        exact h4,
      exact this,
    apply side.trans h8,
    apply (nine8 this).1,
    apply nine5 this,
      right, right,
      exact h1.1.symm,
    exact h7,
  split,
    exact six14 (six26 h).2.2,
  split,
    intro h_4,
    suffices : l a b = l a c,
      have h_5 : c ∈ l a b,
        rw this,
        simp,
      exact h h_5,
    exact six21 h_1 (six14 (six26 h).1) (six14 (six26 h).2.2) ht.1 h_4 (six17a a b) (six17a a c),
  split,
    intro h_4,
    apply (four10 h).1,
    exact (seven24 (six14 (six26 h).2.2) (six17a a c)).2 h_4,
  constructor,
  split,
    exact (six17a a c),
  exact h_3,
right, right,
apply Bl.symm,
apply nine5 _,
  exact (seven24 (six14 (six26 h).2.2) (six17a a c)).1 (six17b a c),
  exact h7,
split,
  exact six14 (six26 h).2.2,
split,
  intro h_3,
  suffices : l a b = l a c,
    have h_5 : c ∈ l a b,
      rw this,
      simp,
    exact h h_5,
  exact six21 h_1 (six14 (six26 h).1) (six14 (six26 h).2.2) ht.1 h_3 (six17a a b) (six17a a c),
split,
  intro h_3,
  exact (four10 h).1 h_3,
constructor,
split,
  exact (six17a a c),
exact h_2
end

theorem nine24c {a b c : point} : ¬col a b c → planeof a b c ⊆ planeof a c b :=
begin
intro h,
intros x hx,
cases hx,
  exact nine24b h hx,
cases hx,
  have h1 : l a b ⊆ planeof a c b,
    unfold planeof,
    apply nine22 (six28 (four10 h).1) (six17b a b) (six26 h).1.symm,
  exact h1 hx,
unfold planeof,
have h1 := seven5 a c,
have h2 : l a c = l a (S a c),
  apply six18 (six14 (six26 h).2.2),
    exact seven12a (six26 h).2.2,
    simp,
  right, right,
  exact h1.1.symm,
rw h2,
have h3 : ¬col a b (S a c),
  intro h_1,
  apply h,
  exact (seven24 (six14 (six26 h).1) (six17a a b)).2 h_1,
have h4 : side (l a b) x (S a c),
  apply (nine8 hx.symm).1,
  split,
    exact (six14 (six26 h).1),
  split,
    exact h3,
  split,
    exact h,
  constructor,
  split,
    exact (six17a a b),
  exact h1.1.symm,
exact nine24b h3 h4
end

theorem nine24d {a b c : point} : ¬col a b c → planeof a b c = planeof a c b :=
begin
intro h,
ext,
split,
  intro h1,
  exact nine24c h h1,
intro h1,
exact nine24c (four10 h).1 h1
end

theorem nine24e (a b c : point) : planeof a b c = planeof b a c :=
begin
unfold planeof,
suffices : l a b = l b a,
  rwa this,
ext,
split,
  intro h,
  exact (four11 h).2.1,
intro h,
exact (four11 h).2.1
end

theorem nine24 {a b c : point} : ¬col a b c → planeof a b c = planeof a c b ∧ planeof a b c = planeof b a c
∧ planeof a b c = planeof b c a ∧ planeof a b c = planeof c a b ∧ planeof a b c = planeof c b a :=
begin
intro h,
repeat {split};
simp [nine24d h, nine24e];
exact eq.trans (nine24e a c b) (eq.trans (nine24d (four10 h).2.2.2.1) (nine24e c b a))
end

theorem nine24a {a b c : point} : ¬col a b c → l a b ⊆ planeof a b c ∧ l b c ⊆ planeof a b c ∧ l a c ⊆ planeof a b c :=
begin
intro h,
split,
  intros x hx,
  right, left,
  assumption,
split,
  rw (nine24 h).2.2.1,
  intros x hx,
  right, left,
  assumption,
rw (nine24 h).1,
intros x hx,
right, left,
assumption
end

lemma nine25a {a b p q r : point} (h : ¬col p q r) (h1 : a ∈ pl (l p q) r) (h2 : b ∈ pl (l p q) r) (h3 : a ≠ b)
(h_2 : b ∉ l p q) : l a b ⊆ pl (l p q) r ∧ ∃ c, pl (l p q) r = planeof a b c :=
begin
have h4 : p ≠ b,
  exact (six18a h_2).1.symm,
have h5 : pl (l p q) r = pl (l p q) b,
  exact nine21b h2 h_2,
rw h5,
have h6 : planeof p q b = planeof p b q,
    exact (nine24 h_2).1,
unfold planeof at h6,
rw h6,
cases em (a ∈ l p b) with h_3 h_3,
  have h7 : l p b = l a b,
        exact six18 (six14 h4) h3 h_3 (six17b p b) ,
  rw h7,
  have h8 : q ∉ l a b,
    intro h_4,
    rw ←h7 at h_4,
    exact h_2 (four11 h_4).1,
  split,
    exact (nine24a h8).1,
  existsi q,
  unfold planeof,
rw (eq.trans h5 h6) at h1,
have h7 : pl (l p b) q = pl (l p b) a,
  exact nine21b h1 h_3,
rw h7,
have h8 : planeof p b a = planeof a b p,
  exact (nine24 h_3).2.2.2.2,
unfold planeof at h8,
rw h8,
split,
  exact (nine24a (four10 h_3).2.2.2.2).1,
existsi p,
unfold planeof
end

theorem nine25 {a b : point} {P : set point} : plane P → a ∈ P → b ∈ P → a ≠ b → l a b ⊆ P ∧ ∃ c, P = planeof a b c :=
begin
intros h h1 h2 h3,
unfold plane at h,
rcases h with ⟨p, q, r, h⟩,
rw h.2 at *,
cases em (a ∈ l p q),
  cases em (b ∈ l p q),
    have h4 : l p q = l a b,
      exact six18 (six14 (six26 h.1).1) h3 h_1 h_2,
    split,
      rw ←h4,
      exact (nine24a h.1).1,
    existsi r,
    rw h4,
    unfold planeof,
  exact nine25a h.1 h1 h2 h3 h_2,
rw six17 a b,
split,
  exact (nine25a h.1 h2 h1 h3.symm h_1).1,
cases (nine25a h.1 h2 h1 h3.symm h_1).2 with c hc,
existsi c,
rw nine24e a b c,
exact hc
end

theorem nine26 {a b c : point} {P : set point} : ¬col a b c → plane P → a ∈ P → b ∈ P → c ∈ P → P = planeof a b c :=
begin
intros h h1 h2 h3 h4,
cases (nine25 h1 h2 h3 (six26 h).1).2 with c' hc',
subst P,
exact nine21b h4 h
end

theorem nine27 (a b c : point) : a ∈ planeof a b c ∧ b ∈ planeof a b c ∧ c ∈ planeof a b c :=
begin
split,
  right, left,
  simp,
split,
  right, left,
  simp,
by_cases h : a = b,
  subst b,
  right, left, left,
  exact three3 a c,
by_cases h1 : c ∈ l a b,
  right, left,
  exact h1,
left,
exact side.refl (six14 h) h1
end

theorem nine28 {p : point} {A : set point} : line A → plane (pl A p) → p ∉ A :=
begin
intros h h1 h2,
rcases h1 with ⟨x, y, z, h1⟩,
apply h1.1,
suffices : pl A p = A,
  rw this at h1,
  have h3 := nine27 x y z,
  rw [planeof, h1.2.symm] at h3,
  exact six23.2 ⟨A, h, h3⟩,
ext t,
split,
  intro h3,
  cases h3,
    exfalso,
    exact (nine11 h3).2.2 h2,
  cases h3,
    exact h3,
  exfalso,
  exact h3.2.1 h2,
intro h3,
right, left,
exact h3
end

theorem nine31 {p q r s : point} : side (l p q) s r → side (l p r) s q → Bl q (l p s) r :=
begin
intros h h1,
have h2 : ¬col p q r,
  cases h with x hx,
  exact hx.2.2.1,
have h3 := seven5 p r,
have h4 : Bl r (l p q) (S p r),
  split,
    exact (nine11 h).1,
  split,
    exact h2,
  split,
    intro h_1,
    apply h2,
    exact (seven24 (nine11 h).1 (six17a p q)).2 h_1,
  constructor,
  split,
    exact (six17a p q),
  exact h3.1,
have h5 : Bl (S p r) (l p q) s,
  exact ((nine8 h4).2 h.symm).symm,
cases h5.2.2.2 with t ht,
have h6 : sided (S p r) t s,
  apply six7 ht.2,
  intro h_1,
  subst t,
  exact h4.2.2.1 ht.1,
have h7 : side (l p r) t s,
  apply nine12 (nine11 h1).1 ((seven24 (nine11 h1).1 (six17a p r)).1 (six17b p r)) h6,
    intro h_1,
    suffices : (S p r) ≠ t,
      apply (nine11 h1).2.1,
      suffices : l p r = l (S p r) t,
        rw this,
        left,
        exact ht.2,
      apply six18 (six14 (six26 h2).2.2) this,
        right, right,
        exact h3.1.symm,
      exact h_1,
    intro h_2,
    subst t,
    apply h4.2.2.1,
    exact ht.1,
have h8 : sided p t q,
  apply (nine19 (six14 (six26 h2).2.2) (six17a p r) _ _).1,
    exact (four11 ht.1).2.2.2.2,
  exact side.trans h7 h1,
have h9 : p ≠ s,
  intro h_1,
  subst s,
  apply (nine11 h).2.1,
  simp,
have h10 : side (l p s) t q,
  apply nine12 (six14 h9) (six17a p s) h8 _,
  intro h_1,
  apply (nine11 h).2.1,
  suffices : l p q = l p s,
    rw this,
    simp,
  exact six21 h8.1 (nine11 h).1 (six14 h9) ht.1 h_1 (six17a p q) (six17a p s),
have h11 : Bl r (l p s) (S p r),
  split,
    exact six14 h9,
  split,
    exact (four10 (nine11 h1).2.1).1,
  split,
    intro h_1,
    apply (four10 (nine11 h1).2.1).1,
    exact (seven24 (six14 h9) (six17a p s)).2 h_1,
  existsi p,
  split,
    simp,
  exact h3.1,
apply (nine8 h11.symm).2 (side.trans _ h10),
apply (nine12 (six14 h9) (six17b p s) (six7 ht.2.symm _) (nine11 h10).2.1).symm,
intro h_1,
subst t,
exact (nine11 h10).2.1 (six17b p s)
end

end Euclidean_plane


/-
Copyright (c) 2018 Sander Dahmen, Johannes Hölzl, Robert Y. Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sander Dahmen, Johannes Hölzl, Robert Y. Lewis

"On large subsets of 𝔽ⁿ_q with no three-term arithmetic progression"
by J. S. Ellenberg and D. Gijswijt

This file proves a result about the coefficients of a complex polynomial.
It is independent of the rest of our development so far, and used in section_13b.lean.
It corresponds to the first part of section 13 of our blueprint.

NOTE: after simplifications to the proof suggested by Dion Gijswijt, this part of the argument
is unnecessary. This file is not imported in the final result.
-/

import tactic.linarith
import data.polynomial
import analysis.complex.exponential

variables {α : Type*} {β : Type*} {γ : Type*}

namespace units
variables [division_ring α] {a b : α}
end units

variable [discrete_field β]

open finset

def geom_sum0 [semiring α] (x : α) (n : ℕ) : α :=
(range n).sum (λ i, x^i)

lemma geom_sum_one [semiring α] {k : ℕ} : geom_sum0 (1 : α) k = k :=
by simp [geom_sum0,one_pow]

-- Lemma 13.3 from the notes
lemma geom_sum_bound (x: ℝ) (M : ℕ) (h1 : 0 < x) (h2 : x < 1) : geom_sum0 (1/x) (M+1) < (1 - x)⁻¹ * (x^M)⁻¹ :=
have hxn0 : x ≠ 0 := ne_of_gt h1,
have hxn1 : x ≠ 1 := ne_of_lt h2,
let M' := (M : ℤ) in
have h : geom_sum0 (1/x) (M+1) = (1 - x)⁻¹ * (x^M)⁻¹ * (1 - x^(M + 1)), from
  calc geom_sum0 (1/x) (M+1) = (range (M+1)).sum (λ i, (1/x)^i) : by rw [geom_sum0]
  ... = (range (M+1)).sum (λ i, x⁻¹ ^i) : by simp
  ... = (x - 1)⁻¹ * (x - x⁻¹ ^ (M+1) * x) : by rw [geom_sum_inv hxn1 hxn0 (M+1)]
  ... = (x - 1)⁻¹ * (x - x⁻¹ ^ (M'+1) * x) : by refl
  ... = (x - 1)⁻¹ * ((x^M')⁻¹ * (x^(M'+1) - 1)) :
  begin
    congr, rw [mul_sub, fpow_add hxn0, fpow_add, fpow_one, fpow_one, mul_one,
      mul_assoc, inv_mul_cancel hxn0, ← mul_assoc, inv_mul_cancel, one_mul, mul_one,
      ← fpow_inv, ← fpow_inv, ← fpow_mul, ← fpow_mul],
    simp,
    exact fpow_ne_zero_of_ne_zero hxn0 _,
    exact inv_ne_zero hxn0
  end
  ... = (x - 1)⁻¹ * (x^M)⁻¹ * (x^(M+1) - 1) : by rw[mul_assoc]; refl
  ... = (1 - x)⁻¹ * (x^M)⁻¹ * (1 - x^(M + 1)) :
  begin
    rw [← neg_sub, ← neg_sub (1:ℝ)],
    simp only [neg_inv', neg_mul_eq_neg_mul, (neg_mul_comm _ _).symm, neg_neg]
  end,
have hRight : 1 - x^(M+1) < 1, from
  calc 1 - x^(M+1) < 1-0 : sub_lt_sub_left (pow_pos h1 (M+1)) 1
       ... = 1 : by simp,
have hLeft : (1 - x)⁻¹ * (x ^ M)⁻¹ > 0, from
  have hh : 1-x > 0 := by linarith,
  have foo : (1-x)⁻¹ > 0 :=
  calc (1-x)⁻¹ = 1/(1-x) : by rw inv_eq_one_div
       ... > 0 : one_div_pos_of_pos hh,
  have bar : (x^M)⁻¹ > 0 :=
  calc (x^M)⁻¹ = 1/(x^M) : by rw inv_eq_one_div
       ... > 0 : one_div_pos_of_pos (pow_pos h1 M),
  mul_pos foo bar,
calc geom_sum0 (1/x) (M+1) = (1 - x)⁻¹ * (x^M)⁻¹ * (1 - x^(M + 1)) : h
   ... < (1 - x)⁻¹ * (x^M)⁻¹ * 1 : mul_lt_mul_of_pos_left hRight hLeft
   ... = (1 - x)⁻¹ * (x^M)⁻¹ : by rw mul_one

/-- `is_k_uroot x k`: `x` is a `k`-th root of unity -/
def is_k_uroot [semiring α] (x : α) (k : ℕ) : Prop := k > 0 ∧ x^k=1

namespace is_k_uroot

variable [semiring α]

def to_unit {x : α} {k : ℕ} (h : is_k_uroot x k) : units α :=
{ val := x,
  inv := x^(k-1),
  val_inv :=
  calc x * x ^ (k - 1) = x^(1+(k-1)) : by rw[pow_add, pow_one]
    ... = x^k : by rw[nat.add_sub_cancel'] ; exact h.1
    ... = 1 : h.2,
  inv_val :=
  calc x ^ (k - 1) * x = x^(1+(k-1)) : by rw[add_comm,pow_add, pow_one]
    ... = x^k : by rw[nat.add_sub_cancel'] ; exact h.1
    ... = 1 : h.2 }

@[simp] lemma coe_to_unit {x : α} {k : ℕ} (h : is_k_uroot x k) : (h.to_unit : α) = x := rfl

@[simp] lemma to_unit_pow_k {x : α} {k : ℕ} (h : is_k_uroot x k) : h.to_unit ^ k = 1 :=
by ext; rw [units.coe_pow, units.coe_one, coe_to_unit, h.2]

end is_k_uroot

def is_primitive_k_uroot [semiring α] (x : α) (k : ℕ) : Prop :=
is_k_uroot x k ∧ (∀n, is_k_uroot x n → k ≤ n)

section geom_sum_uroot

variables [domain α] [discrete_field β]

lemma geom_sum_uroot {x : α} {k : ℕ} (hx : is_k_uroot x k) (i : ℤ) (h : hx.to_unit ^ i ≠ 1):
  (geom_sum0 (hx.to_unit ^ i : units _) k : α) = 0 :=
let x' : ℤ → units α := λi, hx.to_unit ^ i in
have eq_zero : (geom_sum0 (x' i) k : α) * ((x' i) - 1) = 0, from
  calc (geom_sum0 (x' i) k : α) * ((x' i) - 1) = (x' i)^k - 1 : geom_sum_mul _ _
    ... = (x' (k * i)) - 1 : begin simp only [x'], rw[←units.coe_pow, mul_comm, gpow_mul], refl end
    ... = 0 : by simp only [x', gpow_mul, gpow_coe_nat, hx.to_unit_pow_k, one_gpow, units.coe_one, sub_self],
have ne_zero : ((x' i) - 1 : α) ≠ 0,
  by rwa [(≠), sub_eq_zero, ← units.coe_one, ← units.ext_iff],
begin
  rw mul_eq_zero at eq_zero,
  exact eq_zero.resolve_right ne_zero
end

lemma geom_sum_uroot' {x : α} {k : ℕ} (hx : is_k_uroot x k) (i : ℕ) (h : x^i ≠ 1):
  geom_sum0 (x^i) k = 0 :=
have eq_zero : geom_sum0 (x^i) k  * (x^i - 1) = 0, from
  calc geom_sum0 (x^i) k * (x^i - 1) = (x^i)^k - 1 : geom_sum_mul _ _
    ... = (x^(k * i)) - 1 : by rw[mul_comm, pow_mul]
    ... = 0 : by simp only [pow_mul, one_pow, hx.2, sub_self],
have ne_zero : x^i - 1 ≠ 0,
  by rwa [(≠), sub_eq_zero],
begin
  rw mul_eq_zero at eq_zero,
  exact eq_zero.resolve_right ne_zero
end

lemma geom_sum_uroot'' {x : β} {k : ℕ} (hx : is_k_uroot x k) (i : ℤ) (h : x^i ≠ 1):
  geom_sum0 (x^i) k = 0 :=
have eq_zero : geom_sum0 (x^i) k  * (x^i - 1) = 0, from
   calc geom_sum0 (x^i) k * (x^i - 1) = (x^i)^k - 1 : geom_sum_mul _ _
    ... = (x^(k * i : ℤ)) - 1 : by rw [mul_comm, fpow_mul, fpow_of_nat]
    ... = _ : by rw [fpow_mul, fpow_of_nat, hx.2, one_fpow, sub_self],
have ne_zero : x^i - 1 ≠ 0,
  by rwa [(≠), sub_eq_zero],
begin
  rw mul_eq_zero at eq_zero,
  exact eq_zero.resolve_right ne_zero
end

-- Only necessary for more general framework:
lemma uroot_pow_one {x : β} {k : ℕ} (hx : is_primitive_k_uroot x k)
  (i : ℕ) (h : k ∣ i) :
  x^i=1 :=
match h with ⟨d,hd⟩ := by rw [hd, pow_mul,hx.1.2,one_pow]
end

-- lemma uroot_pow_not_one {x : β} {k : ℕ} (hx : is_primitive_k_uroot x k)
-- (i : nat) (h : ¬ (k ∣ i)) :
--   x^i ≠ 1 := sorry

end geom_sum_uroot

--- Spcial case of Thoerem 13.7, as used in proof of Lemma 13.10
open complex
local notation `π` := real.pi
noncomputable def ζk (k : ℤ) : ℂ := exp (2*π*I/k)

lemma abs_of_uroot (k : ℤ): abs (ζk k) = 1 :=
calc abs (exp (2*π*I/k))
      = abs (exp 0) : by rw abs_exp_eq_iff_re_eq; simp [div_eq_mul_inv]
  ... = 1 : by simp

-- Lemma 13.5 special case(s)

lemma pi_ne_zero : real.pi ≠ 0 :=
  ne_of_gt real.pi_pos

lemma my_exp_nat_mul (z: ℂ) (n : ℕ) : complex.exp z ^ n = complex.exp (z*n) :=
by rw[←exp_nat_mul,mul_comm]

lemma my_exp_int_mul (z: ℂ) : ∀ n : ℤ, complex.exp z ^ n= complex.exp (z*n)
| (int.of_nat n) := my_exp_nat_mul z n
| -[1+n]         :=
calc exp z ^ -[1+ n] = exp z ^ -((n:ℤ) + 1) : rfl
  ... = exp z ^ -(1 * ((n:ℤ)+1)) : by rw [one_mul]
  ... = ((exp z)^(-1:ℤ)) ^ ((n:ℤ)+1) : by rw [neg_mul_eq_neg_mul, fpow_mul]
  ... = ((exp z)^(-1:ℤ)) ^ (n+1) : rfl
  ... = (exp (-z)) ^ (n+1) : by rw [fpow_inv, exp_neg]
  ... = exp (-z*(n+1)) : my_exp_nat_mul _ _
  ... = exp (z*(-(n+1))) : by rw [←neg_mul_eq_neg_mul, neg_mul_eq_mul_neg]
--  ... = exp (z * ↑-[1+ n]) : rfl

lemma exp_2piI_eq : exp (2*π*I)=1 :=
  have h : ∃ (n : ℤ), 1 * (2 * ↑π * I) = ↑n * (2 * ↑π * I) :=
    by existsi (1:ℤ); simp, by rwa [←one_mul (2 * ↑π * I), complex.exp_eq_one_iff]

lemma foo (k : ℕ) : (ζk k)^k=1 :=
if h : k =0 then by rw [h, pow_zero]
else
calc (ζk k)^k = exp ((2*π*I/k)*k) : my_exp_int_mul _ k
     ... = 1 : by rw [div_mul_cancel, exp_2piI_eq]; simp [h]

lemma bar (k n : ℤ) (hknz : k ≠ 0): (ζk k)^n =1 ↔ k∣ n :=
have h : (ζk k)^n=exp ((n/k) * (2 * π * I)) :=
calc (ζk k)^n= _ : my_exp_int_mul _ n
 ... = exp ((n/k) * (2 * π * I)) :
   by simp[div_eq_mul_inv, mul_assoc, mul_comm, mul_left_comm],
calc (ζk k)^n =1 ↔ exp ((n/k) * (2 * π * I)) =1 : by rw h
... ↔ (∃ (i : ℤ), (i : ℂ) * k = n) :
  by simp [exp_eq_one_iff, domain.mul_right_inj, I_ne_zero, pi_ne_zero, two_ne_zero',
    div_eq_iff_mul_eq, hknz]
... ↔ k ∣ n :
begin
  refine exists_congr (assume i, _),
  rw [← int.cast_mul, int.cast_inj, mul_comm, eq_comm],
end

lemma geom_sum_uroot_pow_nmid (k : ℕ) (i : ℤ) (hnmid : ¬ (k : ℤ) ∣ i) :
  geom_sum0 ((ζk k)^i) k = 0 :=
if h : k =0 then by simp [geom_sum0, h]
else
have hh : (k:ℤ) ≠ 0 := by simp[h],
have X : ζk ↑k ^ i ≠ 1 := by simp [bar (k:ℤ) i hh, hnmid],
have hpow1 : (ζk ↑k ^ i) ^ k = 1 :=
calc (ζk ↑k ^ i) ^ k = (ζk ↑k ^ i) ^ (k:ℤ)  : rfl
    ... = (ζk ↑k ^ ↑k)^ i : by rw[←fpow_mul,mul_comm,fpow_mul]
    ... = (ζk k ^ k)^ i : by refl
    ... = 1 : by rw [foo, one_fpow],
begin
rw [geom_sum0, geom_sum,hpow1],
simpa,
end

lemma geom_sum_uroot_pow_mid (k : ℕ) (i : ℤ) (hmid: (k : ℤ) ∣ i) :
  geom_sum0 ((ζk k)^i) k = k :=
if h : k =0 then by simp [geom_sum0, h]
else
have hh : (k:ℤ) ≠ 0 := by simp[h],
calc geom_sum0 ((ζk k)^i) k = geom_sum0 1 k : by rw [(bar k i hh).2 hmid]
  ... = k : geom_sum_one

lemma pick_out_div (m i e : ℕ) (h1 : i < m) (h2 : e < m) : e=i ↔ (m:ℤ) ∣ e-i :=
have hm : -(m:ℤ) <e-i := by linarith,
have he : (e:ℤ)-i<m := by linarith,
have hmpos : (m:ℤ) ≥ 0 := by linarith,
begin
split,
intro,
simp*,
rintro ⟨k, hk⟩,
have X : (m:ℤ)=↑m*1 := by rw [mul_one],
rw [X,hk] at he,
rw [X,hk,neg_mul_eq_mul_neg] at hm,
have hk1 : k < 1 :=lt_of_mul_lt_mul_left he hmpos,
have hkneg1 : -1 < k :=lt_of_mul_lt_mul_left hm hmpos,
have hk0 : k=0 := by linarith,
rw [hk0,mul_zero, ←neg_add_eq_sub] at hk,
linarith,
end

open polynomial

lemma zetak_ne_zero (k : ℤ) : ζk k ≠ 0 := exp_ne_zero _

lemma pick_out_coef' (f : polynomial ℂ) (m i : ℕ)
  (h1 : i < m) (h2 : m > nat_degree f) (r : ℂ) (h3 : r ≠ 0):
  (range m).sum (λ j, (eval (r*(ζk m)^j) f)/(r^i * (ζk m)^(i*j)) ) = (coeff f i) * m :=
  let ζ := (ζk m) in
  calc (range m).sum (λ j, (eval (r*ζ^j) f)/(r^i * ζ^(i*j)) )
   = (range m).sum (λ j,(f.support.sum (λ e,(f.to_fun e)*(r*ζ^j)^e))*(r^i * ζ^(i*j))⁻¹) : rfl
  ... = (range m).sum (λ j,f.support.sum (λ e,(f.to_fun e)*(r*ζ^j)^e*(r^i * ζ^(i*j))⁻¹))
        : by congr; funext; rw [sum_mul] --by simp[sum_mul]
  ... = f.support.sum (λ e,(range m).sum (λ j,(f.to_fun e)*(r*ζ^j)^e*(r^i * ζ^(i*j))⁻¹))
        : sum_comm -- rw [sum_comm] also works here, but not simp ...
  ... = f.support.sum (λ e,(range m).sum (λ j,(f.to_fun e)*r^((e:ℤ)-i)*ζ^((j:ℤ)*(e-i)))) :
  begin
    simp [-sub_eq_add_neg, fpow_sub, h3, mul_sub, zetak_ne_zero, mul_fpow, mul_inv', mul_assoc, mul_comm, mul_left_comm, div_eq_mul_inv, -fpow_of_nat,
      (fpow_of_nat _ _).symm, -fpow_mul, (fpow_mul _ _ _).symm],
  end
  ... = f.support.sum (λ e,(f.to_fun e)*r^((e:ℤ)-i)*(range m).sum (λ j,ζ^((j:ℤ)*(e-i))))
        : by simp only [mul_sum, eq_self_iff_true, sub_eq_add_neg]
  ... = f.support.sum (λ e,(f.to_fun e)*r^((e:ℤ)-i)*(range m).sum (λ j,(ζ^((e:ℤ)-i))^(j:ℤ)))
        : by congr; funext; congr; funext; rw [mul_comm, fpow_mul]
  ... = f.support.sum (λ e,(f.to_fun e)*r^((e:ℤ)-i)*geom_sum0 (ζ^((e:ℤ)-i)) m)
        : rfl
  ... = (f.to_fun i)*r^((i:ℤ)-i)*geom_sum0 (ζ^((i:ℤ)-i)) m :
  begin
    refine sum_eq_single i _ _,
    intros e hes henei,
    have heltdf : e ≤ nat_degree f :=
      have hc : coeff f e ≠ 0 := finsupp.mem_support_iff.1 hes,
      le_nat_degree_of_ne_zero hc,
    have heltm : e < m := begin linarith, end,
    change ¬ e = i at henei,
    have hnmid : ¬ (m:ℤ) ∣ e-i := mt (pick_out_div m i e h1 heltm).2 henei,
    have hsum0 : geom_sum0 (ζ ^ (↑e - ↑i)) m =0 := by rw[geom_sum_uroot_pow_nmid]; exact hnmid,
    rw[hsum0,mul_zero],
    intro h,
    have hfi0 : f.to_fun i = 0 := (finsupp.not_mem_support_iff).1 h,
    rw[hfi0,mul_assoc,zero_mul],
  end
  ... = (coeff f i) * m
      : by rw[sub_eq_zero.2, fpow_zero, fpow_zero, geom_sum_one, coeff]; simp

lemma pick_out_coef (f : polynomial ℂ) (i m : ℕ)
  (h1 : m > i) (h2 : m > nat_degree f) (r : ℝ) (h3 : r > 0) :
  (coeff f i) * m = (range m).sum (λ j,
  (eval (r*(ζk m)^j) f)/(r^i * (ζk m)^(i*j))) :=
eq.symm  $ pick_out_coef' f m i h1 h2 (r:ℂ) $
  by simp only [*, ne_of_gt h3, ne.def, not_false_iff, complex.of_real_eq_zero]