CubicPathwidth.Alg.Proofs2.T4LoopStep

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

import CubicPathwidth.Alg.Plan2Deletion
import CubicPathwidth.Alg.Proofs.Targets

/-!
# D2a2: one round of `t4Loop` preserves the structural invariant `T4LoopInv`

Proof of `T4LoopInvStep` (`Plan2Deletion.lean`, task D2a2) from the Stage 2 hypotheses
`ReduceRecordMaximal`, `ComponentsConnected`, `OpsRecordCongr`, `OpsRecordAppend` and
`OpsRecordFrame`. Stage 1 results (`T4Inv` bookkeeping, `ThinOK`, the commit step, the
specs of the graph layer) are imported from `Proofs/T3LoopPreserves.lean` and
`Proofs/Targets.lean`.

Four cases of one round: fuel exhaustion (the stack is dumped into `final`), a sweep
finalization, a thin round (`red` empties `J.copy.removeNode w`), and a commit (the
components of `red` replace `J`; the record is extended by the frame rule).
-/

noncomputable section

namespace CubicPathwidth.Alg

open Graph

namespace T4LoopStep

/-! ## Same graphs and records -/

theorem sameGraph_trans {G H K : Graph} (h : SameGraph G H) (h' : SameGraph H K) :
    SameGraph G K :=
  ⟨fun v => (h.1 v).trans (h'.1 v), fun u v => (h.2 u v).trans (h'.2 u v)⟩

theorem opsRecord_nil_iff (F R : Graph) : OpsRecord F [] R ↔ SameGraph F R := Iff.rfl

theorem opsRecord_del_iff (F : Graph) (w : Nat) (ops : List Op) (R : Graph) :
    OpsRecord F (Op.del w :: ops) R ↔ w ∈ F.nodes ∧ OpsRecord (F.removeNode w) ops R :=
  Iff.rfl

theorem opsRecord_red_iff (F : Graph) (v : Nat) (nb : List Nat) (ops : List Op) (R : Graph) :
    OpsRecord F (Op.red v nb :: ops) R ↔
      (v ∈ F.nodes ∧ nb.Nodup ∧ nb.length ≤ 2 ∧ (∀ x, x ∈ nb ↔ F.Adj v x) ∧
        OpsRecord (redStep F v) ops R) :=
  Iff.rfl

/-- Changing the final graph of a record by a graph with the same nodes and edges. -/
theorem opsRecord_right_congr : ∀ (ops : List Op) (F R R' : Graph),
    SameGraph R R' → OpsRecord F ops R → OpsRecord F ops R'
  | [], F, R, R', h, hF => by
    rw [opsRecord_nil_iff] at hF ⊢
    exact sameGraph_trans hF h
  | Op.red v nb :: ops, F, R, R', h, hF => by
    rw [opsRecord_red_iff] at hF ⊢
    exact ⟨hF.1, hF.2.1, hF.2.2.1, hF.2.2.2.1, opsRecord_right_congr ops _ R R' h hF.2.2.2.2⟩
  | Op.del w :: ops, F, R, R', h, hF => by
    rw [opsRecord_del_iff] at hF ⊢
    exact ⟨hF.1, opsRecord_right_congr ops _ R R' h hF.2⟩

/-- `SameGraph` between the copy-and-remove graph of `J` and the remove of `J`. -/
theorem copy_removeNode_sameGraph (hRem : RemoveNodeSpec) (hInd : InducedSpec)
    (J : Graph) (hJ : J.WF) (w : Nat) : SameGraph (J.copy.removeNode w) (J.removeNode w) := by
  have hc := hInd J (fun _ => true) hJ
  have hcopyN : ∀ x, x ∈ J.copy.nodes ↔ x ∈ J.nodes := fun x => by
    have := hc.2.1 x
    simp only [Graph.copy]
    simpa using this
  have hcopyA : ∀ x y, J.copy.Adj x y ↔ J.Adj x y := fun x y => by
    have := hc.2.2 x y
    simp only [Graph.copy]
    simpa using this
  have h1 := hRem J.copy w hc.1
  have h2 := hRem J w hJ
  refine ⟨fun x => ?_, fun x y => ?_⟩
  · rw [h1.2.1 x, h2.2.1 x, hcopyN x]
  · rw [h1.2.2 x y, h2.2.2 x y, hcopyA x y]

/-- A graph with no nodes is `SameGraph` to `Graph.empty`. -/
theorem sameGraph_empty_of_numNodes (G : Graph) (hG : G.WF) (h : G.numNodes = 0) :
    SameGraph G Graph.empty := by
  have hn : G.nodes = [] := by
    unfold Graph.numNodes at h
    exact List.length_eq_zero_iff.1 h
  refine ⟨fun x => ?_, fun u v => ?_⟩
  · rw [hn]
    simp [Graph.empty]
  · constructor
    · intro hA
      have := hG.nbrs_sub u v hA
      rw [hn] at this
      exact absurd this (List.not_mem_nil)
    · intro hA
      simp [Graph.empty, Graph.Adj, Graph.nbrs] at hA

/-! ## `unionAll` -/

theorem unionAll_nodes_iff {gs : List Graph} (hgs : ∀ J ∈ gs, J.WF) (x : Nat) :
    x ∈ (unionAll gs).nodes ↔ ∃ J ∈ gs, x ∈ J.nodes :=
  (unionAllSpec gs hgs).2.1 x

theorem unionAll_adj_iff {gs : List Graph} (hgs : ∀ J ∈ gs, J.WF) (x y : Nat) :
    (unionAll gs).Adj x y ↔ ∃ J ∈ gs, J.Adj x y :=
  (unionAllSpec gs hgs).2.2 x y

theorem unionAll_wf {gs : List Graph} (hgs : ∀ J ∈ gs, J.WF) : (unionAll gs).WF :=
  (unionAllSpec gs hgs).1

/-- `unionAll` does not see the order of its list (`SameGraph`). -/
theorem unionAll_perm_sameGraph {gs gs' : List Graph} (hp : gs.Perm gs')
    (hgs : ∀ J ∈ gs, J.WF) : SameGraph (unionAll gs) (unionAll gs') := by
  have hgs' : ∀ J ∈ gs', J.WF := fun J hJ => hgs J (hp.symm.subset hJ)
  refine ⟨fun x => ?_, fun x y => ?_⟩
  · rw [unionAll_nodes_iff hgs, unionAll_nodes_iff hgs']
    exact ⟨fun ⟨J, hJ, h⟩ => ⟨J, hp.subset hJ, h⟩, fun ⟨J, hJ, h⟩ => ⟨J, hp.symm.subset hJ, h⟩⟩
  · rw [unionAll_adj_iff hgs, unionAll_adj_iff hgs']
    exact ⟨fun ⟨J, hJ, h⟩ => ⟨J, hp.subset hJ, h⟩, fun ⟨J, hJ, h⟩ => ⟨J, hp.symm.subset hJ, h⟩⟩

theorem unionAll_cons_nodes {J : Graph} {L : List Graph} (hJ : J.WF)
    (hL : ∀ J' ∈ L, J'.WF) (x : Nat) :
    x ∈ (unionAll (J :: L)).nodes ↔ x ∈ J.nodes ∨ x ∈ (unionAll L).nodes := by
  have hgs : ∀ J' ∈ J :: L, J'.WF := by
    intro J' hJ'
    rcases List.mem_cons.1 hJ' with rfl | h
    · exact hJ
    · exact hL J' h
  rw [unionAll_nodes_iff hgs, unionAll_nodes_iff hL]
  constructor
  · rintro ⟨J', hJ', h⟩
    rcases List.mem_cons.1 hJ' with rfl | h'
    · exact Or.inl h
    · exact Or.inr ⟨J', h', h⟩
  · rintro (h | ⟨J', hJ', h⟩)
    · exact ⟨J, List.mem_cons_self, h⟩
    · exact ⟨J', List.mem_cons_of_mem _ hJ', h⟩

theorem unionAll_cons_adj {J : Graph} {L : List Graph} (hJ : J.WF)
    (hL : ∀ J' ∈ L, J'.WF) (x y : Nat) :
    (unionAll (J :: L)).Adj x y ↔ J.Adj x y ∨ (unionAll L).Adj x y := by
  have hgs : ∀ J' ∈ J :: L, J'.WF := by
    intro J' hJ'
    rcases List.mem_cons.1 hJ' with rfl | h
    · exact hJ
    · exact hL J' h
  rw [unionAll_adj_iff hgs, unionAll_adj_iff hL]
  constructor
  · rintro ⟨J', hJ', h⟩
    rcases List.mem_cons.1 hJ' with rfl | h'
    · exact Or.inl h
    · exact Or.inr ⟨J', h', h⟩
  · rintro (h | ⟨J', hJ', h⟩)
    · exact ⟨J, List.mem_cons_self, h⟩
    · exact ⟨J', List.mem_cons_of_mem _ hJ', h⟩

theorem unionAll_append_nodes {gs1 gs2 : List Graph} (h1 : ∀ J ∈ gs1, J.WF)
    (h2 : ∀ J ∈ gs2, J.WF) (x : Nat) :
    x ∈ (unionAll (gs1 ++ gs2)).nodes ↔ x ∈ (unionAll gs1).nodes ∨ x ∈ (unionAll gs2).nodes := by
  have hgs : ∀ J ∈ gs1 ++ gs2, J.WF := fun J hJ =>
    (List.mem_append.1 hJ).elim (h1 J) (h2 J)
  rw [unionAll_nodes_iff hgs, unionAll_nodes_iff h1, unionAll_nodes_iff h2]
  constructor
  · rintro ⟨J', hJ', h⟩
    rcases List.mem_append.1 hJ' with h' | h'
    · exact Or.inl ⟨J', h', h⟩
    · exact Or.inr ⟨J', h', h⟩
  · rintro (⟨J', hJ', h⟩ | ⟨J', hJ', h⟩)
    · exact ⟨J', List.mem_append_left _ hJ', h⟩
    · exact ⟨J', List.mem_append_right _ hJ', h⟩

theorem unionAll_append_adj {gs1 gs2 : List Graph} (h1 : ∀ J ∈ gs1, J.WF)
    (h2 : ∀ J ∈ gs2, J.WF) (x y : Nat) :
    (unionAll (gs1 ++ gs2)).Adj x y ↔ (unionAll gs1).Adj x y ∨ (unionAll gs2).Adj x y := by
  have hgs : ∀ J ∈ gs1 ++ gs2, J.WF := fun J hJ =>
    (List.mem_append.1 hJ).elim (h1 J) (h2 J)
  rw [unionAll_adj_iff hgs, unionAll_adj_iff h1, unionAll_adj_iff h2]
  constructor
  · rintro ⟨J', hJ', h⟩
    rcases List.mem_append.1 hJ' with h' | h'
    · exact Or.inl ⟨J', h', h⟩
    · exact Or.inr ⟨J', h', h⟩
  · rintro (⟨J', hJ', h⟩ | ⟨J', hJ', h⟩)
    · exact ⟨J', List.mem_append_left _ hJ', h⟩
    · exact ⟨J', List.mem_append_right _ hJ', h⟩

/-! ## Components -/

/-- The nodes of the component graphs of `Js` are the nodes of `Js`. -/
theorem componentGraphs_mem_nodes (hInd : InducedSpec) (hComp : ComponentsSpec)
    (Js : Graph) (hJs : Js.WF) (x : Nat) :
    (∃ C ∈ componentGraphs Js, x ∈ C.nodes) ↔ x ∈ Js.nodes := by
  constructor
  · rintro ⟨C, hC, hx⟩
    obtain ⟨c, _, rfl⟩ := CubicPathwidth.Alg.T3.componentGraphs_mem hC
    exact (((hInd Js c.contains hJs).2.1 x).1 hx).1
  · intro hx
    have hx' : x ∈ Js.components.flatten := (hComp Js hJs).1.symm.subset hx
    obtain ⟨c, hc, hxc⟩ := List.mem_flatten.1 hx'
    refine ⟨Js.induced c.contains, CubicPathwidth.Alg.T3.mem_componentGraphs_of hc, ?_⟩
    exact ((hInd Js c.contains hJs).2.1 x).2 ⟨hx, List.contains_iff_mem.2 hxc⟩

/-- Adjacency in the component graphs of `Js` is adjacency in `Js`. -/
theorem componentGraphs_adj_iff (hInd : InducedSpec) (hComp : ComponentsSpec)
    (Js : Graph) (hJs : Js.WF) (x y : Nat) :
    (∃ C ∈ componentGraphs Js, C.Adj x y) ↔ Js.Adj x y := by
  constructor
  · rintro ⟨C, hC, hA⟩
    obtain ⟨c, _, rfl⟩ := CubicPathwidth.Alg.T3.componentGraphs_mem hC
    exact (((hInd Js c.contains hJs).2.2 x y).1 hA).1
  · intro hA
    have hy : y ∈ Js.nodes := hJs.nbrs_sub x y hA
    have hx : x ∈ Js.nodes := hJs.nbrs_sub y x (hJs.symm x y hA)
    have hx' : x ∈ Js.components.flatten := (hComp Js hJs).1.symm.subset hx
    obtain ⟨c, hc, hxc⟩ := List.mem_flatten.1 hx'
    have hyc : y ∈ c := (hComp Js hJs).2.2 c hc x hxc y hA
    refine ⟨Js.induced c.contains, CubicPathwidth.Alg.T3.mem_componentGraphs_of hc, ?_⟩
    exact ((hInd Js c.contains hJs).2.2 x y).2
      ⟨hA, List.contains_iff_mem.2 hxc, List.contains_iff_mem.2 hyc⟩

/-- Reachability inside a neighbour-closed set lifts to its induced graph. -/
theorem rtg_induced_of_closed (G : Graph) (c : List Nat)
    (hcl : ∀ x ∈ c, ∀ y, G.Adj x y → y ∈ c)
    (hA : ∀ x y, (G.induced c.contains).Adj x y ↔
      G.Adj x y ∧ c.contains x = true ∧ c.contains y = true)
    (x y : Nat) (hx : x ∈ c) (h : Relation.ReflTransGen G.Adj x y) :
    Relation.ReflTransGen (G.induced c.contains).Adj x y := by
  have key : ∀ z, Relation.ReflTransGen G.Adj x z →
      z ∈ c ∧ Relation.ReflTransGen (G.induced c.contains).Adj x z := by
    intro z hz
    induction hz with
    | refl => exact ⟨hx, Relation.ReflTransGen.refl⟩
    | tail _ hbc ih =>
      obtain ⟨hb, hrt⟩ := ih
      have hc := hcl _ hb _ hbc
      exact ⟨hc, hrt.tail ((hA _ _).2 ⟨hbc, List.contains_iff_mem.2 hb,
        List.contains_iff_mem.2 hc⟩)⟩
  exact (key y h).2

/-- Degrees of a neighbour-closed component are the degrees in the parent graph. -/
theorem degree_induced_of_closed (G : Graph) (hG : G.WF) (c : List Nat)
    (hI : (G.induced c.contains).WF)
    (hA : ∀ x y, (G.induced c.contains).Adj x y ↔
      G.Adj x y ∧ c.contains x = true ∧ c.contains y = true)
    (hcl : ∀ x ∈ c, ∀ y, G.Adj x y → y ∈ c) (v : Nat) (hv : v ∈ c) :
    (G.induced c.contains).degree v = G.degree v := by
  unfold Graph.degree
  apply List.Perm.length_eq
  rw [List.perm_ext_iff_of_nodup (hI.nbrs_nodup v) (hG.nbrs_nodup v)]
  intro x
  constructor
  · intro hx
    exact ((hA v x).1 hx).1
  · intro hx
    exact (hA v x).2 ⟨hx, List.contains_iff_mem.2 hv, List.contains_iff_mem.2 (hcl v hv x hx)⟩

theorem componentGraphs_wf (hInd : InducedSpec) (Js : Graph) (hJs : Js.WF) :
    ∀ C ∈ componentGraphs Js, C.WF := by
  intro C hC
  obtain ⟨c, _, rfl⟩ := CubicPathwidth.Alg.T3.componentGraphs_mem hC
  exact (hInd Js c.contains hJs).1

/-- The component graphs of a connected graph of minimum degree `≥ 3` are pieces. -/
theorem piece_of_component (hInd : InducedSpec) (hComp : ComponentsSpec)
    (hConn : ComponentsConnected) (Js : Graph) (hJs : Js.WF)
    (hdeg : ∀ v ∈ Js.nodes, 3 ≤ Js.degree v) :
    ∀ C ∈ componentGraphs Js, T4Piece C := by
  intro C hC
  obtain ⟨c, hc, rfl⟩ := CubicPathwidth.Alg.T3.componentGraphs_mem hC
  obtain ⟨hperm, hne, hcl⟩ := hComp Js hJs
  have hI := hInd Js c.contains hJs
  have hA := hI.2.2
  have hcl' : ∀ x ∈ c, ∀ y, Js.Adj x y → y ∈ c := hcl c hc
  refine ⟨hI.1, ?_, ?_, ?_⟩
  · obtain ⟨x, hx⟩ := List.exists_mem_of_ne_nil c (hne c hc)
    intro h
    have hxN : x ∈ (Js.induced c.contains).nodes :=
      ((hI.2.1 x).2 ⟨hperm.subset (List.mem_flatten.2 ⟨c, hc, hx⟩), List.contains_iff_mem.2 hx⟩)
    rw [h] at hxN
    exact List.not_mem_nil hxN
  · intro x hx y hy
    have hx1 := (hI.2.1 x).1 hx
    have hy1 := (hI.2.1 y).1 hy
    exact rtg_induced_of_closed Js c hcl' hA x y (List.contains_iff_mem.1 hx1.2)
      (hConn Js hJs c hc x (List.contains_iff_mem.1 hx1.2) y (List.contains_iff_mem.1 hy1.2))
  · intro v hv
    have hv1 := (hI.2.1 v).1 hv
    rw [degree_induced_of_closed Js hJs c hI.1 hA hcl' v (List.contains_iff_mem.1 hv1.2)]
    exact hdeg v hv1.1

/-! ## The records of one round -/

/-- The commit record: `J` with the deletion of `w` and the reductions of
`J.copy.removeNode w` is a legal record from `J` to the reduced graph. -/
theorem del_record_of (hRem : RemoveNodeSpec) (hInd : InducedSpec) (hMax : ReduceRecordMaximal)
    (hCongr : OpsRecordCongr) (J : Graph) (hJ : J.WF) (w : Nat) (hw : w ∈ J.nodes) :
    OpsRecord J (Op.del w :: (reduceRecordF (J.copy.removeNode w)).2.1)
      (reduceRecordF (J.copy.removeNode w)).1 := by
  have hK := CubicPathwidth.Alg.T3.copy_remove_facts hRem hInd J hJ w
  have hmx : OpsRecord (J.copy.removeNode w) (reduceRecordF (J.copy.removeNode w)).2.1
      (reduceRecordF (J.copy.removeNode w)).1 := (hMax _ hK.1).1
  have hS := copy_removeNode_sameGraph hRem hInd J hJ w
  have hJR : OpsRecord (J.removeNode w) (reduceRecordF (J.copy.removeNode w)).2.1
      (reduceRecordF (J.copy.removeNode w)).1 :=
    hCongr _ _ _ _ hK.1 (hRem J w hJ).1 hS hmx
  rw [opsRecord_del_iff]
  exact ⟨hw, hJR⟩

/-- The thin record: when the reduction of `J.copy.removeNode w` empties the graph, the
record of `J` (deletion of `w`, then the reductions) ends in the empty graph. -/
theorem thin_record_of (hRem : RemoveNodeSpec) (hInd : InducedSpec) (hMax : ReduceRecordMaximal)
    (hCongr : OpsRecordCongr) (hRed : ReduceRecordSpec) (J : Graph) (hJ : J.WF) (w : Nat)
    (hw : w ∈ J.nodes) (hz : (reduceRecordF (J.copy.removeNode w)).1.numNodes = 0) :
    OpsRecord J (Op.del w :: (reduceRecordF (J.copy.removeNode w)).2.1) Graph.empty := by
  have hK := CubicPathwidth.Alg.T3.copy_remove_facts hRem hInd J hJ w
  have hsp := CubicPathwidth.Alg.T3.red_specs hRed _ hK.1
  have hJR := del_record_of hRem hInd hMax hCongr J hJ w hw
  have hsg : SameGraph (reduceRecordF (J.copy.removeNode w)).1 Graph.empty :=
    sameGraph_empty_of_numNodes _ hsp.1 hz
  rw [opsRecord_del_iff] at hJR ⊢
  exact ⟨hw, opsRecord_right_congr _ _ _ _ hsg hJR.2⟩

/-- The record of a commit round: the record of `J` (deletion of `w`, then the reductions
ending in `Js`) is framed by the other graphs of the stack and `final`, and the global
record is extended by it. -/
theorem commit_record_of (hInd : InducedSpec) (hComp : ComponentsSpec) (hFrame : OpsRecordFrame)
    (hApp : OpsRecordAppend) (G0 J : Graph) (rest F : List Graph) (ops red : List Op) (w : Nat)
    (Js : Graph) (hG0 : G0.WF) (hJ : J.WF)
    (hRec : OpsRecord G0 ops (unionAll (J :: (rest ++ F))))
    (hdisj : ∀ B ∈ rest ++ F, ∀ x ∈ J.nodes, x ∉ B.nodes)
    (hF : ∀ B ∈ rest ++ F, B.WF) (hJs : Js.WF) (hDel : OpsRecord J (Op.del w :: red) Js) :
    OpsRecord G0 (ops ++ (Op.del w :: red)) (unionAll ((componentGraphs Js).reverse ++ rest ++ F)) := by
  have hMWF : ∀ X ∈ J :: (rest ++ F), X.WF := by
    intro X hX
    rcases List.mem_cons.1 hX with h | h
    · exact h ▸ hJ
    · exact hF X h
  have hLWF : ∀ X ∈ rest ++ F, X.WF := hF
  have hCsRevWF : ∀ C ∈ (componentGraphs Js).reverse, C.WF := fun C hC =>
    componentGraphs_wf hInd Js hJs C (List.mem_reverse.1 hC)
  have hM : (unionAll (J :: (rest ++ F))).WF := unionAll_wf hMWF
  have hL : (unionAll (rest ++ F)).WF := unionAll_wf hLWF
  have hdisj' : ∀ x, x ∈ J.nodes → x ∉ (unionAll (rest ++ F)).nodes := by
    intro x hx hxL
    obtain ⟨B, hB, hxB⟩ := (unionAll_nodes_iff hLWF x).1 hxL
    exact hdisj B hB x hx hxB
  have hMnodes := unionAll_cons_nodes hJ hLWF
  have hMadj := unionAll_cons_adj hJ hLWF
  have hCsNodes : ∀ x, x ∈ (unionAll (componentGraphs Js).reverse).nodes ↔ x ∈ Js.nodes := by
    intro x
    rw [unionAll_nodes_iff hCsRevWF]
    simp only [List.mem_reverse]
    exact componentGraphs_mem_nodes hInd hComp Js hJs x
  have hCsAdj : ∀ x y, (unionAll (componentGraphs Js).reverse).Adj x y ↔ Js.Adj x y := by
    intro x y
    rw [unionAll_adj_iff hCsRevWF]
    simp only [List.mem_reverse]
    exact componentGraphs_adj_iff hInd hComp Js hJs x y
  have hM'nodes : ∀ v, v ∈ (unionAll ((componentGraphs Js).reverse ++ (rest ++ F))).nodes ↔
      v ∈ Js.nodes ∨ v ∈ (unionAll (rest ++ F)).nodes := by
    intro v
    rw [unionAll_append_nodes hCsRevWF hLWF v, hCsNodes v]
  have hM'adj : ∀ u v, (unionAll ((componentGraphs Js).reverse ++ (rest ++ F))).Adj u v ↔
      Js.Adj u v ∨ (unionAll (rest ++ F)).Adj u v := by
    intro u v
    rw [unionAll_append_adj hCsRevWF hLWF u v, hCsAdj u v]
  have hfr := hFrame J Js (unionAll (rest ++ F)) (unionAll (J :: (rest ++ F)))
    (unionAll ((componentGraphs Js).reverse ++ (rest ++ F))) (Op.del w :: red) hJ hL hM
    hdisj' hMnodes hMadj hM'nodes hM'adj hDel
  have hrec2 := hApp G0 _ _ ops (Op.del w :: red) hG0 hM hRec hfr
  have e : (componentGraphs Js).reverse ++ rest ++ F = (componentGraphs Js).reverse ++ (rest ++ F) :=
    List.append_assoc _ _ _
  rw [e]
  exact hrec2

/-! ## The loop invariant step -/

end T4LoopStep

open T4LoopStep

/-- (D2a2) One round of `t4Loop` preserves the structural invariant `T4LoopInv`. -/
theorem t4LoopInvStep_of (hMax : ReduceRecordMaximal) (hConn : ComponentsConnected)
    (hCongr : OpsRecordCongr) (hApp : OpsRecordAppend) (hFrame : OpsRecordFrame) :
    T4LoopInvStep := by
  have hRem : RemoveNodeSpec := removeNodeSpec
  have hInd : InducedSpec := inducedSpec
  have hComp : ComponentsSpec := componentsSpec
  have hRed : ReduceRecordSpec := reduceRecordSpec
  have hWF : WFBasics := wfBasics
  unfold T4LoopInvStep
  refine ⟨fun G0 stack final ops hG0 hInv => ?_, fun G0 J rest final ops hG0 hInv => ?_⟩
  · -- fuel exhaustion: the stack is dumped into `final`
    obtain ⟨hT, hThin, hRec, hPc, hTh⟩ := hInv
    have hp : (stack ++ final.map (fun e => e.graph)).Perm
        ((final ++ stack.map fun J => FinalEntry.mk J FinalKind.sweep []).map
          (fun e => e.graph)) := by
      rw [CubicPathwidth.Alg.T3.map_graph_append_sweep]
      exact List.perm_append_comm
    have hgs : ∀ X ∈ stack ++ final.map (fun e => e.graph), X.WF := fun X hX => (hPc X hX).1
    unfold T4LoopInv
    refine ⟨?_, ?_, ?_, ?_, ?_⟩
    · rw [List.nil_append]
      exact CubicPathwidth.Alg.T3.T4Inv_perm hT hp
    · exact CubicPathwidth.Alg.T3.thinOK_sweep_list final hThin stack
    · rw [List.nil_append]
      exact opsRecord_right_congr _ _ _ _ (unionAll_perm_sameGraph hp hgs) hRec
    · intro X hX
      rw [List.nil_append] at hX
      exact hPc X (hp.symm.subset hX)
    · intro e he hk
      rcases List.mem_append.1 he with he | he
      · exact hTh e he hk
      · obtain ⟨J, _, rfl⟩ := List.mem_map.1 he
        simp at hk
  · -- one round at the head `J` of the stack
    obtain ⟨hT, hThin, hRec, hPc, hTh⟩ := hInv
    have hJp : T4Piece J := hPc J (by simp)
    have hJ : J.WF := hJp.1
    have hA : ∀ X ∈ J :: (rest ++ final.map (fun e => e.graph)), X.WF := by
      intro X hX
      exact (hPc X hX).1
    refine ⟨fun hmax => ?_, fun hmax => ?_⟩
    · -- finalize a graph of maximum degree at most `5`
      have hp := CubicPathwidth.Alg.T3.perm_entry_snoc rest final J FinalKind.sweep []
      unfold T4LoopInv
      refine ⟨CubicPathwidth.Alg.T3.T4Inv_perm hT hp, CubicPathwidth.Alg.T3.thinOK_sweep final hThin J, ?_, ?_, ?_⟩
      · exact opsRecord_right_congr _ _ _ _ (unionAll_perm_sameGraph hp hA) hRec
      · intro X hX
        exact hPc X (hp.symm.subset hX)
      · intro e he hk
        rcases List.mem_append.1 he with he | he
        · exact hTh e he hk
        · rw [List.mem_singleton] at he
          subst he
          simp at hk
    · -- a round with the chosen vertex `w`
      dsimp only
      have hpos : 0 < J.maxDegree := by omega
      have hw : t4ChooseW J ∈ J.nodes := CubicPathwidth.Alg.T3.t4ChooseW_mem J hpos
      have hK := CubicPathwidth.Alg.T3.copy_remove_facts hRem hInd J hJ (t4ChooseW J)
      have hspec := CubicPathwidth.Alg.T3.red_specs hRed _ hK.1
      have hmx : OpsRecord (J.copy.removeNode (t4ChooseW J))
          (reduceRecordF (J.copy.removeNode (t4ChooseW J))).2.1
          (reduceRecordF (J.copy.removeNode (t4ChooseW J))).1 ∧
          (∀ v ∈ (reduceRecordF (J.copy.removeNode (t4ChooseW J))).1.nodes,
            3 ≤ (reduceRecordF (J.copy.removeNode (t4ChooseW J))).1.degree v) :=
        ⟨(hMax _ hK.1).1, (hMax _ hK.1).2.1⟩
      refine ⟨fun hz => ?_, fun hz => ?_⟩
      · -- thin round: the graph of `w` is emptied
        have hJR := thin_record_of hRem hInd hMax hCongr hRed J hJ (t4ChooseW J) hw hz
        unfold T4LoopInv
        have hp := CubicPathwidth.Alg.T3.perm_entry_snoc rest final J FinalKind.thin
          (Op.del (t4ChooseW J) :: (reduceRecordF (J.copy.removeNode (t4ChooseW J))).2.1)
        refine ⟨CubicPathwidth.Alg.T3.T4Inv_perm hT hp, CubicPathwidth.Alg.T3.thinOK_thin final hThin J
          (t4ChooseW J) _ hspec.2.2.2 hw, ?_, ?_, ?_⟩
        · exact opsRecord_right_congr _ _ _ _ (unionAll_perm_sameGraph hp hA) hRec
        · intro X hX
          exact hPc X (hp.symm.subset hX)
        · intro e he hk
          rcases List.mem_append.1 he with he | he
          · exact hTh e he hk
          · rw [List.mem_singleton] at he
            subst he
            refine ⟨hJR, ?_⟩
            rw [CubicPathwidth.Alg.T3.deletedSet_del_cons,
              CubicPathwidth.Alg.T3.deletedSet_nil_of_red _ hspec.2.2.2]
            rfl
      · -- commit round: `J` is replaced by the components of the reduced graph
        have hcommitT := CubicPathwidth.Alg.T3.commit_inv' hWF hInd hComp G0 J
          (J.copy.removeNode (t4ChooseW J)) (reduceRecordF (J.copy.removeNode (t4ChooseW J))).1
          rest (final.map (fun e : FinalEntry => e.graph)) ops
          (reduceRecordF (J.copy.removeNode (t4ChooseW J))).2.1 (t4ChooseW J) hT hw hK.2.1 hK.2.2
          hspec.1 hspec.2.1 hspec.2.2.1 hspec.2.2.2
        have hPair : (J :: (rest ++ final.map (fun e : FinalEntry => e.graph))).Pairwise
            (fun A B : Graph => ∀ x, x ∈ A.nodes → x ∉ B.nodes) := by
          obtain ⟨_, hP, _, _, _⟩ := hT
          exact hP
        have hdisj : ∀ B ∈ rest ++ final.map (fun e : FinalEntry => e.graph), ∀ x ∈ J.nodes,
            x ∉ B.nodes :=
          fun B hB x hx => (List.pairwise_cons.1 hPair).1 B hB x hx
        have hmemRF : ∀ B ∈ rest ++ final.map (fun e : FinalEntry => e.graph),
            B ∈ (J :: rest) ++ final.map (fun e : FinalEntry => e.graph) := by
          intro B hB
          rcases List.mem_append.1 hB with h | h
          · exact List.mem_append_left _ (List.mem_cons_of_mem J h)
          · exact List.mem_append_right _ h
        have hFWF : ∀ B ∈ rest ++ final.map (fun e : FinalEntry => e.graph), B.WF :=
          fun B hB => (hPc B (hmemRF B hB)).1
        unfold T4LoopInv
        refine ⟨hcommitT, hThin, ?_, ?_, ?_⟩
        · exact commit_record_of hInd hComp hFrame hApp G0 J rest
            (final.map (fun e : FinalEntry => e.graph)) ops
            (reduceRecordF (J.copy.removeNode (t4ChooseW J))).2.1 (t4ChooseW J)
            (reduceRecordF (J.copy.removeNode (t4ChooseW J))).1 hG0 hJ hRec hdisj hFWF hspec.1
            (del_record_of hRem hInd hMax hCongr J hJ (t4ChooseW J) hw)
        · intro X hX
          rcases List.mem_append.1 hX with h | h
          · rcases List.mem_append.1 h with h' | h'
            · exact piece_of_component hInd hComp hConn _ hspec.1 hmx.2 X (List.mem_reverse.1 h')
            · exact hPc X (hmemRF X (List.mem_append_left _ h'))
          · exact hPc X (hmemRF X (List.mem_append_right _ h))
        · intro e he hk
          exact hTh e he hk

end CubicPathwidth.Alg

end

#print axioms CubicPathwidth.Alg.t4LoopInvStep_of
Back to top