CubicPathwidth.ForestStructure
Source file CubicPathwidth/ForestStructure.lean of the Lean project (how it is built).
import CubicPathwidth.FiniteComponents
/-! Forest structure and balanced separators using finite incidence counts. -/
noncomputable section
namespace CubicPathwidth
variable {n : ℕ} (G : SimpleGraph (Fin n))
def ForestSection (U : Finset (Fin n)) : Prop :=
∀ S : Finset (Fin n), S ⊆ U → S.Nonempty → degreeExcess G S < 0
theorem ForestSection.mono {U V : Finset (Fin n)} (h : ForestSection G U)
(hV : V ⊆ U) : ForestSection G V := fun S hS => h S (hS.trans hV)
/-- Growing a nonempty set inside a connected section never decreases its
edge-minus-vertex excess: every new vertex has an old neighbour. -/
theorem connected_excess_mono {U S : Finset (Fin n)} (hU : SectionConnected G U)
(hS : S ⊆ U) (hne : S.Nonempty) : degreeExcess G S ≤ degreeExcess G U := by
classical
have go : ∀ k : ℕ, ∀ S : Finset (Fin n), (U \ S).card = k →
S ⊆ U → S.Nonempty → degreeExcess G S ≤ degreeExcess G U := by
intro k
induction k using Nat.strong_induction_on with
| h k ih =>
intro S hk hS hne
by_cases heq : S = U
· subst S
exact le_rfl
· obtain ⟨u, hu, v, hv, huv⟩ := connected_cross_edge G hU hS hne heq
obtain ⟨hvU, hvS⟩ := Finset.mem_sdiff.mp hv
have hsub : insert v S ⊆ U := Finset.insert_subset hvU hS
have hlt : (U \ insert v S).card < k := by
have hc := Finset.card_sdiff_add_card_eq_card hS
have hc' := Finset.card_sdiff_add_card_eq_card hsub
rw [Finset.card_insert_of_notMem hvS] at hc'
omega
have hrec := ih _ hlt (insert v S) rfl hsub (Finset.insert_nonempty _ _)
have hdegree : 1 ≤ (sectionNeighbors G S v).card := Finset.card_pos.mpr
⟨u, mem_sectionNeighbors.mpr ⟨hu, huv.symm⟩⟩
rw [degreeExcess_insert G hvS] at hrec
omega
exact go _ S rfl hS hne
theorem connected_excess_lower {U : Finset (Fin n)} (hU : SectionConnected G U) :
-2 ≤ degreeExcess G U := by
obtain ⟨v, hv⟩ := hU.1
have h := connected_excess_mono G hU (Finset.singleton_subset_iff.mpr hv)
(Finset.singleton_nonempty v)
simpa [degreeExcess, incidence_singleton] using h
theorem forest_of_connected_negative {U : Finset (Fin n)}
(hU : SectionConnected G U) (hneg : degreeExcess G U < 0) : ForestSection G U := by
intro S hS hne
exact (connected_excess_mono G hU hS hne).trans_lt hneg
/-- A component after deleting a vertex of a forest has at most one neighbour
of that vertex. Two such neighbours would force nonnegative excess. -/
theorem forest_component_neighbors_le_one {U T : Finset (Fin n)} {v : Fin n}
(hU : ForestSection G U) (hv : v ∈ U) (hT : T ∈ components G (U.erase v)) :
(sectionNeighbors G T v).card ≤ 1 := by
have ht := mem_components G hT
have hvT : v ∉ T := fun h => Finset.notMem_erase v U (ht.1 h)
have hlow := connected_excess_lower G ht.2.2
have hneg := hU (insert v T) (Finset.insert_subset hv
(ht.1.trans (Finset.erase_subset _ _))) (Finset.insert_nonempty _ _)
rw [degreeExcess_insert G hvT] at hneg
omega
theorem connected_component_neighbor {U T : Finset (Fin n)} {v : Fin n}
(hU : SectionConnected G U) (hv : v ∈ U) (hT : T ∈ components G (U.erase v)) :
∃ w ∈ T, G.Adj v w := by
have ht := mem_components G hT
have hTU := ht.1.trans (Finset.erase_subset v U)
have hvT : v ∉ T := fun h => Finset.notMem_erase v U (ht.1 h)
have hne : T ≠ U := by intro he; exact hvT (he.symm ▸ hv)
obtain ⟨w, hw, z, hz, hwz⟩ := connected_cross_edge G hU hTU ht.2.2.1 hne
have hzv : z = v := by
by_contra h
exact (Finset.mem_sdiff.mp hz).2
(ht.2.1 w hw z (Finset.mem_erase.mpr ⟨h, (Finset.mem_sdiff.mp hz).1⟩) hwz)
subst z
exact ⟨w, hw, hwz.symm⟩
def largestBranch (U : Finset (Fin n)) (v : Fin n) : ℕ :=
(U.erase v).sup (fun w => (component G (U.erase v) w).card)
/-- A finite tree has a vertex whose deletion leaves components of at most
half its order. The proof moves into a heavy branch until the maximum falls. -/
theorem forest_centroid {U : Finset (Fin n)}
(hforest : ForestSection G U) (hconn : SectionConnected G U) :
∃ v ∈ U, ∀ T ∈ components G (U.erase v), 2 * T.card ≤ U.card := by
classical
obtain ⟨v, hv, hmin⟩ := Finset.exists_min_image U (largestBranch G U) hconn.1
refine ⟨v, hv, ?_⟩
intro T hT
have hTmax : T.card ≤ largestBranch G U v := by
obtain ⟨w, hw, rfl⟩ := Finset.mem_image.mp hT
exact Finset.le_sup (f := fun z => (component G (U.erase v) z).card) hw
by_contra hlarge
have hpositive : 0 < largestBranch G U v := by omega
have hne : (U.erase v).Nonempty := by
by_contra hn
have hz : U.erase v = ∅ := Finset.not_nonempty_iff_eq_empty.mp hn
simp [largestBranch, hz] at hpositive
obtain ⟨r, hr, hrmax⟩ := Finset.exists_max_image (U.erase v)
(fun w => (component G (U.erase v) w).card) hne
let C := component G (U.erase v) r
have hCmem : C ∈ components G (U.erase v) := Finset.mem_image.mpr ⟨r, hr, rfl⟩
have hc := mem_components G hCmem
have hCmax : C.card = largestBranch G U v := by
exact le_antisymm (Finset.le_sup (f := fun z => (component G (U.erase v) z).card) hr)
(Finset.sup_le hrmax)
have hCbig : U.card < 2 * C.card := by omega
obtain ⟨w, hwC, hvw⟩ := connected_component_neighbor G hconn hv hCmem
have hwU : w ∈ U := Finset.mem_of_mem_erase (hc.1 hwC)
have hnle := forest_component_neighbors_le_one G hforest hv hCmem
have hsingle : sectionNeighbors G C v = {w} := by
apply Finset.eq_singleton_iff_unique_mem.mpr
refine ⟨mem_sectionNeighbors.mpr ⟨hwC, hvw⟩, ?_⟩
intro z hz
exact (Finset.card_le_one.mp hnle) z hz w (mem_sectionNeighbors.mpr ⟨hwC, hvw⟩)
have hdclosed : ClosedIn G (U.erase w) (U \ C) := by
intro a ha z hz hadj
refine Finset.mem_sdiff.mpr ⟨Finset.mem_of_mem_erase hz, ?_⟩
intro hzC
by_cases hav : a = v
· subst a
have hzN : z ∈ sectionNeighbors G C v := mem_sectionNeighbors.mpr ⟨hzC, hadj⟩
rw [hsingle] at hzN
exact (Finset.mem_erase.mp hz).1 (Finset.mem_singleton.mp hzN)
· exact (Finset.mem_sdiff.mp ha).2 (hc.2.1 z hzC a
(Finset.mem_erase.mpr ⟨hav, (Finset.mem_sdiff.mp ha).1⟩) hadj.symm)
have hnew : largestBranch G U w ≤ C.card - 1 := by
apply Finset.sup_le
intro z hz
let S := component G (U.erase w) z
have hs := component_subset G (U.erase w) z
rcases connected_subset_or_disjoint G hs (component_connected G hz) hdclosed with hd | hd
· have hb := Finset.card_le_card hd
have hCU : C ⊆ U := hc.1.trans (Finset.erase_subset _ _)
have hsum := Finset.card_sdiff_add_card_eq_card hCU
omega
· have hsub : S ⊆ C.erase w := by
intro a ha
have haU := Finset.mem_of_mem_erase (hs ha)
have haC : a ∈ C := by
by_contra hnot
exact Finset.disjoint_left.mp hd ha (Finset.mem_sdiff.mpr ⟨haU, hnot⟩)
exact Finset.mem_erase.mpr ⟨(Finset.mem_erase.mp (hs ha)).1, haC⟩
have hb := Finset.card_le_card hsub
rw [Finset.card_erase_of_mem hwC] at hb
exact hb
have hold := hmin w hwU
have hcp := Finset.card_pos.mpr hc.2.2.1
omega
end CubicPathwidth
Back to top