CubicPathwidth.Alg.Proofs.G7Concat

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

import CubicPathwidth.Alg.Spec

/-!
# G7: `ConcatValid`

Concatenating valid decompositions of pairwise vertex-disjoint graphs gives a valid
decomposition of their union. Proof by induction on the list of parts: the bags of the
head part come first, then the bags of the rest. A vertex of the head part lies in no
bag of the rest (disjointness and `BagsWithin`), and a vertex of the rest lies in no bag
of the head part (`BagsWithin`), so each interval property and each edge is inherited
from the head part or from the rest.
-/

noncomputable section

namespace CubicPathwidth.Alg

namespace G7

/-- Bag indices of an append, on the left. -/
theorem inBag_append_left {A B : List Bag} {i v : Nat} (h : i < A.length) :
    InBag (A ++ B) i v ↔ InBag A i v := by
  unfold InBag
  rw [List.getElem?_append_left h]

/-- Bag indices of an append, on the right. -/
theorem inBag_append_right {A B : List Bag} {i v : Nat} (h : A.length ≤ i) :
    InBag (A ++ B) i v ↔ InBag B (i - A.length) v := by
  unfold InBag
  rw [List.getElem?_append_right h]

/-- A bag index of a decomposition is a genuine index. -/
theorem inBag_lt {bags : List Bag} {i v : Nat} (h : InBag bags i v) : i < bags.length := by
  obtain ⟨B, hB, _⟩ := h
  obtain ⟨h1, _⟩ := List.getElem?_eq_some_iff.1 hB
  exact h1

/-- Vertices of bags lie in the graph when the bags are within it. -/
theorem inBag_mem {G : Graph} {bags : List Bag} (hbw : BagsWithin G bags) {i v : Nat}
    (h : InBag bags i v) : v ∈ G.nodes := by
  obtain ⟨B, hB, hvB⟩ := h
  exact hbw B (List.mem_of_getElem? hB) v hvB

/-- Two parts: the head `A` (with bags `BA`) and the union of the rest (with bags `bs`),
the head's vertices being disjoint from the rest. -/
theorem step (hWF : WFBasics) (hU : UnionAllSpec) (A : Graph) (BA : List Bag)
    (gs : List Graph) (bs : List Bag)
    (hA : A.WF ∧ ValidPD A BA ∧ BagsWithin A BA)
    (hgs : ∀ J ∈ gs, J.WF)
    (hdisj : ∀ J ∈ gs, ∀ x ∈ A.nodes, x ∉ J.nodes)
    (hI : ValidPD (Graph.unionAll gs) bs ∧ BagsWithin (Graph.unionAll gs) bs) :
    ValidPD (Graph.unionAll (A :: gs)) (BA ++ bs) ∧
      BagsWithin (Graph.unionAll (A :: gs)) (BA ++ bs) := by
  obtain ⟨hAwf, hAvp, hAbw⟩ := hA
  obtain ⟨hIvp, hIbw⟩ := hI
  have hwf : ∀ J ∈ A :: gs, J.WF := by
    intro J hJ
    rcases List.mem_cons.1 hJ with h | h
    · rw [h]; exact hAwf
    · exact hgs J h
  have hUn := hU (A :: gs) hwf
  have hUg := hU gs hgs
  have hnodes : ∀ x, x ∈ (Graph.unionAll (A :: gs)).nodes ↔
      x ∈ A.nodes ∨ x ∈ (Graph.unionAll gs).nodes := by
    intro x
    rw [hUn.2.1 x, hUg.2.1 x]
    simp
  have hdisj' : ∀ x, x ∈ A.nodes → x ∉ (Graph.unionAll gs).nodes := by
    intro x hxA hxU
    obtain ⟨J, hJ, hxJ⟩ := (hUg.2.1 x).1 hxU
    exact hdisj J hJ x hxA hxJ
  constructor
  · unfold ValidPD
    refine ⟨?_, ?_, ?_⟩
    · -- coverage
      intro v hv
      rcases (hnodes v).1 hv with hvA | hvU
      · obtain ⟨i, hi⟩ := hAvp.1 v hvA
        exact ⟨i, (inBag_append_left (inBag_lt hi)).2 hi⟩
      · obtain ⟨i, hi⟩ := hIvp.1 v hvU
        refine ⟨BA.length + i, ?_⟩
        rw [inBag_append_right (by omega), Nat.add_sub_cancel_left]
        exact hi
    · -- intervals
      intro v hv i j k hij hjk hi hk
      rcases (hnodes v).1 hv with hvA | hvU
      · -- v in the head: it lies in no later bag
        have hlt : ∀ m, InBag (BA ++ bs) m v → m < BA.length := by
          intro m hm
          by_contra hc
          have hc' := Nat.not_lt.mp hc
          rw [inBag_append_right hc'] at hm
          exact hdisj' v hvA (inBag_mem hIbw hm)
        have hi1 := hlt i hi
        have hk1 := hlt k hk
        have hj1 : j < BA.length := by omega
        rw [inBag_append_left hj1]
        exact hAvp.2.1 v hvA i j k hij hjk ((inBag_append_left hi1).1 hi)
          ((inBag_append_left hk1).1 hk)
      · -- v not in the head: it lies in no earlier bag
        have hvnA : v ∉ A.nodes := fun h => hdisj' v h hvU
        have hi1 : BA.length ≤ i := by
          by_contra hc
          exact hvnA (inBag_mem hAbw ((inBag_append_left (Nat.not_le.mp hc)).1 hi))
        have hk1 : BA.length ≤ k := by
          by_contra hc
          exact hvnA (inBag_mem hAbw ((inBag_append_left (Nat.not_le.mp hc)).1 hk))
        rw [inBag_append_right (by omega : BA.length ≤ j)]
        exact hIvp.2.1 v hvU (i - BA.length) (j - BA.length) (k - BA.length)
          (by omega) (by omega) ((inBag_append_right hi1).1 hi)
          ((inBag_append_right hk1).1 hk)
    · -- edges
      intro u v _ hadj
      obtain ⟨J, hJ, hJadj⟩ := (hUn.2.2 u v).1 hadj
      rcases List.mem_cons.1 hJ with hJA | hJg
      · rw [hJA] at hJadj
        obtain ⟨huA, _, _, _⟩ := hWF A hAwf u v hJadj
        obtain ⟨B, hB, hu', hv'⟩ := hAvp.2.2 u v huA hJadj
        exact ⟨B, List.mem_append.2 (Or.inl hB), hu', hv'⟩
      · obtain ⟨huJ, _, _, _⟩ := hWF J (hgs J hJg) u v hJadj
        have huU : u ∈ (Graph.unionAll gs).nodes := (hUg.2.1 u).2 ⟨J, hJg, huJ⟩
        obtain ⟨B, hB, hu', hv'⟩ := hIvp.2.2 u v huU ((hUg.2.2 u v).2 ⟨J, hJg, hJadj⟩)
        exact ⟨B, List.mem_append.2 (Or.inr hB), hu', hv'⟩
  · -- bags lie in the union
    intro B hB v hv
    rcases List.mem_append.1 hB with hB' | hB'
    · exact (hnodes v).2 (Or.inl (hAbw B hB' v hv))
    · exact (hnodes v).2 (Or.inr (hIbw B hB' v hv))

/-- Concatenation over a list of parts (induction on the list). -/
theorem concat_all (hWF : WFBasics) (hU : UnionAllSpec) :
    ∀ parts : List (Graph × List Bag),
      (∀ p ∈ parts, p.1.WF ∧ ValidPD p.1 p.2 ∧ BagsWithin p.1 p.2) →
      parts.Pairwise (fun A B => ∀ x, x ∈ A.1.nodes → x ∉ B.1.nodes) →
      ValidPD (Graph.unionAll (parts.map (·.1))) (parts.flatMap (·.2)) ∧
        BagsWithin (Graph.unionAll (parts.map (·.1))) (parts.flatMap (·.2))
  | [], _, _ => by
    have hE : ∀ x, x ∉ (Graph.unionAll []).nodes := by
      intro x hx
      obtain ⟨J, hJ, _⟩ := ((hU [] (by simp)).2.1 x).1 hx
      simp at hJ
    refine ⟨⟨fun v hv => absurd hv (hE v), fun v hv => absurd hv (hE v),
      fun u _ hu _ => absurd hu (hE u)⟩, ?_⟩
    intro B hB
    simp at hB
  | p :: rest, hp, hpw => by
    obtain ⟨hpwf, hpvp, hpbw⟩ := hp p (List.mem_cons_self)
    have hpw' := List.pairwise_cons.1 hpw
    have ih := concat_all hWF hU rest (fun q hq => hp q (List.mem_cons_of_mem _ hq)) hpw'.2
    have hdisj : ∀ J ∈ rest.map (·.1), ∀ x ∈ p.1.nodes, x ∉ J.nodes := by
      intro J hJ x hx
      obtain ⟨q, hq, rfl⟩ := List.mem_map.1 hJ
      exact hpw'.1 q hq x hx
    have hgs : ∀ J ∈ rest.map (·.1), J.WF := by
      intro J hJ
      obtain ⟨q, hq, rfl⟩ := List.mem_map.1 hJ
      exact (hp q (List.mem_cons_of_mem _ hq)).1
    simp only [List.map_cons, List.flatMap_cons]
    exact step hWF hU p.1 p.2 (rest.map (·.1)) (rest.flatMap (·.2))
      ⟨hpwf, hpvp, hpbw⟩ hgs hdisj ih

end G7

/-- Concatenating decompositions of vertex-disjoint graphs decomposes their union. -/
theorem concatValid_of (hWF : WFBasics) (hU : UnionAllSpec) : ConcatValid := by
  unfold ConcatValid
  intro parts hp hpw
  exact G7.concat_all hWF hU parts hp hpw

#print axioms CubicPathwidth.Alg.concatValid_of

end CubicPathwidth.Alg
Back to top