CubicPathwidth.Alg.Proofs2.D4LoopFuel

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

import CubicPathwidth.Alg.Plan2
import CubicPathwidth.Alg.Proofs.Targets

/-!
# Task D4: the deletion loop of `algo_T4` never runs out of fuel (`Spec2.lean` §2)

`t4LoopNoFallback_of` takes `ReduceRecordNoFallback` as hypothesis and proves
`T4LoopNoFallback`.

Route. The measure is `S(stack) = ∑_{J ∈ stack} |V(J)|`. Every graph in the work list is
well formed and has at least one node (components are nonempty and `induced` keeps the
nodes of a component). A sweep or thin step removes one graph of `S`-size `≥ 1`. A
commit step on `J` replaces `J` by the component graphs of `Js`, the reduction of
`K = J - w` with `w ∈ V(J)`, so the new total is at most `|V(J)| - 1 + S(rest)`
(`Js ⊆ K` and `|K| + 1 ≤ |J|`). Hence `S` drops by at least one per step, and the
initial total is at most `|V(H)| < 2|V(H)| + 1` (the fuel). The reduction flags inside
`t4Loop` are `false` by `ReduceRecordNoFallback`, applied to `J.copy.removeNode w`
(well formed by `copy_remove_facts`).
-/

namespace CubicPathwidth.Alg

open Graph

namespace D4

/-- Termwise comparison of sums over lists of naturals. -/
theorem sum_map_le {α : Type} (f g : α → ℕ) (l : List α) (h : ∀ a ∈ l, f a ≤ g a) :
    (l.map f).sum ≤ (l.map g).sum := by
  induction l with
  | nil => simp
  | cons a l ih =>
    simp only [List.map_cons, List.sum_cons]
    exact Nat.add_le_add (h a (by simp)) (ih fun b hb => h b (List.mem_cons_of_mem _ hb))

/-- Reversing a list does not change the sum of the node counts. -/
theorem sum_reverse_map (L : List Graph) :
    (L.reverse.map Graph.numNodes).sum = (L.map Graph.numNodes).sum :=
  ((List.reverse_perm L).map Graph.numNodes).sum_eq

/-- Each component graph is well formed and has at least one node. -/
theorem componentGraphs_good {Js : Graph} (hJs : Js.WF) :
    ∀ C ∈ componentGraphs Js, C.WF ∧ 1 ≤ C.numNodes := by
  intro C hC
  obtain ⟨c, hc, rfl⟩ := T3.componentGraphs_mem hC
  refine ⟨(inducedSpec Js c.contains hJs).1, ?_⟩
  obtain ⟨hperm, hne, _⟩ := componentsSpec Js hJs
  obtain ⟨x, hx⟩ : ∃ x, x ∈ c := List.exists_mem_of_ne_nil c (hne c hc)
  have hxJs : x ∈ Js.nodes := hperm.subset (List.mem_flatten.2 ⟨c, hc, hx⟩)
  have hxC : x ∈ (Js.induced c.contains).nodes :=
    ((inducedSpec Js c.contains hJs).2.1 x).2 ⟨hxJs, List.contains_iff_mem.2 hx⟩
  unfold Graph.numNodes
  exact List.length_pos_of_mem hxC

/-- The node counts of the component graphs of `Js` add up to at most `Js.numNodes`. -/
theorem sum_numNodes_componentGraphs {Js : Graph} (hJs : Js.WF) :
    ((componentGraphs Js).map Graph.numNodes).sum ≤ Js.numNodes := by
  obtain ⟨hperm, _, _⟩ := componentsSpec Js hJs
  have hlen : (Js.components.map List.length).sum = Js.numNodes := by
    rw [← List.length_flatten, hperm.length_eq]
    rfl
  have hterm : ∀ c ∈ Js.components,
      (Js.induced c.contains).numNodes ≤ (fun c : List Nat => c.length) c := by
    intro c _
    have hw := (inducedSpec Js c.contains hJs).1
    have hsub : ∀ x ∈ (Js.induced c.contains).nodes, x ∈ c := by
      intro x hx
      exact List.contains_iff_mem.1 ((((inducedSpec Js c.contains hJs).2.1 x).1 hx).2)
    unfold Graph.numNodes
    exact (hw.nodup.subperm hsub).length_le
  unfold componentGraphs
  rw [List.map_map, ← hlen]
  exact sum_map_le _ _ _ fun c hc => hterm c hc

/-- The loop with fuel bounded below by the measure never raises the reduction flag. -/
theorem loop_noflag (hR1 : ReduceRecordNoFallback) :
    ∀ (fuel : ℕ) (stack : List Graph) (final : List FinalEntry) (ops : List Op),
      (∀ J ∈ stack, J.WF ∧ 1 ≤ J.numNodes) →
      (stack.map Graph.numNodes).sum ≤ fuel →
      (t4Loop fuel stack final ops).2.2 = false := by
  intro fuel
  induction fuel with
  | zero =>
    intro stack final ops hst hsum
    cases stack with
    | nil => rw [t4Loop]
    | cons J rest =>
      exfalso
      have h1 := (hst J List.mem_cons_self).2
      simp only [List.map_cons, List.sum_cons] at hsum
      omega
  | succ f ih =>
    intro stack final ops hst hsum
    cases stack with
    | nil => rw [t4Loop]
    | cons J rest =>
      obtain ⟨hJ, hJn⟩ := hst J List.mem_cons_self
      have hrest : ∀ K ∈ rest, K.WF ∧ 1 ≤ K.numNodes :=
        fun K hK => hst K (List.mem_cons_of_mem _ hK)
      simp only [List.map_cons, List.sum_cons] at hsum
      by_cases hmax : J.maxDegree ≤ 5
      · rw [t4Loop]
        simp only [hmax, ↓reduceIte]
        exact ih rest _ ops hrest (by omega)
      · have hpos : 0 < J.maxDegree := by omega
        have hwmem := T3.t4ChooseW_mem J hpos
        have hK := T3.copy_remove_facts removeNodeSpec inducedSpec J hJ (t4ChooseW J)
        have hspec := T3.red_specs reduceRecordSpec _ hK.1
        have hRF := hR1 _ hK.1
        rw [t4Loop]
        simp only [hmax, ↓reduceIte]
        by_cases hz : (reduceRecordF (J.copy.removeNode (t4ChooseW J))).1.numNodes = 0
        · simp only [hz, ↓reduceIte]
          exact Bool.or_eq_false_iff.2 ⟨ih rest _ _ hrest (by omega), hRF⟩
        · simp only [hz, ↓reduceIte]
          -- the commit step
          set w := t4ChooseW J with hw
          set K := J.copy.removeNode w with hKdef
          set Js := (reduceRecordF K).1 with hJsdef
          have hJsWF : Js.WF := hspec.1
          have hJsSub : ∀ x ∈ Js.nodes, x ∈ K.nodes := hspec.2.1
          have hJsle : Js.numNodes ≤ K.numNodes := by
            unfold Graph.numNodes
            exact (hJsWF.nodup.subperm hJsSub).length_le
          have hwK : w ∉ K.nodes := fun h => ((hK.2.1 w).1 h).2 rfl
          have hnd : (w :: K.nodes).Nodup := List.nodup_cons.2 ⟨hwK, hK.1.nodup⟩
          have hsubJ : ∀ x ∈ w :: K.nodes, x ∈ J.nodes := by
            intro x hx
            rcases List.mem_cons.1 hx with rfl | hx
            · exact hwmem
            · exact ((hK.2.1 x).1 hx).1
          have hKlt : K.numNodes + 1 ≤ J.numNodes := by
            unfold Graph.numNodes
            simpa using (hnd.subperm hsubJ).length_le
          have hnew : ∀ C ∈ (componentGraphs Js).reverse ++ rest, C.WF ∧ 1 ≤ C.numNodes := by
            intro C hC
            rcases List.mem_append.1 hC with hC | hC
            · exact componentGraphs_good hJsWF C (List.mem_reverse.1 hC)
            · exact hrest C hC
          have hsumC := sum_numNodes_componentGraphs hJsWF
          have hsumNew : (((componentGraphs Js).reverse ++ rest).map Graph.numNodes).sum ≤ f := by
            rw [List.map_append, List.sum_append, sum_reverse_map]
            omega
          exact Bool.or_eq_false_iff.2 ⟨ih _ _ _ hnew hsumNew, hRF⟩

end D4

/-- `algo_T4`'s deletion loop has no fallback from the initial call (`Spec2.lean` §2),
from `ReduceRecordNoFallback`. -/
theorem t4LoopNoFallback_of (hR1 : ReduceRecordNoFallback) : T4LoopNoFallback := by
  intro G hG
  have hG0 : (nonIsolated G).WF := (inducedSpec G (fun v => G.degree v != 0) hG).1
  have hc : (nonIsolated G).copy.WF := (inducedSpec _ (fun _ => true) hG0).1
  have hH : (reduceRecordF (nonIsolated G).copy).1.WF := (reduceRecordSpec _ hc).1
  have hstack : ∀ J ∈ (componentGraphs (reduceRecordF (nonIsolated G).copy).1).reverse,
      J.WF ∧ 1 ≤ J.numNodes := by
    intro J hJ
    exact D4.componentGraphs_good hH J (List.mem_reverse.1 hJ)
  have hsum : ((componentGraphs (reduceRecordF (nonIsolated G).copy).1).reverse.map
      Graph.numNodes).sum ≤ 2 * (reduceRecordF (nonIsolated G).copy).1.numNodes + 1 := by
    rw [D4.sum_reverse_map]
    have := D4.sum_numNodes_componentGraphs hH
    omega
  exact D4.loop_noflag hR1 _ _ [] _ hstack hsum

#print axioms CubicPathwidth.Alg.t4LoopNoFallback_of

end CubicPathwidth.Alg
Back to top