CubicPathwidth.Alg.Proofs.G8SeparatorGlue

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

import CubicPathwidth.Alg.Spec

/-!
# G8: gluing at a separator (`SeparatorGlueValid`)

The parts `(c, B_c)` of `pd_tw2` have vertex lists that are pairwise disjoint and
partition `H.nodes \ X`; every bag of part `c` is extended by `X`. Vertices of `X` lie in
every bag; a vertex outside `X` lies in the bags of its unique part only, which form an
interval by validity of that part. Helpers live in `CubicPathwidth.Alg.G8`.
-/

namespace CubicPathwidth.Alg

namespace G8

/-- Convexity of the positions of `v` in a list of bags (the second clause of `ValidPD`). -/
def ConvV (bs : List Bag) (v : Nat) : Prop :=
  ∀ i j k, i ≤ j → j ≤ k → InBag bs i v → InBag bs k v → InBag bs j v

/-- The bags of `parts` after adding the separator `X` to each bag. -/
abbrev outOf (parts : List (List Nat × List Bag)) (X : Bag) : List Bag :=
  parts.flatMap fun p => p.2.map (fun B => bagUnion B X)

theorem not_contains_of_not_mem {X : List Nat} {v : Nat} (h : v ∉ X) :
    (!X.contains v) = true := by
  cases hc : X.contains v with
  | false => rfl
  | true => exact absurd (List.contains_iff_mem.mp hc) h

theorem exists_inBag_iff (bs : List Bag) (v : Nat) :
    (∃ i, InBag bs i v) ↔ ∃ B ∈ bs, v ∈ B := by
  constructor
  · rintro ⟨i, hi⟩
    unfold InBag at hi
    obtain ⟨B, hB, hv⟩ := hi
    exact ⟨B, List.mem_of_getElem? hB, hv⟩
  · rintro ⟨B, hB, hv⟩
    obtain ⟨i, hi⟩ := List.mem_iff_getElem?.mp hB
    exact ⟨i, by unfold InBag; exact ⟨B, hi, hv⟩⟩

theorem inBag_append (A B : List Bag) (i v : Nat) :
    InBag (A ++ B) i v ↔
      (i < A.length ∧ InBag A i v) ∨ (A.length ≤ i ∧ InBag B (i - A.length) v) := by
  unfold InBag
  by_cases h : i < A.length
  · rw [List.getElem?_append_left h]
    constructor
    · rintro ⟨C, hC, hv⟩
      exact Or.inl ⟨h, C, hC, hv⟩
    · rintro (⟨_, hA⟩ | ⟨h', _⟩)
      · exact hA
      · omega
  · rw [List.getElem?_append_right (by omega)]
    constructor
    · rintro ⟨C, hC, hv⟩
      exact Or.inr ⟨by omega, C, hC, hv⟩
    · rintro (⟨h', _⟩ | ⟨_, hB⟩)
      · omega
      · exact hB

theorem inBag_map_bagUnion (bs : List Bag) (X : Bag) (v : Nat) (hv : v ∉ X) (i : Nat) :
    InBag (bs.map (fun B => bagUnion B X)) i v ↔ InBag bs i v := by
  unfold InBag
  rw [List.getElem?_map]
  constructor
  · rintro ⟨C, hC, hvC⟩
    rcases Option.eq_none_or_eq_some (bs[i]?) with hn | ⟨B, hB⟩
    · rw [hn] at hC
      simp at hC
    · rw [hB] at hC
      have hCB : bagUnion B X = C := Option.some.inj hC
      refine ⟨B, hB, ?_⟩
      rw [← hCB] at hvC
      simp only [bagUnion, List.mem_append] at hvC
      exact hvC.resolve_right hv
  · rintro ⟨C, hC, hvC⟩
    refine ⟨bagUnion C X, by simp [hC], ?_⟩
    simp only [bagUnion, List.mem_append]
    exact Or.inl hvC

theorem convV_nil (v : Nat) : ConvV [] v := by
  unfold ConvV
  intro i j k _ _ hi _
  unfold InBag at hi
  obtain ⟨B, hB, _⟩ := hi
  simp at hB

theorem convV_all (bs : List Bag) (v : Nat) (h : ∀ B ∈ bs, v ∈ B) : ConvV bs v := by
  unfold ConvV
  intro i j k hij hjk _ hk
  unfold InBag at hk ⊢
  obtain ⟨B, hB, _⟩ := hk
  obtain ⟨hlt, _⟩ := List.getElem?_eq_some_iff.mp hB
  exact ⟨bs[j], List.getElem?_eq_getElem (by omega), h _ (List.getElem_mem (by omega))⟩

theorem convV_append (A B : List Bag) (v : Nat) (hA : ConvV A v) (hB : ConvV B v)
    (h : ¬ ((∃ C ∈ A, v ∈ C) ∧ (∃ C ∈ B, v ∈ C))) : ConvV (A ++ B) v := by
  unfold ConvV
  intro i j k hij hjk hi hk
  rw [inBag_append] at hi hk ⊢
  rcases hi with ⟨hiA, hiA'⟩ | ⟨hiB, hiB'⟩ <;>
    rcases hk with ⟨hkA, hkA'⟩ | ⟨hkB, hkB'⟩
  · exact Or.inl ⟨by omega, hA i j k hij hjk hiA' hkA'⟩
  · exact absurd ⟨(exists_inBag_iff A v).mp ⟨i, hiA'⟩,
      (exists_inBag_iff B v).mp ⟨k - A.length, hkB'⟩⟩ h
  · omega
  · exact Or.inr ⟨by omega, hB (i - A.length) (j - A.length) (k - A.length)
      (by omega) (by omega) hiB' hkB'⟩

theorem convV_flatMap (X : Bag) (v : Nat) :
    ∀ parts : List (List Nat × List Bag),
      (parts.map (fun x => x.1)).flatten.Nodup →
      (∀ p ∈ parts, (∃ C ∈ p.2.map (fun B => bagUnion B X), v ∈ C) → v ∈ p.1) →
      (∀ p ∈ parts, ConvV (p.2.map (fun B => bagUnion B X)) v) →
      ConvV (parts.flatMap fun p => p.2.map (fun B => bagUnion B X)) v := by
  intro parts
  induction parts with
  | nil =>
    intro _ _ _
    rw [List.flatMap_nil]
    exact convV_nil v
  | cons p rest ih =>
    intro hnd hocc hconv
    rw [List.flatMap_cons]
    have hnd' : (p.1 ++ (rest.map (fun x => x.1)).flatten).Nodup := by
      simpa only [List.map_cons, List.flatten_cons] using hnd
    obtain ⟨-, hrest, hdisj⟩ := List.nodup_append.mp hnd'
    refine convV_append _ _ v (hconv p (by simp)) ?_ ?_
    · exact ih hrest (fun q hq => hocc q (by simp [hq])) (fun q hq => hconv q (by simp [hq]))
    · rintro ⟨⟨C, hC, hvC⟩, ⟨D, hD, hvD⟩⟩
      obtain ⟨q, hq, hDq⟩ := List.mem_flatMap.mp hD
      have hvp : v ∈ p.1 := hocc p (by simp) ⟨C, hC, hvC⟩
      have hvq : v ∈ q.1 := hocc q (by simp [hq]) ⟨D, hDq, hvD⟩
      exact hdisj v hvp v (List.mem_flatten.mpr ⟨q.1, List.mem_map.mpr ⟨q, hq, rfl⟩, hvq⟩) rfl

theorem cover_part (H : Graph) (v : Nat) (hInd : InducedSpec) (hH : H.WF)
    (p : List Nat × List Bag)
    (hp : ValidPD (H.induced p.1.contains) p.2 ∧ BagsWithin (H.induced p.1.contains) p.2)
    (hvH : v ∈ H.nodes) (hvp : v ∈ p.1) : ∃ B ∈ p.2, v ∈ B := by
  obtain ⟨⟨hcov, -, -⟩, -⟩ := hp
  obtain ⟨i, hi⟩ := hcov v
    (((hInd H p.1.contains hH).2.1 v).mpr ⟨hvH, List.contains_iff_mem.mpr hvp⟩)
  exact (exists_inBag_iff p.2 v).mp ⟨i, hi⟩

theorem edge_part (H : Graph) (hInd : InducedSpec) (hH : H.WF)
    (p : List Nat × List Bag)
    (hp : ValidPD (H.induced p.1.contains) p.2 ∧ BagsWithin (H.induced p.1.contains) p.2)
    (u v : Nat) (huH : u ∈ H.nodes) (huv : H.Adj u v) (hu : u ∈ p.1) (hv : v ∈ p.1) :
    ∃ B ∈ p.2, u ∈ B ∧ v ∈ B := by
  obtain ⟨⟨-, -, hedge⟩, -⟩ := hp
  have hadj := ((hInd H p.1.contains hH).2.2 u v).mpr
    ⟨huv, List.contains_iff_mem.mpr hu, List.contains_iff_mem.mpr hv⟩
  have hnu := ((hInd H p.1.contains hH).2.1 u).mpr ⟨huH, List.contains_iff_mem.mpr hu⟩
  exact hedge u v hnu hadj

theorem occ_part (H : Graph) (X : Bag) (v : Nat) (hvX : v ∉ X) (hInd : InducedSpec)
    (hH : H.WF) (p : List Nat × List Bag)
    (hbw : BagsWithin (H.induced p.1.contains) p.2) :
    (∃ C ∈ p.2.map (fun B => bagUnion B X), v ∈ C) → v ∈ p.1 := by
  rintro ⟨C, hC, hvC⟩
  obtain ⟨B, hB, rfl⟩ := List.mem_map.mp hC
  simp only [bagUnion, List.mem_append] at hvC
  rcases hvC with h | h
  · have h2 := ((hInd H p.1.contains hH).2.1 v).mp (hbw B hB v h)
    exact List.contains_iff_mem.mp h2.2
  · exact absurd h hvX

theorem conv_part (H : Graph) (X : Bag) (v : Nat) (hvX : v ∉ X) (hvH : v ∈ H.nodes)
    (hInd : InducedSpec) (hH : H.WF) (p : List Nat × List Bag)
    (hp : ValidPD (H.induced p.1.contains) p.2 ∧ BagsWithin (H.induced p.1.contains) p.2) :
    ConvV (p.2.map (fun B => bagUnion B X)) v := by
  obtain ⟨⟨-, hconv, -⟩, hbw⟩ := hp
  unfold ConvV
  by_cases hvp : v ∈ p.1
  · intro i j k hij hjk hi hk
    have hmem : v ∈ (H.induced p.1.contains).nodes :=
      ((hInd H p.1.contains hH).2.1 v).mpr ⟨hvH, List.contains_iff_mem.mpr hvp⟩
    exact (inBag_map_bagUnion p.2 X v hvX j).mpr
      (hconv v hmem i j k hij hjk ((inBag_map_bagUnion p.2 X v hvX i).mp hi)
        ((inBag_map_bagUnion p.2 X v hvX k).mp hk))
  · intro i j k _ _ hi _
    exact absurd (occ_part H X v hvX hInd hH p hbw ((exists_inBag_iff _ v).mp ⟨i, hi⟩)) hvp

theorem glue_core (hWF : WFBasics) (hInd : InducedSpec) (H : Graph) (X : List Nat)
    (parts : List (List Nat × List Bag))
    (hH : H.WF) (hX : ∀ x ∈ X, x ∈ H.nodes)
    (hperm : (parts.map (fun x => x.1)).flatten.Perm (H.nodes.filter fun v => !X.contains v))
    (hclosed : ∀ p ∈ parts, ∀ x ∈ p.1, ∀ y, H.Adj x y → y ∈ p.1 ∨ y ∈ X)
    (hparts : ∀ p ∈ parts,
      ValidPD (H.induced p.1.contains) p.2 ∧ BagsWithin (H.induced p.1.contains) p.2) :
    ValidPD H (if (outOf parts X).isEmpty then [X] else outOf parts X) ∧
      BagsWithin H (if (outOf parts X).isEmpty then [X] else outOf parts X) := by
  have hflatNd : (parts.map (fun x => x.1)).flatten.Nodup :=
    hperm.nodup_iff.mpr (hH.nodup.filter _)
  -- every vertex of `H` outside `X` lies in some part
  have hcoverV : ∀ v ∈ H.nodes, v ∉ X → ∃ p ∈ parts, v ∈ p.1 := by
    intro v hv hvX
    have h : v ∈ (parts.map (fun x => x.1)).flatten := by
      rw [hperm.mem_iff, List.mem_filter]
      exact ⟨hv, not_contains_of_not_mem hvX⟩
    obtain ⟨l, hl, hvl⟩ := List.mem_flatten.mp h
    obtain ⟨p, hp, rfl⟩ := List.mem_map.mp hl
    exact ⟨p, hp, hvl⟩
  have hmemOut : ∀ p ∈ parts, ∀ B ∈ p.2, bagUnion B X ∈ outOf parts X := by
    intro p hp B hB
    exact List.mem_flatMap.mpr ⟨p, hp, List.mem_map.mpr ⟨B, hB, rfl⟩⟩
  have hallX : ∀ B ∈ outOf parts X, ∀ x ∈ X, x ∈ B := by
    intro B hB x hx
    obtain ⟨p, -, hB'⟩ := List.mem_flatMap.mp hB
    obtain ⟨B', -, rfl⟩ := List.mem_map.mp hB'
    simp only [bagUnion, List.mem_append]
    exact Or.inr hx
  have hBWout : ∀ B ∈ outOf parts X, ∀ v ∈ B, v ∈ H.nodes := by
    intro B hB v hv
    obtain ⟨p, hp, hB'⟩ := List.mem_flatMap.mp hB
    obtain ⟨B', hB'', rfl⟩ := List.mem_map.mp hB'
    simp only [bagUnion, List.mem_append] at hv
    rcases hv with h | h
    · have h2 := ((hInd H p.1.contains hH).2.1 v).mp ((hparts p hp).2 B' hB'' v h)
      exact h2.1
    · exact hX v h
  have hcoverOut : ∀ v ∈ H.nodes, v ∉ X → ∃ B ∈ outOf parts X, v ∈ B := by
    intro v hv hvX
    obtain ⟨p, hp, hvp⟩ := hcoverV v hv hvX
    obtain ⟨B', hB', hvB'⟩ := cover_part H v hInd hH p (hparts p hp) hv hvp
    refine ⟨bagUnion B' X, hmemOut p hp B' hB', ?_⟩
    simp only [bagUnion, List.mem_append]
    exact Or.inl hvB'
  by_cases hE : outOf parts X = []
  · -- no bag from the parts: the parts are empty, so `H.nodes ⊆ X`
    have hres : (if (outOf parts X).isEmpty then [X] else outOf parts X) = [X] := by
      simp [hE]
    rw [hres]
    have hall : ∀ v ∈ H.nodes, v ∈ X := by
      intro v hv
      by_contra hvX
      obtain ⟨B, hB, -⟩ := hcoverOut v hv hvX
      rw [hE] at hB
      simp at hB
    unfold ValidPD BagsWithin
    refine ⟨⟨?_, ?_, ?_⟩, ?_⟩
    · intro v hv
      exact (exists_inBag_iff [X] v).mpr ⟨X, List.mem_singleton_self X, hall v hv⟩
    · intro v hv
      exact convV_all [X] v (fun B hB => by rw [List.mem_singleton.mp hB]; exact hall v hv)
    · intro u v hu huv
      exact ⟨X, List.mem_singleton_self X, hall u hu, hall v (hWF H hH u v huv).2.1⟩
    · intro B hB v hv
      rw [List.mem_singleton.mp hB] at hv
      exact hX v hv
  · -- some bag comes from a part; the result is `outOf parts X`
    have hres : (if (outOf parts X).isEmpty then [X] else outOf parts X) = outOf parts X := by
      have hne : (outOf parts X).isEmpty = false := by
        cases h : (outOf parts X).isEmpty
        · rfl
        · exact absurd (List.isEmpty_iff.mp h) hE
      simp only [hne]
      rfl
    rw [hres]
    obtain ⟨B0, hB0⟩ := List.exists_mem_of_ne_nil _ hE
    unfold ValidPD BagsWithin
    refine ⟨⟨?_, ?_, ?_⟩, ?_⟩
    · intro v hv
      refine (exists_inBag_iff _ v).mpr ?_
      by_cases hvX : v ∈ X
      · exact ⟨B0, hB0, hallX B0 hB0 v hvX⟩
      · exact hcoverOut v hv hvX
    · intro v hv
      by_cases hvX : v ∈ X
      · exact convV_all _ v (fun B hB => hallX B hB v hvX)
      · exact convV_flatMap X v parts hflatNd
          (fun p hp => occ_part H X v hvX hInd hH p (hparts p hp).2)
          (fun p hp => conv_part H X v hvX hv hInd hH p (hparts p hp))
    · intro u v hu huv
      obtain ⟨hu', hv', -, -⟩ := hWF H hH u v huv
      by_cases huX : u ∈ X <;> by_cases hvX : v ∈ X
      · exact ⟨B0, hB0, hallX B0 hB0 u huX, hallX B0 hB0 v hvX⟩
      · obtain ⟨p, hp, hvp⟩ := hcoverV v hv' hvX
        obtain ⟨B', hB', hvB'⟩ := cover_part H v hInd hH p (hparts p hp) hv' hvp
        refine ⟨bagUnion B' X, hmemOut p hp B' hB', ?_, ?_⟩
        · simp only [bagUnion, List.mem_append]
          exact Or.inr huX
        · simp only [bagUnion, List.mem_append]
          exact Or.inl hvB'
      · obtain ⟨p, hp, hup⟩ := hcoverV u hu' huX
        obtain ⟨B', hB', huB'⟩ := cover_part H u hInd hH p (hparts p hp) hu' hup
        refine ⟨bagUnion B' X, hmemOut p hp B' hB', ?_, ?_⟩
        · simp only [bagUnion, List.mem_append]
          exact Or.inl huB'
        · simp only [bagUnion, List.mem_append]
          exact Or.inr hvX
      · obtain ⟨p, hp, hup⟩ := hcoverV u hu' huX
        have hvp : v ∈ p.1 := (hclosed p hp u hup v huv).resolve_right hvX
        obtain ⟨B', hB', huB', hvB'⟩ :=
          edge_part H hInd hH p (hparts p hp) u v hu' huv hup hvp
        refine ⟨bagUnion B' X, hmemOut p hp B' hB', ?_, ?_⟩
        · simp only [bagUnion, List.mem_append]
          exact Or.inl huB'
        · simp only [bagUnion, List.mem_append]
          exact Or.inl hvB'
    · intro B hB v hv
      exact hBWout B hB v hv

end G8

/-- Gluing at a separator `X` (the shape of `pd_tw2`). -/
theorem separatorGlueValid_of (hWF : WFBasics) (hInd : InducedSpec) : SeparatorGlueValid := by
  intro H X parts hH hX hperm hclosed hparts
  exact G8.glue_core hWF hInd H X parts hH hX hperm hclosed hparts

end CubicPathwidth.Alg

#print axioms CubicPathwidth.Alg.separatorGlueValid_of
Back to top