CubicPathwidth.Alg.Proofs2.DeletionBound
Source file CubicPathwidth/Alg/Proofs2/DeletionBound.lean of the Lean project (how it is built).
import CubicPathwidth.Alg.Plan2Deletion
import CubicPathwidth.Alg.Proofs.Targets
import CubicPathwidth.T4.SeqH
import CubicPathwidth.T4.BasicPsi
/-!
# (D5) The deletion-process bound and the final facts of `algo_T4`
Proves `deletionProcessBound_of` and `t4FinalFacts_of` (`Plan2Deletion.lean`, task D5)
from the Stage 2 hypotheses `T4LoopRun`, `T4LoopInvInit`, `ReduceRecordMaximal`, and the
Stage 1 graph facts `inducedSpec`, `componentsSpec`, `reduceRecordSpec`, and the bootstrap
sequence `T4.seqClaim_h`.
Route. Run `T4LoopRun` from the initial state of `algoT4Full`. The start value
`∑ ψ⁻(components of H) ≤ ψ(H) ≤ ψ(G0.copy) = ψ(G0) = ψ(G)` (`H` the reduced graph),
using `ψ`-monotonicity of `T4.sigma`, degrees not increasing under reduction, and
`σ 0 = 0` for isolated vertices. The final facts come from the invariant at the end.
-/
noncomputable section
namespace CubicPathwidth.Alg
open Graph
namespace D5
/-! ## Generic list and sum facts -/
theorem list_sum_map_le {α : Type} (f g : α → ℝ) : ∀ L : List α,
(∀ x ∈ L, f x ≤ g x) → (L.map f).sum ≤ (L.map g).sum
| [], _ => by simp
| x :: xs, h => by
simp only [List.map_cons, List.sum_cons]
exact add_le_add (h x (by simp))
(list_sum_map_le f g xs fun y hy => h y (by simp [hy]))
theorem sum_filter_eq (f : Nat → ℝ) (p : Nat → Bool) : ∀ L : List Nat,
(∀ x ∈ L, p x = false → f x = 0) → (L.map f).sum = ((L.filter p).map f).sum
| [], _ => by simp
| x :: xs, h => by
have ih := sum_filter_eq f p xs fun y hy hp => h y (List.mem_cons_of_mem _ hy) hp
by_cases hx : p x = true
· simp [hx, ih]
· have hx' : p x = false := by simpa using hx
have h0 := h x (by simp) hx'
simp [hx', h0, ih]
theorem sum_le_of_sub {f : Nat → ℝ} (hf : ∀ x, 0 ≤ f x) {L M : List Nat}
(hL : L.Nodup) (hM : M.Nodup) (hsub : ∀ x ∈ L, x ∈ M) :
(L.map f).sum ≤ (M.map f).sum := by
rw [← List.sum_toFinset f hL, ← List.sum_toFinset f hM]
apply Finset.sum_le_sum_of_subset_of_nonneg
· intro x hx
simp only [List.mem_toFinset] at hx ⊢
exact hsub x hx
· intro x _ _
exact hf x
/-! ## Bootstrap sequences -/
theorem bp_mono {b : ℕ → ℝ} (hb : T4.BootProps b) : Monotone b := by
apply monotone_nat_of_le_succ
intro n
rcases Nat.lt_or_ge n 2 with h | h
· interval_cases n <;> simp [hb.zero.1, hb.zero.2.1, hb.zero.2.2]
· have := hb.mono (n + 1) (by omega)
simpa using this
theorem bp_nonneg {b : ℕ → ℝ} (hb : T4.BootProps b) (d : ℕ) : 0 ≤ b d := by
have := bp_mono hb (Nat.zero_le d)
rwa [hb.zero.1] at this
theorem sigma_bp : T4.BootProps T4.sigma := T4.seqClaim_h.1
/-! ## Degrees and `psiPort` -/
theorem degree_eq_of_mem_iff {J K : Graph} {x : Nat} (hJ : (J.nbrs x).Nodup)
(hK : (K.nbrs x).Nodup) (h : ∀ y, y ∈ J.nbrs x ↔ y ∈ K.nbrs x) :
J.degree x = K.degree x :=
((List.perm_ext_iff_of_nodup hJ hK).2 h).length_eq
theorem psi_congr {b : ℕ → ℝ} {J K : Graph} (hJ : J.WF) (hK : K.WF)
(hperm : J.nodes.Perm K.nodes) (hadj : ∀ x y, J.Adj x y ↔ K.Adj x y) :
psiPort b J = psiPort b K := by
unfold psiPort
calc (J.nodes.map fun v => b (J.degree v)).sum
= (K.nodes.map fun v => b (J.degree v)).sum := (hperm.map _).sum_eq
_ = (K.nodes.map fun v => b (K.degree v)).sum := by
refine congrArg List.sum (List.map_congr_left ?_)
intro x _
congr 1
exact degree_eq_of_mem_iff (hJ.nbrs_nodup x) (hK.nbrs_nodup x) fun y => hadj x y
theorem psi_nonIsolated {b : ℕ → ℝ} (h0 : b 0 = 0) {G : Graph} (hG : G.WF) :
psiPort b (nonIsolated G) = psiPort b G := by
have hI := inducedSpec G (fun v => G.degree v != 0) hG
have hperm : (G.nodes.filter fun v => G.degree v != 0).Perm (nonIsolated G).nodes :=
(List.perm_ext_iff_of_nodup (hG.nodup.filter _) hI.1.nodup).2 fun x => by
rw [hI.2.1 x, List.mem_filter]
have hkeep : ∀ x y, G.Adj x y → (G.degree y != 0) = true := by
intro x y hxy
have hx : x ∈ G.nbrs y := hG.symm x y hxy
have hpos := List.length_pos_of_mem hx
unfold Graph.degree
simp only [bne_iff_ne, ne_eq]
omega
have hsub : ∀ x ∈ G.nodes, (fun v => G.degree v != 0) x = false →
(fun v => b (G.degree v)) x = 0 := by
intro x _ hx
have hd : G.degree x = 0 := by
simp only [bne_eq_false_iff_eq] at hx
exact hx
simp [hd, h0]
unfold psiPort
rw [sum_filter_eq (fun v => b (G.degree v)) (fun v => G.degree v != 0) G.nodes hsub]
calc ((nonIsolated G).nodes.map fun v => b ((nonIsolated G).degree v)).sum
= ((G.nodes.filter fun v => G.degree v != 0).map
fun v => b ((nonIsolated G).degree v)).sum := (hperm.symm.map _).sum_eq
_ = ((G.nodes.filter fun v => G.degree v != 0).map fun v => b (G.degree v)).sum := by
refine congrArg List.sum (List.map_congr_left ?_)
intro x hx
have hxk : (G.degree x != 0) = true := by
have := (List.mem_filter.1 hx).2
simpa using this
congr 1
apply degree_eq_of_mem_iff (hI.1.nbrs_nodup x) (hG.nbrs_nodup x)
intro y
refine (hI.2.2 x y).trans ?_
constructor
· exact fun h => h.1
· intro h
exact ⟨h, by simpa using hxk, by simpa using hkeep x y h⟩
theorem psi_copy {b : ℕ → ℝ} {G : Graph} (hG : G.WF) :
psiPort b G.copy = psiPort b G := by
apply psi_congr (inducedSpec G _ hG).1 hG
· exact (List.perm_ext_iff_of_nodup (inducedSpec G _ hG).1.nodup hG.nodup).2
fun x => by rw [(inducedSpec G _ hG).2.1 x]; simp
· intro x y
rw [(inducedSpec G _ hG).2.2 x y]
simp
theorem psi_le_of_reduce {b : ℕ → ℝ} (hb : T4.BootProps b) {G H : Graph} (hG : G.WF)
(hH : H.WF) (hsub : ∀ x ∈ H.nodes, x ∈ G.nodes)
(hdeg : ∀ v ∈ H.nodes, H.degree v ≤ G.degree v) :
psiPort b H ≤ psiPort b G := by
unfold psiPort
calc (H.nodes.map fun v => b (H.degree v)).sum
≤ (H.nodes.map fun v => b (G.degree v)).sum :=
list_sum_map_le _ _ _ fun x hx => bp_mono hb (hdeg x hx)
_ ≤ (G.nodes.map fun v => b (G.degree v)).sum :=
sum_le_of_sub (fun x => bp_nonneg hb _) hH.nodup hG.nodup hsub
/-! ## Components -/
theorem sum_map_sum_eq (f : Nat → ℝ) : ∀ L : List (List Nat),
(L.map fun c => (c.map f).sum).sum = ((L.flatten).map f).sum
| [] => by simp
| c :: cs => by
simp only [List.map_cons, List.sum_cons, List.flatten_cons, List.map_append,
List.sum_append, sum_map_sum_eq f cs]
theorem components_psi (b : ℕ → ℝ) {H : Graph} (hH : H.WF) :
((componentGraphs H).map (psiPort b)).sum = psiPort b H := by
obtain ⟨hperm, _, hclos⟩ := componentsSpec H hH
have hcomp : ∀ c ∈ H.components,
psiPort b (H.induced c.contains) = (c.map fun v => b (H.degree v)).sum := by
intro c hc
have hcnd : c.Nodup := by
have hfl : H.components.flatten.Nodup := hperm.nodup_iff.2 hH.nodup
exact (List.nodup_flatten.1 hfl).1 c hc
have hsubH : ∀ x ∈ c, x ∈ H.nodes := fun x hx =>
hperm.subset (List.mem_flatten.2 ⟨c, hc, hx⟩)
have hperm2 : (H.nodes.filter c.contains).Perm c := by
apply (List.perm_ext_iff_of_nodup (hH.nodup.filter _) hcnd).2
intro x
simp only [List.mem_filter, List.elem_eq_mem, decide_eq_true_eq]
constructor
· exact fun h => h.2
· exact fun h => ⟨hsubH x h, h⟩
unfold psiPort
have hdeg : ∀ x ∈ H.nodes.filter c.contains,
b ((H.induced c.contains).degree x) = b (H.degree x) := by
intro x hx
have hxc : x ∈ c := by
have := (List.mem_filter.1 hx).2
simpa using this
congr 1
apply degree_eq_of_mem_iff ((inducedSpec H _ hH).1.nbrs_nodup x) (hH.nbrs_nodup x)
intro y
show (H.induced c.contains).Adj x y ↔ H.Adj x y
rw [(inducedSpec H _ hH).2.2 x y]
constructor
· exact fun h => h.1
· intro h
refine ⟨h, by simpa using hxc, ?_⟩
simpa using hclos c hc x hxc y h
have hperm3 : (H.induced c.contains).nodes.Perm (H.nodes.filter c.contains) :=
(List.perm_ext_iff_of_nodup (inducedSpec H _ hH).1.nodup (hH.nodup.filter _)).2
fun x => by rw [(inducedSpec H _ hH).2.1 x, List.mem_filter]
rw [(hperm3.map _).sum_eq, List.map_congr_left hdeg]
exact (hperm2.map _).sum_eq
have hmap : (componentGraphs H).map (psiPort b)
= H.components.map fun c => (c.map fun v => b (H.degree v)).sum := by
unfold componentGraphs
rw [List.map_map]
exact List.map_congr_left fun c hc => hcomp c hc
rw [hmap, sum_map_sum_eq]
unfold psiPort
exact (hperm.map _).sum_eq
theorem psiMinus_comps_le {b : ℕ → ℝ} (hb : T4.BootProps b) {H : Graph} (hH : H.WF) :
((componentGraphs H).map (psiMinusPort b)).sum ≤ psiPort b H := by
rw [← components_psi b hH]
apply list_sum_map_le _ _ _
intro C _
unfold psiMinusPort
linarith [T4.BasicAux.runMin_nonneg hb (minDegree C)]
/-! ## The start value and the initial deletions -/
theorem reduceLoop_noDel (fuel : Nat) : ∀ (G : Graph) (stack : List Nat) (opsRev : List Op),
(∀ o ∈ opsRev, ∀ w, o ≠ Op.del w) →
∀ o ∈ (reduceLoop fuel G stack opsRev).2.1, ∀ w, o ≠ Op.del w := by
induction fuel with
| zero =>
intro G stack opsRev h o ho
cases stack <;> simp only [reduceLoop, List.mem_reverse] at ho <;> exact h o ho
| succ k ih =>
intro G stack opsRev h o ho
cases stack with
| nil =>
simp only [reduceLoop, List.mem_reverse] at ho
exact h o ho
| cons v rest =>
simp only [reduceLoop] at ho
split at ho
· exact ih G rest opsRev h o ho
· split at ho
· exact ih _ _ _ (by
intro o' ho' w hw
rcases List.mem_cons.1 ho' with rfl | ho''
· cases hw
· exact h o' ho'' w hw) o ho
· exact ih _ _ _ (by
intro o' ho' w hw
rcases List.mem_cons.1 ho' with rfl | ho''
· cases hw
· exact h o' ho'' w hw) o ho
theorem deletedSet_nil_of {ops : List Op} (h : ∀ o ∈ ops, ∀ w, o ≠ Op.del w) :
deletedSet ops = [] := by
unfold deletedSet
rw [List.filterMap_eq_nil_iff]
intro a ha
cases a with
| red v nb => rfl
| del w => exact absurd rfl (h _ ha w)
theorem reduceRecordF_deleted (G : Graph) : deletedSet (reduceRecordF G).2.1 = [] := by
apply deletedSet_nil_of
intro o ho w
unfold reduceRecordF at ho
exact reduceLoop_noDel _ _ _ _ (by simp) o ho w
/-- The state of the loop in `algoT4Full` (with its fuel), as a function of `G`. -/
def t4Run (G : Graph) : List FinalEntry × List Op × Bool :=
t4Loop (2 * (reduceRecordF (nonIsolated G).copy).1.numNodes + 1)
(componentGraphs (reduceRecordF (nonIsolated G).copy).1).reverse []
(reduceRecordF (nonIsolated G).copy).2.1
theorem start_le (hMax : ReduceRecordMaximal) {G : Graph} (hG : G.WF) :
T4Pot T4.sigma ((componentGraphs (reduceRecordF (nonIsolated G).copy).1).reverse) []
(reduceRecordF (nonIsolated G).copy).2.1 ≤ psiPort T4.sigma G := by
have hG0 : (nonIsolated G).WF := (inducedSpec G _ hG).1
have hC : (nonIsolated G).copy.WF := (inducedSpec _ _ hG0).1
have hm := hMax _ hC
have hs := reduceRecordSpec _ hC
have hperm : (((componentGraphs (reduceRecordF (nonIsolated G).copy).1).reverse).map
(psiMinusPort T4.sigma)).sum
= ((componentGraphs (reduceRecordF (nonIsolated G).copy).1).map
(psiMinusPort T4.sigma)).sum :=
((List.reverse_perm _).map _).sum_eq
simp only [T4Pot, reduceRecordF_deleted, List.map_nil, List.append_nil, List.length_nil,
Nat.cast_zero, zero_add]
rw [hperm]
calc _ ≤ psiPort T4.sigma (reduceRecordF (nonIsolated G).copy).1 :=
psiMinus_comps_le sigma_bp hs.1
_ ≤ psiPort T4.sigma (nonIsolated G).copy :=
psi_le_of_reduce sigma_bp hC hs.1 hs.2.1 hm.2.2
_ = psiPort T4.sigma (nonIsolated G) := psi_copy hG0
_ = psiPort T4.sigma G := psi_nonIsolated sigma_bp.zero.1 hG
/-! ## The run -/
theorem run_facts (hRun : T4LoopRun) (hInit : T4LoopInvInit) (G : Graph) (hG : G.WF) :
T4LoopInv (nonIsolated G) [] (t4Run G).1 (t4Run G).2.1 ∧
T4Pot T4.sigma [] (t4Run G).1 (t4Run G).2.1 ≤
T4Pot T4.sigma ((componentGraphs (reduceRecordF (nonIsolated G).copy).1).reverse) []
(reduceRecordF (nonIsolated G).copy).2.1 ∧
((t4Run G).2.2 = false → ∀ e ∈ (t4Run G).1, e.kind = FinalKind.sweep →
e.graph.maxDegree ≤ 5) := by
refine hRun (nonIsolated G) (2 * (reduceRecordF (nonIsolated G).copy).1.numNodes + 1)
((componentGraphs (reduceRecordF (nonIsolated G).copy).1).reverse) [] _
(inducedSpec G _ hG).1 (hInit G hG) ?_
intro e he
simp at he
theorem fallback_run {G : Graph} {lab : Labeler} (hfb : (algoT4Full G lab).fallback = false) :
(t4Run G).2.2 = false := by
have h : ((reduceRecordF (nonIsolated G).copy).2.2 || (t4Run G).2.2 ||
(((t4Run G).1.map (t4Decompose lab)).any (·.2)) ||
(undoF (nonIsolated G) (t4Run G).2.1 (unionAll ((t4Run G).1.map (·.graph)))
(((t4Run G).1.map (t4Decompose lab)).flatMap (·.1))).2) = false := hfb
simp only [Bool.or_eq_false_iff] at h
exact h.1.1.2
/-! ## Maximum degree -/
theorem foldl_max_ge (G : Graph) : ∀ (l : List Nat) (m : Nat),
m ≤ l.foldl (fun m v => max m (G.degree v)) m
| [], _ => le_rfl
| x :: xs, m => le_trans (le_max_left m (G.degree x)) (foldl_max_ge G xs _)
theorem foldl_max_mem (G : Graph) : ∀ (l : List Nat) (m v : Nat), v ∈ l →
G.degree v ≤ l.foldl (fun m v => max m (G.degree v)) m
| [], _, _, h => by simp at h
| x :: xs, m, v, h => by
rw [List.foldl_cons]
rcases List.mem_cons.1 h with rfl | h'
· exact le_trans (le_max_right _ _) (foldl_max_ge G xs _)
· exact foldl_max_mem G xs _ v h'
theorem maxDegLE_of_maxDegree {G : Graph} {k : Nat} (h : G.maxDegree ≤ k) :
G.MaxDegLE k := by
intro v hv
have := foldl_max_mem G G.nodes 0 v hv
unfold Graph.maxDegree at h
exact le_trans this h
end D5
open D5 in
/-- (D5, first theorem) The deletion-process bound from the run of `t4Loop`. -/
theorem deletionProcessBound_of (hRun : T4LoopRun) (hInit : T4LoopInvInit)
(hMax : ReduceRecordMaximal) : DeletionProcessBound := by
intro G hG lab hfb
obtain ⟨_, h2, _⟩ := run_facts hRun hInit G hG
have hs := start_le hMax hG
have hfin : ((algoT4Full G lab).numDeleted : ℝ) +
((algoT4Full G lab).final.map fun e => psiMinusPort T4.sigma e.graph).sum
= ((deletedSet (t4Run G).2.1).length : ℝ) +
(((t4Run G).1.map fun e => e.graph).map (psiMinusPort T4.sigma)).sum := by
simp only [List.map_map]
rfl
rw [hfin]
unfold T4Pot at h2 hs
simp only [List.nil_append] at h2 hs
linarith
open D5 in
/-- (D5, second theorem) The final facts of `algo_T4` without fallback. -/
theorem t4FinalFacts_of (hRun : T4LoopRun) (hInit : T4LoopInvInit) : T4FinalFacts := by
intro G hG lab hfb e he
obtain ⟨h1, _, h3⟩ := run_facts hRun hInit G hG
have hl := fallback_run hfb
have he' : e ∈ (t4Run G).1 := he
have hmem : e.graph ∈ ([] ++ (t4Run G).1.map (·.graph)) := by
simpa using List.mem_map_of_mem (f := fun e : FinalEntry => e.graph) he'
have hwf : e.graph.WF := h1.1.1 e.graph hmem
have hsub : ∀ x ∈ e.graph.nodes, x ∈ (nonIsolated G).nodes := fun x hx =>
(h1.1.2.2.1 e.graph hmem x hx).1
refine ⟨h1.2.2.2.1 e.graph hmem, ?_, ?_⟩
· exact (hwf.nodup.subperm hsub).length_le
· intro hk
exact maxDegLE_of_maxDegree (h3 hl e he' hk)
#print axioms deletionProcessBound_of
#print axioms t4FinalFacts_of
end CubicPathwidth.Alg
Back to top