CubicPathwidth.Alg.Proofs2.AlgoT4Internal

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

import CubicPathwidth.Alg.Plan2Deletion
import CubicPathwidth.Alg.Proofs.Targets
import CubicPathwidth.T4.SeqH

/-!
# K4b: internal form of Theorem 4 for `algo_T4` (`AlgoT4InternalBound`)

Task `algoT4InternalBound_of` (`Plan2Deletion.lean`, K4b). Hypotheses: `SweepComponentBound`
(K4a), `AlgoT4Width` (A3), `ThinComponentWidth` (U5), `DeletionProcessBound` (D5),
`AlgoT4NoFallback` (N4), `T4FinalFacts`, `PsiPortFacts` (D3), `RelabelOfSimpleGraph` (X1),
`DegreeTransfer` (X3). Taken from Stage 1 / T4: `ofSimpleGraphSpec`, `T4.seqClaim_h`.

Route: the labeler is chosen per graph by `SweepComponentBound` (at `ε/2`). Every bag
of `final` has at most `U0 + 1` vertices, where `U0 = ∑ψ⁻ + σ₃ + (ε/2) n₀ + N₁ + B`,
`B = 3 log₂ n₀ + 1`, `n₀` the number of non-isolated vertices. Then `A3` and `D5` give
`pdWidth ≤ DW + σ₃ + ε n₀ + N₁ + (6 log₂ n₀ + 2)` with `DW = degreeWeight S thm4Coeff`.
-/

noncomputable section

namespace CubicPathwidth.Alg

open Graph

namespace K4b

/-! ## 1. Bag widths -/

theorem maxBagCard_cast_le (bags : List Bag) (w : ℝ) (hw : 0 ≤ w)
    (h : ∀ B ∈ bags, (B.toFinset.card : ℝ) ≤ w) : (maxBagCard bags : ℝ) ≤ w := by
  induction bags with
  | nil => simpa [maxBagCard] using hw
  | cons B bs ih =>
    have h1 : (B.toFinset.card : ℝ) ≤ w := h B (by simp)
    have h2 : (maxBagCard bs : ℝ) ≤ w := ih (fun C hC => h C (by simp [hC]))
    have hc : maxBagCard (B :: bs) = max B.toFinset.card (maxBagCard bs) := by
      simp [maxBagCard]
    rw [hc, Nat.cast_max]
    exact max_le h1 h2

theorem pdWidth_le_of_bags (bags : List Bag) (w : ℝ) (hw : 0 ≤ w + 1)
    (h : ∀ B ∈ bags, (B.toFinset.card : ℝ) ≤ w + 1) : pdWidth bags ≤ w := by
  have := maxBagCard_cast_le bags (w + 1) hw h
  unfold pdWidth
  linarith

theorem card_le_maxBagCard (B : Bag) : ∀ bags : List Bag, B ∈ bags →
    B.toFinset.card ≤ maxBagCard bags := by
  intro bags
  induction bags with
  | nil => intro h; simp at h
  | cons C cs ih =>
    intro h
    have hc : maxBagCard (C :: cs) = max C.toFinset.card (maxBagCard cs) := by
      simp [maxBagCard]
    rw [hc]
    rcases List.mem_cons.1 h with h' | h'
    · subst h'
      exact le_max_left _ _
    · exact le_max_of_le_right (ih h')

theorem card_le_of_pdWidth (bags : List Bag) (w : ℝ) (hp : pdWidth bags ≤ w)
    (B : Bag) (hB : B ∈ bags) : (B.toFinset.card : ℝ) ≤ w + 1 := by
  have h1 : (B.toFinset.card : ℝ) ≤ (maxBagCard bags : ℝ) := by
    exact_mod_cast card_le_maxBagCard B bags hB
  unfold pdWidth at hp
  linarith

/-! ## 2. Sums over `range n` and the potential of `ofSimpleGraph` -/

theorem sum_range_map (n : ℕ) (f : ℕ → ℝ) :
    ((List.range n).map f).sum = ∑ i : Fin n, f i.val := by
  induction n with
  | zero => simp
  | succ m ih =>
    rw [List.range_succ, List.map_append, List.sum_append, ih, Fin.sum_univ_castSucc]
    simp

theorem psiPort_ofSimpleGraph {n : ℕ} (S : SimpleGraph (Fin n)) [DecidableRel S.Adj]
    (hdeg : ∀ i : Fin n, (Graph.ofSimpleGraph S).degree i.val = S.degree i) (b : ℕ → ℝ) :
    psiPort b (Graph.ofSimpleGraph S) = T4.degreeWeight S b := by
  unfold psiPort T4.degreeWeight
  have hn : (Graph.ofSimpleGraph S).nodes = List.range n := rfl
  rw [hn, sum_range_map n (fun v => b ((Graph.ofSimpleGraph S).degree v))]
  apply Finset.sum_congr rfl
  intro i _
  rw [hdeg i]
  convert rfl

theorem nonIsolated_numNodes_eq {n : ℕ} (S : SimpleGraph (Fin n)) [DecidableRel S.Adj]
    (hWF : (Graph.ofSimpleGraph S).WF)
    (hdeg : ∀ i : Fin n, (Graph.ofSimpleGraph S).degree i.val = S.degree i) :
    (nonIsolated (Graph.ofSimpleGraph S)).numNodes = nonIsolatedCount S := by
  have hn : (Graph.ofSimpleGraph S).nodes = List.range n := rfl
  have hnd : (nonIsolated (Graph.ofSimpleGraph S)).nodes.Nodup := by
    unfold nonIsolated
    exact (inducedSpec _ _ hWF).1.nodup
  have hmem : ∀ x, x ∈ (nonIsolated (Graph.ofSimpleGraph S)).nodes ↔
      x < n ∧ (Graph.ofSimpleGraph S).degree x ≠ 0 := by
    intro x
    have h := (inducedSpec (Graph.ofSimpleGraph S)
      (fun v => (Graph.ofSimpleGraph S).degree v != 0) hWF).2.1 x
    unfold nonIsolated
    rw [h, hn, List.mem_range]
    simp
  have hset : (nonIsolated (Graph.ofSimpleGraph S)).nodes.toFinset =
      (Finset.univ.filter fun v : Fin n => S.degree v ≠ 0).map Fin.valEmbedding := by
    ext x
    rw [List.mem_toFinset, Finset.mem_map, hmem]
    constructor
    · rintro ⟨hxn, hxd⟩
      refine ⟨⟨x, hxn⟩, Finset.mem_filter.2 ⟨Finset.mem_univ _, ?_⟩, rfl⟩
      have h := hdeg ⟨x, hxn⟩
      rw [← h]
      exact hxd
    · rintro ⟨i, hi, rfl⟩
      have hi' : S.degree i ≠ 0 := (Finset.mem_filter.1 hi).2
      refine ⟨i.isLt, ?_⟩
      show (Graph.ofSimpleGraph S).degree i.val ≠ 0
      rw [hdeg i]
      exact hi'
  unfold Graph.numNodes nonIsolatedCount
  rw [← List.toFinset_card_of_nodup hnd, hset, Finset.card_map]
  convert rfl

/-! ## 3. A linear bound for `6 log₂ n + 2` -/

theorem log_linear (c η : ℝ) (hc : 0 ≤ c) (hη : 0 < η) :
    ∃ N : ℕ, ∀ n : ℕ, N ≤ n → 3 * (Nat.log 2 n : ℝ) + 1 + c ≤ η * n := by
  have hL : 0 < Real.log 2 := Real.log_pos (by norm_num)
  have hlog : ∀ n : ℕ, 1 ≤ n → (Nat.log 2 n : ℝ) * Real.log 2 ≤ 2 * Real.sqrt n := by
    intro n hn
    have hn0 : (0:ℝ) < n := by exact_mod_cast hn
    have h2 : ((2:ℝ) ^ Nat.log 2 n) ≤ n := by
      exact_mod_cast Nat.pow_log_le_self 2 (by omega)
    have h3 : (Nat.log 2 n : ℝ) * Real.log 2 = Real.log ((2:ℝ) ^ Nat.log 2 n) := by
      rw [Real.log_pow]
    have h4 : Real.log n ≤ 2 * Real.sqrt n := by
      have hs : 0 < Real.sqrt n := Real.sqrt_pos.2 hn0
      have h5 := Real.log_le_sub_one_of_pos hs
      rw [Real.log_sqrt hn0.le] at h5
      linarith
    rw [h3]
    exact (Real.log_le_log (by positivity) h2).trans h4
  set K : ℝ := 6 / Real.log 2 with hK
  have hK0 : 0 ≤ K := by positivity
  set S₀ : ℝ := (K + 1 + c) / η + 1 with hS₀
  have hS₀1 : 1 ≤ S₀ := by
    have : 0 ≤ (K + 1 + c) / η := by positivity
    linarith
  refine ⟨⌈S₀ ^ 2⌉₊ + 1, fun n hn => ?_⟩
  have hn1 : 1 ≤ n := by omega
  have hnS : S₀ ^ 2 ≤ (n : ℝ) := by
    have h : (⌈S₀ ^ 2⌉₊ : ℝ) ≤ n := by
      exact_mod_cast (show ⌈S₀ ^ 2⌉₊ ≤ n by omega)
    exact (Nat.le_ceil _).trans h
  set s : ℝ := Real.sqrt n with hs
  have hs0 : 0 ≤ s := Real.sqrt_nonneg _
  have hsS : S₀ ≤ s := by
    calc S₀ = Real.sqrt (S₀ ^ 2) := (Real.sqrt_sq (by linarith)).symm
      _ ≤ Real.sqrt n := Real.sqrt_le_sqrt hnS
  have hsq : s ^ 2 = (n : ℝ) := Real.sq_sqrt (by positivity)
  have hk : 3 * (Nat.log 2 n : ℝ) ≤ K * s := by
    have h1 : (Nat.log 2 n : ℝ) ≤ 2 * s / Real.log 2 := by
      rw [le_div_iff₀ hL]
      have := hlog n hn1
      linarith
    have h2 : K * s = 6 * s / Real.log 2 := by rw [hK]; ring
    rw [h2]
    calc 3 * (Nat.log 2 n : ℝ) ≤ 3 * (2 * s / Real.log 2) := by linarith
      _ = 6 * s / Real.log 2 := by ring
  have he : η * ((K + 1 + c) / η) = K + 1 + c := by field_simp
  have h1 : K + 1 + c ≤ η * S₀ := by
    have : η * S₀ = η * ((K + 1 + c) / η) + η := by rw [hS₀]; ring
    rw [this, he]
    linarith
  have hA : (K + 1 + c) * s ≤ η * S₀ * s := mul_le_mul_of_nonneg_right h1 hs0
  have hB : η * S₀ * s ≤ η * s * s := by
    apply mul_le_mul_of_nonneg_right _ hs0
    exact mul_le_mul_of_nonneg_left hsS hη.le
  have hC : K * s + 1 + c ≤ (K + 1 + c) * s := by
    nlinarith [mul_nonneg (by linarith : (0:ℝ) ≤ 1 + c) (by linarith : (0:ℝ) ≤ s - 1)]
  calc 3 * (Nat.log 2 n : ℝ) + 1 + c ≤ K * s + 1 + c := by linarith
    _ ≤ η * s * s := by linarith
    _ = η * n := by rw [← hsq]; ring

theorem logBound (ε : ℝ) (hε : 0 < ε) :
    ∃ C : ℝ, ∀ n : ℕ, 6 * (Nat.log 2 n : ℝ) + 2 ≤ ε / 2 * n + C := by
  obtain ⟨N, hN⟩ := log_linear 0 (ε / 4) le_rfl (by linarith)
  have hC0 : (0 : ℝ) ≤ 6 * (Nat.log 2 N : ℝ) + 2 := by positivity
  refine ⟨6 * (Nat.log 2 N : ℝ) + 2, fun n => ?_⟩
  have hn : (0 : ℝ) ≤ (n : ℝ) := Nat.cast_nonneg n
  have hεn : 0 ≤ ε / 2 * (n : ℝ) := by positivity
  by_cases h : N ≤ n
  · have := hN n h
    linarith
  · have hlt : n ≤ N := by omega
    have hlog : Nat.log 2 n ≤ Nat.log 2 N := Nat.log_mono_right hlt
    have hlogR : (Nat.log 2 n : ℝ) ≤ (Nat.log 2 N : ℝ) := by exact_mod_cast hlog
    linarith

end K4b

open K4b

/-! ## 4. The internal bound (main theorem, namespace `CubicPathwidth.Alg`) -/

theorem algoT4InternalBound_of (hSw : SweepComponentBound) (hA3 : AlgoT4Width)
    (hU5 : ThinComponentWidth) (hD5 : DeletionProcessBound) (hN4 : AlgoT4NoFallback)
    (hFin : T4FinalFacts) (hPsi : PsiPortFacts) (hX1 : RelabelOfSimpleGraph)
    (hX3 : DegreeTransfer) : AlgoT4InternalBound := by
  unfold DegreeTransfer at hX3
  have hSeq : T4.BootProps T4.sigma ∧ ∀ d : ℕ, T4.sigma d ≤ T4.thm4Coeff d :=
    T4.seqClaim_h
  have hσ3 : (0 : ℝ) ≤ T4.sigma 3 := by norm_num [T4.sigma]
  intro hT ε hε
  obtain ⟨N₁, hN₁⟩ := hSw hT (ε / 2) (by linarith)
  obtain ⟨C₂, hC₂⟩ := logBound ε hε
  have hN₁0 : (0 : ℝ) ≤ N₁ := Nat.cast_nonneg _
  -- labels: one sweep labeling per graph (chosen with `SweepComponentBound`)
  have hex : ∀ J : Graph, ∃ Y : Labels,
      (J.WF ∧ J.MaxDegLE 5 ∧ ∀ v ∈ J.nodes, 3 ≤ J.degree v) →
        pdWidth (plainLayout J Y) ≤ psiPort T4.sigma J + ε / 2 * (J.numNodes : ℝ) + N₁ := by
    intro J
    by_cases h : J.WF ∧ J.MaxDegLE 5 ∧ ∀ v ∈ J.nodes, 3 ≤ J.degree v
    · obtain ⟨Y, hY⟩ := hN₁ J h.1 h.2.1 h.2.2
      exact ⟨Y, fun _ => hY⟩
    · exact ⟨fun _ => 0, fun h' => absurd h' h⟩
  choose lab hlab using hex
  refine ⟨T4.sigma 3 + N₁ + C₂, ?_⟩
  intro n S _
  have hO : OfSimpleGraphSpec := ofSimpleGraphSpec
  have hWF : (Graph.ofSimpleGraph S).WF := (hO n S).1
  have hrel : IsRelabel (Graph.ofSimpleGraph S) S Fin.val := hX1 n S
  have hdeg : ∀ i : Fin n, (Graph.ofSimpleGraph S).degree i.val = S.degree i := by
    intro i
    have h := hX3 _ n S Fin.val hWF hrel i
    convert h.symm
  have hN : (algoT4Full (Graph.ofSimpleGraph S) lab).fallback = false := hN4 _ hWF lab
  refine ⟨lab, hN, ?_⟩
  have hFe := hFin _ hWF lab hN
  have hDe := hD5 _ hWF lab hN
  have hAe := hA3 _ hWF lab hN
  have hUe := hU5 _ hWF lab hN
  have hcnt := nonIsolated_numNodes_eq S hWF hdeg
  have hPsiG := psiPort_ofSimpleGraph S hdeg T4.sigma
  have hDW : T4.degreeWeight S T4.sigma ≤ T4.degreeWeight S T4.thm4Coeff := by
    unfold T4.degreeWeight
    exact Finset.sum_le_sum fun v _ => hSeq.2 _
  have hPiece : ∀ e ∈ (algoT4Full (Graph.ofSimpleGraph S) lab).final,
      e.graph.WF ∧ e.graph.nodes ≠ [] ∧ ∀ v ∈ e.graph.nodes, 3 ≤ e.graph.degree v := by
    intro e he
    obtain ⟨h1, h2, _, h4⟩ := (hFe e he).1
    exact ⟨h1, h2, h4⟩
  have hnonneg : ∀ e ∈ (algoT4Full (Graph.ofSimpleGraph S) lab).final,
      0 ≤ psiMinusPort T4.sigma e.graph := by
    intro e he
    obtain ⟨h1, h2, h4⟩ := hPiece e he
    exact (hPsi T4.sigma hSeq.1 e.graph h1 h2 h4).1
  have hall : ∀ x ∈ ((algoT4Full (Graph.ofSimpleGraph S) lab).final.map
      fun e => psiMinusPort T4.sigma e.graph), 0 ≤ x := by
    intro x hx
    obtain ⟨e, he, rfl⟩ := List.mem_map.1 hx
    exact hnonneg e he
  have hSg0 : 0 ≤ ((algoT4Full (Graph.ofSimpleGraph S) lab).final.map
      fun e => psiMinusPort T4.sigma e.graph).sum := List.sum_nonneg hall
  have hSgle : ∀ e ∈ (algoT4Full (Graph.ofSimpleGraph S) lab).final,
      psiMinusPort T4.sigma e.graph ≤ ((algoT4Full (Graph.ofSimpleGraph S) lab).final.map
        fun e => psiMinusPort T4.sigma e.graph).sum := by
    intro e he
    apply List.single_le_sum hall
    exact List.mem_map_of_mem he
  obtain ⟨n₀, hn₀⟩ : ∃ m : ℕ, m = (nonIsolated (Graph.ofSimpleGraph S)).numNodes :=
    ⟨_, rfl⟩
  obtain ⟨Sg, hSg⟩ : ∃ s : ℝ, s = ((algoT4Full (Graph.ofSimpleGraph S) lab).final.map
      fun e => psiMinusPort T4.sigma e.graph).sum := ⟨_, rfl⟩
  rw [← hSg] at hSg0 hSgle hDe
  rw [← hn₀] at hAe
  have hB0 : (0 : ℝ) ≤ (Nat.log 2 n₀ : ℝ) := Nat.cast_nonneg _
  have hεn0 : 0 ≤ ε / 2 * (n₀ : ℝ) := mul_nonneg (by linarith) (Nat.cast_nonneg _)
  have hbag : ∀ e ∈ (algoT4Full (Graph.ofSimpleGraph S) lab).final,
      pdWidth (t4Decompose lab e).1 ≤
        Sg + T4.sigma 3 + ε / 2 * (n₀ : ℝ) + N₁ + (3 * (Nat.log 2 n₀ : ℝ) + 1) := by
    intro e he
    have hnum : (e.graph.numNodes : ℝ) ≤ (n₀ : ℝ) := by
      rw [hn₀]
      exact_mod_cast (hFe e he).2.1
    cases hk : e.kind with
    | sweep =>
      have hdeg5 : e.graph.MaxDegLE 5 := (hFe e he).2.2 hk
      have hdec : (t4Decompose lab e).1 = plainLayout e.graph (lab e.graph) := by
        simp [t4Decompose, hk]
      rw [hdec]
      obtain ⟨hw, hne, hmin⟩ := hPiece e he
      have h1 := hlab e.graph ⟨hw, hdeg5, hmin⟩
      have h2 := (hPsi T4.sigma hSeq.1 e.graph hw hne hmin).2
      have h3 := hSgle e he
      have h4 : ε / 2 * (e.graph.numNodes : ℝ) ≤ ε / 2 * (n₀ : ℝ) :=
        mul_le_mul_of_nonneg_left hnum (by linarith)
      linarith
    | thin =>
      have hU := hUe e he hk
      have hlog : Nat.log 2 e.graph.numNodes ≤ Nat.log 2 n₀ := by
        rw [hn₀]
        exact Nat.log_mono_right (hFe e he).2.1
      have hlogR : (Nat.log 2 e.graph.numNodes : ℝ) ≤ (Nat.log 2 n₀ : ℝ) := by
        exact_mod_cast hlog
      linarith
  have hU0 : 0 ≤ Sg + T4.sigma 3 + ε / 2 * (n₀ : ℝ) + N₁ + (3 * (Nat.log 2 n₀ : ℝ) + 1) := by
    linarith
  have hflat : pdWidth (((algoT4Full (Graph.ofSimpleGraph S) lab).final.map
        (t4Decompose lab)).flatMap (·.1)) ≤
      Sg + T4.sigma 3 + ε / 2 * (n₀ : ℝ) + N₁ + (3 * (Nat.log 2 n₀ : ℝ) + 1) := by
    refine pdWidth_le_of_bags _ _ (by linarith) ?_
    intro B hB
    obtain ⟨part, hpart, hBp⟩ := List.mem_flatMap.1 hB
    obtain ⟨e, he, rfl⟩ := List.mem_map.1 hpart
    exact card_le_of_pdWidth _ _ (hbag e he) B hBp
  have hεcount : ε * (n₀ : ℝ) = ε * (nonIsolatedCount S : ℝ) := by
    rw [hn₀, hcnt]
  have hlogn := hC₂ n₀
  linarith

end CubicPathwidth.Alg

#print axioms CubicPathwidth.Alg.algoT4InternalBound_of
Back to top