CubicPathwidth.ForestDecomposition

Source file CubicPathwidth/ForestDecomposition.lean of the Lean project (how it is built).

import CubicPathwidth.ForestStructure
import CubicPathwidth.SectionAssembly
import CubicPathwidth.BoundaryAssembly

/-! Actual narrow path decompositions of finite forests. -/

noncomputable section
namespace CubicPathwidth
open SectionDecomposition

variable {n : ℕ} (G : SimpleGraph (Fin n))

theorem section_of_components (U : Finset (Fin n)) {w : ℝ} (hw : -1 ≤ w)
    (hparts : ∀ T ∈ components G U,
      ∃ P : SectionDecomposition G T, P.toBagPath.WidthAtMost w) :
    ∃ P : SectionDecomposition G U, P.toBagPath.WidthAtMost w := by
  have go : ∀ A : Finset (Finset (Fin n)), A ⊆ components G U →
      ∃ P : SectionDecomposition G (A.biUnion id), P.toBagPath.WidthAtMost w := by
    intro A
    induction A using Finset.induction_on with
    | empty =>
      intro _
      let P : SectionDecomposition G ∅ := {
        toBagPath := BagPath.single ∅
        bag_subset := by intro i hi; exact Finset.Subset.refl _
        vertex_covered := by simp
        edge_covered := by simp }
      refine ⟨P, ?_⟩
      intro i hi
      simpa [P, BagPath.single] using (show (0 : ℝ) ≤ w + 1 by linarith)
    | @insert T A hnot ih =>
      intro hA
      have hT := hA (Finset.mem_insert_self _ _)
      have hA' : A ⊆ components G U := (Finset.subset_insert _ _).trans hA
      obtain ⟨P, hP⟩ := ih hA'
      obtain ⟨Q, hQ⟩ := hparts T hT
      have hdis : Disjoint (A.biUnion id) T := by
        apply Finset.disjoint_left.mpr
        intro v hv hvT
        obtain ⟨S, hS, hvS⟩ := Finset.mem_biUnion.mp hv
        exact Finset.disjoint_left.mp (components_disjoint G (hA' hS) hT
          (by intro he; subst S; exact hnot hS)) hvS hvT
      have hsep : ∀ v ∈ T, ∀ u ∈ A.biUnion id, G.Adj v u → u ∈ (∅ : Finset (Fin n)) := by
        intro v hv u hu hadj
        obtain ⟨S, hS, huS⟩ := Finset.mem_biUnion.mp hu
        have huU := (mem_components G (hA' hS)).1 huS
        have huT := (mem_components G hT).2.1 v hv u huU hadj
        exact False.elim (Finset.disjoint_left.mp hdis
          (Finset.mem_biUnion.mpr ⟨S, hS, huS⟩) huT)
      let P' := P.endAtSubset ∅ (Finset.empty_subset _)
      have hP' : P'.toBagPath.WidthAtMost w := endAtSubset_width _ _ _ hP
      obtain ⟨R, _, hR⟩ := append_component P' Q ∅ (Finset.empty_subset _) hdis
        (endAtSubset_last _ _ _) hsep hP' hQ
      have heq : (insert T A).biUnion id = (A.biUnion id) ∪ T := by
        simp [Finset.union_comm]
      rw [heq]
      exact ⟨R, by simpa using hR⟩
  have h := go (components G U) (Finset.Subset.refl _)
  rw [components_cover G U] at h
  exact h

theorem sqrt_half_bound {a b : ℕ} (h : 2 * a ≤ b) :
    4 * Real.sqrt (a : ℝ) ≤ 3 * Real.sqrt (b : ℝ) := by
  have ha := Real.sqrt_nonneg (a : ℝ)
  have hb := Real.sqrt_nonneg (b : ℝ)
  have ha2 := Real.sq_sqrt (Nat.cast_nonneg a : (0 : ℝ) ≤ a)
  have hb2 := Real.sq_sqrt (Nat.cast_nonneg b : (0 : ℝ) ≤ b)
  have hcast : 2 * (a : ℝ) ≤ b := by exact_mod_cast h
  nlinarith [sq_nonneg (4 * Real.sqrt (a : ℝ) - 3 * Real.sqrt (b : ℝ))]

/-- A generous square-root bound keeps the original asymptotic theorem
unchanged while avoiding a separate formal logarithmic-error calculation. -/
theorem forest_section_decomposition (U : Finset (Fin n)) (hU : ForestSection G U) :
    ∃ P : SectionDecomposition G U, P.toBagPath.WidthAtMost (4 * Real.sqrt (U.card : ℝ)) := by
  have go : ∀ m : ℕ, ∀ U : Finset (Fin n), U.card = m → ForestSection G U →
      ∃ P : SectionDecomposition G U, P.toBagPath.WidthAtMost (4 * Real.sqrt (U.card : ℝ)) := by
    intro m
    induction m using Nat.strong_induction_on with
    | h m ih =>
      intro U hm hforest
      let _ : Decidable (SectionConnected G U) := Classical.propDecidable _
      by_cases hconn : SectionConnected G U
      · obtain ⟨v, hv, hcentroid⟩ := forest_centroid G hforest hconn
        have hnpos := Finset.card_pos.mpr hconn.1
        have hroot : (1 : ℝ) ≤ Real.sqrt (U.card : ℝ) := by
          have hn : (1 : ℝ) ≤ U.card := by exact_mod_cast hnpos
          simpa using Real.sqrt_le_sqrt hn
        obtain ⟨P, hP⟩ := section_of_components G (U.erase v)
          (show -1 ≤ 3 * Real.sqrt (U.card : ℝ) by nlinarith [Real.sqrt_nonneg (U.card : ℝ)])
          (by
            intro T hT
            have ht := mem_components G hT
            have hc := hcentroid T hT
            have hlt : T.card < m := by omega
            obtain ⟨Q, hQ⟩ := ih _ hlt T rfl
              (ForestSection.mono G hforest (ht.1.trans (Finset.erase_subset _ _)))
            exact ⟨Q, hQ.mono (sqrt_half_bound hc)⟩)
        have heq : (U.erase v) ∪ {v} = U := by
          rw [Finset.union_comm, Finset.singleton_union, Finset.insert_erase hv]
        have hwidth := (hold_width P {v} hP).mono
          (show 3 * Real.sqrt (U.card : ℝ) + (({v} : Finset (Fin n)).card : ℝ) ≤
              4 * Real.sqrt (U.card : ℝ) by simp only [Finset.card_singleton, Nat.cast_one]; linarith)
        have h : ∃ Q : SectionDecomposition G ((U.erase v) ∪ {v}),
            Q.toBagPath.WidthAtMost (4 * Real.sqrt (U.card : ℝ)) := ⟨P.hold {v}, hwidth⟩
        rw [heq] at h
        exact h
      · apply section_of_components G U (by nlinarith [Real.sqrt_nonneg (U.card : ℝ)])
        intro T hT
        have ht := mem_components G hT
        have hne : T ≠ U := by intro he; exact hconn (he ▸ ht.2.2)
        have hlt : T.card < m := by
          rw [← hm]
          exact Finset.card_lt_card (Finset.ssubset_iff_subset_ne.mpr ⟨ht.1, hne⟩)
        obtain ⟨P, hP⟩ := ih _ hlt T rfl (ForestSection.mono G hforest ht.1)
        have hc : (T.card : ℝ) ≤ U.card := by exact_mod_cast Finset.card_le_card ht.1
        exact ⟨P, hP.mono (mul_le_mul_of_nonneg_left (Real.sqrt_le_sqrt hc) (by norm_num))⟩
  exact go _ U rfl hU

theorem degreeExcess_eq_sum (U : Finset (Fin n)) :
    degreeExcess G U = ∑ v ∈ U, (((sectionNeighbors G U v).card : ℤ) - 2) := by
  simp [degreeExcess, incidence, Finset.sum_sub_distrib, mul_comm]

theorem sum_component_excess (U : Finset (Fin n)) :
    ∑ T ∈ components G U, degreeExcess G T = degreeExcess G U := by
  classical
  simp_rw [degreeExcess_eq_sum]
  have he : ∀ T ∈ components G U, ∀ v ∈ T, sectionNeighbors G T v = sectionNeighbors G U v := by
    intro T hT v hv
    have ht := mem_components G hT
    ext w
    simp only [mem_sectionNeighbors]
    exact ⟨fun h => ⟨ht.1 h.1, h.2⟩, fun h => ⟨ht.2.1 v hv w h.1 h.2, h.2⟩⟩
  calc
    _ = ∑ T ∈ components G U, ∑ v ∈ T, (((sectionNeighbors G U v).card : ℤ) - 2) := by
      apply Finset.sum_congr rfl
      intro T hT
      apply Finset.sum_congr rfl
      intro v hv
      rw [he T hT v hv]
    _ = ∑ v ∈ (components G U).biUnion id, (((sectionNeighbors G U v).card : ℤ) - 2) := by
      symm
      apply Finset.sum_biUnion
      intro S hS T hT hne
      exact components_disjoint G hS hT hne
    _ = _ := by rw [components_cover]

/-- The formerly missing tree-component construction is now supplied. -/
theorem forestComponentBound : ForestComponentBound coreOverhead := by
  classical
  intro n G hG F hbad
  obtain ⟨S, hSF, hclosed, hneg⟩ : ∃ S, S ⊆ F ∧ ClosedIn G F S ∧ degreeExcess G S < 0 := by
    simpa only [NonnegativeComponentExcess, not_forall, not_le, exists_prop] using hbad
  have hsome : ∃ T ∈ components G S, degreeExcess G T < 0 := by
    by_contra hn
    have hnonneg : ∀ T ∈ components G S, 0 ≤ degreeExcess G T := by
      intro T hT
      by_contra h
      exact hn ⟨T, hT, by omega⟩
    have hs := Finset.sum_nonneg hnonneg
    rw [sum_component_excess] at hs
    omega
  obtain ⟨T, hT, hTneg⟩ := hsome
  have ht := mem_components G hT
  obtain ⟨P, hP⟩ := forest_section_decomposition G T (forest_of_connected_negative G ht.2.2 hTneg)
  refine ⟨T, ht.2.2.1, ht.1.trans hSF, closed_trans G hclosed ht.2.1 ht.1, P, ?_⟩
  apply hP.mono
  have hc : (T.card : ℝ) ≤ F.card := by exact_mod_cast Finset.card_le_card (ht.1.trans hSF)
  have hs := Real.sqrt_le_sqrt hc
  have hp := Real.sqrt_nonneg (F.card : ℝ)
  unfold coreOverhead
  linarith

end CubicPathwidth
Back to top