CubicPathwidth.T4.BasicGlue

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

import CubicPathwidth.T4.ProcessDefs

/-!
# Torso components as sections, and gluing them (`lem:basic`, first case)

Helper facts for `CubicPathwidth/T4/Basic.lean`.

* `coreTorso_eq_induced`: for `U ⊆ B`, the torso of `(F \ (B \ U), U)` is the induced
  torso `inducedOnFin (tgraph G F B) U`. In particular a torso component `C` gives
  the relabelled graph of `ComponentClaim`, and the whole core gives `coreTorso G F B`.
* Degree and weight bounds: a vertex of the relabelled component has torso degree at
  most its torso degree in `(F, B)`, so `degreeWeight` is at most `∑_{v ∈ U} b (tdeg v)`.
* `section_union`, `glueSections`: sections on disjoint pieces with no edges between
  them glue into a section on their union, at the maximum width.
* `unliftSection`: a section on `U` is a path decomposition of `inducedOnFin G U`.
-/

noncomputable section

namespace CubicPathwidth
namespace T4
namespace BasicAux

open T2 SectionDecomposition

variable {n : ℕ}

/-! ## Adjacency of the torso and its relabelled component -/

theorem tgraph_adj_iff (G : SimpleGraph (Fin n)) (F B : Finset (Fin n)) (u v : Fin n) :
    (tgraph G F B).Adj u v ↔ u ≠ v ∧ u ∈ B ∧ v ∈ B ∧ (G.Adj u v ∨
      ∃ T ∈ components G (F \ B), u ∈ attachment G B T ∧ v ∈ attachment G B T) :=
  Iff.rfl

theorem diff_diff_eq_of_subset {F B U : Finset (Fin n)} (hU : U ⊆ B) :
    (F \ (B \ U)) \ U = F \ B := by
  ext x
  have hx : x ∈ U → x ∈ B := fun h => hU h
  simp only [Finset.mem_sdiff]
  tauto

theorem mem_attachment_inner (G : SimpleGraph (Fin n)) {B U : Finset (Fin n)}
    (hU : U ⊆ B) {x : Fin n} (hx : x ∈ U) (T : Finset (Fin n)) :
    x ∈ attachment G U T ↔ x ∈ attachment G B T := by
  rw [mem_attachment G, mem_attachment G]
  exact ⟨fun h => ⟨hU hx, h.2⟩, fun h => ⟨hx, h.2⟩⟩

theorem coreTorso_adj_induced (G : SimpleGraph (Fin n)) (F B U : Finset (Fin n))
    (hU : U ⊆ B) (i j : Fin U.card) :
    (coreTorso G (F \ (B \ U)) U).Adj i j ↔
      (tgraph G F B).Adj (enumerate U i) (enumerate U j) := by
  have hi : enumerate U i ∈ U := (mem_iff_enumerate U _).mpr ⟨i, rfl⟩
  have hj : enumerate U j ∈ U := (mem_iff_enumerate U _).mpr ⟨j, rfl⟩
  have hne : i ≠ j ↔ enumerate U i ≠ enumerate U j := (enumerate U).injective.ne_iff.symm
  rw [tgraph_adj_iff]
  show (i ≠ j ∧ (G.Adj (enumerate U i) (enumerate U j) ∨
      ∃ T ∈ components G ((F \ (B \ U)) \ U),
        enumerate U i ∈ attachment G U T ∧ enumerate U j ∈ attachment G U T)) ↔ _
  rw [diff_diff_eq_of_subset hU, hne]
  simp only [mem_attachment_inner G hU hi, mem_attachment_inner G hU hj]
  constructor
  · rintro ⟨hne', h⟩
    exact ⟨hne', hU hi, hU hj, h⟩
  · rintro ⟨hne', -, -, h⟩
    exact ⟨hne', h⟩

/-- The torso of a component `U ⊆ B`, relabelled onto `Fin U.card`, is the induced
torso of the state `(F, B)`. -/
theorem coreTorso_eq_induced (G : SimpleGraph (Fin n)) (F B U : Finset (Fin n))
    (hU : U ⊆ B) :
    coreTorso G (F \ (B \ U)) U = inducedOnFin (tgraph G F B) U := by
  ext i j
  exact coreTorso_adj_induced G F B U hU i j

/-! ## Degrees and weights -/

theorem sum_enumerate (U : Finset (Fin n)) (f : Fin n → ℝ) :
    ∑ i : Fin U.card, f (enumerate U i) = ∑ v ∈ U, f v := by
  rw [← Finset.sum_coe_sort U f]
  exact Equiv.sum_comp U.equivFin.symm (fun x : U => f x.val)

open scoped Classical in

theorem degree_inducedOnFin_le (G' : SimpleGraph (Fin n)) (U : Finset (Fin n))
    (i : Fin U.card) :
    (inducedOnFin G' U).degree i ≤ G'.degree (enumerate U i) := by
  classical
  have hsub : ((inducedOnFin G' U).neighborFinset i).image (enumerate U) ⊆
      G'.neighborFinset (enumerate U i) := by
    intro u hu
    obtain ⟨w, hw, rfl⟩ := Finset.mem_image.mp hu
    exact (G'.mem_neighborFinset _ _).mpr (((inducedOnFin G' U).mem_neighborFinset i w).mp hw)
  calc (inducedOnFin G' U).degree i = ((inducedOnFin G' U).neighborFinset i).card := rfl
    _ = (((inducedOnFin G' U).neighborFinset i).image (enumerate U)).card :=
        (Finset.card_image_of_injective _ (enumerate U).injective).symm
    _ ≤ (G'.neighborFinset (enumerate U i)).card := Finset.card_le_card hsub
    _ = G'.degree (enumerate U i) := rfl

open scoped Classical in

theorem tdeg_eq_degree (G : SimpleGraph (Fin n)) (F B : Finset (Fin n)) (v : Fin n) :
    tdeg G F B v = (tgraph G F B).degree v := rfl

open scoped Classical in

/-- A vertex of the relabelled component has degree at most its torso degree. -/
theorem degree_coreTorso_le (G : SimpleGraph (Fin n)) (F B U : Finset (Fin n))
    (hU : U ⊆ B) (i : Fin U.card) :
    (coreTorso G (F \ (B \ U)) U).degree i ≤ tdeg G F B (enumerate U i) := by
  rw [tdeg_eq_degree, coreTorso_eq_induced G F B U hU]
  exact degree_inducedOnFin_le _ _ _

open scoped Classical in

theorem maxDegreeAtMost_coreTorso (G : SimpleGraph (Fin n)) (F B U : Finset (Fin n))
    (hU : U ⊆ B) {k : ℕ} (hk : ∀ v ∈ U, tdeg G F B v ≤ k) :
    MaxDegreeAtMost k (coreTorso G (F \ (B \ U)) U) := by
  unfold MaxDegreeAtMost
  intro i
  exact (degree_coreTorso_le G F B U hU i).trans
    (hk _ ((mem_iff_enumerate U _).mpr ⟨i, rfl⟩))

open scoped Classical in

/-- The weight of the relabelled component is at most `∑_{v ∈ U} b (tdeg v)`. -/
theorem degreeWeight_coreTorso_le {b : ℕ → ℝ} (hb : BootProps b) (G : SimpleGraph (Fin n))
    (F B U : Finset (Fin n)) (hU : U ⊆ B) :
    degreeWeight (coreTorso G (F \ (B \ U)) U) b ≤ ∑ v ∈ U, b (tdeg G F B v) := by
  rw [← sum_enumerate U (fun v => b (tdeg G F B v))]
  unfold degreeWeight
  apply Finset.sum_le_sum
  intro i _
  exact hb.monotone (degree_coreTorso_le G F B U hU i)

/-! ## Sections on components and their union -/

/-- The empty section. -/
def emptySection (G : SimpleGraph (Fin n)) : SectionDecomposition G ∅ where
  lastIndex := 0
  bag := fun _ => ∅
  interval := by
    intro i j k _ _ _ v hv
    simp at hv
  bag_subset := by
    intro i _ v hv
    simp at hv
  vertex_covered := by
    intro v hv
    simp at hv
  edge_covered := by
    intro u hu
    simp at hu

theorem emptySection_width (G : SimpleGraph (Fin n)) {w : ℝ} (hw : -1 ≤ w) :
    (emptySection G).toBagPath.WidthAtMost w := by
  intro i _
  change ((∅ : Finset (Fin n)).card : ℝ) ≤ w + 1
  simp only [Finset.card_empty, Nat.cast_zero]
  linarith

/-- Two sections on disjoint sets with no edges between them give a section on the
union, whose width is the maximum of the two widths. -/
theorem section_union (G : SimpleGraph (Fin n)) {C U : Finset (Fin n)}
    (P : SectionDecomposition G C) (Q : SectionDecomposition G U)
    (hdisj : Disjoint C U) (hno : ∀ x ∈ C, ∀ y ∈ U, ¬ G.Adj x y) {a b : ℝ}
    (ha : P.toBagPath.WidthAtMost a) (hb : Q.toBagPath.WidthAtMost b) :
    ∃ R : SectionDecomposition G (C ∪ U), R.toBagPath.WidthAtMost (max a b) := by
  have compat : BagPath.Compatible P.toBagPath Q.toBagPath := by
    intro v i j hi hj hvi hvj
    exact (Finset.disjoint_left.mp hdisj (P.bag_subset i hi hvi)
      (Q.bag_subset j hj hvj)).elim
  refine ⟨{ toBagPath := P.toBagPath.concat Q.toBagPath compat
            bag_subset := ?_
            vertex_covered := ?_
            edge_covered := ?_ }, BagPath.concat_width compat ha hb⟩
  · intro i hi v hv
    by_cases h : i ≤ P.lastIndex
    · rw [BagPath.concat_bag_left _ _ _ i h] at hv
      exact Finset.mem_union_left _ (P.bag_subset i h hv)
    · obtain ⟨j, rfl⟩ : ∃ j, i = P.lastIndex + 1 + j := ⟨i - (P.lastIndex + 1), by omega⟩
      rw [BagPath.concat_bag_right _ _ _ j] at hv
      have hj : j ≤ Q.lastIndex := by
        have : P.lastIndex + 1 + j ≤ P.lastIndex + Q.lastIndex + 1 := hi
        omega
      exact Finset.mem_union_right _ (Q.bag_subset j hj hv)
  · intro v hv
    rcases Finset.mem_union.mp hv with h | h
    · obtain ⟨i, hi, hvi⟩ := P.vertex_covered v h
      refine ⟨i, ?_, ?_⟩
      · change i ≤ P.lastIndex + Q.lastIndex + 1
        omega
      · rw [BagPath.concat_bag_left _ _ _ i hi]
        exact hvi
    · obtain ⟨j, hj, hvj⟩ := Q.vertex_covered v h
      refine ⟨P.lastIndex + 1 + j, ?_, ?_⟩
      · change P.lastIndex + 1 + j ≤ P.lastIndex + Q.lastIndex + 1
        omega
      · rw [BagPath.concat_bag_right _ _ _ j]
        exact hvj
  · intro u hu v hv huv
    rcases Finset.mem_union.mp hu with hu' | hu' <;>
      rcases Finset.mem_union.mp hv with hv' | hv'
    · obtain ⟨i, hi, hui, hvi⟩ := P.edge_covered u hu' v hv' huv
      refine ⟨i, ?_, ?_, ?_⟩
      · change i ≤ P.lastIndex + Q.lastIndex + 1
        omega
      · rw [BagPath.concat_bag_left _ _ _ i hi]
        exact hui
      · rw [BagPath.concat_bag_left _ _ _ i hi]
        exact hvi
    · exact (hno u hu' v hv' huv).elim
    · exact (hno v hv' u hu' huv.symm).elim
    · obtain ⟨j, hj, huj, hvj⟩ := Q.edge_covered u hu' v hv' huv
      refine ⟨P.lastIndex + 1 + j, ?_, ?_, ?_⟩
      · change P.lastIndex + 1 + j ≤ P.lastIndex + Q.lastIndex + 1
        omega
      · rw [BagPath.concat_bag_right _ _ _ j]
        exact huj
      · rw [BagPath.concat_bag_right _ _ _ j]
        exact hvj

/-- Glue sections over a finite family of pairwise disjoint pieces. Each piece is
closed under the adjacency of `G`, so there are no edges between different pieces. -/
theorem glueSections (G : SimpleGraph (Fin n)) {w : ℝ} (hw : -1 ≤ w)
    (𝒞 : Finset (Finset (Fin n))) :
    ∀ U : Finset (Fin n), 𝒞.biUnion id = U →
      (∀ C ∈ 𝒞, ∀ u ∈ C, ∀ v, G.Adj u v → v ∈ C) →
      (∀ C ∈ 𝒞, ∀ D ∈ 𝒞, C ≠ D → Disjoint C D) →
      (∀ C ∈ 𝒞, ∃ P : SectionDecomposition G C, P.toBagPath.WidthAtMost w) →
      ∃ P : SectionDecomposition G U, P.toBagPath.WidthAtMost w := by
  classical
  induction 𝒞 using Finset.induction_on with
  | empty =>
    intro U hU _ _ _
    subst hU
    rw [Finset.biUnion_empty]
    exact ⟨emptySection G, emptySection_width G hw⟩
  | @insert C 𝒞' hC ih =>
    intro U hU hcl hdis hP
    subst hU
    have hcl' : ∀ D ∈ 𝒞', ∀ u ∈ D, ∀ v, G.Adj u v → v ∈ D :=
      fun D hD => hcl D (Finset.mem_insert_of_mem hD)
    have hdis' : ∀ D ∈ 𝒞', ∀ E ∈ 𝒞', D ≠ E → Disjoint D E :=
      fun D hD E hE hne =>
        hdis D (Finset.mem_insert_of_mem hD) E (Finset.mem_insert_of_mem hE) hne
    have hP' : ∀ D ∈ 𝒞', ∃ P : SectionDecomposition G D, P.toBagPath.WidthAtMost w :=
      fun D hD => hP D (Finset.mem_insert_of_mem hD)
    obtain ⟨Q, hQ⟩ := ih (𝒞'.biUnion id) rfl hcl' hdis' hP'
    obtain ⟨P, hPw⟩ := hP C (Finset.mem_insert_self _ _)
    have hdisj : Disjoint C (𝒞'.biUnion id) := by
      rw [Finset.disjoint_biUnion_right]
      intro D hD
      exact hdis C (Finset.mem_insert_self _ _) D (Finset.mem_insert_of_mem hD)
        (fun h => hC (by rw [h]; exact hD))
    have hno : ∀ x ∈ C, ∀ y ∈ 𝒞'.biUnion id, ¬ G.Adj x y := by
      intro x hx y hy hxy
      have hyC := hcl C (Finset.mem_insert_self _ _) x hx y hxy
      exact Finset.disjoint_left.mp hdisj hyC hy
    obtain ⟨R, hR⟩ := section_union G P Q hdisj hno hPw hQ
    rw [Finset.biUnion_insert]
    exact ⟨R, hR.mono (max_le le_rfl le_rfl)⟩

/-! ## Sections as path decompositions of induced graphs -/

theorem mem_boundaryPreimage_iff (U X : Finset (Fin n)) (v : Fin U.card) :
    v ∈ boundaryPreimage U X ↔ enumerate U v ∈ X := by
  simp [boundaryPreimage]

/-- A section on `U` is a path decomposition of the induced graph `G[U]`. -/
def unliftSection {G : SimpleGraph (Fin n)} {U : Finset (Fin n)}
    (P : SectionDecomposition G U) : PathDecomposition (inducedOnFin G U) where
  lastIndex := P.lastIndex
  bag := fun i => boundaryPreimage U (P.bag i.val)
  vertex_covered := by
    intro v
    have hv : enumerate U v ∈ U := (mem_iff_enumerate U _).mpr ⟨v, rfl⟩
    obtain ⟨i, hi, hvi⟩ := P.vertex_covered _ hv
    exact ⟨⟨i, by omega⟩, (mem_boundaryPreimage_iff U _ v).mpr hvi⟩
  edge_covered := by
    intro u v huv
    have hu : enumerate U u ∈ U := (mem_iff_enumerate U _).mpr ⟨u, rfl⟩
    have hv : enumerate U v ∈ U := (mem_iff_enumerate U _).mpr ⟨v, rfl⟩
    have huv' : G.Adj (enumerate U u) (enumerate U v) := huv
    obtain ⟨i, hi, hui, hvi⟩ := P.edge_covered _ hu _ hv huv'
    exact ⟨⟨i, by omega⟩, (mem_boundaryPreimage_iff U _ u).mpr hui,
      (mem_boundaryPreimage_iff U _ v).mpr hvi⟩
  interval := by
    intro i j k hij hjk v hv
    have hv' : enumerate U v ∈ P.bag i.val ∧ enumerate U v ∈ P.bag k.val :=
      ⟨(mem_boundaryPreimage_iff U _ v).mp hv.1, (mem_boundaryPreimage_iff U _ v).mp hv.2⟩
    exact (mem_boundaryPreimage_iff U _ v).mpr
      (P.interval i.val j.val k.val (Fin.le_def.mp hij) (Fin.le_def.mp hjk)
        (Nat.le_of_lt_succ k.isLt) _ hv')

theorem unliftSection_width {G : SimpleGraph (Fin n)} {U : Finset (Fin n)}
    (P : SectionDecomposition G U) {w : ℝ} (hP : P.toBagPath.WidthAtMost w) :
    (unliftSection P).WidthAtMost w := by
  intro i
  have hi : i.val ≤ P.lastIndex := Nat.le_of_lt_succ i.isLt
  change ((boundaryPreimage U (P.bag i.val)).card : ℝ) ≤ w + 1
  rw [boundaryPreimage_card U _ (P.bag_subset i.val hi)]
  exact hP i.val hi

theorem hasPathwidthAtMost_of_section {G : SimpleGraph (Fin n)} {U : Finset (Fin n)}
    {w : ℝ} (P : SectionDecomposition G U) (hP : P.toBagPath.WidthAtMost w) :
    HasPathwidthAtMost (inducedOnFin G U) w :=
  ⟨unliftSection P, unliftSection_width P hP⟩

theorem section_of_hasPathwidth {G : SimpleGraph (Fin n)} {U : Finset (Fin n)}
    {w W : ℝ} (h : HasPathwidthAtMost (inducedOnFin G U) w) (hw : w ≤ W) :
    ∃ P : SectionDecomposition G U, P.toBagPath.WidthAtMost W := by
  obtain ⟨D, hD⟩ := h
  exact ⟨lift G U D, (lift_width G U D hD).mono hw⟩

end BasicAux
end T4
end CubicPathwidth
Back to top