import Mathlib.Combinatorics.SimpleGraph.Basic import Mathlib.Combinatorics.SimpleGraph.Finite import Mathlib.Combinatorics.SimpleGraph.Coloring import Mathlib.Combinatorics.SimpleGraph.Subgraph import Mathlib.Combinatorics.SimpleGraph.Path import Mathlib.Combinatorics.SimpleGraph.Walk import Mathlib.Combinatorics.SimpleGraph.Maps import Mathlib.Order.Disjoint import Mathlib.Data.List.Basic import Mathlib.Data.List.Lemmas import Mathlib.Data.Fintype.Basic import Mathlib.Data.Fintype.Card import Mathlib.Data.Fintype.Sets import Mathlib.Data.Set.Basic import Mathlib.Tactic.Linarith open SimpleGraph List Walk Set.Notation open Classical variable {α : Type} {V : Type} [Fintype V] (G : SimpleGraph V) [DecidableRel G.Adj] noncomputable def extend_coloring (S : Set V) (S_coloring : Coloring (G.induce S) α) (v : V) (c : α) (h : c ∉ S_coloring '' (S ↓∩ G.neighborSet v)) : Coloring (G.induce (S ∪ {v})) α := by simp at h apply Coloring.mk case color => intro ⟨x, mem⟩ by_cases hx : x ∈ S · exact S_coloring ⟨x, hx⟩ · exact c case valid => rintro ⟨x₁, mem_x₁⟩ ⟨x₂, mem_x₂⟩ intro adj by_cases hx₁ : x₁ ∈ S <;> by_cases hx₂ : x₂ ∈ S -- 4 cases according to whether x₁ and/or x₂ are in S or not · simp [hx₁, hx₂] exact S_coloring.valid adj · simp [hx₁, hx₂] replace hx₂ : x₂ = v := mem_x₂.resolve_left hx₂ simp [hx₂] at adj exact h x₁ (G.adj_symm adj) hx₁ · simp [hx₁, hx₂] replace hx₁ : x₁ = v := mem_x₁.resolve_left hx₁ simp [hx₁] at adj -- TODO the following 2 lines are kind of cumbersome intro wrong exact (h x₂ adj hx₂) (Eq.symm wrong) · intro a simp_all only [comap_adj, Function.Embedding.coe_subtype] simp_all only [Set.union_singleton, Set.mem_insert_iff, or_false, SimpleGraph.irrefl] lemma preimage_val_card (A B : Set V) : (A ↓∩ B).toFinset.card = (A ∩ B).toFinset.card := by apply Finset.card_bij' case i => exact fun a _ => ↑a case j => intro a h simp only [Set.toFinset_inter, Finset.mem_inter, Set.mem_toFinset] at h exact ⟨a, h.left⟩ case hi => intro a ha simp_all only [not_false_eq_true, true_and, Set.mem_toFinset, Set.mem_preimage, Set.toFinset_inter, Finset.mem_inter, Subtype.coe_prop, and_self] case hj => intro a ha simp_all only [not_false_eq_true, true_and, Set.mem_toFinset, Set.mem_preimage] simp_all only [Set.toFinset_inter, Finset.mem_inter, Set.mem_toFinset] case left_inv => intro a ha simp_all only [not_false_eq_true, true_and, Subtype.coe_eta] case right_inv => intro a ha simp_all only [not_false_eq_true, true_and] lemma extend_coloring' {k : ℕ} (S : Set V) (S_colorable : Colorable (G.induce S) k) (v : V) (h : (G.neighborSet v ∩ S).toFinset.card < k) : Colorable (G.induce (S ∪ {v})) k := by have S_coloring := S_colorable.some let N := G.neighborSet v have card_fact : (S ↓∩ N).toFinset.card = (S ∩ N).toFinset.card := by -- without "convert" this gives a timeout error have foo := preimage_val_card S N convert foo have unused_color : ∃ c : Fin k, c ∉ S_coloring '' (S ↓∩ N) := by suffices (S_coloring '' (S ↓∩ N)).toFinset.card < (Set.univ : Set (Fin k)).toFinset.card from by have ⟨c, hc⟩ := Finset.exists_mem_not_mem_of_card_lt_card this simp only [Set.mem_toFinset] at hc exact ⟨c, hc.right⟩ simp only [Set.toFinset_image, Set.toFinset_univ, Finset.card_univ, Fintype.card_fin] calc (Finset.image (⇑S_coloring) (S ↓∩ N).toFinset).card ≤ (S ↓∩ N).toFinset.card := Finset.card_image_le _ = (S ∩ N).toFinset.card := card_fact _ = (N ∩ S).toFinset.card := by simp only [Set.inter_comm] _ < k := h have ⟨c, hc⟩ := unused_color exact Nonempty.intro (extend_coloring G S S_coloring v c hc) lemma extend_coloring'' {k : ℕ} (S : Set V) (S_colorable : Colorable (G.induce S) k) (v : V) (h : G.degree v < k) : Colorable (G.induce (S ∪ {v})) k := by apply extend_coloring' · assumption · calc (G.neighborSet v ∩ S).toFinset.card ≤ (G.neighborSet v).toFinset.card := by simp only [Set.toFinset_inter] apply Finset.card_le_card simp only [Set.subset_toFinset, Finset.coe_inter, Set.coe_toFinset, Set.inter_subset_left] _ = G.degree v := by simp only [Set.toFinset_card, G.card_neighborSet_eq_degree] _ < k := h theorem color_path (k : ℕ) (maxDeg_le_k : G.maxDegree ≤ k) {u v : V} (P : G.Path u v) (S : Set V) (P_outside_S : ∀ x ∈ P.val.support, x ∉ S) (S_colorable : Colorable (G.induce S) k) : Colorable (G.induce (S ∪ P.val.support.tail.toFinset)) k := by classical let ⟨W, W_is_path⟩ := P cases W with | nil => simp rw [Finset.coe_empty, Set.union_empty] exact S_colorable | @cons u w v adj W' => simp at * let P' : G.Path w v := ⟨W', IsPath.of_cons W_is_path⟩ have P'_colorable := color_path k maxDeg_le_k P' S (P_outside_S.right) S_colorable let N := G.neighborSet w -- set of vertices already colored by P'_coloring let C := S ∪ W'.support.tail.toFinset have u_not_in_W' : u ∉ W'.support := ((Walk.cons_isPath_iff adj W').mp W_is_path).right have u_not_in_W'_tail : u ∉ W'.support.tail := by intro wrong have u_in_W' := List.Mem.tail w wrong rw [←(Walk.support_eq_cons W')] at u_in_W' contradiction have hu : u ∈ (N \ C) := by simp [N, C] exact ⟨G.adj_symm adj, P_outside_S.left, u_not_in_W'_tail⟩ have h : (N ∩ C).toFinset.card < k := by have ineq1 : (N ∩ C).toFinset.card + (N \ C).toFinset.card ≤ k := calc _ = N.toFinset.card := by simp only [Set.toFinset_inter, Set.toFinset_diff, Finset.card_inter_add_card_sdiff] _ ≤ G.maxDegree := G.degree_le_maxDegree w _ ≤ k := maxDeg_le_k have ineq2 : 1 ≤ (N \ C).toFinset.card := by simp only [Finset.one_le_card, Set.toFinset_nonempty] exact ⟨u, hu⟩ linarith have extended_coloring := by apply extend_coloring' G C P'_colorable w -- TODO without "convert" this gives a timeout error convert h have fact : (W'.support.tail.toFinset ∪ {w} : Set V) = W'.support.toFinset := by simp only [coe_toFinset, Set.union_def, Set.mem_setOf_eq, Set.mem_singleton_iff, Or.comm, mem_support_iff] rw [Set.union_assoc, fact] at extended_coloring exact extended_coloring lemma induce_maxDegree_mono (S : Set V) : (G.induce S).maxDegree ≤ G.maxDegree := by simp only [G.induce_eq_coe_induce_top S] apply maxDegree_le_of_forall_degree_le intro v rw [Subgraph.coe_degree] calc ((⊤ : G.Subgraph).induce S).degree v ≤ G.degree v := Subgraph.degree_le ((⊤ : G.Subgraph).induce S) v _ ≤ G.maxDegree := G.degree_le_maxDegree v noncomputable def extend_path_maximally {u v : V} (P : G.Path u v) : ∃ w : V, ∃ Q : G.Walk w u, IsPath (Walk.append Q P.1) ∧ G.neighborFinset w ⊆ (Walk.append Q P.1).support.toFinset := by replace ⟨P, hP⟩ := P induction hn : Fintype.card V - P.support.length generalizing u P case zero => have fact : P.support.toFinset = Finset.univ := by apply Finset.eq_univ_of_card rw [isPath_def] at hP rw [←(List.toFinset_card_of_nodup hP)] at hn apply Nat.le_antisymm · exact Finset.card_le_univ P.support.toFinset · omega use u, Walk.nil simp only [Walk.nil_append, fact, Finset.coe_univ, Finset.subset_univ, and_true] assumption case succ n ih => by_cases hu : G.neighborFinset u ⊆ P.support.toFinset case pos => use u, Walk.nil simp only [Walk.nil_append] exact ⟨hP, hu⟩ case neg => simp [Finset.subset_iff] at hu have ⟨x, e, hx⟩ := hu replace e : G.Adj x u := G.adj_symm e let P' := Walk.cons e P have hP' : IsPath P' := IsPath.cons hP hx have hn' : Fintype.card V - P'.support.length = n := by simp only [P', Walk.support_cons, List.length_cons] omega have ⟨w, Q', hQ'⟩ := ih P' hP' hn' let Q := Walk.concat Q' e use w, Q simp only [Q, Walk.concat_append] simp only [P'] at hQ' assumption theorem brooks' (k : ℕ) (k_ge_3 : k ≥ 3) (maxDeg_le_k : G.maxDegree ≤ k) (no_max_clique : CliqueFree G (k + 1)) : Colorable G k := by induction hn : Fintype.card V using Nat.strong_induction_on generalizing V G case h n ih _ _ => by_cases h : n ≤ k · have n_colorable := G.colorable_of_fintype rw [hn] at n_colorable exact Colorable.mono h n_colorable · by_cases k_reg : G.IsRegularOfDegree k -- Assume G is not k-regular. case neg => simp [IsRegularOfDegree] at k_reg have ⟨x, hx⟩ := k_reg let S : Set V := Set.univ \ {x} let G' := G.induce S -- Apply induction have S_maxDeg_le_k : G'.maxDegree ≤ k := sorry -- induce_maxDegree_mono G S have S_no_max_clique : G'.CliqueFree (k + 1) := CliqueFree.comap (Embedding.induce S) no_max_clique have S_card : Fintype.card (↑S) = n - 1 := by simp only [S, ←Set.toFinset_card, Set.toFinset_diff, Set.toFinset_univ, Set.toFinset_singleton] have fact := Finset.card_inter_add_card_sdiff Finset.univ {x} simp [hn] at fact omega have fact : n - 1 < n := by omega have S_colorable : (G.induce S).Colorable k := ih (n - 1) fact (G.induce S) S_maxDeg_le_k S_no_max_clique S_card replace hx : G.degree x < k := by have hx' : G.degree x ≤ k := Nat.le_trans (G.degree_le_maxDegree x) maxDeg_le_k omega have G_colorable := extend_coloring'' G S S_colorable x hx have fact : S ∪ {x} = Set.univ := by simp only [Set.union_singleton, Set.insert_diff_singleton, Set.mem_univ, Set.insert_eq_of_mem, S] rw [fact] at G_colorable exact Colorable.of_embedding (G.induceUnivIso.symm.toEmbedding) G_colorable -- Assume G is k-regular. case pos => -- Pick any vertex v. have V_nonempty : Nonempty V := by apply Fintype.card_pos_iff.mp omega let v := V_nonempty.some -- Since G does not contain a clique on k+1 vertices, there exist -- two neighbours x, y of v that are not adjacent in G. have claim : ∃ x y : V, x ≠ y ∧ G.Adj v x ∧ G.Adj v y ∧ ¬G.Adj x y := by by_contra wrong apply no_max_clique case t => exact (G.neighborSet v ∪ {v}).toFinset case a => apply IsNClique.mk case card_eq => simp only [Set.union_singleton, Set.toFinset_insert, Set.mem_toFinset, mem_neighborSet, SimpleGraph.irrefl, not_false_eq_true, Finset.card_insert_of_not_mem, Set.toFinset_card, Fintype.card_ofFinset, Nat.add_left_inj] have fact : ({x | G.Adj v x} : Finset V) = G.neighborFinset v := by ext a simp only [Finset.mem_filter, Finset.mem_univ, true_and, mem_neighborFinset] simp only [fact, card_neighborFinset_eq_degree] exact k_reg v case isClique => intro x hx y hy x_ne_y simp at hx hy cases' hx with x_eq_v hx <;> cases' hy with y_eq_v hy · rw [x_eq_v, y_eq_v] at x_ne_y contradiction · rw [←x_eq_v] at hy assumption · rw [←y_eq_v] at hx exact G.adj_symm hx · simp at wrong exact wrong x y x_ne_y hx hy have ⟨x, y, x_ne_y, hx, hy, x_nadj_y⟩ := claim sorry