import logic.equiv.basic
import data.set.basic

structure partition (X : Type) :=
(C : set (set X))
(Hnonempty : ∀ c ∈ C, c ≠ ∅)
(Hcover : ∀ x, ∃ c ∈ C, x ∈ c)
(Hunique : ∀ c d ∈ C, c ∩ d ≠ ∅ → c = d)

def partition.ext {X : Type} (P Q : partition X) (H : P.C = Q.C) : P = Q :=
begin
  cases P, cases Q,
  simpa using H,
end

def equivalence_class {X : Type} (R : X → X → Prop) (x : X) := {y : X | R y x}

lemma mem_class {X : Type} {R : X → X → Prop} (HR : equivalence R) (x : X) : x ∈ equivalence_class R x :=
begin
  cases HR with HRR HR,
  exact HRR x,
end

-- here is the bijection between equivalence relations and partitions
example (X : Type) : {R : X → X → Prop // equivalence R} ≃ partition X :=
{ to_fun := λ R, {
    C := { S : set X | ∃ x : X, S = equivalence_class R x},
    Hnonempty := begin
      intro c,
      intro hc,
      cases hc with x hx,
      rw set.ne_empty_iff_nonempty,
      use x,
      rw hx,
      exact mem_class R.2 x,
    end,
    Hcover := begin
      intro x,
      use equivalence_class R x,
      existsi _,
      { exact mem_class R.2 x },
      use x,
    end,
    Hunique := begin
      intros c hc d hd hcd,
      rw set.ne_empty_iff_nonempty at hcd,
      cases hcd with x hx,
      cases hc with a ha,
      cases hd with b hb,
      cases R with  R HR,
      cases hx with hxc hxd,
      rw ha at *,
      rw hb at *,
      change R x a at hxc,
      change R x b at hxd,
      rcases HR with ⟨HRR, HRS, HRT⟩,
      apply set.subset.antisymm,
      { intros y hy,
        change R y a at hy,
        change R y b,
        refine HRT _ hxd,
        refine HRT hy _,
        apply HRS,
        assumption
      },
      { intros y hy,
        change R y a,
        change R y b at hy,
        refine HRT _ hxc,
        refine HRT hy _,
        apply HRS,
        assumption,
      }
    end },
  inv_fun := λ P, ⟨λ x y, ∃ c ∈ P.C, x ∈ c ∧ y ∈ c, begin
    split,
    { intro x,
      cases P.Hcover x with c hc,
      cases hc with hc hxc,
      use c,
      use hc,
      split; assumption,
    },
    split,
    { intros x y hxy,
      cases hxy with c hc,
      cases hc with hc1 hc2,
      use c,
      use hc1,
      cases hc2 with hx hy,
      split; assumption
    },
    { rintros x y z ⟨c, hc, hxc, hyc⟩ ⟨d, hd, hyd, hzd⟩,
      use c,
      use hc,
      split,
      exact hxc,
      have hcd : c = d,
      { apply P.Hunique c hc d hd,
        rw set.ne_empty_iff_nonempty,
        use y,
        split,
        use hyc,
        use hyd,
      },
      rw hcd,
      use hzd,
    }
  end⟩,
  left_inv := begin
    rintro ⟨R, HRR, HRS, HRT⟩,
    ext x y,
    suffices : (∃ (c : set X), (∃ (x : X), c = equivalence_class R x) ∧ x ∈ c ∧ y ∈ c) ↔ R x y,
      simpa,
    split,
    { rintro ⟨c, ⟨z, rfl⟩, ⟨hx, hy⟩⟩,
      refine HRT hx _,
      apply HRS,
      exact hy,
    },
    { intro H,
      use equivalence_class R x,
      use x,
      split,
      exact HRR x,
      exact HRS H,
    }
  end,
  right_inv := begin
    intro P,
    dsimp,
    cases P with C _ _ _,
    dsimp,
    apply partition.ext,
    dsimp, -- dsimps everywhere
    ext c,
    split,
    { intro h,
      dsimp at h,
      cases h with x hx,
      rw hx, clear hx,
      rcases P_Hcover x with ⟨d, hd, hxd⟩,
      convert hd, -- not taught in NNG
      clear c,
      ext y,
      split,
      { intro hy,
        unfold equivalence_class at hy,
        dsimp at hy,
        rcases hy with ⟨e, he, hye, hxe⟩,
        convert hye, -- not taught
        refine P_Hunique d hd e he _,
        rw set.ne_empty_iff_nonempty,
        use x,
        split;assumption
      },
      { intro hyd,
        unfold equivalence_class, dsimp,
        use d,
        use hd,
        split;assumption
      },
    },
    { intro hc,
      dsimp,
      have h := P_Hnonempty c hc,
      rw set.ne_empty_iff_nonempty at h,
      cases h with x hxc,
      use x,
      unfold equivalence_class,
      ext y,
      split,
      { intro hyc,
        dsimp,
        use c,
        use hc,
        split;assumption,
      },
      { intro h,
        dsimp at h,
        rcases h with ⟨d, hd, hyd, hxd⟩,
        convert hyd,
        apply P_Hunique c hc d hd,
        rw set.ne_empty_iff_nonempty,
        use x,
        split;assumption
      }
    }
  end }


import data.real.basic
import .uwyo_sqrt2
import analysis.specific_limits

open_locale topological_space
open filter

lemma aux_0 (X : ℚ) (hX: 0 < X): ( X * X + 2) / (2 * X) - X = (2 - X * X) / (2 * X) :=
begin
  set Y := X * X with hY,
  have h1 : 2 - Y = 2 + Y - 2 * Y, linarith,
  rw add_comm 2 Y at h1,
  rw h1,
  set V := 2 * X with hV,
  have h31 : V ≠ 0, linarith,
  have h2 := sub_div (Y+2) (2*Y) V,
  rw h2,
  have h32 : (2 * Y) / V = X,
    apply (div_eq_iff h31).mpr,
    rw [hY, hV], ring,
  rw h32,
  done
end

lemma aux_1 (X Y V : ℚ) (G : X ≠ 0) (hY : Y = X * X) (hV : V = 2 * X) (G1 : Y ≠ 0) :
  4 * (Y + 2) / V * ((Y + 2) / (V)) = Y + 2 * 2 + (2*2/(X * X)) :=
begin
  -- this is a struggle
      rw hV, rw hY,
      norm_num, field_simp,
      have h211 : 2 * X * ( 2 * X ) = 4 * X * X,
        ring,
      rw h211, rw mul_assoc 4 X X,
      rw ← hY, field_simp,
      rw mul_assoc,
      have h212 : (Y+2) * (Y + 2) = Y * Y + 4 * Y +4, ring,
      rw h212,
      set T := 4 * (Y * Y + 4 * Y + 4) with hT,
      rw ← hT,
      have h214 : (4: ℚ) ≠ 0, linarith,
      have h213 : 4 * Y ≠ 0, exact mul_ne_zero h214 G1,
      apply (div_eq_iff h213).mpr,
      have h214 : (Y + 4 + (4/Y)) * (4 * Y) = (Y+4) * (4*Y) + (4/Y) * (4 * Y),
        ring,
      rw h214,
      have h215 : (4/Y) * (4 * Y) = 16, ring,
        rw mul_assoc,
        have h216 : Y * Y⁻¹ = 1, exact mul_inv_cancel G1,
        rw h216, linarith,
      rw h215,
      rw hT, ring, done
end

lemma aux_2 (X : ℚ) (G : X ≠ 0) : ( 2 / X - X ) * ( 2 / X - X ) = 4 / (X*X) - 4 + X * X :=
begin
  set V := (2/X) with hV,
  have h1 : V * V = 4 / (X * X),
    rw hV, ring, field_simp,
    have h11 : X ^ 2 = X * X, ring,
    rw h11,
  rw ← h1,
  have h2 : (V - X) * (V - X) = V * V - 2 * V * X + X * X, ring,
  rw h2,
  have h3 : V * X = 2, field_simp, ring, rw mul_assoc, rw mul_comm X⁻¹ _,
    rw mul_inv_cancel G, linarith,
  rw mul_assoc 2 V X, rw h3,
  linarith, done
end

-- This proof (considerably shorter than mine) is due to Reid Barton
lemma aux_3 (s : ℕ → ℝ) (hs : ∀ n : ℕ, real.sqrt 2 < s n) : ¬ (tendsto s at_top (𝓝 0)) :=
begin
  rw metric.tendsto_at_top,
  push_neg,
  refine ⟨real.sqrt 2, by norm_num, λ N, ⟨N, le_refl _, _⟩⟩,
  change real.sqrt 2 ≤ abs (s N - 0),
  refine le_trans _ (le_abs_self _),
  specialize hs N,
  linarith, done
end

lemma no_rat_sq_eq_two (X : ℚ) (hX1 : X ≠ 0) :  0 ≠ ( 2 / X - X ) :=
begin
  by_contradiction H,
  push_neg at H,
  have h1 := congr_arg (λ (b : ℚ), X * b) H,
  simp only [] at h1,
  rw mul_zero at h1,
  have h2 : X * (2 / X - X) = 2 - X ^ 2,
    ring,
    have h21 : ( - X + 2 * X⁻¹) * X = - X * X + 2 * X⁻¹ * X, ring,
    rw h21, rw mul_assoc 2 (X⁻¹) X, rw mul_comm (X⁻¹) _, rw mul_inv_cancel hX1,
    ring,
  rw ← h1 at h2,
  have h2 : X ^ 2 = 2, linarith,
  have h3 : ∃ r : ℚ, r ^ 2 = 2,
    use X, exact h2,
  exact rational_not_sqrt_two h3, -- from uwyo_sqrt2
  done
end


/-
Copyright (c) 2021 Arthur Paulino. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Arthur Paulino, Kyle Miller

! This file was ported from Lean 3 source module combinatorics.simple_graph.coloring
! leanprover-community/mathlib commit 70fd9563a21e7b963887c9360bd29b2393e6225a
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Combinatorics.SimpleGraph.Clique
import Mathlib.Data.Nat.Lattice
import Mathlib.Data.Setoid.Partition
import Mathlib.Order.Antichain

/-!
# Graph Coloring

This module defines colorings of simple graphs (also known as proper
colorings in the literature). A graph coloring is the attribution of
"colors" to all of its vertices such that adjacent vertices have
different colors. A coloring can be represented as a homomorphism into
a complete graph, whose vertices represent the colors.

## Main definitions

* `G.Coloring α` is the type of `α`-colorings of a simple graph `G`,
  with `α` being the set of available colors. The type is defined to
  be homomorphisms from `G` into the complete graph on `α`, and
  colorings have a coercion to `V → α`.

* `G.Colorable n` is the proposition that `G` is `n`-colorable, which
  is whether there exists a coloring with at most *n* colors.

* `G.chromaticNumber` is the minimal `n` such that `G` is
  `n`-colorable, or `0` if it cannot be colored with finitely many
  colors.

* `C.colorClass c` is the set of vertices colored by `c : α` in the
  coloring `C : G.Coloring α`.

* `C.colorClasses` is the set containing all color classes.

## Todo:

  * Gather material from:
    * https://github.com/leanprover-community/mathlib/blob/simple_graph_matching/src/combinatorics/simple_graph/coloring.lean
    * https://github.com/kmill/lean-graphcoloring/blob/master/src/graph.lean

  * Trees

  * Planar graphs

  * Chromatic polynomials

  * develop API for partial colorings, likely as colorings of subgraphs (`H.coe.Coloring α`)
-/

universe u v

namespace SimpleGraph

variable {V : Type u} (G : SimpleGraph V)

/-- An `α`-coloring of a simple graph `G` is a homomorphism of `G` into the complete graph on `α`.
This is also known as a proper coloring.
-/
abbrev Coloring (α : Type v) := G →g (⊤ : SimpleGraph α)
#align simple_graph.coloring SimpleGraph.Coloring

variable {G} {α : Type v} (C : G.Coloring α)

theorem Coloring.valid {v w : V} (h : G.Adj v w) : C v ≠ C w :=
  C.map_rel h
#align simple_graph.coloring.valid SimpleGraph.Coloring.valid

/-- Construct a term of `SimpleGraph.Coloring` using a function that
assigns vertices to colors and a proof that it is as proper coloring.

(Note: this is a definitionally the constructor for `SimpleGraph.Hom`,
but with a syntactically better proper coloring hypothesis.)
-/
@[match_pattern]
def Coloring.mk (color : V → α) (valid : ∀ {v w : V}, G.Adj v w → color v ≠ color w) :
    G.Coloring α :=
  ⟨color, @valid⟩
#align simple_graph.coloring.mk SimpleGraph.Coloring.mk

/-- The color class of a given color.
-/
def Coloring.colorClass (c : α) : Set V := { v : V | C v = c }
#align simple_graph.coloring.color_class SimpleGraph.Coloring.colorClass

/-- The set containing all color classes. -/
def Coloring.colorClasses : Set (Set V) := (Setoid.ker C).classes
#align simple_graph.coloring.color_classes SimpleGraph.Coloring.colorClasses

theorem Coloring.mem_colorClass (v : V) : v ∈ C.colorClass (C v) := rfl
#align simple_graph.coloring.mem_color_class SimpleGraph.Coloring.mem_colorClass

theorem Coloring.colorClasses_isPartition : Setoid.IsPartition C.colorClasses :=
  Setoid.isPartition_classes (Setoid.ker C)
#align simple_graph.coloring.color_classes_is_partition SimpleGraph.Coloring.colorClasses_isPartition

theorem Coloring.mem_colorClasses {v : V} : C.colorClass (C v) ∈ C.colorClasses :=
  ⟨v, rfl⟩
#align simple_graph.coloring.mem_color_classes SimpleGraph.Coloring.mem_colorClasses

theorem Coloring.colorClasses_finite [Finite α] : C.colorClasses.Finite :=
  Setoid.finite_classes_ker _
#align simple_graph.coloring.color_classes_finite SimpleGraph.Coloring.colorClasses_finite

theorem Coloring.card_colorClasses_le [Fintype α] [Fintype C.colorClasses] :
    Fintype.card C.colorClasses ≤ Fintype.card α := by
  simp [colorClasses]
  -- porting note: brute force instance declaration `[Fintype (Setoid.classes (Setoid.ker C))]`
  haveI : Fintype (Setoid.classes (Setoid.ker C)) := by assumption
  convert Setoid.card_classes_ker_le C
#align simple_graph.coloring.card_color_classes_le SimpleGraph.Coloring.card_colorClasses_le

theorem Coloring.not_adj_of_mem_colorClass {c : α} {v w : V} (hv : v ∈ C.colorClass c)
    (hw : w ∈ C.colorClass c) : ¬G.Adj v w := fun h => C.valid h (Eq.trans hv (Eq.symm hw))
#align simple_graph.coloring.not_adj_of_mem_color_class SimpleGraph.Coloring.not_adj_of_mem_colorClass

theorem Coloring.color_classes_independent (c : α) : IsAntichain G.Adj (C.colorClass c) :=
  fun _ hv _ hw _ => C.not_adj_of_mem_colorClass hv hw
#align simple_graph.coloring.color_classes_independent SimpleGraph.Coloring.color_classes_independent

-- TODO make this computable
noncomputable instance [Fintype V] [Fintype α] : Fintype (Coloring G α) := by
  classical
  change Fintype (RelHom G.Adj (⊤ : SimpleGraph α).Adj)
  apply Fintype.ofInjective _ RelHom.coe_fn_injective

variable (G)

/-- Whether a graph can be colored by at most `n` colors. -/
def Colorable (n : ℕ) : Prop := Nonempty (G.Coloring (Fin n))
#align simple_graph.colorable SimpleGraph.Colorable

/-- The coloring of an empty graph. -/
def coloringOfIsEmpty [IsEmpty V] : G.Coloring α :=
  Coloring.mk isEmptyElim fun {v} => isEmptyElim v
#align simple_graph.coloring_of_is_empty SimpleGraph.coloringOfIsEmpty

theorem colorable_of_isEmpty [IsEmpty V] (n : ℕ) : G.Colorable n :=
  ⟨G.coloringOfIsEmpty⟩
#align simple_graph.colorable_of_is_empty SimpleGraph.colorable_of_isEmpty

theorem isEmpty_of_colorable_zero (h : G.Colorable 0) : IsEmpty V := by
  constructor
  intro v
  obtain ⟨i, hi⟩ := h.some v
  exact Nat.not_lt_zero _ hi
#align simple_graph.is_empty_of_colorable_zero SimpleGraph.isEmpty_of_colorable_zero

/-- The "tautological" coloring of a graph, using the vertices of the graph as colors. -/
def selfColoring : G.Coloring V := Coloring.mk id fun {_ _} => G.ne_of_adj
#align simple_graph.self_coloring SimpleGraph.selfColoring

/-- The chromatic number of a graph is the minimal number of colors needed to color it.
If `G` isn't colorable with finitely many colors, this will be 0. -/
noncomputable def chromaticNumber : ℕ :=
  infₛ { n : ℕ | G.Colorable n }
#align simple_graph.chromatic_number SimpleGraph.chromaticNumber

/-- Given an embedding, there is an induced embedding of colorings. -/
def recolorOfEmbedding {α β : Type _} (f : α ↪ β) : G.Coloring α ↪ G.Coloring β where
  toFun C := (Embedding.completeGraph f).toHom.comp C
  inj' := by -- this was strangely painful; seems like missing lemmas about embeddings
    intro C C' h
    dsimp only at h
    ext v
    apply (Embedding.completeGraph f).inj'
    change ((Embedding.completeGraph f).toHom.comp C) v = _
    rw [h]
    rfl
#align simple_graph.recolor_of_embedding SimpleGraph.recolorOfEmbedding

/-- Given an equivalence, there is an induced equivalence between colorings. -/
def recolorOfEquiv {α β : Type _} (f : α ≃ β) : G.Coloring α ≃ G.Coloring β where
  toFun := G.recolorOfEmbedding f.toEmbedding
  invFun := G.recolorOfEmbedding f.symm.toEmbedding
  left_inv C := by
    ext v
    apply Equiv.symm_apply_apply
  right_inv C := by
    ext v
    apply Equiv.apply_symm_apply
#align simple_graph.recolor_of_equiv SimpleGraph.recolorOfEquiv

/-- There is a noncomputable embedding of `α`-colorings to `β`-colorings if
`β` has at least as large a cardinality as `α`. -/
noncomputable def recolorOfCardLE {α β : Type _} [Fintype α] [Fintype β]
    (hn : Fintype.card α ≤ Fintype.card β) : G.Coloring α ↪ G.Coloring β :=
  G.recolorOfEmbedding <| (Function.Embedding.nonempty_of_card_le hn).some
#align simple_graph.recolor_of_card_le SimpleGraph.recolorOfCardLE

variable {G}

theorem Colorable.mono {n m : ℕ} (h : n ≤ m) (hc : G.Colorable n) : G.Colorable m :=
  ⟨G.recolorOfCardLE (by simp [h]) hc.some⟩
#align simple_graph.colorable.mono SimpleGraph.Colorable.mono

theorem Coloring.to_colorable [Fintype α] (C : G.Coloring α) : G.Colorable (Fintype.card α) :=
  ⟨G.recolorOfCardLE (by simp) C⟩
#align simple_graph.coloring.to_colorable SimpleGraph.Coloring.to_colorable

theorem colorable_of_fintype (G : SimpleGraph V) [Fintype V] : G.Colorable (Fintype.card V) :=
  G.selfColoring.to_colorable
#align simple_graph.colorable_of_fintype SimpleGraph.colorable_of_fintype

/-- Noncomputably get a coloring from colorability. -/
noncomputable def Colorable.toColoring [Fintype α] {n : ℕ} (hc : G.Colorable n)
    (hn : n ≤ Fintype.card α) : G.Coloring α := by
  rw [← Fintype.card_fin n] at hn
  exact G.recolorOfCardLE hn hc.some
#align simple_graph.colorable.to_coloring SimpleGraph.Colorable.toColoring

theorem colorable_iff_exists_bdd_nat_coloring (n : ℕ) :
    G.Colorable n ↔ ∃ C : G.Coloring ℕ, ∀ v, C v < n := by
  constructor
  · rintro hc
    have C : G.Coloring (Fin n) := hc.toColoring (by simp)
    let f := Embedding.completeGraph (@Fin.valEmbedding n)
    use f.toHom.comp C
    intro v
    cases' C with color valid
    exact Fin.is_lt (color v)
  · rintro ⟨C, Cf⟩
    refine' ⟨Coloring.mk _ _⟩
    · exact fun v => ⟨C v, Cf v⟩
    · rintro v w hvw
      simp only [Fin.mk_eq_mk, Ne.def]
      exact C.valid hvw
#align simple_graph.colorable_iff_exists_bdd_nat_coloring SimpleGraph.colorable_iff_exists_bdd_nat_coloring

theorem colorable_set_nonempty_of_colorable {n : ℕ} (hc : G.Colorable n) :
    { n : ℕ | G.Colorable n }.Nonempty :=
  ⟨n, hc⟩
#align simple_graph.colorable_set_nonempty_of_colorable SimpleGraph.colorable_set_nonempty_of_colorable

theorem chromaticNumber_bddBelow : BddBelow { n : ℕ | G.Colorable n } :=
  ⟨0, fun _ _ => zero_le _⟩
#align simple_graph.chromatic_number_bdd_below SimpleGraph.chromaticNumber_bddBelow

theorem chromaticNumber_le_of_colorable {n : ℕ} (hc : G.Colorable n) : G.chromaticNumber ≤ n := by
  rw [chromaticNumber]
  apply cinfₛ_le chromaticNumber_bddBelow
  constructor
  exact Classical.choice hc
#align simple_graph.chromatic_number_le_of_colorable SimpleGraph.chromaticNumber_le_of_colorable

theorem chromaticNumber_le_card [Fintype α] (C : G.Coloring α) :
    G.chromaticNumber ≤ Fintype.card α :=
  cinfₛ_le chromaticNumber_bddBelow C.to_colorable
#align simple_graph.chromatic_number_le_card SimpleGraph.chromaticNumber_le_card

theorem colorable_chromaticNumber {m : ℕ} (hc : G.Colorable m) : G.Colorable G.chromaticNumber := by
  classical
  dsimp only [chromaticNumber]
  rw [Nat.infₛ_def]
  apply Nat.find_spec
  exact colorable_set_nonempty_of_colorable hc
#align simple_graph.colorable_chromatic_number SimpleGraph.colorable_chromaticNumber

theorem colorable_chromaticNumber_of_fintype (G : SimpleGraph V) [Finite V] :
    G.Colorable G.chromaticNumber := by
  cases nonempty_fintype V
  exact colorable_chromaticNumber G.colorable_of_fintype
#align simple_graph.colorable_chromatic_number_of_fintype SimpleGraph.colorable_chromaticNumber_of_fintype

theorem chromaticNumber_le_one_of_subsingleton (G : SimpleGraph V) [Subsingleton V] :
    G.chromaticNumber ≤ 1 := by
  rw [chromaticNumber]
  apply cinfₛ_le chromaticNumber_bddBelow
  constructor
  refine' Coloring.mk (fun _ => 0) _
  intro v w
  rw [Subsingleton.elim v w]
  simp
#align simple_graph.chromatic_number_le_one_of_subsingleton SimpleGraph.chromaticNumber_le_one_of_subsingleton

theorem chromaticNumber_eq_zero_of_isempty (G : SimpleGraph V) [IsEmpty V] :
    G.chromaticNumber = 0 := by
  rw [← nonpos_iff_eq_zero]
  apply cinfₛ_le chromaticNumber_bddBelow
  apply colorable_of_isEmpty
#align simple_graph.chromatic_number_eq_zero_of_isempty SimpleGraph.chromaticNumber_eq_zero_of_isempty

theorem isEmpty_of_chromaticNumber_eq_zero (G : SimpleGraph V) [Finite V]
    (h : G.chromaticNumber = 0) : IsEmpty V := by
  have h' := G.colorable_chromaticNumber_of_fintype
  rw [h] at h'
  exact G.isEmpty_of_colorable_zero h'
#align simple_graph.is_empty_of_chromatic_number_eq_zero SimpleGraph.isEmpty_of_chromaticNumber_eq_zero

theorem chromaticNumber_pos [Nonempty V] {n : ℕ} (hc : G.Colorable n) : 0 < G.chromaticNumber := by
  apply le_cinfₛ (colorable_set_nonempty_of_colorable hc)
  intro m hm
  by_contra h'
  simp only [not_le, Nat.lt_one_iff] at h'
  obtain ⟨i, hi⟩ := hm.some (Classical.arbitrary V)
  have h₁: i < 0 := lt_of_lt_of_le hi (Nat.le_of_lt_succ h')
  exact Nat.not_lt_zero _ h₁
#align simple_graph.chromatic_number_pos SimpleGraph.chromaticNumber_pos

theorem colorable_of_chromaticNumber_pos (h : 0 < G.chromaticNumber) :
    G.Colorable G.chromaticNumber := by
  obtain ⟨h, hn⟩ := Nat.nonempty_of_pos_infₛ h
  exact colorable_chromaticNumber hn
#align simple_graph.colorable_of_chromatic_number_pos SimpleGraph.colorable_of_chromaticNumber_pos

theorem Colorable.mono_left {G' : SimpleGraph V} (h : G ≤ G') {n : ℕ} (hc : G'.Colorable n) :
    G.Colorable n :=
  ⟨hc.some.comp (Hom.mapSpanningSubgraphs h)⟩
#align simple_graph.colorable.mono_left SimpleGraph.Colorable.mono_left

theorem Colorable.chromaticNumber_le_of_forall_imp {V' : Type _} {G' : SimpleGraph V'} {m : ℕ}
    (hc : G'.Colorable m) (h : ∀ n, G'.Colorable n → G.Colorable n) :
    G.chromaticNumber ≤ G'.chromaticNumber := by
  apply cinfₛ_le chromaticNumber_bddBelow
  apply h
  apply colorable_chromaticNumber hc
#align simple_graph.colorable.chromatic_number_le_of_forall_imp SimpleGraph.Colorable.chromaticNumber_le_of_forall_imp

theorem Colorable.chromaticNumber_mono (G' : SimpleGraph V) {m : ℕ} (hc : G'.Colorable m)
    (h : G ≤ G') : G.chromaticNumber ≤ G'.chromaticNumber :=
  hc.chromaticNumber_le_of_forall_imp fun _ => Colorable.mono_left h
#align simple_graph.colorable.chromatic_number_mono SimpleGraph.Colorable.chromaticNumber_mono

theorem Colorable.chromaticNumber_mono_of_embedding {V' : Type _} {G' : SimpleGraph V'} {n : ℕ}
    (h : G'.Colorable n) (f : G ↪g G') : G.chromaticNumber ≤ G'.chromaticNumber :=
  h.chromaticNumber_le_of_forall_imp fun _ => Colorable.of_embedding f
#align simple_graph.colorable.chromatic_number_mono_of_embedding SimpleGraph.Colorable.chromaticNumber_mono_of_embedding

theorem chromaticNumber_eq_card_of_forall_surj [Fintype α] (C : G.Coloring α)
    (h : ∀ C' : G.Coloring α, Function.Surjective C') : G.chromaticNumber = Fintype.card α := by
  apply le_antisymm
  · apply chromaticNumber_le_card C
  · by_contra hc
    rw [not_le] at hc
    obtain ⟨n, cn, hc⟩ :=
      exists_lt_of_cinfₛ_lt (colorable_set_nonempty_of_colorable C.to_colorable) hc
    rw [← Fintype.card_fin n] at hc
    have f := (Function.Embedding.nonempty_of_card_le (le_of_lt hc)).some
    have C' := cn.some
    specialize h (G.recolorOfEmbedding f C')
    have h1 : Function.Surjective f := Function.Surjective.of_comp h
    have h2 := Fintype.card_le_of_surjective _ h1
    exact Nat.lt_le_antisymm hc h2
#align simple_graph.chromatic_number_eq_card_of_forall_surj SimpleGraph.chromaticNumber_eq_card_of_forall_surj

theorem chromaticNumber_bot [Nonempty V] : (⊥ : SimpleGraph V).chromaticNumber = 1 := by
  let C : (⊥ : SimpleGraph V).Coloring (Fin 1) :=
      Coloring.mk (fun _ => 0) fun {v w} h => False.elim h
  apply le_antisymm
  · exact chromaticNumber_le_card C
  · exact chromaticNumber_pos C.to_colorable
#align simple_graph.chromatic_number_bot SimpleGraph.chromaticNumber_bot

@[simp]
theorem chromaticNumber_top [Fintype V] : (⊤ : SimpleGraph V).chromaticNumber = Fintype.card V := by
  apply chromaticNumber_eq_card_of_forall_surj (selfColoring _)
  intro C
  rw [← Finite.injective_iff_surjective]
  intro v w
  contrapose
  intro h
  exact C.valid h
#align simple_graph.chromatic_number_top SimpleGraph.chromaticNumber_top

theorem chromaticNumber_top_eq_zero_of_infinite (V : Type _) [Infinite V] :
    (⊤ : SimpleGraph V).chromaticNumber = 0 := by
  let n := (⊤ : SimpleGraph V).chromaticNumber
  by_contra hc
  replace hc := pos_iff_ne_zero.mpr hc
  apply Nat.not_succ_le_self n
  convert_to (⊤ : SimpleGraph { m | m < n + 1 }).chromaticNumber ≤ _
  · rw [SimpleGraph.chromaticNumber_top, Fintype.card_ofFinset,
        Finset.card_range, Nat.succ_eq_add_one]
  refine' (colorable_of_chromaticNumber_pos hc).chromaticNumber_mono_of_embedding _
  apply Embedding.completeGraph
  exact (Function.Embedding.subtype _).trans (Infinite.natEmbedding V)
#align simple_graph.chromatic_number_top_eq_zero_of_infinite SimpleGraph.chromaticNumber_top_eq_zero_of_infinite

/-- The bicoloring of a complete bipartite graph using whether a vertex
is on the left or on the right. -/
def CompleteBipartiteGraph.bicoloring (V W : Type _) : (completeBipartiteGraph V W).Coloring Bool :=
  Coloring.mk (fun v => v.isRight)
    (by
      intro v w
      cases v <;> cases w <;> simp)
#align simple_graph.complete_bipartite_graph.bicoloring SimpleGraph.CompleteBipartiteGraph.bicoloring

theorem CompleteBipartiteGraph.chromaticNumber {V W : Type _} [Nonempty V] [Nonempty W] :
    (completeBipartiteGraph V W).chromaticNumber = 2 := by
  apply chromaticNumber_eq_card_of_forall_surj (CompleteBipartiteGraph.bicoloring V W)
  intro C b
  have v := Classical.arbitrary V
  have w := Classical.arbitrary W
  have h : (completeBipartiteGraph V W).Adj (Sum.inl v) (Sum.inr w) := by simp
  have hn := C.valid h
  by_cases he : C (Sum.inl v) = b
  · exact ⟨_, he⟩
  · by_cases he' : C (Sum.inr w) = b
    · exact ⟨_, he'⟩
    · exfalso
      cases b <;>
        simp only [Bool.eq_true_eq_not_eq_false, Bool.eq_false_eq_not_eq_true] at he he' <;>
          rw [he, he'] at hn <;>
        contradiction
#align simple_graph.complete_bipartite_graph.chromatic_number SimpleGraph.CompleteBipartiteGraph.chromaticNumber

/-! ### Cliques -/

theorem IsClique.card_le_of_coloring {s : Finset V} (h : G.IsClique s) [Fintype α]
    (C : G.Coloring α) : s.card ≤ Fintype.card α := by
  rw [isClique_iff_induce_eq] at h
  have f : G.induce ↑s ↪g G := Embedding.comap (Function.Embedding.subtype fun x => x ∈ ↑s) G
  rw [h] at f
  convert Fintype.card_le_of_injective _ (C.comp f.toHom).injective_of_top_hom using 1
  simp
#align simple_graph.is_clique.card_le_of_coloring SimpleGraph.IsClique.card_le_of_coloring

theorem IsClique.card_le_of_colorable {s : Finset V} (h : G.IsClique s) {n : ℕ}
    (hc : G.Colorable n) : s.card ≤ n := by
  convert h.card_le_of_coloring hc.some
  simp
#align simple_graph.is_clique.card_le_of_colorable SimpleGraph.IsClique.card_le_of_colorable

-- TODO eliminate `Finite V` constraint once chromatic numbers are refactored.
-- This is just to ensure the chromatic number exists.
theorem IsClique.card_le_chromaticNumber [Finite V] {s : Finset V} (h : G.IsClique s) :
    s.card ≤ G.chromaticNumber := by
  cases nonempty_fintype V
  exact h.card_le_of_colorable G.colorable_chromaticNumber_of_fintype
#align simple_graph.is_clique.card_le_chromatic_number SimpleGraph.IsClique.card_le_chromaticNumber

protected theorem Colorable.cliqueFree {n m : ℕ} (hc : G.Colorable n) (hm : n < m) :
    G.CliqueFree m := by
  by_contra h
  simp only [CliqueFree, isNClique_iff, not_forall, Classical.not_not] at h
  obtain ⟨s, h, rfl⟩ := h
  exact Nat.lt_le_antisymm hm (h.card_le_of_colorable hc)
#align simple_graph.colorable.clique_free SimpleGraph.Colorable.cliqueFree

-- TODO eliminate `Finite V` constraint once chromatic numbers are refactored.
-- This is just to ensure the chromatic number exists.
theorem cliqueFree_of_chromaticNumber_lt [Finite V] {n : ℕ} (hc : G.chromaticNumber < n) :
    G.CliqueFree n :=
  G.colorable_chromaticNumber_of_fintype.cliqueFree hc
#align simple_graph.clique_free_of_chromatic_number_lt SimpleGraph.cliqueFree_of_chromaticNumber_lt

end SimpleGraph


import data.set.basic

variables (R A : Type)
variables (𝕍 : set R → set A) (𝕀 : set A → set R)

open set

-- 𝕍 𝕀 𝕍 = 𝕍 for a contravariant Galois connection
-- for example the one between R=k[X₁,X₂,…,Xₙ] and A=𝔸ⁿ
-- in the theory of algebraic varieties
example
  (𝕍_antimono : ∀ J₁ J₂ : set R, J₁ ⊆ J₂ → 𝕍 J₂ ⊆ 𝕍 J₁)
  (𝕀_antimono : ∀ W₁ W₂ : set A, W₁ ⊆ W₂ → 𝕀 W₂ ⊆ 𝕀 W₁)
  (galois : ∀ J : set R, ∀ W : set A, J ⊆ 𝕀 W ↔ W ⊆ 𝕍 J) :
  ∀ J : set R, 𝕍 (𝕀 (𝕍 J)) = 𝕍 J :=
begin
  intro J,
  apply set.subset.antisymm,
  { apply 𝕍_antimono,
    rw galois},
  { rw ←galois}
end


import algebra.group

open array

variables {n : ℕ} {α : Type*} [group α] (a b c : array n α)

instance : has_mul (array n α) := ⟨array.map₂ (*)⟩
instance : has_one (array n α) := ⟨mk_array n 1⟩
instance : has_inv (array n α) := ⟨flip array.map has_inv.inv⟩

private lemma mul_assoc : a * b * c = a * (b * c) :=
begin
  apply array.ext,
  intros i,
  apply mul_assoc,
end

private lemma one_mul : 1 * a = a :=
begin
  apply array.ext,
  intros i,
  apply one_mul,
end

private lemma mul_one : a * 1 = a :=
begin
  apply array.ext,
  intros i,
  apply mul_one,
end

private lemma mul_left_inv : a⁻¹ * a = 1 :=
begin
  apply array.ext,
  intros i,
  apply mul_left_inv,
end

instance array_group : group (array n α) :=
{
  mul := (*),
  mul_assoc := mul_assoc,
  one := 1,
  one_mul := one_mul,
  mul_one := mul_one,
  inv := has_inv.inv,
  mul_left_inv := mul_left_inv,
}

@[simp] lemma array.read_mul {a₁ a₂ : array n α} {i : fin n} : (a₁ * a₂).read i = a₁.read i * a₂.read i := rfl


import tactic.structure_helper
import tactic.nat_num_game
/-

  mynat/definition.lean -- definition of mynat.

  Supplies:
  constants zero : mynat and one : mynat
  function S : mynat → mynat
  notation 0 for zero and 1 for one.

The below code will be *invisible to the player*
-/

-- definition of "the natural numbers"
@[derive decidable_eq]
inductive mynat
| zero : mynat
| succ (n : mynat) : mynat

namespace mynat

instance : has_zero mynat := ⟨mynat.zero⟩
@[leakage] theorem mynat_zero_eq_zero : mynat.zero = 0 := rfl

def one : mynat := succ 0

instance : has_one mynat := ⟨mynat.one⟩

theorem one_eq_succ_zero : 1 = succ 0 := rfl

lemma zero_ne_succ (m : mynat) : (0 : mynat) ≠ succ m := λ h, by cases h

lemma succ_inj {m n : mynat} (h : succ m = succ n) : m = n := by cases h; refl

end mynat

attribute [symm] ne.symm


import interior_world.level3 --hide

/-

# Level 4: The interior is the maximal open subset

-/
variables {X : Type} -- hide
variables [topological_space X] (x : X)  (A : set X) -- hide

namespace topological_space -- hide

/- Lemma
If B is an open set contained in A, then B is contained in the interior of A.
-/
lemma interior_maximal (B : set X) (h : B ⊆ A) (hopen : is_open B):
  B ⊆ interior A :=
begin
  intros x x_in_B,
  rw interior_def',
  use B,
  exact ⟨⟨hopen, h⟩, x_in_B⟩,

end

end topological_space -- hide


import .vector_space .seq .subspace

universes u v
variables {V : Type u} {F : Type v} [field F] [vector_space V F]

-- Linear span of a finite list/seq of vectors
inductive span {n} (v : seq V n) : set V
-- span(v_1,...,v_n) = {sum a_iv_i | a_i ∈ F}
| intro (a : seq F n) : span (seq.sum (λ i, a i ⋅ v i))

theorem set.ext {α} {s₁ s₂ : set α} : (∀ a : α, a ∈ s₁ ↔ a ∈ s₂) ↔ s₁ = s₂ :=
⟨λ h, funext (λ a, propext (h a)), λ p _, by rw p⟩

-- span(∅) = {0}
lemma span_empty : @span _ F _ _ 0 ∅ = just (0 : V) :=
begin
  -- Show v ∈ span ∅ ↔ v ∈ {0}
  apply set.ext.mp, intro,
  apply iff.intro,
  -- Trivial, sum always evaluates to 0
  all_goals {intro h, cases h, split},
  exact seq.empty,
end

lemma sum_zero {n} {v : seq V n} : seq.sum (λ i, (0 : F) ⋅ v i) = (0 : V) :=
begin
  induction n with m ih,
  refl,
  --show seq.iterate (λ i, (0 : F) ⋅ v i) 0 (λ _, (+)) = 0,
  simp * at *,
  --rw ih,
  --show (0 : V) + seq.sum (λ (i : fin (nat.succ m)), 0) = 0
  admit
end

--variables {m : ℕ} {v : seq V (m + 1)}
--#check (0 : V) + seq.sum (λ (i : fin (nat.succ m)), 0) = 0

instance span_is_subspace {n} {vs : seq V n} :
  @subspace _ F _ _ (@span _ F _ _ _ vs) :=
{ contains_zero := by rw ←sum_zero; split,
  add_closed    := sorry,
  mul_closed    := sorry }

def linearly_independent {n} (v : seq V n) :=
∀ a : seq F n, seq.sum (λ i, a i ⋅ v i) = 0 → a = 0

/-def is_basis {n} (v : seq V n) :=
  (linearly_independent v) ∧ ((@span V F f vsi n v) = (@set.univ V))-/


import MyNat.Definition
namespace MyNat
open MyNat
/-!
# Proposition world.

## Level 2: `intro`.

Let's prove an implication. Let `P` be a true/false statement, and let's prove that `P → P`. You
will see that our goal in the lemma below starts out with `P → P`. Constructing a term of type `P →
P` (which is what solving this goal *means*) in this case amounts to proving that `P → P`, and
computer scientists think of this as coming up with a function which sends proofs of `P` to proofs
of `P`.

To define an implication `P ⟹ Q` we need to choose an arbitrary proof `p : P` of `P` and then,
perhaps using `p`, construct a proof of `Q`.  The Lean way to say "let's assume `P` is true" is
`intro p`, i.e., "let's assume we have a proof of `P`".

## Note for worriers.

Those of you who know something about the subtle differences between truth and provability
discovered by Goedel -- these are not relevant here. Imagine we are working in a fixed model of
mathematics, and when I say "proof" I actually mean "truth in the model", or "proof in the
metatheory".

## Rule of thumb:

If your goal is to prove `P → Q` (i.e. that `P → Q`)
then `intro p`, meaning "assume `p` is a proof of `P`", will make progress.

To solve the goal below, you have to come up with a function from
`P` (thought of as the set of proofs of `P`!) to itself. Start with

`intro p`

(i.e. "let `p` be a proof of `P`") and note that our
local context now looks like this:

```
P : Prop,
p : P
⊢ P
```

Our job now is to construct a proof of `P`. But `p` is a proof of `P`.
So

`exact p`

will close the goal. Note that `exact P` will not work -- don't
confuse a true/false statement (which could be false!) with a proof.
We will stick with the convention of capital letters for propositions
and small letters for proofs.

## Lemma : imp_self
If `P` is a proposition then `P → P`.
-/
lemma imp_self (P : Prop) : P → P := by
  intro p
  exact p

/-!
Next up [Level 3](./Level3.lean.md)
-/