CubicPathwidth.Alg.Proofs.C5ReduceRecord

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

import CubicPathwidth.Alg.Spec

/-!
# C5: `ReduceRecordSpec` (invariant of the reduction loop)

Task C5 of the formalisation. The statement `reduceRecordSpec_of` takes the
hypotheses `WFBasics`, `AddEdgeSpec`, `RemoveNodeSpec` (proved in other files; only the
last two are used).

Strategy. For arbitrary fuel, stack and accumulated ops `L` (order irrelevant), the
invariant `Inv G0 G L` says: `G` is well formed; its nodes are nodes of `G0`; an edge of
`G0` between nodes of `G` is an edge of `G`; every op of `L` is `red v nb` with `v` a node
of `G0` no longer in `G`, and `nb` in `G0`; every node of `G0` is in `G` or among the
removed vertices of `L`. `reduceLoop` preserves it by induction on the fuel.
-/

namespace CubicPathwidth.Alg

open Graph

namespace C5

/-- The graph part of one step of `reduceLoop`: `G1` is the graph after `removeNode v` and
`nb` the neighbour list of `v`; two neighbours are joined by `addEdge`. -/
def stepG (G1 : Graph) (nb : List Nat) : Graph :=
  match nb with
  | [a, b] => G1.addEdge a b
  | _ => G1

/-- The invariant of the reduction loop relative to its start `G0`. -/
def Inv (G0 G : Graph) (L : List Op) : Prop :=
  G.WF ∧ (∀ x ∈ G.nodes, x ∈ G0.nodes) ∧
  (∀ x y, x ∈ G.nodes → y ∈ G.nodes → G0.Adj x y → G.Adj x y) ∧
  (∀ o ∈ L, ∃ v nb, o = Op.red v nb ∧ v ∈ G0.nodes ∧ v ∉ G.nodes ∧ ∀ x ∈ nb, x ∈ G0.nodes) ∧
  (∀ x ∈ G0.nodes, x ∈ G.nodes ∨ x ∈ redVertices L)

theorem mem_redVertices_reverse (L : List Op) (x : Nat) :
    x ∈ redVertices L.reverse ↔ x ∈ redVertices L := by
  unfold redVertices
  rw [List.mem_filterMap, List.mem_filterMap]
  simp only [List.mem_reverse]

theorem inv_reverse {G0 G : Graph} {L : List Op} (h : Inv G0 G L) :
    Inv G0 G L.reverse := by
  obtain ⟨h1, h2, h3, h4, h5⟩ := h
  refine ⟨h1, h2, h3, ?_, fun x hx => ?_⟩
  · intro o ho
    exact h4 o (List.mem_reverse.1 ho)
  · rcases h5 x hx with h | h
    · exact Or.inl h
    · exact Or.inr ((mem_redVertices_reverse L x).2 h)

/-- The graph step keeps well-formedness, the node set of `G1` and the edges of `G1`
(`AddEdgeSpec` adds edges only between nodes; here the two neighbours are nodes of `G1`
and distinct, by `nbrs_nodup`). -/
theorem stepG_props (hAdd : AddEdgeSpec) (G1 : Graph) (nb : List Nat) (hG1 : G1.WF)
    (hnb : nb.Nodup) (hnbN : ∀ x ∈ nb, x ∈ G1.nodes) :
    (stepG G1 nb).WF ∧ (∀ x, x ∈ (stepG G1 nb).nodes ↔ x ∈ G1.nodes) ∧
      (∀ x y, G1.Adj x y → (stepG G1 nb).Adj x y) := by
  rcases nb with _ | ⟨a, _ | ⟨b, _ | ⟨c, l⟩⟩⟩
  · exact ⟨hG1, fun _ => Iff.rfl, fun _ _ h => h⟩
  · exact ⟨hG1, fun _ => Iff.rfl, fun _ _ h => h⟩
  · have hab : a ≠ b := by
      intro h
      subst h
      simp at hnb
    have ha : a ∈ G1.nodes := hnbN a (by simp)
    have hb : b ∈ G1.nodes := hnbN b (by simp)
    obtain ⟨h1, h2, h3⟩ := hAdd G1 a b hG1 hab
    refine ⟨h1, ?_, ?_⟩
    · intro x
      show x ∈ (G1.addEdge a b).nodes ↔ x ∈ G1.nodes
      rw [h2 x]
      constructor
      · rintro (h | rfl | rfl)
        · exact h
        · exact ha
        · exact hb
      · intro h
        exact Or.inl h
    · intro x y h
      show (G1.addEdge a b).Adj x y
      rw [h3 x y]
      exact Or.inl h
  · exact ⟨hG1, fun _ => Iff.rfl, fun _ _ h => h⟩

/-- One non-skipped step of the loop preserves the invariant. -/
theorem step_inv (hRem : RemoveNodeSpec) (hAdd : AddEdgeSpec) (G0 G : Graph) (L : List Op)
    (v : Nat) (hI : Inv G0 G L) (hm : G.mem v = true) :
    Inv G0 (stepG (G.removeNode v) (G.nbrs v)) (Op.red v (G.nbrs v) :: L) := by
  obtain ⟨hG, hsub, hedge, hops, hcov⟩ := hI
  have hv : v ∈ G.nodes := (hG.mem_iff v).1 hm
  obtain ⟨hR1, hR2, hR3⟩ := hRem G v hG
  have hnbN : ∀ x ∈ G.nbrs v, x ∈ (G.removeNode v).nodes := by
    intro x hx
    rw [hR2]
    exact ⟨hG.nbrs_sub v x hx, fun h => hG.loopless v (h ▸ hx)⟩
  obtain ⟨hS1, hS2, hS3⟩ :=
    stepG_props hAdd (G.removeNode v) (G.nbrs v) hR1 (hG.nbrs_nodup v) hnbN
  refine ⟨hS1, ?_, ?_, ?_, ?_⟩
  · intro x hx
    rw [hS2, hR2] at hx
    exact hsub x hx.1
  · intro x y hx hy hG0
    rw [hS2, hR2] at hx hy
    have hGxy := hedge x y hx.1 hy.1 hG0
    exact hS3 x y ((hR3 x y).2 ⟨hGxy, hx.2, hy.2⟩)
  · intro o ho
    rcases List.mem_cons.1 ho with rfl | ho
    · refine ⟨v, G.nbrs v, rfl, hsub v hv, ?_, fun x hx => hsub x (hG.nbrs_sub v x hx)⟩
      rw [hS2, hR2]
      simp
    · obtain ⟨v', nb', h1, h2, h3, h4⟩ := hops o ho
      refine ⟨v', nb', h1, h2, ?_, h4⟩
      intro hmem
      exact h3 ((hR2 v').1 ((hS2 v').1 hmem)).1
  · intro x hx
    rcases hcov x hx with h | h
    · by_cases hxv : x = v
      · right
        rw [hxv]
        simp [redVertices]
      · left
        rw [hS2, hR2]
        exact ⟨h, hxv⟩
    · right
      have h' : x ∈ redVertices (Op.red v (G.nbrs v) :: L) := by
        simp only [redVertices, List.filterMap_cons] at h ⊢
        exact List.mem_cons_of_mem _ h
      exact h'

/-- The loop preserves the invariant, for every fuel, stack and start. -/
theorem loop_inv (hRem : RemoveNodeSpec) (hAdd : AddEdgeSpec) (G0 : Graph) (fuel : Nat) :
    ∀ (G : Graph) (stack : List Nat) (L : List Op), Inv G0 G L →
      Inv G0 (reduceLoop fuel G stack L).1 (reduceLoop fuel G stack L).2.1 := by
  induction fuel with
  | zero =>
    intro G stack L hI
    cases stack with
    | nil =>
      simp only [reduceLoop]
      exact inv_reverse hI
    | cons v rest =>
      simp only [reduceLoop]
      exact inv_reverse hI
  | succ n ih =>
    intro G stack L hI
    cases stack with
    | nil =>
      simp only [reduceLoop]
      exact inv_reverse hI
    | cons v rest =>
      by_cases hc : (!G.mem v || G.degree v > 2) = true
      · simp only [reduceLoop, hc]
        exact ih G rest L hI
      · have hm : G.mem v = true := by
          cases h : G.mem v
          · exact absurd (by simp [h] at hc ⊢) hc
          · rfl
        simp only [reduceLoop, hc]
        exact ih _ _ _ (step_inv hRem hAdd G0 G L v hI hm)

end C5

/-- C5: `reduce_record` (`reduceRecord`) satisfies `ReduceRecordSpec`. -/
theorem reduceRecordSpec_of (hWF : WFBasics) (hAdd : AddEdgeSpec) (hRem : RemoveNodeSpec) :
    ReduceRecordSpec := by
  unfold ReduceRecordSpec
  intro G hG
  have hI : C5.Inv G G [] :=
    ⟨hG, fun _ hx => hx, fun _ _ _ _ h => h,
      fun o ho => absurd ho (List.not_mem_nil), fun _ hx => Or.inl hx⟩
  have key := C5.loop_inv hRem hAdd G (3 * G.numNodes + 1) G
    (G.nodes.filter fun v => G.degree v ≤ 2).reverse [] hI
  dsimp only [reduceRecord, reduceRecordF]
  exact ⟨key.1, key.2.1, key.2.2.1, key.2.2.2.1, key.2.2.2.2⟩

#print axioms CubicPathwidth.Alg.reduceRecordSpec_of

end CubicPathwidth.Alg
Back to top