Dev/MonadicDependence/NowhereDenseBridge/Full.lean
| 1 | import Catalog.Sparsity.Preliminaries.Full |
| 2 | import Catalog.Sparsity.NowhereDense.Full |
| 3 | import Catalog.Sparsity.ShallowMinor.Full |
| 4 | import Catalog.Sparsity.ShallowTopologicalMinor.Full |
| 5 | import Catalog.Sparsity.Ramsey.Full |
| 6 | import Catalog.Sparsity.MulticolorRamsey.Full |
| 7 | import Dev.MonadicDependence.NowhereDense.Full |
| 8 | import Dev.MonadicDependence.Subdivision.Full |
| 9 | |
| 10 | namespace Dev.MonadicDependence.NowhereDenseBridge |
| 11 | |
| 12 | open Catalog.Sparsity.Preliminaries |
| 13 | open Catalog.Sparsity.ShallowMinor |
| 14 | open Catalog.Sparsity.ShallowTopologicalMinor |
| 15 | open Dev.MonadicDependence.Subdivision |
| 16 | |
| 17 | /-- Adjacency between two consecutive subdivision vertices on the same |
| 18 | oriented edge of `subdividedClique N r`. -/ |
| 19 | private lemma subdividedClique_adj_subdivision |
| 20 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) |
| 21 | (k k' : Fin r) (h : k.val + 1 = k'.val) : |
| 22 | (subdividedClique N r).Adj |
| 23 | (Sum.inr ⟨e, k⟩ : SubdividedCliqueVert N r) |
| 24 | (Sum.inr ⟨e, k'⟩ : SubdividedCliqueVert N r) := by |
| 25 | refine ⟨fun heq => ?_, Or.inl ⟨rfl, h⟩⟩ |
| 26 | simp only [Sum.inr.injEq, Prod.mk.injEq] at heq |
| 27 | have : k.val = k'.val := congrArg Fin.val heq.2 |
| 28 | omega |
| 29 | |
| 30 | /-- Adjacency between the last subdivision vertex of an oriented edge and |
| 31 | its head principal vertex. -/ |
| 32 | private lemma subdividedClique_adj_principal_right |
| 33 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) |
| 34 | (k : Fin r) (hk : k.val = r - 1) : |
| 35 | (subdividedClique N r).Adj |
| 36 | (Sum.inr ⟨e, k⟩ : SubdividedCliqueVert N r) |
| 37 | (Sum.inl e.1.2 : SubdividedCliqueVert N r) := by |
| 38 | refine ⟨?_, Or.inr (Or.inr ⟨rfl, hk⟩)⟩ |
| 39 | intro heq; nomatch heq |
| 40 | |
| 41 | /-- Adjacency between the tail principal vertex of an oriented edge and |
| 42 | its first subdivision vertex. -/ |
| 43 | private lemma subdividedClique_adj_principal_left |
| 44 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) |
| 45 | (k : Fin r) (hk : k.val = 0) : |
| 46 | (subdividedClique N r).Adj |
| 47 | (Sum.inl e.1.1 : SubdividedCliqueVert N r) |
| 48 | (Sum.inr ⟨e, k⟩ : SubdividedCliqueVert N r) := by |
| 49 | refine ⟨?_, Or.inl (Or.inl ⟨rfl, hk⟩)⟩ |
| 50 | intro heq; nomatch heq |
| 51 | |
| 52 | /-- The tail segment of a subdivided-clique edge path, starting at the |
| 53 | subdivision vertex indexed by `k` and ending at the head principal |
| 54 | vertex. -/ |
| 55 | private def subdivisionTailWalk : |
| 56 | {N : ℕ} → {r : ℕ} → (e : {p : Fin N × Fin N // p.1 < p.2}) → (k : Fin r) → |
| 57 | (subdividedClique N r).Walk (Sum.inr ⟨e, k⟩) (Sum.inl e.1.2) |
| 58 | | _, 0, _, k => k.elim0 |
| 59 | | N, r' + 1, e, k => |
| 60 | Fin.reverseInduction |
| 61 | (motive := fun (k : Fin (r' + 1)) => |
| 62 | (subdividedClique N (r' + 1)).Walk |
| 63 | (Sum.inr ⟨e, k⟩ : SubdividedCliqueVert N (r' + 1)) |
| 64 | (Sum.inl e.1.2)) |
| 65 | (SimpleGraph.Walk.cons |
| 66 | (subdividedClique_adj_principal_right e (Fin.last r') rfl) |
| 67 | SimpleGraph.Walk.nil) |
| 68 | (fun i w => |
| 69 | SimpleGraph.Walk.cons |
| 70 | (subdividedClique_adj_subdivision e i.castSucc i.succ rfl) |
| 71 | w) |
| 72 | k |
| 73 | |
| 74 | private lemma subdivisionTailWalk_length |
| 75 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) (k : Fin r) : |
| 76 | (subdivisionTailWalk e k).length = r - k.val := by |
| 77 | match r, k with |
| 78 | | r' + 1, k => |
| 79 | induction k using Fin.reverseInduction with |
| 80 | | last => |
| 81 | simp [subdivisionTailWalk] |
| 82 | | cast i ih => |
| 83 | simp [subdivisionTailWalk] at ih ⊢ |
| 84 | have hi : i.val < r' := i.isLt |
| 85 | omega |
| 86 | |
| 87 | private lemma mem_subdivisionTailWalk_support |
| 88 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) (k : Fin r) |
| 89 | {x : SubdividedCliqueVert N r} |
| 90 | (hx : x ∈ (subdivisionTailWalk e k).support) : |
| 91 | x = .inl e.1.2 ∨ ∃ j : Fin r, k.val ≤ j.val ∧ x = .inr ⟨e, j⟩ := by |
| 92 | revert x |
| 93 | match r, k with |
| 94 | | r' + 1, k => |
| 95 | induction k using Fin.reverseInduction with |
| 96 | | last => |
| 97 | intro x hx |
| 98 | simp [subdivisionTailWalk] at hx |
| 99 | rcases hx with rfl | rfl |
| 100 | · exact Or.inr ⟨Fin.last r', le_rfl, rfl⟩ |
| 101 | · exact Or.inl rfl |
| 102 | | cast i ih => |
| 103 | intro x hx |
| 104 | simp [subdivisionTailWalk] at hx |
| 105 | rcases hx with rfl | hx |
| 106 | · exact Or.inr ⟨i.castSucc, le_rfl, rfl⟩ |
| 107 | · rcases ih hx with h | ⟨j, hj, hxj⟩ |
| 108 | · exact Or.inl h |
| 109 | · refine Or.inr ⟨j, ?_, hxj⟩ |
| 110 | have : i.castSucc.val + 1 = i.succ.val := rfl |
| 111 | omega |
| 112 | |
| 113 | private lemma subdivisionTailWalk_isPath |
| 114 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) (k : Fin r) : |
| 115 | (subdivisionTailWalk e k).IsPath := by |
| 116 | match r, k with |
| 117 | | r' + 1, k => |
| 118 | induction k using Fin.reverseInduction with |
| 119 | | last => |
| 120 | simp [subdivisionTailWalk] |
| 121 | | cast i ih => |
| 122 | simp [subdivisionTailWalk] |
| 123 | refine ⟨ih, ?_⟩ |
| 124 | intro hmem |
| 125 | rcases mem_subdivisionTailWalk_support e i.succ hmem with h | ⟨j, hj, hxj⟩ |
| 126 | · nomatch h |
| 127 | · simp only [Sum.inr.injEq, Prod.mk.injEq] at hxj |
| 128 | have hval : i.castSucc.val = j.val := congrArg Fin.val hxj.2 |
| 129 | have hi : i.castSucc.val + 1 = i.succ.val := rfl |
| 130 | omega |
| 131 | |
| 132 | /-- The canonical routed walk along the subdivided edge corresponding to |
| 133 | `e`. -/ |
| 134 | private def forwardSubdivisionWalk : |
| 135 | {N : ℕ} → {r : ℕ} → (e : {p : Fin N × Fin N // p.1 < p.2}) → |
| 136 | (subdividedClique N r).Walk (Sum.inl e.1.1) (Sum.inl e.1.2) |
| 137 | | _, 0, e => |
| 138 | SimpleGraph.Walk.cons |
| 139 | (show (subdividedClique _ 0).Adj (Sum.inl e.1.1) (Sum.inl e.1.2) from |
| 140 | ⟨fun heq => absurd (Sum.inl.inj heq) (Fin.ne_of_lt e.2), |
| 141 | Or.inl rfl⟩) |
| 142 | SimpleGraph.Walk.nil |
| 143 | | _, r' + 1, e => |
| 144 | SimpleGraph.Walk.cons |
| 145 | (subdividedClique_adj_principal_left e (⟨0, Nat.succ_pos _⟩ : Fin (r' + 1)) rfl) |
| 146 | (subdivisionTailWalk e (⟨0, Nat.succ_pos _⟩ : Fin (r' + 1))) |
| 147 | |
| 148 | private lemma forwardSubdivisionWalk_length |
| 149 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) : |
| 150 | (@forwardSubdivisionWalk N r e).length = r + 1 := by |
| 151 | match r with |
| 152 | | 0 => simp [forwardSubdivisionWalk] |
| 153 | | r' + 1 => |
| 154 | simp [forwardSubdivisionWalk, subdivisionTailWalk_length] |
| 155 | |
| 156 | private lemma forwardSubdivisionWalk_isPath |
| 157 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) : |
| 158 | (@forwardSubdivisionWalk N r e).IsPath := by |
| 159 | match r with |
| 160 | | 0 => |
| 161 | simp [forwardSubdivisionWalk] |
| 162 | exact Fin.ne_of_lt e.2 |
| 163 | | r' + 1 => |
| 164 | simp [forwardSubdivisionWalk] |
| 165 | refine ⟨subdivisionTailWalk_isPath e _, ?_⟩ |
| 166 | intro hmem |
| 167 | rcases mem_subdivisionTailWalk_support e _ hmem with h | ⟨j, _, hxj⟩ |
| 168 | · exact absurd (Sum.inl.inj h) (Fin.ne_of_lt e.2) |
| 169 | · nomatch hxj |
| 170 | |
| 171 | private noncomputable def completeEdgeOrient |
| 172 | {N : ℕ} (e : (SimpleGraph.completeGraph (Fin N)).edgeSet) : |
| 173 | {p : Fin N × Fin N // p.1 < p.2} := by |
| 174 | have hne : e.1.out.1 ≠ e.1.out.2 := by |
| 175 | have heMem : s(e.1.out.1, e.1.out.2) ∈ (SimpleGraph.completeGraph (Fin N)).edgeSet := by |
| 176 | rw [Sym2.mk, e.1.out_eq] |
| 177 | exact e.2 |
| 178 | have heAdj : (SimpleGraph.completeGraph (Fin N)).Adj e.1.out.1 e.1.out.2 := by |
| 179 | rwa [SimpleGraph.mem_edgeSet] at heMem |
| 180 | exact (SimpleGraph.top_adj _ _).mp heAdj |
| 181 | by_cases h : e.1.out.1 < e.1.out.2 |
| 182 | · exact ⟨(e.1.out.1, e.1.out.2), h⟩ |
| 183 | · exact ⟨(e.1.out.2, e.1.out.1), lt_of_le_of_ne (le_of_not_gt h) hne.symm⟩ |
| 184 | |
| 185 | private lemma completeEdgeOrient_spec |
| 186 | {N : ℕ} (e : (SimpleGraph.completeGraph (Fin N)).edgeSet) : |
| 187 | s((completeEdgeOrient e).1.1, (completeEdgeOrient e).1.2) = (e : Sym2 (Fin N)) := by |
| 188 | by_cases h : e.1.out.1 < e.1.out.2 |
| 189 | · simp [completeEdgeOrient, h, Sym2.mk, e.1.out_eq] |
| 190 | · simp [completeEdgeOrient, h, Sym2.eq_swap, Sym2.mk, e.1.out_eq] |
| 191 | |
| 192 | private noncomputable def completeEdgeTail |
| 193 | {N : ℕ} (e : (SimpleGraph.completeGraph (Fin N)).edgeSet) : Fin N := |
| 194 | (completeEdgeOrient e).1.1 |
| 195 | |
| 196 | private lemma completeEdgeTail_mem |
| 197 | {N : ℕ} (e : (SimpleGraph.completeGraph (Fin N)).edgeSet) : |
| 198 | completeEdgeTail e ∈ (e : Sym2 (Fin N)) := by |
| 199 | refine ⟨(completeEdgeOrient e).1.2, ?_⟩ |
| 200 | simpa [completeEdgeTail] using (completeEdgeOrient_spec e).symm |
| 201 | |
| 202 | private noncomputable def completeEdgeHead |
| 203 | {N : ℕ} (e : (SimpleGraph.completeGraph (Fin N)).edgeSet) : Fin N := |
| 204 | Sym2.Mem.other (completeEdgeTail_mem e) |
| 205 | |
| 206 | private lemma completeEdgeHead_eq |
| 207 | {N : ℕ} (e : (SimpleGraph.completeGraph (Fin N)).edgeSet) : |
| 208 | completeEdgeHead e = (completeEdgeOrient e).1.2 := by |
| 209 | have hmem : completeEdgeHead e ∈ (e : Sym2 (Fin N)) := by |
| 210 | exact Sym2.other_mem (completeEdgeTail_mem e) |
| 211 | have hmem' : completeEdgeHead e ∈ |
| 212 | s((completeEdgeOrient e).1.1, (completeEdgeOrient e).1.2) := by |
| 213 | simpa [completeEdgeOrient_spec e] using hmem |
| 214 | have hne : completeEdgeHead e ≠ completeEdgeTail e := by |
| 215 | simpa [completeEdgeHead] using |
| 216 | (SimpleGraph.completeGraph (Fin N)).edge_other_ne e.2 (completeEdgeTail_mem e) |
| 217 | have hcases : completeEdgeHead e = completeEdgeTail e ∨ |
| 218 | completeEdgeHead e = (completeEdgeOrient e).1.2 := by |
| 219 | simpa [completeEdgeTail] using (Sym2.mem_iff.mp hmem') |
| 220 | exact hcases.resolve_left hne |
| 221 | |
| 222 | private noncomputable def completeEdgeWalk |
| 223 | {N r : ℕ} (e : (SimpleGraph.completeGraph (Fin N)).edgeSet) : |
| 224 | (subdividedClique N r).Walk |
| 225 | (Sum.inl (completeEdgeTail e)) |
| 226 | (Sum.inl (Sym2.Mem.other (completeEdgeTail_mem e))) := by |
| 227 | exact (forwardSubdivisionWalk (completeEdgeOrient e)).copy rfl |
| 228 | (congrArg Sum.inl (completeEdgeHead_eq e).symm) |
| 229 | |
| 230 | /-- Every vertex on the canonical subdivided-edge walk lies either at one |
| 231 | endpoint or on the subdivision chain of that same edge. -/ |
| 232 | private lemma mem_forwardSubdivisionWalk_support |
| 233 | {N r : ℕ} (e : {p : Fin N × Fin N // p.1 < p.2}) |
| 234 | {x : SubdividedCliqueVert N r} |
| 235 | (hx : x ∈ (forwardSubdivisionWalk e).support) : |
| 236 | x = .inl e.1.1 ∨ x = .inl e.1.2 ∨ ∃ k : Fin r, x = .inr ⟨e, k⟩ := by |
| 237 | match r with |
| 238 | | 0 => |
| 239 | simp [forwardSubdivisionWalk] at hx |
| 240 | rcases hx with rfl | rfl |
| 241 | · exact Or.inl rfl |
| 242 | · exact Or.inr (Or.inl rfl) |
| 243 | | r' + 1 => |
| 244 | simp [forwardSubdivisionWalk] at hx |
| 245 | rcases hx with rfl | hx |
| 246 | · exact Or.inl rfl |
| 247 | · rcases mem_subdivisionTailWalk_support e _ hx with h | ⟨j, _, hj⟩ |
| 248 | · exact Or.inr (Or.inl h) |
| 249 | · exact Or.inr (Or.inr ⟨j, hj⟩) |
| 250 | |
| 251 | /-- Forward-direction helper: a subgraph copy of an `r`-subdivided clique |
| 252 | of order `N` induces a depth-`⌈r/2⌉` shallow topological minor model of |
| 253 | `K_N`. The eventual Close session should build the explicit routed paths |
| 254 | along the subdivision edges. -/ |
| 255 | private theorem subdividedClique_isShallowTopologicalMinor |
| 256 | {V : Type} [DecidableEq V] [Fintype V] (G : SimpleGraph V) |
| 257 | (N r : ℕ) (hContain : (subdividedClique N r).IsContained G) : |
| 258 | IsShallowTopologicalMinor (SimpleGraph.completeGraph (Fin N)) G ((r + 1) / 2) := by |
| 259 | rcases hContain with ⟨copy⟩ |
| 260 | let model : |
| 261 | ShallowTopologicalMinorModel |
| 262 | (SimpleGraph.completeGraph (Fin N)) |
| 263 | G |
| 264 | ((r + 1) / 2) := |
| 265 | { branchVertex := |
| 266 | ⟨fun i => copy (Sum.inl i), fun _ _ h => Sum.inl.inj (copy.injective h)⟩ |
| 267 | edgeTail := completeEdgeTail |
| 268 | edgeTail_mem := completeEdgeTail_mem |
| 269 | edgePath := fun e => (completeEdgeWalk e).map copy.toHom |
| 270 | edgePath_isPath := by |
| 271 | intro e |
| 272 | exact SimpleGraph.Walk.map_isPath_of_injective copy.injective |
| 273 | (by simpa [completeEdgeWalk] using |
| 274 | (forwardSubdivisionWalk_isPath (completeEdgeOrient e))) |
| 275 | edgePath_length := by |
| 276 | intro e |
| 277 | calc |
| 278 | ((completeEdgeWalk e).map copy.toHom).length = r + 1 := by |
| 279 | simp [completeEdgeWalk, forwardSubdivisionWalk_length] |
| 280 | _ ≤ 2 * ((r + 1) / 2) + 1 := by omega |
| 281 | edgePath_interior_avoids_branch := by |
| 282 | intro e x hx htail hhead w |
| 283 | rw [SimpleGraph.Walk.support_map] at hx |
| 284 | rcases List.mem_map.mp hx with ⟨y, hy, rfl⟩ |
| 285 | have hy' : y ∈ (forwardSubdivisionWalk (completeEdgeOrient e)).support := by |
| 286 | simpa [completeEdgeWalk] using hy |
| 287 | rcases mem_forwardSubdivisionWalk_support (e := completeEdgeOrient e) hy' with |
| 288 | htail' | hhead' | ⟨k, hk⟩ |
| 289 | · exact (htail (by simpa [completeEdgeWalk] using congrArg copy htail')).elim |
| 290 | · have hheadEq : |
| 291 | copy (Sum.inl (completeEdgeOrient e).1.2) = |
| 292 | copy (Sum.inl (Sym2.Mem.other (completeEdgeTail_mem e))) := by |
| 293 | rw [← completeEdgeHead_eq e] |
| 294 | rfl |
| 295 | exact (hhead ((congrArg copy hhead').trans hheadEq)).elim |
| 296 | · intro hw |
| 297 | have : (Sum.inr ⟨completeEdgeOrient e, k⟩ : SubdividedCliqueVert N r) = Sum.inl w := by |
| 298 | exact hk.symm.trans (copy.injective hw) |
| 299 | nomatch this |
| 300 | edgePath_interior_disjoint := by |
| 301 | intro e e' x hne hx hx' htail hhead htail' hhead' |
| 302 | rw [SimpleGraph.Walk.support_map] at hx hx' |
| 303 | rcases List.mem_map.mp hx with ⟨y, hy, rfl⟩ |
| 304 | rcases List.mem_map.mp hx' with ⟨y', hy', hyy'⟩ |
| 305 | have hy0 : y ∈ (forwardSubdivisionWalk (completeEdgeOrient e)).support := by |
| 306 | simpa [completeEdgeWalk] using hy |
| 307 | have hy0' : y' ∈ (forwardSubdivisionWalk (completeEdgeOrient e')).support := by |
| 308 | simpa [completeEdgeWalk] using hy' |
| 309 | rcases mem_forwardSubdivisionWalk_support (e := completeEdgeOrient e) hy0 with |
| 310 | hxTail | hxHead | ⟨k, hk⟩ |
| 311 | · exact (htail (by simpa [completeEdgeWalk] using congrArg copy hxTail)).elim |
| 312 | · have hheadEq : |
| 313 | copy (Sum.inl (completeEdgeOrient e).1.2) = |
| 314 | copy (Sum.inl (Sym2.Mem.other (completeEdgeTail_mem e))) := by |
| 315 | rw [← completeEdgeHead_eq e] |
| 316 | rfl |
| 317 | exact (hhead ((congrArg copy hxHead).trans hheadEq)).elim |
| 318 | · rcases mem_forwardSubdivisionWalk_support (e := completeEdgeOrient e') hy0' with |
| 319 | hxTail' | hxHead' | ⟨k', hk'⟩ |
| 320 | · exact (htail' (hyy'.symm.trans (by simpa [completeEdgeWalk] using congrArg copy hxTail'))).elim |
| 321 | · have hheadEq' : |
| 322 | copy (Sum.inl (completeEdgeOrient e').1.2) = |
| 323 | copy (Sum.inl (Sym2.Mem.other (completeEdgeTail_mem e'))) := by |
| 324 | rw [← completeEdgeHead_eq e'] |
| 325 | rfl |
| 326 | exact (hhead' (hyy'.symm.trans ((congrArg copy hxHead').trans hheadEq'))).elim |
| 327 | · have horient : |
| 328 | completeEdgeOrient e = completeEdgeOrient e' := by |
| 329 | have hyy : y = y' := copy.injective hyy'.symm |
| 330 | have hpair : |
| 331 | (⟨completeEdgeOrient e, k⟩ : {p : Fin N × Fin N // p.1 < p.2} × Fin r) = |
| 332 | ⟨completeEdgeOrient e', k'⟩ := by |
| 333 | exact Sum.inr.inj (hk.symm.trans (hyy.trans hk')) |
| 334 | exact congrArg Prod.fst hpair |
| 335 | apply hne |
| 336 | apply Subtype.ext |
| 337 | have hsym : |
| 338 | s((completeEdgeOrient e).1.1, (completeEdgeOrient e).1.2) = |
| 339 | s((completeEdgeOrient e').1.1, (completeEdgeOrient e').1.2) := by |
| 340 | simpa using |
| 341 | congrArg (fun z : {p : Fin N × Fin N // p.1 < p.2} => s(z.1.1, z.1.2)) horient |
| 342 | calc |
| 343 | (e : Sym2 (Fin N)) = s((completeEdgeOrient e).1.1, (completeEdgeOrient e).1.2) := |
| 344 | (completeEdgeOrient_spec e).symm |
| 345 | _ = s((completeEdgeOrient e').1.1, (completeEdgeOrient e').1.2) := hsym |
| 346 | _ = (e' : Sym2 (Fin N)) := completeEdgeOrient_spec e' } |
| 347 | exact ⟨model⟩ |
| 348 | |
| 349 | /-- Shallow-minor nowhere denseness implies the local subdivided-clique |
| 350 | formulation. This is the linear parameter translation |
| 351 | `N_r := ω_{⌈r/2⌉}(C) + 1`. -/ |
| 352 | private theorem catalog_nowhereDense_to_dev_nowhereDense |
| 353 | (C : GraphClass) |
| 354 | (hCat : Catalog.Sparsity.NowhereDense.IsNowhereDense C) : |
| 355 | Dev.MonadicDependence.NowhereDense.IsNowhereDense C := by |
| 356 | intro r |
| 357 | rcases hCat ((r + 1) / 2) with ⟨t, ht⟩ |
| 358 | refine ⟨t + 1, ?_⟩ |
| 359 | intro V _ _ G hCG hContain |
| 360 | have hTop : |
| 361 | IsShallowTopologicalMinor (SimpleGraph.completeGraph (Fin (t + 1))) G ((r + 1) / 2) := |
| 362 | subdividedClique_isShallowTopologicalMinor G (t + 1) r hContain |
| 363 | exact ht G hCG (shallowTopologicalMinor_toShallowMinor hTop) |
| 364 | |
| 365 | /-- Step 1 data for the backward direction: starting from a shallow minor |
| 366 | model of `K_{t+1}`, record the centre-to-centre candidate walks obtained |
| 367 | by concatenating the branch-radius walks with the bridge edge. Each walk |
| 368 | has length at most `2 d + 1`. -/ |
| 369 | private structure CandidatePathData {V : Type} (G : SimpleGraph V) (d t : ℕ) where |
| 370 | model : ShallowMinorModel (SimpleGraph.completeGraph (Fin (t + 1))) G d |
| 371 | /-- For every pair of distinct clique vertices `i ≠ j`, a walk in `G` |
| 372 | between the corresponding branch-set centres. -/ |
| 373 | candidateWalk : ∀ {i j : Fin (t + 1)}, i ≠ j → |
| 374 | G.Walk (model.center i) (model.center j) |
| 375 | /-- Each candidate walk has length at most `2 d + 1`. -/ |
| 376 | candidateWalk_length_le : ∀ {i j : Fin (t + 1)} (h : i ≠ j), |
| 377 | (candidateWalk h).length ≤ 2 * d + 1 |
| 378 | |
| 379 | /-- Step 2 data: after a multicolour Ramsey pass, all candidate paths on a |
| 380 | subclique `subclique` of size at least `m` share a common length |
| 381 | `commonLength ≤ 2d + 1`. |
| 382 | |
| 383 | `hasCommonLengthWalk` is stated existentially (rather than fixing |
| 384 | `candidateWalk` itself) so that we can symmetrise the orientation: for a |
| 385 | subclique edge `{i, j}`, the common-length walk is realised by whichever of |
| 386 | `candidateWalk (i ≠ j)` or the reverse of `candidateWalk (j ≠ i)` matches |
| 387 | the Ramsey-monochromatic colour. Step 1 makes no symmetry guarantee |
| 388 | between `candidateWalk h` and `candidateWalk h.symm`, and the existential |
| 389 | form keeps Step 1 unchanged. |
| 390 | |
| 391 | The size parameter `m` records the lower bound on the monochromatic |
| 392 | subclique produced by `multicolorRamsey`. It threads through downstream |
| 393 | steps so that Step 6 can pick a final `t` large enough to contradict the |
| 394 | local nowhere-dense hypothesis. -/ |
| 395 | private structure UniformLengthData {V : Type} (G : SimpleGraph V) (d t m : ℕ) |
| 396 | extends CandidatePathData G d t where |
| 397 | subclique : Finset (Fin (t + 1)) |
| 398 | subclique_card_ge : m ≤ subclique.card |
| 399 | commonLength : ℕ |
| 400 | commonLength_le : commonLength ≤ 2 * d + 1 |
| 401 | hasCommonLengthWalk : ∀ {i j : Fin (t + 1)}, |
| 402 | i ∈ subclique → j ∈ subclique → i ≠ j → |
| 403 | ∃ w : G.Walk (model.center i) (model.center j), w.length = commonLength |
| 404 | |
| 405 | /-- Step 3 data: after the iterative two-colour Ramsey refinement, the |
| 406 | branching pattern at every interior level is canonical on the surviving |
| 407 | subclique. Concretely: |
| 408 | |
| 409 | * `canonicalWalk` fixes a specific common-length walk between subclique |
| 410 | centres, chosen via `Classical.choose` on the inherited |
| 411 | `hasCommonLengthWalk` existential so that the rest of the scaffold can |
| 412 | talk about concrete vertices of the walk. |
| 413 | * `patternShared i h` is the shared/disjoint flag at focus vertex `i` and |
| 414 | interior level `h`: `true` means all canonical walks from `center i` |
| 415 | pass through the same `h`-th vertex on the subclique, `false` means the |
| 416 | `h`-th vertices are pairwise distinct as the other endpoint varies. |
| 417 | Values outside the relevant range (`h ≥ commonLength`) are unspecified |
| 418 | and the spec fields take no view of them. -/ |
| 419 | private structure CanonicalPatternData {V : Type} (G : SimpleGraph V) (d t m : ℕ) |
| 420 | extends UniformLengthData G d t m where |
| 421 | /-- A concrete walk of length `commonLength` between the branch-set centres |
| 422 | of any two distinct subclique vertices. Chosen to realise the inherited |
| 423 | `hasCommonLengthWalk` existential. -/ |
| 424 | canonicalWalk : ∀ {i j : Fin (t + 1)}, |
| 425 | i ∈ subclique → j ∈ subclique → i ≠ j → |
| 426 | G.Walk (model.center i) (model.center j) |
| 427 | /-- Each canonical walk has length exactly `commonLength`. -/ |
| 428 | canonicalWalk_length : ∀ {i j : Fin (t + 1)} |
| 429 | (hi : i ∈ subclique) (hj : j ∈ subclique) (hij : i ≠ j), |
| 430 | (canonicalWalk hi hj hij).length = commonLength |
| 431 | /-- Branching-pattern bit: for each focus vertex `i` and level `h`, |
| 432 | `patternShared i h = true` means "all canonical walks from `center i` |
| 433 | share the `h`-th vertex on the subclique", `false` means "they have |
| 434 | pairwise distinct `h`-th vertices". Levels `h ≥ commonLength` are |
| 435 | unconstrained. -/ |
| 436 | patternShared : Fin (t + 1) → ℕ → Bool |
| 437 | /-- Spec for the "shared" bit: if `patternShared i h = true`, then for any |
| 438 | two other subclique vertices `j`, `k`, the `h`-th vertices of the |
| 439 | canonical walks `center i → center j` and `center i → center k` agree. -/ |
| 440 | patternShared_shared : ∀ {i j k : Fin (t + 1)} |
| 441 | (hi : i ∈ subclique) (hj : j ∈ subclique) (hk : k ∈ subclique) |
| 442 | (hij : i ≠ j) (hik : i ≠ k) |
| 443 | {h : ℕ}, h < commonLength → patternShared i h = true → |
| 444 | (canonicalWalk hi hj hij).getVert h = |
| 445 | (canonicalWalk hi hk hik).getVert h |
| 446 | /-- Spec for the "disjoint" bit: if `patternShared i h = false`, then for |
| 447 | any two distinct other subclique vertices `j ≠ k`, the `h`-th vertices of |
| 448 | the canonical walks `center i → center j` and `center i → center k` |
| 449 | differ. -/ |
| 450 | patternShared_disjoint : ∀ {i j k : Fin (t + 1)} |
| 451 | (hi : i ∈ subclique) (hj : j ∈ subclique) (hk : k ∈ subclique) |
| 452 | (hij : i ≠ j) (hik : i ≠ k) (_hjk : j ≠ k) |
| 453 | {h : ℕ}, h < commonLength → patternShared i h = false → |
| 454 | (canonicalWalk hi hj hij).getVert h ≠ |
| 455 | (canonicalWalk hi hk hik).getVert h |
| 456 | |
| 457 | /-- Step 4 data: after the shared prefixes/suffixes have been trimmed and any |
| 458 | residual interior collisions cleaned up, we have, on the surviving subclique, |
| 459 | a new system of internally disjoint walks of uniform length `trimmedLength + 1` |
| 460 | between trimmed centres `c_i' ∈ B_i`, with `trimmedLength ≤ 2d`. |
| 461 | |
| 462 | The interior-disjointness spec is stated so that Step 5 can assemble a |
| 463 | `subdividedClique`-shaped subgraph copy: interiors of distinct trimmed walks |
| 464 | are entirely disjoint, and no interior vertex of a walk coincides with any |
| 465 | trimmed centre (other than the walk's own endpoints). -/ |
| 466 | private structure TrimmedPathData {V : Type} (G : SimpleGraph V) (d t m : ℕ) |
| 467 | extends CanonicalPatternData G d t m where |
| 468 | /-- Uniform internal-path length, `ℓ' ≤ 2d`. -/ |
| 469 | trimmedLength : ℕ |
| 470 | trimmedLength_le : trimmedLength ≤ 2 * d |
| 471 | /-- Trimmed centre `c_i'` at the tip of `i`'s shared prefix. Lies in the |
| 472 | branch set `B_i` of the minor model for every subclique vertex `i`. -/ |
| 473 | trimmedCenter : Fin (t + 1) → V |
| 474 | trimmedCenter_mem : ∀ {i : Fin (t + 1)}, |
| 475 | i ∈ subclique → trimmedCenter i ∈ model.branchSet i |
| 476 | /-- Trimmed walk between the trimmed centres of two distinct subclique |
| 477 | vertices, of uniform length `trimmedLength + 1`. -/ |
| 478 | trimmedWalk : ∀ {i j : Fin (t + 1)}, |
| 479 | i ∈ subclique → j ∈ subclique → i ≠ j → |
| 480 | G.Walk (trimmedCenter i) (trimmedCenter j) |
| 481 | trimmedWalk_length : ∀ {i j : Fin (t + 1)} |
| 482 | (hi : i ∈ subclique) (hj : j ∈ subclique) (hij : i ≠ j), |
| 483 | (trimmedWalk hi hj hij).length = trimmedLength + 1 |
| 484 | trimmedWalk_isPath : ∀ {i j : Fin (t + 1)} |
| 485 | (hi : i ∈ subclique) (hj : j ∈ subclique) (hij : i ≠ j), |
| 486 | (trimmedWalk hi hj hij).IsPath |
| 487 | /-- Centre-avoidance: no vertex of any trimmed walk equals any trimmed |
| 488 | centre of the subclique, except at the walk's two own endpoints. -/ |
| 489 | trimmedWalk_avoids_centres : ∀ {i j k : Fin (t + 1)} |
| 490 | (hi : i ∈ subclique) (hj : j ∈ subclique) (_hk : k ∈ subclique) |
| 491 | (hij : i ≠ j) {v : V}, |
| 492 | v ∈ (trimmedWalk hi hj hij).support → |
| 493 | v = trimmedCenter k → k = i ∨ k = j |
| 494 | /-- Pairwise interior-disjointness: if a vertex lies on two trimmed walks |
| 495 | indexed by distinct unordered pairs, it must already be one of the two |
| 496 | endpoints of the first walk (and hence, by centre-avoidance on the other |
| 497 | walk, also an endpoint of the second — the shared endpoint case). -/ |
| 498 | trimmedWalk_interior_disjoint : ∀ {i j i' j' : Fin (t + 1)} |
| 499 | (hi : i ∈ subclique) (hj : j ∈ subclique) (hij : i ≠ j) |
| 500 | (hi' : i' ∈ subclique) (hj' : j' ∈ subclique) (hi'j' : i' ≠ j') |
| 501 | (_hpair_ne : s(i, j) ≠ s(i', j')) |
| 502 | {v : V}, |
| 503 | v ∈ (trimmedWalk hi hj hij).support → |
| 504 | v ∈ (trimmedWalk hi' hj' hi'j').support → |
| 505 | v = trimmedCenter i ∨ v = trimmedCenter j |
| 506 | |
| 507 | /-- Step 5 data: the cleaned path system has been packaged as a subgraph copy |
| 508 | of a subdivided clique in `G`. The subdivision order is at least `m`, which |
| 509 | is what Step 6 eventually inverts against the local nowhere-dense bound. -/ |
| 510 | private structure CleanSubdivisionData {V : Type} (G : SimpleGraph V) (d t m : ℕ) |
| 511 | extends TrimmedPathData G d t m where |
| 512 | subdivisionOrder : ℕ |
| 513 | subdivisionOrder_ge : m ≤ subdivisionOrder |
| 514 | contained : (subdividedClique subdivisionOrder trimmedLength).IsContained G |
| 515 | |
| 516 | /-- Backward direction, Step 1: from a shallow minor model, build the |
| 517 | centre-to-centre candidate paths of length at most `2d + 1`. -/ |
| 518 | private noncomputable def backward_step1_candidate_paths |
| 519 | {V : Type} [DecidableEq V] [Fintype V] {G : SimpleGraph V} |
| 520 | {d t : ℕ} |
| 521 | (hMinor : IsShallowMinor (SimpleGraph.completeGraph (Fin (t + 1))) G d) : |
| 522 | CandidatePathData G d t := by |
| 523 | classical |
| 524 | let model := hMinor.some |
| 525 | have hwalk : ∀ {i j : Fin (t + 1)}, i ≠ j → |
| 526 | ∃ w : G.Walk (model.center i) (model.center j), w.length ≤ 2 * d + 1 := by |
| 527 | intro i j hij |
| 528 | have hadj : (SimpleGraph.completeGraph (Fin (t + 1))).Adj i j := |
| 529 | (SimpleGraph.top_adj i j).mpr hij |
| 530 | obtain ⟨x, hx, y, hy, hxy⟩ := model.branchEdge i j hadj |
| 531 | obtain ⟨pxi, _, hxilen, _⟩ := model.branchRadius i x hx |
| 532 | obtain ⟨pyj, _, hyjlen, _⟩ := model.branchRadius j y hy |
| 533 | refine ⟨pxi.append (SimpleGraph.Walk.cons hxy pyj.reverse), ?_⟩ |
| 534 | simp [SimpleGraph.Walk.length_append, SimpleGraph.Walk.length_cons, |
| 535 | SimpleGraph.Walk.length_reverse] |
| 536 | omega |
| 537 | exact |
| 538 | { model := model |
| 539 | candidateWalk := fun {_ _} h => (hwalk h).choose |
| 540 | candidateWalk_length_le := fun {_ _} h => (hwalk h).choose_spec } |
| 541 | |
| 542 | /-- Backward direction, Step 2: multicolour Ramsey normalises the candidate |
| 543 | path lengths. We apply `Catalog.Sparsity.MulticolorRamsey.multicolorRamsey` |
| 544 | to the colouring `{i, j} ↦ min ((candidateWalk (i ≠ j)).length) |
| 545 | ((candidateWalk (j ≠ i)).length)`, with all colours targeting a |
| 546 | monochromatic subclique of size `m`. The hypothesis `hThresh` asserts that |
| 547 | the Ramsey threshold fits into `t + 1`, so Ramsey fires and the output |
| 548 | carries a subclique of size at least `m`. The final `t` / `m` choice is |
| 549 | deferred to `backward_step6_extract_bound`. -/ |
| 550 | private noncomputable def backward_step2_uniform_length |
| 551 | {V : Type} [DecidableEq V] [Fintype V] {G : SimpleGraph V} |
| 552 | {d t m : ℕ} |
| 553 | (hStep1 : CandidatePathData G d t) |
| 554 | (hThresh : |
| 555 | (Catalog.Sparsity.MulticolorRamsey.multicolorRamsey |
| 556 | (List.replicate (2 * d + 2) m) |
| 557 | List.replicate_succ_ne_nil).choose ≤ t + 1) : |
| 558 | UniformLengthData G d t m := by |
| 559 | classical |
| 560 | -- Symmetric length function on ordered pairs; clamp to `Fin (2d + 2)`. |
| 561 | let lenFn : Fin (t + 1) → Fin (t + 1) → ℕ := fun i j => |
| 562 | if h : i = j then 0 |
| 563 | else min (hStep1.candidateWalk h).length |
| 564 | (hStep1.candidateWalk (Ne.symm h)).length |
| 565 | have lenFn_le : ∀ i j, lenFn i j ≤ 2 * d + 1 := by |
| 566 | intro i j |
| 567 | change (if h : i = j then 0 else _) ≤ _ |
| 568 | by_cases h : i = j |
| 569 | · simp [h] |
| 570 | · rw [dif_neg h] |
| 571 | have h1 := hStep1.candidateWalk_length_le h |
| 572 | have h2 := hStep1.candidateWalk_length_le (Ne.symm h) |
| 573 | omega |
| 574 | have lenFn_symm : ∀ i j, lenFn i j = lenFn j i := by |
| 575 | intro i j |
| 576 | change (if h : i = j then 0 else _) = (if h : j = i then 0 else _) |
| 577 | by_cases h : i = j |
| 578 | · subst h; rfl |
| 579 | · have h' : j ≠ i := Ne.symm h |
| 580 | rw [dif_neg h, dif_neg h'] |
| 581 | exact Nat.min_comm _ _ |
| 582 | -- `multicolorRamsey` demands colours in `Fin sizes.length`. With |
| 583 | -- `sizes := List.replicate (2 d + 2) m`, `sizes.length` is propositionally |
| 584 | -- but not definitionally `2 d + 2`, so the colour function is typed in |
| 585 | -- `Fin sizes.length` and we bridge via `List.length_replicate`. |
| 586 | let colourFn : Sym2 (Fin (t + 1)) → |
| 587 | Fin (List.replicate (2 * d + 2) m).length := |
| 588 | Sym2.lift |
| 589 | ⟨fun i j => ⟨lenFn i j, by |
| 590 | rw [List.length_replicate] |
| 591 | exact Nat.lt_succ_of_le (lenFn_le i j)⟩, |
| 592 | fun i j => Fin.ext (lenFn_symm i j)⟩ |
| 593 | -- `multicolorRamsey` lives in `Prop`; the target type `UniformLengthData` |
| 594 | -- is a `Type`, so destructuring via `obtain` would fail with |
| 595 | -- `Exists.casesOn can only eliminate into Prop`. Use `Classical.choose` |
| 596 | -- instead, mirroring the Step 1 idiom for `IsShallowMinor`. |
| 597 | let hRam := |
| 598 | Catalog.Sparsity.MulticolorRamsey.multicolorRamsey |
| 599 | (List.replicate (2 * d + 2) m) |
| 600 | List.replicate_succ_ne_nil |
| 601 | have hcard : hRam.choose ≤ Fintype.card (Fin (t + 1)) := by |
| 602 | simpa [Fintype.card_fin] using hThresh |
| 603 | let hRamOut := hRam.choose_spec hcard colourFn |
| 604 | let i_ram : Fin (List.replicate (2 * d + 2) m).length := hRamOut.choose |
| 605 | let hS := hRamOut.choose_spec |
| 606 | let S : Finset (Fin (t + 1)) := hS.choose |
| 607 | have hSpair : (↑S : Set (Fin (t + 1))).Pairwise |
| 608 | (fun u v => colourFn s(u, v) = i_ram) := |
| 609 | hS.choose_spec.2 |
| 610 | have hSgeM : m ≤ S.card := by |
| 611 | have hsize : (List.replicate (2 * d + 2) m).get i_ram ≤ S.card := |
| 612 | hS.choose_spec.1 |
| 613 | -- `get` of a replicated list is the replicated value. |
| 614 | have hi_lt : i_ram.val < 2 * d + 2 := by |
| 615 | have := i_ram.isLt |
| 616 | simpa [List.length_replicate] using this |
| 617 | have hget : (List.replicate (2 * d + 2) m).get i_ram = m := by |
| 618 | simp [List.get_eq_getElem, List.getElem_replicate] |
| 619 | rw [hget] at hsize |
| 620 | exact hsize |
| 621 | refine |
| 622 | { toCandidatePathData := hStep1 |
| 623 | subclique := S |
| 624 | subclique_card_ge := hSgeM |
| 625 | commonLength := i_ram.val |
| 626 | commonLength_le := by |
| 627 | have hi := i_ram.isLt |
| 628 | have hLen : (List.replicate (2 * d + 2) m).length = 2 * d + 2 := |
| 629 | List.length_replicate |
| 630 | omega |
| 631 | hasCommonLengthWalk := ?_ } |
| 632 | intro a b ha hb hab |
| 633 | have haSet : a ∈ (↑S : Set (Fin (t + 1))) := by simpa using ha |
| 634 | have hbSet : b ∈ (↑S : Set (Fin (t + 1))) := by simpa using hb |
| 635 | have hcol : colourFn s(a, b) = i_ram := hSpair haSet hbSet hab |
| 636 | have hval : lenFn a b = i_ram.val := by |
| 637 | have hv := congrArg Fin.val hcol |
| 638 | simpa [colourFn, Sym2.lift_mk] using hv |
| 639 | have hlen : min (hStep1.candidateWalk hab).length |
| 640 | (hStep1.candidateWalk (Ne.symm hab)).length = i_ram.val := by |
| 641 | have : lenFn a b = min (hStep1.candidateWalk hab).length |
| 642 | (hStep1.candidateWalk (Ne.symm hab)).length := by |
| 643 | change (if h : a = b then 0 else _) = _ |
| 644 | rw [dif_neg hab] |
| 645 | rw [this] at hval |
| 646 | exact hval |
| 647 | rcases Nat.le_total (hStep1.candidateWalk hab).length |
| 648 | (hStep1.candidateWalk (Ne.symm hab)).length with hle | hle |
| 649 | · refine ⟨hStep1.candidateWalk hab, ?_⟩ |
| 650 | rw [Nat.min_eq_left hle] at hlen |
| 651 | exact hlen |
| 652 | · refine ⟨(hStep1.candidateWalk (Ne.symm hab)).reverse, ?_⟩ |
| 653 | rw [SimpleGraph.Walk.length_reverse] |
| 654 | rw [Nat.min_eq_right hle] at hlen |
| 655 | exact hlen |
| 656 | |
| 657 | /-- Non-emptiness helper for Step 3's Ramsey sizes list: the list is |
| 658 | `List.replicate K m` with `K` positive. -/ |
| 659 | private lemma step3_sizes_ne_nil (d t m : ℕ) : |
| 660 | List.replicate |
| 661 | (Fintype.card (Fin (t + 1) → Fin (2 * d + 1) → Bool)) m ≠ [] := by |
| 662 | rw [ne_eq, List.replicate_eq_nil_iff] |
| 663 | exact Fintype.card_ne_zero |
| 664 | |
| 665 | /-- Backward direction, Step 3: iterative two-colour Ramsey normalises the |
| 666 | shared-prefix/shared-suffix branching pattern. |
| 667 | |
| 668 | `hThresh3` bounds the threshold returned by multicolour Ramsey applied with |
| 669 | `(t+1)*(2d+1)`-bit colours (one bit per focus vertex, interior level). |
| 670 | Combined with the inherited `m ≤ hStep2.subclique.card`, it guarantees the |
| 671 | Ramsey call fires on the subclique's subtype. The Ramsey-monochromatic |
| 672 | colour then reads off the canonical branching pattern: for each focus |
| 673 | vertex `i` in the refined subclique and each interior level `h`, either all |
| 674 | canonical walks from `center i` share the same `h`-th vertex on the refined |
| 675 | subclique, or they have pairwise distinct `h`-th vertices. -/ |
| 676 | private noncomputable def backward_step3_canonical_pattern |
| 677 | {V : Type} [DecidableEq V] [Fintype V] {G : SimpleGraph V} |
| 678 | {d t m : ℕ} |
| 679 | (hStep2 : UniformLengthData G d t m) |
| 680 | (hThresh3 : |
| 681 | (Catalog.Sparsity.MulticolorRamsey.multicolorRamsey |
| 682 | (List.replicate |
| 683 | (Fintype.card (Fin (t + 1) → Fin (2 * d + 1) → Bool)) m) |
| 684 | (step3_sizes_ne_nil d t m)).choose ≤ m) : |
| 685 | CanonicalPatternData G d t m := by |
| 686 | classical |
| 687 | -- Shorthand for hStep2's subclique. |
| 688 | let S₂ : Finset (Fin (t + 1)) := hStep2.subclique |
| 689 | -- Pick concrete walks from the inherited existential. |
| 690 | let walk : ∀ {i j : Fin (t + 1)}, |
| 691 | i ∈ S₂ → j ∈ S₂ → i ≠ j → |
| 692 | G.Walk (hStep2.model.center i) (hStep2.model.center j) := |
| 693 | fun hi hj hij => (hStep2.hasCommonLengthWalk hi hj hij).choose |
| 694 | have walk_length : ∀ {i j : Fin (t + 1)} (hi : i ∈ S₂) (hj : j ∈ S₂) |
| 695 | (hij : i ≠ j), |
| 696 | (walk hi hj hij).length = hStep2.commonLength := |
| 697 | fun hi hj hij => (hStep2.hasCommonLengthWalk hi hj hij).choose_spec |
| 698 | -- Colour type for the Step-3 Ramsey: one Bool per (focus vertex, level). |
| 699 | let ColourT : Type := Fin (t + 1) → Fin (2 * d + 1) → Bool |
| 700 | let K : ℕ := Fintype.card ColourT |
| 701 | let sizes : List ℕ := List.replicate K m |
| 702 | -- Raw colour: given two subclique vertices `a ≠ b`, for each `(i, h)` the |
| 703 | -- bit says whether the `h`-th vertex of walk `i → a` equals walk `i → b` |
| 704 | -- at position `h`. When `i ∈ {a, b}` or `i ∉ S₂` we return `true` |
| 705 | -- (the branch is irrelevant; chosen so the raw function is symmetric in |
| 706 | -- `a, b`). |
| 707 | let rawBit : ↥S₂ → ↥S₂ → ColourT := fun a b i h => |
| 708 | if hia : i = a.val then true |
| 709 | else if hib : i = b.val then true |
| 710 | else if hi : i ∈ S₂ then |
| 711 | decide ((walk hi a.property hia).getVert h.val = |
| 712 | (walk hi b.property hib).getVert h.val) |
| 713 | else true |
| 714 | have rawBit_sym : ∀ a b, rawBit a b = rawBit b a := by |
| 715 | intro a b |
| 716 | funext i h |
| 717 | show (if hia : i = a.val then (true : Bool) |
| 718 | else if hib : i = b.val then (true : Bool) |
| 719 | else if hi : i ∈ S₂ then |
| 720 | decide ((walk hi a.property hia).getVert h.val = |
| 721 | (walk hi b.property hib).getVert h.val) |
| 722 | else (true : Bool)) = |
| 723 | (if hia : i = b.val then (true : Bool) |
| 724 | else if hib : i = a.val then (true : Bool) |
| 725 | else if hi : i ∈ S₂ then |
| 726 | decide ((walk hi b.property hia).getVert h.val = |
| 727 | (walk hi a.property hib).getVert h.val) |
| 728 | else (true : Bool)) |
| 729 | by_cases hia : i = a.val |
| 730 | · by_cases hib : i = b.val |
| 731 | · rw [dif_pos hia, dif_pos hib] |
| 732 | · rw [dif_pos hia, dif_neg hib, dif_pos hia] |
| 733 | · by_cases hib : i = b.val |
| 734 | · rw [dif_neg hia, dif_pos hib, dif_pos hib] |
| 735 | · by_cases hi : i ∈ S₂ |
| 736 | · rw [dif_neg hia, dif_neg hib, dif_pos hi, |
| 737 | dif_neg hib, dif_neg hia, dif_pos hi] |
| 738 | congr 1 |
| 739 | exact propext eq_comm |
| 740 | · rw [dif_neg hia, dif_neg hib, dif_neg hi, |
| 741 | dif_neg hib, dif_neg hia, dif_neg hi] |
| 742 | -- Sym2-lifted colour on subclique pairs. |
| 743 | let colourFn : Sym2 ↥S₂ → ColourT := Sym2.lift ⟨rawBit, rawBit_sym⟩ |
| 744 | -- We need `colourFn` typed as `Sym2 ↥S₂ → Fin sizes.length`. Bridge via |
| 745 | -- `Fintype.truncEquivFin` and `List.length_replicate`. |
| 746 | let equivCol : ColourT ≃ Fin K := (Fintype.truncEquivFin ColourT).out |
| 747 | have sizes_length : sizes.length = K := List.length_replicate |
| 748 | let finColourFn : Sym2 ↥S₂ → Fin sizes.length := fun p => |
| 749 | Fin.cast sizes_length.symm (equivCol (colourFn p)) |
| 750 | -- Apply the multicolour Ramsey. |
| 751 | have hRam_le : (Catalog.Sparsity.MulticolorRamsey.multicolorRamsey |
| 752 | sizes (step3_sizes_ne_nil d t m)).choose ≤ Fintype.card (↥S₂) := by |
| 753 | rw [Fintype.card_coe] |
| 754 | exact hThresh3.trans hStep2.subclique_card_ge |
| 755 | let hRam := Catalog.Sparsity.MulticolorRamsey.multicolorRamsey |
| 756 | sizes (step3_sizes_ne_nil d t m) |
| 757 | let hOut := hRam.choose_spec hRam_le finColourFn |
| 758 | let c_ram : Fin sizes.length := hOut.choose |
| 759 | let hOut2 := hOut.choose_spec |
| 760 | let T : Finset ↥S₂ := hOut2.choose |
| 761 | have hT_card : sizes.get c_ram ≤ T.card := hOut2.choose_spec.1 |
| 762 | have hT_pair : (↑T : Set ↥S₂).Pairwise |
| 763 | (fun u v => finColourFn s(u, v) = c_ram) := hOut2.choose_spec.2 |
| 764 | -- `sizes.get c_ram = m` since all entries of `sizes` are `m`. |
| 765 | have h_get_eq_m : sizes.get c_ram = m := by |
| 766 | have hi_lt : c_ram.val < K := by |
| 767 | simpa [sizes_length] using c_ram.isLt |
| 768 | simp [sizes, List.get_eq_getElem, List.getElem_replicate] |
| 769 | rw [h_get_eq_m] at hT_card |
| 770 | -- Refined subclique in `Fin (t + 1)`. |
| 771 | let S₃ : Finset (Fin (t + 1)) := T.image Subtype.val |
| 772 | have hS₃_sub : ∀ {x}, x ∈ S₃ → x ∈ S₂ := by |
| 773 | intro x hx |
| 774 | rcases Finset.mem_image.mp hx with ⟨⟨y, hy⟩, _, rfl⟩ |
| 775 | exact hy |
| 776 | have hS₃_card : m ≤ S₃.card := by |
| 777 | rw [show S₃.card = T.card from Finset.card_image_of_injective _ Subtype.val_injective] |
| 778 | exact hT_card |
| 779 | -- The monochromatic colour tuple, pulled back through `equivCol`. |
| 780 | let patternCol : ColourT := equivCol.symm (Fin.cast sizes_length c_ram) |
| 781 | -- Pattern on arbitrary levels: use the Ramsey colour bit for `h < 2*d+1`, |
| 782 | -- and `true` elsewhere (vacuous; only `h < commonLength ≤ 2*d+1` is used). |
| 783 | let patternShared : Fin (t + 1) → ℕ → Bool := fun i h => |
| 784 | if h_lt : h < 2 * d + 1 then patternCol i ⟨h, h_lt⟩ else true |
| 785 | -- Key bridging fact: for two distinct elements `j ≠ k` of `T` (as |
| 786 | -- subclique members), the raw colour at position `(i, h)` equals the |
| 787 | -- monochromatic pattern bit `patternCol i h`. |
| 788 | have colour_eq : ∀ {j k : ↥S₂}, j ∈ T → k ∈ T → j ≠ k → |
| 789 | rawBit j k = patternCol := by |
| 790 | intro j k hj hk hjk |
| 791 | have hpair : finColourFn s(j, k) = c_ram := hT_pair hj hk hjk |
| 792 | have hcol_eq : colourFn s(j, k) = patternCol := by |
| 793 | have hrev : equivCol (colourFn s(j, k)) = Fin.cast sizes_length c_ram := by |
| 794 | have := congrArg (Fin.cast sizes_length) hpair |
| 795 | simpa [finColourFn, Fin.cast_cast] using this |
| 796 | have := congrArg equivCol.symm hrev |
| 797 | simpa [patternCol] using this |
| 798 | simpa [colourFn, Sym2.lift_mk] using hcol_eq |
| 799 | -- Build the shared spec. |
| 800 | have shared_spec : ∀ {i j k : Fin (t + 1)} |
| 801 | (hi : i ∈ S₃) (hj : j ∈ S₃) (hk : k ∈ S₃) |
| 802 | (hij : i ≠ j) (hik : i ≠ k) {h : ℕ}, h < hStep2.commonLength → |
| 803 | patternShared i h = true → |
| 804 | (walk (hS₃_sub hi) (hS₃_sub hj) hij).getVert h = |
| 805 | (walk (hS₃_sub hi) (hS₃_sub hk) hik).getVert h := by |
| 806 | intro i j k hi hj hk hij hik h hh_lt hpat |
| 807 | -- Case split j = k (trivial) vs j ≠ k (use Ramsey monochromaticity). |
| 808 | by_cases hjk : j = k |
| 809 | · subst hjk; rfl |
| 810 | -- `hh_lt : h < commonLength ≤ 2*d+1`, so patternShared unfolds to patternCol. |
| 811 | have hh_lt_all : h < 2 * d + 1 := |
| 812 | lt_of_lt_of_le hh_lt hStep2.commonLength_le |
| 813 | have hpat_col : patternCol i ⟨h, hh_lt_all⟩ = true := by |
| 814 | change (if h_lt : h < 2 * d + 1 then patternCol i ⟨h, h_lt⟩ |
| 815 | else (true : Bool)) = true at hpat |
| 816 | rwa [dif_pos hh_lt_all] at hpat |
| 817 | -- Extract ⟨j, _⟩, ⟨k, _⟩ ∈ T. j, k ∈ S₃ means their "upgraded" versions are in T. |
| 818 | rcases Finset.mem_image.mp hj with ⟨jT, hjT, hjeq⟩ |
| 819 | rcases Finset.mem_image.mp hk with ⟨kT, hkT, hkeq⟩ |
| 820 | subst hjeq |
| 821 | subst hkeq |
| 822 | have hj_ne_k : jT ≠ kT := by |
| 823 | intro heq; apply hjk; exact congrArg Subtype.val heq |
| 824 | -- Apply colour_eq: rawBit jT kT = patternCol, in particular at (i, ⟨h, hh_lt_all⟩). |
| 825 | have hbit : rawBit jT kT i ⟨h, hh_lt_all⟩ = patternCol i ⟨h, hh_lt_all⟩ := by |
| 826 | rw [colour_eq hjT hkT hj_ne_k] |
| 827 | rw [hpat_col] at hbit |
| 828 | -- Unfold rawBit at the (i, ⟨h, hh_lt_all⟩) arguments with i ≠ jT.val, i ≠ kT.val, |
| 829 | -- i ∈ S₂ (via hi ∈ S₃ ⇒ S₂). |
| 830 | have hi_S₂ : i ∈ S₂ := hS₃_sub hi |
| 831 | have hi_ne_j : i ≠ jT.val := hij |
| 832 | have hi_ne_k : i ≠ kT.val := hik |
| 833 | simp only [rawBit] at hbit |
| 834 | rw [dif_neg hi_ne_j, dif_neg hi_ne_k, dif_pos hi_S₂] at hbit |
| 835 | have : decide |
| 836 | ((walk hi_S₂ jT.property hi_ne_j).getVert h = |
| 837 | (walk hi_S₂ kT.property hi_ne_k).getVert h) = true := hbit |
| 838 | exact of_decide_eq_true this |
| 839 | have disjoint_spec : ∀ {i j k : Fin (t + 1)} |
| 840 | (hi : i ∈ S₃) (hj : j ∈ S₃) (hk : k ∈ S₃) |
| 841 | (hij : i ≠ j) (hik : i ≠ k) (hjk : j ≠ k) |
| 842 | {h : ℕ}, h < hStep2.commonLength → patternShared i h = false → |
| 843 | (walk (hS₃_sub hi) (hS₃_sub hj) hij).getVert h ≠ |
| 844 | (walk (hS₃_sub hi) (hS₃_sub hk) hik).getVert h := by |
| 845 | intro i j k hi hj hk hij hik hjk h hh_lt hpat |
| 846 | have hh_lt_all : h < 2 * d + 1 := |
| 847 | lt_of_lt_of_le hh_lt hStep2.commonLength_le |
| 848 | have hpat_col : patternCol i ⟨h, hh_lt_all⟩ = false := by |
| 849 | change (if h_lt : h < 2 * d + 1 then patternCol i ⟨h, h_lt⟩ |
| 850 | else (true : Bool)) = false at hpat |
| 851 | rwa [dif_pos hh_lt_all] at hpat |
| 852 | rcases Finset.mem_image.mp hj with ⟨jT, hjT, hjeq⟩ |
| 853 | rcases Finset.mem_image.mp hk with ⟨kT, hkT, hkeq⟩ |
| 854 | subst hjeq |
| 855 | subst hkeq |
| 856 | have hj_ne_k : jT ≠ kT := by |
| 857 | intro heq; apply hjk; exact congrArg Subtype.val heq |
| 858 | have hbit : rawBit jT kT i ⟨h, hh_lt_all⟩ = patternCol i ⟨h, hh_lt_all⟩ := by |
| 859 | rw [colour_eq hjT hkT hj_ne_k] |
| 860 | rw [hpat_col] at hbit |
| 861 | have hi_S₂ : i ∈ S₂ := hS₃_sub hi |
| 862 | have hi_ne_j : i ≠ jT.val := hij |
| 863 | have hi_ne_k : i ≠ kT.val := hik |
| 864 | simp only [rawBit] at hbit |
| 865 | rw [dif_neg hi_ne_j, dif_neg hi_ne_k, dif_pos hi_S₂] at hbit |
| 866 | exact of_decide_eq_false hbit |
| 867 | -- Package the data. |
| 868 | refine |
| 869 | { toUniformLengthData := |
| 870 | { toCandidatePathData := hStep2.toCandidatePathData |
| 871 | subclique := S₃ |
| 872 | subclique_card_ge := hS₃_card |
| 873 | commonLength := hStep2.commonLength |
| 874 | commonLength_le := hStep2.commonLength_le |
| 875 | hasCommonLengthWalk := fun hi hj hij => |
| 876 | hStep2.hasCommonLengthWalk (hS₃_sub hi) (hS₃_sub hj) hij } |
| 877 | canonicalWalk := fun hi hj hij => walk (hS₃_sub hi) (hS₃_sub hj) hij |
| 878 | canonicalWalk_length := fun hi hj hij => |
| 879 | walk_length (hS₃_sub hi) (hS₃_sub hj) hij |
| 880 | patternShared := patternShared |
| 881 | patternShared_shared := @shared_spec |
| 882 | patternShared_disjoint := @disjoint_spec } |
| 883 | |
| 884 | /-- Backward direction, Step 4: cut the shared prefixes and suffixes, |
| 885 | perform one more Ramsey round on interior collisions, and produce the |
| 886 | system of internally disjoint trimmed walks required by Step 5. |
| 887 | |
| 888 | Currently an open scaffold leaf; see `formalization-notes.md` under "Step 4 |
| 889 | (trimming)" for the proof plan. The design of `TrimmedPathData` above |
| 890 | matches what `backward_step5_build_subdivision` needs to assemble an |
| 891 | `IsContained` witness: uniform-length walks between branch-set-anchored |
| 892 | centres, pairwise interior-disjoint, each a path. -/ |
| 893 | private noncomputable def backward_step4_trim_paths |
| 894 | {V : Type} [DecidableEq V] [Fintype V] {G : SimpleGraph V} |
| 895 | {d t m : ℕ} |
| 896 | (hStep3 : CanonicalPatternData G d t m) : |
| 897 | TrimmedPathData G d t m := by |
| 898 | sorry |
| 899 | |
| 900 | /-- Backward direction, Step 5: package the cleaned path system as a |
| 901 | subdivided-clique subgraph. -/ |
| 902 | private noncomputable def backward_step5_build_subdivision |
| 903 | {V : Type} [DecidableEq V] [Fintype V] {G : SimpleGraph V} |
| 904 | {d t m : ℕ} |
| 905 | (hStep4 : TrimmedPathData G d t m) : |
| 906 | CleanSubdivisionData G d t m := by |
| 907 | sorry |
| 908 | |
| 909 | /-- Backward direction, Step 6: choose a Ramsey threshold `t(d)` and a |
| 910 | subdivision-order target `m` so that any cleaned Step-5 subdivision witness |
| 911 | of order `≥ m` contradicts the local nowhere-dense hypothesis. The |
| 912 | `hThresh` field feeds Step 2's multicolour-Ramsey threshold; `hThresh3` |
| 913 | similarly feeds Step 3's branching-pattern Ramsey. This is where the |
| 914 | six-step scaffold collapses back to the catalog bound |
| 915 | `HasShallowCliqueBound C d t(d)`. -/ |
| 916 | private theorem backward_step6_extract_bound |
| 917 | (C : GraphClass) |
| 918 | (hDev : Dev.MonadicDependence.NowhereDense.IsNowhereDense C) |
| 919 | (d : ℕ) : |
| 920 | ∃ (t m : ℕ), |
| 921 | (Catalog.Sparsity.MulticolorRamsey.multicolorRamsey |
| 922 | (List.replicate (2 * d + 2) m) |
| 923 | List.replicate_succ_ne_nil).choose ≤ t + 1 ∧ |
| 924 | (Catalog.Sparsity.MulticolorRamsey.multicolorRamsey |
| 925 | (List.replicate |
| 926 | (Fintype.card (Fin (t + 1) → Fin (2 * d + 1) → Bool)) m) |
| 927 | (step3_sizes_ne_nil d t m)).choose ≤ m ∧ |
| 928 | ∀ {V : Type} [DecidableEq V] [Fintype V] {G : SimpleGraph V}, |
| 929 | C G → CleanSubdivisionData G d t m → False := by |
| 930 | sorry |
| 931 | |
| 932 | /-- Local subdivided-clique nowhere denseness implies the catalog shallow- |
| 933 | minor formulation. The Ramsey bookkeeping is split into six helper steps |
| 934 | matching `formalization-notes.md`. -/ |
| 935 | private theorem dev_nowhereDense_to_catalog_nowhereDense |
| 936 | (C : GraphClass) |
| 937 | (hDev : Dev.MonadicDependence.NowhereDense.IsNowhereDense C) : |
| 938 | Catalog.Sparsity.NowhereDense.IsNowhereDense C := by |
| 939 | intro d |
| 940 | rcases backward_step6_extract_bound C hDev d with |
| 941 | ⟨t, m, hThresh, hThresh3, hStep6⟩ |
| 942 | refine ⟨t, ?_⟩ |
| 943 | intro V _ _ G hCG hMinor |
| 944 | let step1 : CandidatePathData G d t := backward_step1_candidate_paths hMinor |
| 945 | let step2 : UniformLengthData G d t m := |
| 946 | backward_step2_uniform_length step1 hThresh |
| 947 | let step3 : CanonicalPatternData G d t m := |
| 948 | backward_step3_canonical_pattern step2 hThresh3 |
| 949 | let step4 : TrimmedPathData G d t m := backward_step4_trim_paths step3 |
| 950 | let step5 : CleanSubdivisionData G d t m := |
| 951 | backward_step5_build_subdivision step4 |
| 952 | exact hStep6 hCG step5 |
| 953 | |
| 954 | /-- Folklore equivalence between the local and shallow-minor |
| 955 | formulations of nowhere-denseness. See `Contract.lean` for the |
| 956 | statement-level discussion and `formalization-notes.md` for the |
| 957 | proof strategy. -/ |
| 958 | theorem nowhereDenseBridge (C : GraphClass) : |
| 959 | Dev.MonadicDependence.NowhereDense.IsNowhereDense C ↔ |
| 960 | Catalog.Sparsity.NowhereDense.IsNowhereDense C := by |
| 961 | constructor |
| 962 | · exact dev_nowhereDense_to_catalog_nowhereDense C |
| 963 | · exact catalog_nowhereDense_to_dev_nowhereDense C |
| 964 | |
| 965 | end Dev.MonadicDependence.NowhereDenseBridge |
| 966 |