MaxLeafFormal.Antinorm3

Source file MaxLeafFormal/Antinorm3.lean of the Lean project (how it is built).

Statements of the paper formalised here: Lemma 7.4, Lemma D.4.1, Lemma 7.5, Proposition 7.7.

import Mathlib
import MaxLeafFormal.Rooted
import MaxLeafFormal.RSThetaCert

/-!
# The antinorm certificates for RS-θ
-/

namespace MaxLeafFormal

open Finset

variable {V : Type*} [Fintype V] [DecidableEq V]

open Classical in
/-- The potential Π_{F,ν}(X) of `eq:rst-Phi`. -/
noncomputable def treePotential (T : SimpleGraph V) (ν : V → ℕ) (X : Finset V) : ℕ :=
  (∑ v ∈ univ \ X, ν v)
  + (univ.filter (fun v => v ∉ X ∧ ∀ u, T.Adj v u → u ∉ X)).card
  + Nat.card (T.induce (X : Set V)).ConnectedComponent

/-- W_{F,ν}(y). -/
noncomputable def treeW (T : SimpleGraph V) (ν : V → ℕ) (y : ℝ) : ℝ :=
  ∑ X ∈ (univ : Finset V).powerset, y ^ X.card * (1/2 : ℝ) ^ treePotential T ν X

namespace Antinorm3

open Pointwise

noncomputable section

/-! ### Messages, the cumulative cone and `𝒫_Z` -/

/-- The merge `P ∘ Q` of `eq:rst-merge`. -/
def merge (P Q : ℝ × ℝ × ℝ) : ℝ × ℝ × ℝ :=
  (P.1 * (2 * Q.1 + Q.2.1 + Q.2.2), P.2.1 * (Q.1 + Q.2.1 + Q.2.2 / 2) + P.2.2 * Q.1,
    P.2.2 * (Q.2.1 + Q.2.2 / 2))

def fin (P : ℝ × ℝ × ℝ) : ℝ := P.1 + P.2.1 + P.2.2 / 2

def init (y : ℝ) (j : ℕ) : ℝ × ℝ × ℝ := (y / 2, 0, (1/2 : ℝ) ^ j)

def Kcum : Set (ℝ × ℝ × ℝ) := {P | 0 ≤ P.1 ∧ 0 ≤ P.1 + P.2.1 ∧ 0 ≤ P.1 + P.2.1 + P.2.2}

def PZ (Z : Finset (ℝ × ℝ × ℝ)) : Set (ℝ × ℝ × ℝ) := convexHull ℝ (Z : Set _) + Kcum

noncomputable def cZ (Z : Finset (ℝ × ℝ × ℝ)) (hZ : Z.Nonempty) : ℝ := Z.inf' hZ fin

theorem merge_add_left (P P' Q : ℝ × ℝ × ℝ) : merge (P + P') Q = merge P Q + merge P' Q := by
  simp only [merge, Prod.fst_add, Prod.snd_add, Prod.mk_add_mk]; ext <;> simp <;> ring

theorem merge_add_right (P Q Q' : ℝ × ℝ × ℝ) : merge P (Q + Q') = merge P Q + merge P Q' := by
  simp only [merge, Prod.fst_add, Prod.snd_add, Prod.mk_add_mk]; ext <;> simp <;> ring

theorem merge_smul_left (a : ℝ) (P Q : ℝ × ℝ × ℝ) : merge (a • P) Q = a • merge P Q := by
  simp only [merge, Prod.smul_fst, Prod.smul_snd, Prod.smul_mk, smul_eq_mul]; ext <;> simp <;> ring

theorem merge_smul_right (a : ℝ) (P Q : ℝ × ℝ × ℝ) : merge P (a • Q) = a • merge P Q := by
  simp only [merge, Prod.smul_fst, Prod.smul_snd, Prod.smul_mk, smul_eq_mul]; ext <;> simp <;> ring

theorem merge_zero_left (Q : ℝ × ℝ × ℝ) : merge 0 Q = 0 := by
  simpa using merge_smul_left 0 0 Q

theorem merge_zero_right (P : ℝ × ℝ × ℝ) : merge P 0 = 0 := by
  simpa using merge_smul_right 0 P 0

theorem merge_sum_left {ι : Type*} (s : Finset ι) (f : ι → ℝ × ℝ × ℝ) (Q : ℝ × ℝ × ℝ) :
    merge (∑ i ∈ s, f i) Q = ∑ i ∈ s, merge (f i) Q := by
  classical
  induction s using Finset.induction_on with
  | empty => simp [merge_zero_left]
  | insert a s ha ih => rw [sum_insert ha, sum_insert ha, merge_add_left, ih]

theorem merge_sum_right {ι : Type*} (s : Finset ι) (P : ℝ × ℝ × ℝ) (f : ι → ℝ × ℝ × ℝ) :
    merge P (∑ i ∈ s, f i) = ∑ i ∈ s, merge P (f i) := by
  classical
  induction s using Finset.induction_on with
  | empty => simp [merge_zero_right]
  | insert a s ha ih => rw [sum_insert ha, sum_insert ha, merge_add_right, ih]

theorem fin_add (P Q : ℝ × ℝ × ℝ) : fin (P + Q) = fin P + fin Q := by
  simp only [fin, Prod.fst_add, Prod.snd_add]; ring

theorem fin_smul (a : ℝ) (P : ℝ × ℝ × ℝ) : fin (a • P) = a * fin P := by
  simp only [fin, Prod.smul_fst, Prod.smul_snd, smul_eq_mul]; ring

theorem nonneg_iff (P : ℝ × ℝ × ℝ) : 0 ≤ P ↔ 0 ≤ P.1 ∧ 0 ≤ P.2.1 ∧ 0 ≤ P.2.2 := by
  rw [Prod.le_def, Prod.le_def]; rfl

theorem merge_nonneg {P Q : ℝ × ℝ × ℝ} (hP : 0 ≤ P) (hQ : 0 ≤ Q) : 0 ≤ merge P Q := by
  rw [nonneg_iff] at *
  obtain ⟨a, b, c⟩ := hP; obtain ⟨d, e, f⟩ := hQ
  simp only [merge]
  refine ⟨by positivity, by positivity, by positivity⟩

/-! ### `lem:rst-closure` -/

theorem Kcum_add {P Q : ℝ × ℝ × ℝ} (hP : P ∈ Kcum) (hQ : Q ∈ Kcum) : P + Q ∈ Kcum := by
  obtain ⟨a, b, c⟩ := hP; obtain ⟨d, e, f⟩ := hQ
  simp only [Kcum, Set.mem_ofPred_eq, Prod.fst_add, Prod.snd_add]
  exact ⟨by linarith, by linarith, by linarith⟩

theorem Kcum_smul {a : ℝ} (ha : 0 ≤ a) {P : ℝ × ℝ × ℝ} (hP : P ∈ Kcum) : a • P ∈ Kcum := by
  obtain ⟨b, c, d⟩ := hP
  simp only [Kcum, Set.mem_ofPred_eq, Prod.smul_fst, Prod.smul_snd, smul_eq_mul]
  refine ⟨by positivity, by nlinarith, by nlinarith⟩

theorem Kcum_of_nonneg {P : ℝ × ℝ × ℝ} (hP : 0 ≤ P) : P ∈ Kcum := by
  rw [nonneg_iff] at hP
  obtain ⟨a, b, c⟩ := hP
  exact ⟨a, by linarith, by linarith⟩

theorem zero_mem_Kcum : (0 : ℝ × ℝ × ℝ) ∈ Kcum := Kcum_of_nonneg le_rfl

/-- `lem:rst-closure` (a), first half. -/
theorem merge_Kcum_left {Δ Q : ℝ × ℝ × ℝ} (hΔ : Δ ∈ Kcum) (hQ : 0 ≤ Q) : merge Δ Q ∈ Kcum := by
  obtain ⟨a, b, c⟩ := hΔ
  rw [nonneg_iff] at hQ
  obtain ⟨d, e, f⟩ := hQ
  simp only [Kcum, merge, Set.mem_ofPred_eq]
  refine ⟨by positivity, ?_, ?_⟩
  · nlinarith [mul_nonneg b d, mul_nonneg a d, mul_nonneg a f,
      mul_nonneg c (add_nonneg e (div_nonneg f (by norm_num : (0:ℝ) ≤ 2))) ]
  · nlinarith [mul_nonneg c d, mul_nonneg a d, mul_nonneg a f,
      mul_nonneg c (add_nonneg e (div_nonneg f (by norm_num : (0:ℝ) ≤ 2))) ]

/-- `lem:rst-closure` (a), second half. -/
theorem merge_Kcum_right {Q Δ : ℝ × ℝ × ℝ} (hQ : 0 ≤ Q) (hΔ : Δ ∈ Kcum) : merge Q Δ ∈ Kcum := by
  obtain ⟨a, b, c⟩ := hΔ
  rw [nonneg_iff] at hQ
  obtain ⟨d, e, f⟩ := hQ
  simp only [Kcum, merge, Set.mem_ofPred_eq]
  refine ⟨by nlinarith, by nlinarith, by nlinarith⟩

/-- `lem:rst-closure` (b). -/
theorem fin_nonneg_of_Kcum {Δ : ℝ × ℝ × ℝ} (hΔ : Δ ∈ Kcum) : 0 ≤ fin Δ := by
  obtain ⟨a, b, c⟩ := hΔ
  simp only [fin]; linarith

theorem convexHull_nonneg {Z : Finset (ℝ × ℝ × ℝ)} (hZ0 : ∀ z ∈ Z, 0 ≤ z) {z : ℝ × ℝ × ℝ}
    (hz : z ∈ convexHull ℝ (Z : Set _)) : 0 ≤ z := by
  have : convexHull ℝ (Z : Set (ℝ × ℝ × ℝ)) ⊆ Set.Ici 0 :=
    convexHull_min (fun z hz => hZ0 z hz) (convex_Ici 0)
  exact this hz

/-- `lem:rst-abstract` (a) for the cone `K_cum`, first half (used with `lem:rst-closure`). -/
theorem PZ_add_Kcum {Z : Finset (ℝ × ℝ × ℝ)} {P Δ : ℝ × ℝ × ℝ} (hP : P ∈ PZ Z) (hΔ : Δ ∈ Kcum) :
    P + Δ ∈ PZ Z := by
  obtain ⟨z, hz, Δ', hΔ', rfl⟩ := hP
  exact ⟨z, hz, Δ' + Δ, Kcum_add hΔ' hΔ, by rw [add_assoc]⟩

theorem smul_PZ_add_Kcum {Z : Finset (ℝ × ℝ × ℝ)} {η : ℝ} (hη : 0 < η) {P Δ : ℝ × ℝ × ℝ}
    (hP : P ∈ η • PZ Z) (hΔ : Δ ∈ Kcum) : P + Δ ∈ η • PZ Z := by
  obtain ⟨P', hP', rfl⟩ := hP
  refine ⟨P' + η⁻¹ • Δ, PZ_add_Kcum hP' (Kcum_smul (inv_nonneg.2 hη.le) hΔ), ?_⟩
  simp only [smul_add, smul_smul, mul_inv_cancel₀ hη.ne', one_smul]

/-- `lem:rst-abstract` (a) for the cone `K_cum`, second half (used with `lem:rst-closure`). -/
theorem smul_PZ_mono {Z : Finset (ℝ × ℝ × ℝ)} (hZ0 : ∀ z ∈ Z, 0 ≤ z) {η η' : ℝ} (hη' : 0 < η')
    (hle : η' ≤ η) {P : ℝ × ℝ × ℝ} (hP : P ∈ η • PZ Z) : P ∈ η' • PZ Z := by
  obtain ⟨_, ⟨z, hz, Δ, hΔ, rfl⟩, rfl⟩ := hP
  refine ⟨z + (((η - η') / η') • z + (η / η') • Δ), ⟨z, hz, _, Kcum_add
    (Kcum_of_nonneg (smul_nonneg (div_nonneg (by linarith) hη'.le) (convexHull_nonneg hZ0 hz)))
    (Kcum_smul (div_nonneg (by linarith) hη'.le) hΔ), rfl⟩, ?_⟩
  simp only [smul_add, smul_smul]
  rw [mul_div_cancel₀ _ hη'.ne', mul_div_cancel₀ _ hη'.ne', sub_smul]
  abel

theorem convex_PZ (Z : Finset (ℝ × ℝ × ℝ)) : Convex ℝ (PZ Z) :=
  (convex_convexHull ℝ _).add (by
    intro P hP Q hQ a b ha hb _
    exact Kcum_add (Kcum_smul ha hP) (Kcum_smul hb hQ))

/-! ### Rooted trees: descendants and tops -/

section Rooted

open CDS SimpleGraph

variable {F : SimpleGraph V} (hF : F.IsTree) (r : V)

theorem par_root : par hF r r = r := by
  unfold par; rw [dif_pos rfl]

theorem dist_par (x : V) : F.dist r (par hF r x) = F.dist r x - 1 := by
  by_cases hx : x = r
  · subst hx; rw [par_root]; simp
  · have := (par_spec hF r hx).2; omega

theorem dist_iter (k : ℕ) (u : V) : F.dist r ((par hF r)^[k] u) = F.dist r u - k := by
  induction k with
  | zero => simp
  | succ k ih => rw [Function.iterate_succ_apply', dist_par, ih]; omega

include hF in

theorem eq_root_of_dist {x : V} (h : F.dist r x = 0) : x = r :=
  ((hF.connected.preconnected r x).dist_eq_zero_iff.1 h).symm

include hF in

theorem dist_pos_of_ne {x : V} (h : x ≠ r) : 0 < F.dist r x :=
  Nat.pos_of_ne_zero (fun h' => h (eq_root_of_dist hF r h'))

/-- `u` is a descendant of `c` (inclusive). -/
def desc (c u : V) : Prop := ∃ k, (par hF r)^[k] u = c

open Classical in
/-- The vertex set of the subtree `F_c`. -/
noncomputable def D (c : V) : Finset V := univ.filter (desc hF r c)

theorem mem_D {c u : V} : u ∈ D hF r c ↔ desc hF r c u := by
  simp [D]

/-- The children of `v`. -/
noncomputable def children (v : V) : Finset V := univ.filter (fun w => w ≠ r ∧ par hF r w = v)

theorem mem_children {v w : V} : w ∈ children hF r v ↔ w ≠ r ∧ par hF r w = v := by
  simp [children]

theorem desc_dist {c u : V} (h : desc hF r c u) : F.dist r c ≤ F.dist r u := by
  obtain ⟨k, rfl⟩ := h; rw [dist_iter]; omega

theorem desc_eq_of_dist {c c' u : V} (h : desc hF r c u) (h' : desc hF r c' u) (hc : c ≠ r)
    (hd : F.dist r c = F.dist r c') : c = c' := by
  obtain ⟨k, hk⟩ := h; obtain ⟨k', hk'⟩ := h'
  have h1 := dist_iter hF r k u; have h2 := dist_iter hF r k' u
  rw [hk] at h1; rw [hk'] at h2
  have := dist_pos_of_ne hF r hc
  rw [show k = k' by omega] at hk
  exact hk.symm.trans hk'

theorem iter_root (k : ℕ) : (par hF r)^[k] r = r :=
  Function.iterate_fixed (par_root hF r) k

theorem self_mem_D (v : V) : v ∈ D hF r v := (mem_D hF r).2 ⟨0, rfl⟩

theorem dist_child {v w : V} (hw : w ∈ children hF r v) : F.dist r w = F.dist r v + 1 := by
  obtain ⟨hwr, rfl⟩ := (mem_children hF r).1 hw
  have := (par_spec hF r hwr).2; omega

theorem mem_D_iff {v u : V} : u ∈ D hF r v ↔ u = v ∨ ∃ w ∈ children hF r v, u ∈ D hF r w := by
  constructor
  · intro h
    have hex : ∃ k, (par hF r)^[k] u = v := (mem_D hF r).1 h
    classical
    rcases hk : Nat.find hex with _ | m
    · left; have := Nat.find_spec hex; rw [hk] at this; exact this
    · right
      have hspec := Nat.find_spec hex
      rw [hk, Function.iterate_succ_apply'] at hspec
      have hne : (par hF r)^[m] u ≠ v := Nat.find_min hex (by omega)
      have hner : (par hF r)^[m] u ≠ r := by
        intro h'; rw [h', par_root] at hspec; exact hne (h'.trans hspec)
      exact ⟨_, (mem_children hF r).2 ⟨hner, hspec⟩, (mem_D hF r).2 ⟨m, rfl⟩⟩
  · rintro (rfl | ⟨w, hw, hu⟩)
    · exact self_mem_D hF r u
    · obtain ⟨k, hk⟩ := (mem_D hF r).1 hu
      obtain ⟨-, hpw⟩ := (mem_children hF r).1 hw
      exact (mem_D hF r).2 ⟨k + 1, by rw [Function.iterate_succ_apply', hk, hpw]⟩

theorem D_eq (v : V) : D hF r v = insert v ((children hF r v).biUnion (D hF r)) := by
  ext u; rw [mem_D_iff, mem_insert, mem_biUnion]

theorem D_sub_of_child {v w : V} (hw : w ∈ children hF r v) : D hF r w ⊆ D hF r v :=
  fun u hu => (mem_D_iff hF r).2 (Or.inr ⟨w, hw, hu⟩)

theorem not_mem_D_child {v w : V} (hw : w ∈ children hF r v) : v ∉ D hF r w := by
  intro h
  have := desc_dist hF r ((mem_D hF r).1 h)
  have := dist_child hF r hw
  omega

theorem card_D_child_lt {v w : V} (hw : w ∈ children hF r v) :
    (D hF r w).card < (D hF r v).card :=
  card_lt_card ((ssubset_iff_of_subset (D_sub_of_child hF r hw)).2
    ⟨v, self_mem_D hF r v, not_mem_D_child hF r hw⟩)

theorem D_disjoint {v w w' : V} (hw : w ∈ children hF r v) (hw' : w' ∈ children hF r v)
    (hne : w ≠ w') : Disjoint (D hF r w) (D hF r w') := by
  rw [Finset.disjoint_left]
  intro u hu hu'
  exact hne (desc_eq_of_dist hF r ((mem_D hF r).1 hu) ((mem_D hF r).1 hu')
    ((mem_children hF r).1 hw).1 (by rw [dist_child hF r hw, dist_child hF r hw']))

theorem D_par_mem {w u : V} (hwr : w ≠ r) (hu : u ∈ D hF r w) (huw : u ≠ w) :
    u ≠ r ∧ par hF r u ∈ D hF r w := by
  obtain ⟨k, hk⟩ := (mem_D hF r).1 hu
  have hur : u ≠ r := by rintro rfl; rw [iter_root] at hk; exact hwr hk.symm
  refine ⟨hur, ?_⟩
  rcases k with _ | m
  · exact absurd hk huw
  · exact (mem_D hF r).2 ⟨m, by rw [← Function.iterate_succ_apply]; exact hk⟩

theorem D_edge {w a b : V} (hwr : w ≠ r) (hb : b ∈ D hF r w) (ha : a ∉ D hF r w)
    (hab : F.Adj a b) : b = w ∧ a = par hF r w := by
  rcases (adj_iff_par hF r).1 hab with ⟨har, hpa⟩ | ⟨hbr, hpb⟩
  · exfalso; apply ha
    obtain ⟨k, hk⟩ := (mem_D hF r).1 hb
    exact (mem_D hF r).2 ⟨k + 1, by rw [Function.iterate_succ_apply, hpa, hk]⟩
  · by_cases hbw : b = w
    · exact ⟨hbw, by rw [← hpb, hbw]⟩
    · exfalso; apply ha
      rw [← hpb]; exact (D_par_mem hF r hwr hb hbw).2

theorem D_root : D hF r r = univ := by
  ext u
  simp only [mem_univ, iff_true]
  refine (mem_D hF r).2 ⟨F.dist r u, eq_root_of_dist hF r ?_⟩
  rw [dist_iter]; omega

/-- The tops of `X`: its vertices whose parent is not in `X`, and the root. -/
def tops (X : Finset V) : Finset V := X.filter (fun t => ¬ (t ≠ r ∧ par hF r t ∈ X))

/-- The top of the component of `x` in `F[X]`, found by following parents. -/
noncomputable def topOf (X : Finset V) (x : V) : V :=
  if h : x ≠ r ∧ par hF r x ∈ X then topOf X (par hF r x) else x
termination_by F.dist r x
decreasing_by have := (par_spec hF r h.1).2; omega

theorem topOf_par {X : Finset V} {x : V} (h : x ≠ r ∧ par hF r x ∈ X) :
    topOf hF r X x = topOf hF r X (par hF r x) := by
  rw [topOf]; exact dite_cond_eq_true (eq_true h)

theorem topOf_top {X : Finset V} {x : V} (h : ¬ (x ≠ r ∧ par hF r x ∈ X)) :
    topOf hF r X x = x := by
  rw [topOf]; exact dite_cond_eq_false (eq_false h)

theorem topOf_adj {X : Finset V} {x x' : V} (hx : x ∈ X) (hx' : x' ∈ X) (h : F.Adj x x') :
    topOf hF r X x = topOf hF r X x' := by
  rcases (adj_iff_par hF r).1 h with ⟨hxr, hp⟩ | ⟨hxr, hp⟩
  · rw [topOf_par hF r ⟨hxr, hp ▸ hx'⟩, hp]
  · rw [topOf_par hF r ⟨hxr, hp ▸ hx⟩, hp]

theorem topOf_reach {X : Finset V} {x x' : (X : Set V)}
    (h : (F.induce (X : Set V)).Reachable x x') : topOf hF r X x.1 = topOf hF r X x'.1 := by
  obtain ⟨p⟩ := h
  induction p with
  | nil => rfl
  | cons hadj _ ih =>
    rw [← ih]
    exact topOf_adj hF r (Subtype.prop _) (Subtype.prop _) (by simpa using hadj)

/-- In a tree, the components of `F[X]` correspond to the tops of `X`. -/
theorem comp_eq_tops (X : Finset V) : comp F X = (tops hF r X).card := by
  apply le_antisymm (comp_le_tops hF r X)
  show (tops hF r X).card ≤ _
  unfold comp
  rw [← Fintype.card_coe (tops hF r X), ← Nat.card_eq_fintype_card]
  apply Nat.card_le_card_of_injective
    (fun t : (tops hF r X : Set V) => (F.induce (X : Set V)).connectedComponentMk
      ⟨t.1, (mem_filter.1 t.2).1⟩)
  intro t t' h
  have := topOf_reach hF r (ConnectedComponent.exact h)
  simp only at this
  rw [topOf_top hF r (mem_filter.1 t.2).2, topOf_top hF r (mem_filter.1 t'.2).2] at this
  exact Subtype.ext this

end Rooted

/-! ### `lem:rst-treerec`: the three-state recursion -/

section Recursion

open CDS SimpleGraph

/-- The vertices `u ∈ S`, `u ≠ v`, with `N_F[u] ∩ X = ∅`. -/
def dom (F : SimpleGraph V) [DecidableRel F.Adj] (S : Finset V) (v : V) (X : Finset V) :
    Finset V :=
  (S.erase v).filter (fun u => u ∉ X ∧ ∀ x, F.Adj u x → x ∉ X)

/-- The state of `v` for `X`, as a unit vector: `v ∈ X`; `v ∉ X` with a neighbour in `X`;
`v ∉ X` with no neighbour in `X`. -/
def sv (F : SimpleGraph V) [DecidableRel F.Adj] (v : V) (X : Finset V) : ℝ × ℝ × ℝ :=
  if v ∈ X then (1, 0, 0) else if ∀ u, F.Adj v u → u ∉ X then (0, 0, 1) else (0, 1, 0)

variable {F : SimpleGraph V} [DecidableRel F.Adj] (hF : F.IsTree) (r : V) (ν : V → ℕ) (y : ℝ)

/-- The inner potential `Π^in` of a partial subtree `S` with top `v`. -/
def Pin (S : Finset V) (v : V) (X : Finset V) : ℕ :=
  (∑ u ∈ S \ X, ν u) + (dom F S v X).card + (tops hF r X).card

/-- The message (triple) of a partial subtree `S` with top `v`. -/
def triple (S : Finset V) (v : V) : ℝ × ℝ × ℝ :=
  ∑ X ∈ S.powerset, (y ^ X.card * (1/2 : ℝ) ^ Pin hF r ν S v X) • sv F v X

theorem sv_nonneg (v : V) (X : Finset V) : 0 ≤ sv F v X := by
  unfold sv; split_ifs <;> simp [nonneg_iff]

theorem triple_nonneg (hy : 0 ≤ y) (S : Finset V) (v : V) : 0 ≤ triple hF r ν y S v :=
  sum_nonneg fun X _ => smul_nonneg (by positivity) (sv_nonneg v X)

theorem tops_singleton (v : V) : tops hF r {v} = {v} := by
  ext u
  simp only [tops, mem_filter, mem_singleton]
  constructor
  · exact fun h => h.1
  · rintro rfl
    refine ⟨rfl, fun ⟨hv, hp⟩ => ?_⟩
    exact F.loopless.irrefl _ (hp ▸ (par_spec hF r hv).1)

/-- Base case of `lem:rst-treerec`: one vertex. -/
theorem triple_single (v : V) : triple hF r ν y {v} v = init y (ν v) := by
  unfold triple
  have hP : ({v} : Finset V).powerset = {∅, {v}} := by
    ext X; simp [subset_singleton_iff]
  rw [hP, sum_pair (by simp)]
  have h0 : Pin hF r ν {v} v ∅ = ν v := by simp [Pin, dom, tops]
  have h1 : Pin hF r ν {v} v {v} = 1 := by simp [Pin, dom, tops_singleton]
  rw [h0, h1]
  simp only [sv, card_empty, card_singleton, pow_zero, one_mul, pow_one, mem_singleton,
    if_true, notMem_empty, not_false_eq_true, implies_true, if_false]
  ext <;> simp [init] <;> ring

theorem sum_powerset_union {M : Type*} [AddCommMonoid M] {A B : Finset V} (hAB : Disjoint A B)
    (f : Finset V → M) :
    ∑ X ∈ (A ∪ B).powerset, f X = ∑ Y ∈ A.powerset, ∑ Z ∈ B.powerset, f (Y ∪ Z) := by
  rw [← sum_product']
  refine sum_nbij' (fun X => (X ∩ A, X ∩ B)) (fun p => p.1 ∪ p.2) ?_ ?_ ?_ ?_ ?_
  · intro X _; simp [mem_product, mem_powerset, inter_subset_right]
  · intro p hp
    simp only [mem_product, mem_powerset, coe_product, Set.mem_prod, mem_coe] at hp ⊢
    exact union_subset_union hp.1 hp.2
  · intro X hX
    simp only [mem_coe, mem_powerset] at hX
    simp only [← inter_union_distrib_left, inter_eq_left.2 hX]
  · intro p hp
    simp only [mem_coe, mem_product, mem_powerset] at hp
    have h1 : p.2 ∩ A = ∅ := disjoint_iff_inter_eq_empty.1
      (disjoint_of_subset_left hp.2 hAB.symm)
    have h2 : p.1 ∩ B = ∅ := disjoint_iff_inter_eq_empty.1 (disjoint_of_subset_left hp.1 hAB)
    ext1
    · simp [union_inter_distrib_right, h1, inter_eq_left.2 hp.1]
    · simp [union_inter_distrib_right, h2, inter_eq_left.2 hp.2]
  · intro X hX
    simp only [mem_powerset] at hX
    simp only [← inter_union_distrib_left, inter_eq_left.2 hX]

section Split

variable {A B : Finset V} {v w : V} (hAB : Disjoint A B) (hv : v ∈ A) (hw : w ∈ B)
  (hwr : w ≠ r) (hpw : par hF r w = v)
  (hedge : ∀ a ∈ A, ∀ b ∈ B, F.Adj a b → a = v ∧ b = w)
  (hB : ∀ u ∈ B, u ≠ w → u ≠ r ∧ par hF r u ∈ B)
  (hA : ∀ u ∈ A, u ≠ r → par hF r u ∉ B)
  {Y Z : Finset V} (hY : Y ⊆ A) (hZ : Z ⊆ B)

include hAB hY hZ in

theorem nu_split :
    ∑ u ∈ (A ∪ B) \ (Y ∪ Z), ν u = (∑ u ∈ A \ Y, ν u) + ∑ u ∈ B \ Z, ν u := by
  rw [← sum_union (disjoint_of_subset_left sdiff_subset (disjoint_of_subset_right sdiff_subset hAB))]
  congr 1
  ext u
  simp only [mem_sdiff, mem_union, not_or]
  constructor
  · rintro ⟨hu | hu, h1, h2⟩
    · exact Or.inl ⟨hu, h1⟩
    · exact Or.inr ⟨hu, h2⟩
  · rintro (⟨hu, h1⟩ | ⟨hu, h2⟩)
    · exact ⟨Or.inl hu, h1, fun h => disjoint_left.1 hAB hu (hZ h)⟩
    · exact ⟨Or.inr hu, fun h => disjoint_left.1 hAB (hY h) hu, h2⟩

include hAB hv hw hwr hpw hedge hY hZ in

theorem dom_split :
    (dom F (A ∪ B) v (Y ∪ Z)).card + 0 = (dom F A v Y).card + (dom F B w Z).card
      + (if (w ∉ Z ∧ ∀ x, F.Adj w x → x ∉ Z) ∧ v ∉ Y then 1 else 0) := by
  have hvB : v ∉ B := fun h => disjoint_left.1 hAB hv h
  have hadj : F.Adj w v := by rw [← hpw]; exact (par_spec hF r hwr).1
  simp only [dom, card_filter, add_zero]
  rw [erase_union_distrib, erase_eq_of_notMem hvB, sum_union (disjoint_of_subset_left
    (erase_subset _ _) hAB), ← add_sum_erase B _ hw]
  have h1 : (∑ u ∈ A.erase v, if u ∉ Y ∪ Z ∧ ∀ x, F.Adj u x → x ∉ Y ∪ Z then 1 else 0)
      = ∑ u ∈ A.erase v, if u ∉ Y ∧ ∀ x, F.Adj u x → x ∉ Y then 1 else 0 := by
    apply sum_congr rfl
    intro u hu
    have huA : u ∈ A := mem_of_mem_erase hu
    have huv : u ≠ v := ne_of_mem_erase hu
    have huZ : u ∉ Z := fun h => disjoint_left.1 hAB huA (hZ h)
    congr 1
    apply propext
    simp only [mem_union, not_or]
    constructor
    · exact fun ⟨⟨h1, _⟩, h2⟩ => ⟨h1, fun x hx => (h2 x hx).1⟩
    · refine fun ⟨h1, h2⟩ => ⟨⟨h1, huZ⟩, fun x hx => ⟨h2 x hx, fun hxZ => huv ?_⟩⟩
      exact (hedge u huA x (hZ hxZ) hx).1
  have h2 : (∑ u ∈ B.erase w, if u ∉ Y ∪ Z ∧ ∀ x, F.Adj u x → x ∉ Y ∪ Z then 1 else 0)
      = ∑ u ∈ B.erase w, if u ∉ Z ∧ ∀ x, F.Adj u x → x ∉ Z then 1 else 0 := by
    apply sum_congr rfl
    intro u hu
    have huB : u ∈ B := mem_of_mem_erase hu
    have huw : u ≠ w := ne_of_mem_erase hu
    have huY : u ∉ Y := fun h => disjoint_left.1 hAB (hY h) huB
    congr 1
    apply propext
    simp only [mem_union, not_or]
    constructor
    · exact fun ⟨⟨_, h1⟩, h2⟩ => ⟨h1, fun x hx => (h2 x hx).2⟩
    · refine fun ⟨h1, h2⟩ => ⟨⟨huY, h1⟩, fun x hx => ⟨fun hxY => huw ?_, h2 x hx⟩⟩
      exact (hedge x (hY hxY) u huB hx.symm).2
  have h3 : (if w ∉ Y ∪ Z ∧ ∀ x, F.Adj w x → x ∉ Y ∪ Z then 1 else 0)
      = if (w ∉ Z ∧ ∀ x, F.Adj w x → x ∉ Z) ∧ v ∉ Y then 1 else 0 := by
    have hwY : w ∉ Y := fun h => disjoint_left.1 hAB (hY h) hw
    congr 1
    apply propext
    simp only [mem_union, not_or]
    constructor
    · exact fun ⟨⟨_, h1⟩, h2⟩ => ⟨⟨h1, fun x hx => (h2 x hx).2⟩, (h2 v hadj).1⟩
    · refine fun ⟨⟨h1, h2⟩, h3⟩ => ⟨⟨hwY, h1⟩, fun x hx => ⟨fun hxY => ?_, h2 x hx⟩⟩
      obtain ⟨rfl, -⟩ := hedge x (hY hxY) w hw hx.symm
      exact h3 hxY
  rw [h1, h2, h3]
  ring

include hAB hv hw hwr hpw hB hA hY hZ in

theorem tops_split :
    (tops hF r (Y ∪ Z)).card + (if v ∈ Y ∧ w ∈ Z then 1 else 0)
      = (tops hF r Y).card + (tops hF r Z).card := by
  have hYZ : Disjoint Y Z := disjoint_of_subset_left hY (disjoint_of_subset_right hZ hAB)
  have hvB : v ∉ B := fun h => disjoint_left.1 hAB hv h
  simp only [tops, card_filter]
  rw [sum_union hYZ]
  have h1 : (∑ u ∈ Y, if ¬ (u ≠ r ∧ par hF r u ∈ Y ∪ Z) then 1 else 0)
      = ∑ u ∈ Y, if ¬ (u ≠ r ∧ par hF r u ∈ Y) then 1 else 0 := by
    apply sum_congr rfl
    intro u hu
    congr 1
    apply propext
    simp only [mem_union]
    constructor
    · exact fun h h' => h ⟨h'.1, Or.inl h'.2⟩
    · rintro h ⟨hur, hp | hp⟩
      · exact h ⟨hur, hp⟩
      · exact hA u (hY hu) hur (hZ hp)
  have h2 : (∑ u ∈ Z, if ¬ (u ≠ r ∧ par hF r u ∈ Y ∪ Z) then 1 else 0)
      + (if v ∈ Y ∧ w ∈ Z then 1 else 0)
      = ∑ u ∈ Z, if ¬ (u ≠ r ∧ par hF r u ∈ Z) then 1 else 0 := by
    have key : ∀ u ∈ Z, u ≠ w → ((¬ (u ≠ r ∧ par hF r u ∈ Y ∪ Z)) ↔ ¬ (u ≠ r ∧ par hF r u ∈ Z)) := by
      intro u hu huw
      obtain ⟨hur, hpB⟩ := hB u (hZ hu) huw
      have : par hF r u ∉ Y := fun h => disjoint_left.1 hAB (hY h) hpB
      simp [mem_union, this]
    by_cases hwZ : w ∈ Z
    · rw [← add_sum_erase Z _ hwZ, ← add_sum_erase Z _ hwZ,
        sum_congr rfl (fun u hu => by rw [if_congr (key u (mem_of_mem_erase hu)
          (ne_of_mem_erase hu)) rfl rfl])]
      have hvZ : v ∉ Z := fun h => hvB (hZ h)
      by_cases hvY : v ∈ Y <;> simp [hpw, hwr, hvY, hvZ, hwZ] <;> ring
    · simp only [hwZ, and_false, if_false, add_zero]
      exact sum_congr rfl (fun u hu => by
        rw [if_congr (key u hu (fun h => hwZ (h ▸ hu))) rfl rfl])
  omega

include hAB hv hw hwr hpw hedge hZ in

theorem sv_split :
    sv F v (Y ∪ Z) = if v ∈ Y then (1, 0, 0)
      else if (∀ u, F.Adj v u → u ∉ Y) ∧ w ∉ Z then (0, 0, 1) else (0, 1, 0) := by
  have hvZ : v ∉ Z := fun h => disjoint_left.1 hAB hv (hZ h)
  have hadj : F.Adj v w := by rw [← hpw]; exact (par_spec hF r hwr).1.symm
  have e1 : v ∈ Y ∪ Z ↔ v ∈ Y := by simp [hvZ]
  have e2 : (∀ u, F.Adj v u → u ∉ Y ∪ Z) ↔ (∀ u, F.Adj v u → u ∉ Y) ∧ w ∉ Z := by
    simp only [mem_union, not_or]
    constructor
    · exact fun h => ⟨fun u hu => (h u hu).1, (h w hadj).2⟩
    · refine fun ⟨h, hwZ⟩ u hu => ⟨h u hu, fun huZ => hwZ ?_⟩
      obtain ⟨-, rfl⟩ := hedge v hv u (hZ huZ) hu
      exact huZ
  unfold sv
  simp only [e1, e2]

include hAB hv hw hwr hpw hedge hB hA hY hZ in

theorem term_split :
    (y ^ (Y ∪ Z).card * (1/2 : ℝ) ^ Pin hF r ν (A ∪ B) v (Y ∪ Z)) • sv F v (Y ∪ Z)
      = merge ((y ^ Y.card * (1/2 : ℝ) ^ Pin hF r ν A v Y) • sv F v Y)
          ((y ^ Z.card * (1/2 : ℝ) ^ Pin hF r ν B w Z) • sv F w Z) := by
  have hYZ : Disjoint Y Z := disjoint_of_subset_left hY (disjoint_of_subset_right hZ hAB)
  have hPin : Pin hF r ν (A ∪ B) v (Y ∪ Z) + (if v ∈ Y ∧ w ∈ Z then 1 else 0)
      = Pin hF r ν A v Y + Pin hF r ν B w Z
        + (if (w ∉ Z ∧ ∀ x, F.Adj w x → x ∉ Z) ∧ v ∉ Y then 1 else 0) := by
    unfold Pin
    rw [nu_split ν hAB hY hZ]
    have := dom_split hF r hAB hv hw hwr hpw hedge hY hZ
    have := tops_split hF r hAB hv hw hwr hpw hB hA hY hZ
    omega
  have hc : (1/2 : ℝ) ^ Pin hF r ν (A ∪ B) v (Y ∪ Z) * (1/2) ^ (if v ∈ Y ∧ w ∈ Z then 1 else 0)
      = (1/2) ^ Pin hF r ν A v Y * (1/2) ^ Pin hF r ν B w Z
        * (1/2) ^ (if (w ∉ Z ∧ ∀ x, F.Adj w x → x ∉ Z) ∧ v ∉ Y then 1 else 0) := by
    rw [← pow_add, ← pow_add, ← pow_add, hPin]
  rw [merge_smul_left, merge_smul_right, smul_smul, card_union_of_disjoint hYZ, pow_add,
    sv_split hF r hAB hv hw hwr hpw hedge hZ]
  generalize (1/2 : ℝ) ^ Pin hF r ν (A ∪ B) v (Y ∪ Z) = c at hc ⊢
  generalize (1/2 : ℝ) ^ Pin hF r ν A v Y = a at hc ⊢
  generalize (1/2 : ℝ) ^ Pin hF r ν B w Z = b at hc ⊢
  unfold sv
  split_ifs at hc ⊢ <;> simp only [pow_zero, pow_one, mul_one] at hc <;> ext <;>
    simp [merge] <;>
    first
    | linear_combination (y ^ Y.card * y ^ Z.card) * hc
    | linear_combination (2 * y ^ Y.card * y ^ Z.card) * hc
    | (exfalso; tauto)

include hAB hv hw hwr hpw hedge hB hA in

/-- The step of `lem:rst-treerec`: adding the subtree `B` of the child `w` to the partial
subtree `A` of `v`. -/
theorem triple_split :
    triple hF r ν y (A ∪ B) v = merge (triple hF r ν y A v) (triple hF r ν y B w) := by
  unfold triple
  rw [sum_powerset_union hAB, merge_sum_left]
  apply sum_congr rfl
  intro Y hY
  rw [merge_sum_right]
  apply sum_congr rfl
  intro Z hZ
  exact term_split hF r ν y hAB hv hw hwr hpw hedge hB hA (mem_powerset.1 hY) (mem_powerset.1 hZ)

end Split

theorem fin_zero : fin 0 = 0 := by simp [fin]

theorem fin_sum {ι : Type*} (s : Finset ι) (f : ι → ℝ × ℝ × ℝ) :
    fin (∑ i ∈ s, f i) = ∑ i ∈ s, fin (f i) := by
  classical
  induction s using Finset.induction_on with
  | empty => simp [fin_zero]
  | insert a s ha ih => rw [sum_insert ha, sum_insert ha, fin_add, ih]

/-- The root step of `lem:rst-treerec`: `W_{F,ν}(y) = fin(ψ_r)`. -/
theorem treeW_eq_fin : treeW F ν y = fin (triple hF r ν y univ r) := by
  unfold triple treeW
  rw [fin_sum]
  apply sum_congr rfl
  intro X _
  rw [fin_smul]
  have hTP : treePotential F ν X = Pin hF r ν univ r X
      + (if r ∉ X ∧ ∀ u, F.Adj r u → u ∉ X then 1 else 0) := by
    unfold treePotential Pin
    rw [show Nat.card (F.induce (X : Set V)).ConnectedComponent = (tops hF r X).card from
      comp_eq_tops hF r X]
    have key : ∀ (inst : DecidablePred fun v => v ∉ X ∧ ∀ u, F.Adj v u → u ∉ X),
        (@filter V (fun v => v ∉ X ∧ ∀ u, F.Adj v u → u ∉ X) inst univ).card
        = (dom F univ r X).card + (if r ∉ X ∧ ∀ u, F.Adj r u → u ∉ X then 1 else 0) := by
      intro inst
      unfold dom
      rw [card_filter, card_filter, ← add_sum_erase univ _ (mem_univ r), add_comm]
      congr 1
      refine sum_congr rfl (fun u _ => ?_)
      by_cases h : u ∉ X ∧ ∀ x, F.Adj u x → x ∉ X
      · rw [if_pos h, if_pos h]
      · rw [if_neg h, if_neg h]
    rw [key]
    ring_nf
  rw [hTP, pow_add, mul_assoc]
  congr 2
  by_cases h1 : r ∈ X
  · rw [if_neg (fun h => h.1 h1)]; unfold sv; rw [if_pos h1]; simp [fin]
  · by_cases h2 : ∀ u, F.Adj r u → u ∉ X
    · rw [if_pos ⟨h1, h2⟩]; unfold sv; rw [if_neg h1, if_pos h2]; simp [fin]
    · rw [if_neg (fun h => h2 h.2)]; unfold sv; rw [if_neg h1, if_neg h2]; simp [fin]

end Recursion

/-! ### `lem:rst-F` -/

section Certificate

variable {Z : Finset (ℝ × ℝ × ℝ)}

theorem merge_hull (ha : ∀ z ∈ Z, ∀ z' ∈ Z, merge z z' ∈ PZ Z) {z z' : ℝ × ℝ × ℝ}
    (hz : z ∈ convexHull ℝ (Z : Set _)) (hz' : z' ∈ convexHull ℝ (Z : Set _)) :
    merge z z' ∈ PZ Z := by
  have step1 : ∀ z' ∈ Z, ∀ z ∈ convexHull ℝ (Z : Set (ℝ × ℝ × ℝ)), merge z z' ∈ PZ Z := by
    intro z' hz' z hz
    refine (convexHull_min (fun x hx => ha x hx z' hz') ?_ :
      convexHull ℝ (Z : Set (ℝ × ℝ × ℝ)) ⊆ {x | merge x z' ∈ PZ Z}) hz
    intro a ha' b hb s t hs ht hst
    show merge (s • a + t • b) z' ∈ PZ Z
    rw [merge_add_left, merge_smul_left, merge_smul_left]
    exact convex_PZ Z ha' hb hs ht hst
  refine (convexHull_min (fun x hx => step1 x hx z hz) ?_ :
    convexHull ℝ (Z : Set (ℝ × ℝ × ℝ)) ⊆ {x | merge z x ∈ PZ Z}) hz'
  intro a ha' b hb s t hs ht hst
  show merge z (s • a + t • b) ∈ PZ Z
  rw [merge_add_right, merge_smul_right, merge_smul_right]
  exact convex_PZ Z ha' hb hs ht hst

/-- The merge step of the proof of `lem:rst-F` (`lem:rst-abstract` (b) with `Y = Y' = Z`). -/
theorem merge_mem_smul_PZ (hZ0 : ∀ z ∈ Z, 0 ≤ z) (ha : ∀ z ∈ Z, ∀ z' ∈ Z, merge z z' ∈ PZ Z)
    {η η' : ℝ} (hη' : 0 < η') {P Q : ℝ × ℝ × ℝ} (hP : P ∈ η • PZ Z) (hQ : Q ∈ η' • PZ Z)
    (hQ0 : 0 ≤ Q) : merge P Q ∈ (η * η') • PZ Z := by
  obtain ⟨_, ⟨z, hz, Δ, hΔ, rfl⟩, rfl⟩ := hP
  obtain ⟨Qh, hQh, rfl⟩ := hQ
  have hQh0 : 0 ≤ Qh := by
    have := smul_nonneg (inv_nonneg.2 hη'.le) hQ0
    rwa [smul_smul, inv_mul_cancel₀ hη'.ne', one_smul] at this
  obtain ⟨z', hz', Δ', hΔ', rfl⟩ := hQh
  refine ⟨merge z z' + merge z Δ' + merge Δ (z' + Δ'),
    PZ_add_Kcum (PZ_add_Kcum (merge_hull ha hz hz')
      (merge_Kcum_right (convexHull_nonneg hZ0 hz) hΔ')) (merge_Kcum_left hΔ hQh0), ?_⟩
  simp only [merge_smul_left, merge_smul_right, merge_add_left, merge_add_right]
  module

/-- The tail claim of `lem:rst-F`: if `e₂ ≤ 1`, condition (b) for `j ≤ j₀` and the vector
`(y/2, 0, 0)` at scale `e₁ e₂^(j₀+1)` give (b) for every `j`. -/
theorem init_all (hZ0 : ∀ z ∈ Z, 0 ≤ z) {y e₁ e₂ : ℝ} (he₁ : 0 < e₁) (he₂ : 0 < e₂)
    (he₂1 : e₂ ≤ 1) (j₀ : ℕ) (hb : ∀ j ≤ j₀, init y j ∈ (e₁ * e₂ ^ j) • PZ Z)
    (htail : ((y / 2, 0, 0) : ℝ × ℝ × ℝ) ∈ (e₁ * e₂ ^ (j₀ + 1)) • PZ Z) :
    ∀ j, init y j ∈ (e₁ * e₂ ^ j) • PZ Z := by
  intro j
  by_cases hj : j ≤ j₀
  · exact hb j hj
  · have h1 : init y j = ((y / 2, 0, 0) : ℝ × ℝ × ℝ) + (0, 0, (1/2 : ℝ) ^ j) := by
      simp [init]
    rw [h1]
    refine smul_PZ_mono hZ0 (by positivity) ?_
      (smul_PZ_add_Kcum (by positivity) htail (Kcum_of_nonneg ?_))
    · exact mul_le_mul_of_nonneg_left (pow_le_pow_of_le_one he₂.le he₂1 (by omega)) he₁.le
    · rw [nonneg_iff]; exact ⟨le_rfl, le_rfl, by positivity⟩

theorem cZ_le_fin (hZ : Z.Nonempty) {z : ℝ × ℝ × ℝ} (hz : z ∈ convexHull ℝ (Z : Set _)) :
    cZ Z hZ ≤ fin z := by
  refine (convexHull_min (fun x hx => inf'_le fin hx) ?_ :
    convexHull ℝ (Z : Set (ℝ × ℝ × ℝ)) ⊆ {x | cZ Z hZ ≤ fin x}) hz
  intro a ha b hb s t hs ht hst
  show cZ Z hZ ≤ fin (s • a + t • b)
  rw [fin_add, fin_smul, fin_smul]
  have ha' : cZ Z hZ ≤ fin a := ha
  have hb' : cZ Z hZ ≤ fin b := hb
  have h1 := mul_le_mul_of_nonneg_left ha' hs
  have h2 := mul_le_mul_of_nonneg_left hb' ht
  have h3 : (s + t) * cZ Z hZ = cZ Z hZ := by rw [hst, one_mul]
  linarith

open CDS SimpleGraph in
/-- The induction in the proof of `lem:rst-F`: every subtree message lies in its scaled `𝒫_Z`. -/
theorem triple_D_mem {F : SimpleGraph V} [DecidableRel F.Adj] (hF : F.IsTree) (r : V)
    (ν : V → ℕ) {y e₁ e₂ : ℝ} (hy : 0 ≤ y) (he₁ : 0 < e₁) (he₂ : 0 < e₂)
    (hZ0 : ∀ z ∈ Z, 0 ≤ z) (ha : ∀ z ∈ Z, ∀ z' ∈ Z, merge z z' ∈ PZ Z)
    (hb : ∀ j : ℕ, init y j ∈ (e₁ * e₂ ^ j) • PZ Z) (v : V) :
    triple hF r ν y (D hF r v) v
      ∈ (e₁ ^ (D hF r v).card * e₂ ^ (∑ u ∈ D hF r v, ν u)) • PZ Z := by
  induction hn : (D hF r v).card using Nat.strong_induction_on generalizing v with
  | _ n ih =>
    subst hn
    have key : ∀ C ⊆ children hF r v,
        triple hF r ν y (insert v (C.biUnion (D hF r))) v
          ∈ (e₁ ^ (insert v (C.biUnion (D hF r))).card
              * e₂ ^ (∑ u ∈ insert v (C.biUnion (D hF r)), ν u)) • PZ Z := by
      intro C
      induction C using Finset.induction_on with
      | empty =>
        intro _
        simp only [biUnion_empty, insert_empty, card_singleton, pow_one, sum_singleton]
        rw [triple_single]
        exact hb _
      | insert w C hwC ihC =>
        intro hC
        have hw : w ∈ children hF r v := hC (mem_insert_self w C)
        have hCv : C ⊆ children hF r v := fun c hc => hC (mem_insert_of_mem hc)
        obtain ⟨hwr, hpw⟩ := (mem_children hF r).1 hw
        set A := insert v (C.biUnion (D hF r)) with hAdef
        have hAB : Disjoint A (D hF r w) := by
          rw [hAdef, disjoint_insert_left, disjoint_biUnion_left]
          refine ⟨not_mem_D_child hF r hw, fun c hc => D_disjoint hF r (hCv hc) hw ?_⟩
          rintro rfl; exact hwC hc
        have hU : insert v ((insert w C).biUnion (D hF r)) = A ∪ D hF r w := by
          rw [biUnion_insert, hAdef]
          ext u; simp only [mem_insert, mem_union]; tauto
        have hedge : ∀ a ∈ A, ∀ b ∈ D hF r w, F.Adj a b → a = v ∧ b = w := by
          intro a ha b hb hab
          obtain ⟨h1, h2⟩ := D_edge hF r hwr hb (fun h => disjoint_left.1 hAB ha h) hab
          exact ⟨h2.trans hpw, h1⟩
        have hBp : ∀ u ∈ D hF r w, u ≠ w → u ≠ r ∧ par hF r u ∈ D hF r w :=
          fun u hu huw => D_par_mem hF r hwr hu huw
        have hAp : ∀ u ∈ A, u ≠ r → par hF r u ∉ D hF r w := by
          intro u hu hur hp
          have huD : u ∉ D hF r w := fun h => disjoint_left.1 hAB hu h
          obtain ⟨h1, h2⟩ := D_edge hF r hwr hp huD (par_spec hF r hur).1
          rw [hpw] at h2
          subst h2
          have := (par_spec hF r hur).2
          have := dist_child hF r hw
          rw [h1] at *
          omega
        rw [hU, triple_split hF r ν y hAB (mem_insert_self v _) (self_mem_D hF r w) hwr hpw
          hedge hBp hAp, card_union_of_disjoint hAB, sum_union hAB, pow_add, pow_add,
          show e₁ ^ A.card * e₁ ^ (D hF r w).card * (e₂ ^ (∑ u ∈ A, ν u)
              * e₂ ^ (∑ u ∈ D hF r w, ν u))
            = (e₁ ^ A.card * e₂ ^ (∑ u ∈ A, ν u))
              * (e₁ ^ (D hF r w).card * e₂ ^ (∑ u ∈ D hF r w, ν u)) by ring]
        exact merge_mem_smul_PZ hZ0 ha (by positivity) (ihC hCv)
          (ih _ (card_D_child_lt hF r hw) w rfl) (triple_nonneg hF r ν y hy _ w)
    have := key (children hF r v) subset_rfl
    rwa [← D_eq] at this

open CDS in
/-- `lem:rst-F`, for an arbitrary certificate. -/
theorem tree_bound_of_certificate (y e₁ e₂ : ℝ) (hy : 0 ≤ y) (he₁ : 0 < e₁) (he₂ : 0 < e₂)
    (Z : Finset (ℝ × ℝ × ℝ)) (hZ : Z.Nonempty) (hZ0 : ∀ z ∈ Z, 0 ≤ z)
    (ha : ∀ z ∈ Z, ∀ z' ∈ Z, merge z z' ∈ PZ Z)
    (hb : ∀ j : ℕ, init y j ∈ (e₁ * e₂ ^ j) • PZ Z)
    (T : SimpleGraph V) [DecidableRel T.Adj] (hT : T.IsTree) (ν : V → ℕ) :
    cZ Z hZ * e₁ ^ Fintype.card V * e₂ ^ (∑ v, ν v) ≤ treeW T ν y := by
  obtain ⟨r⟩ := hT.connected.nonempty
  have hm := triple_D_mem hT r ν hy he₁ he₂ hZ0 ha hb r
  rw [D_root] at hm
  rw [treeW_eq_fin hT r ν y]
  obtain ⟨_, ⟨z, hz, Δ, hΔ, rfl⟩, heq⟩ := hm
  rw [← heq, fin_smul, fin_add, card_univ]
  have hη : 0 < e₁ ^ Fintype.card V * e₂ ^ (∑ v, ν v) := by positivity
  have h1 := cZ_le_fin hZ hz
  have h2 := fin_nonneg_of_Kcum hΔ
  calc cZ Z hZ * e₁ ^ Fintype.card V * e₂ ^ (∑ v, ν v)
      = (e₁ ^ Fintype.card V * e₂ ^ (∑ v, ν v)) * cZ Z hZ := by ring
    _ ≤ (e₁ ^ Fintype.card V * e₂ ^ (∑ v, ν v)) * (fin z + fin Δ) :=
        mul_le_mul_of_nonneg_left (by linarith) hη.le

end Certificate

/-! ### Exact rational checks of certificate data -/

section Check

/-- The merge over `ℚ`. -/
def mergeQ (P Q : ℚ × ℚ × ℚ) : ℚ × ℚ × ℚ :=
  (P.1 * (2 * Q.1 + Q.2.1 + Q.2.2), P.2.1 * (Q.1 + Q.2.1 + Q.2.2 / 2) + P.2.2 * Q.1,
    P.2.2 * (Q.2.1 + Q.2.2 / 2))

/-- `P ∈ 𝒦_cum`, decided over `ℚ`. -/
def cumOK (P : ℚ × ℚ × ℚ) : Bool :=
  decide (0 ≤ P.1) && decide (0 ≤ P.1 + P.2.1) && decide (0 ≤ P.1 + P.2.1 + P.2.2)

/-- `∑ μ_k z_k` for a list of pairs `(k, μ_k)`. -/
def combQ (Z : List (ℚ × ℚ × ℚ)) (mu : List (ℕ × ℚ)) : ℚ × ℚ × ℚ :=
  mu.foldr (fun km acc => (acc.1 + km.2 * (Z.getD km.1 0).1,
    acc.2.1 + km.2 * (Z.getD km.1 0).2.1, acc.2.2 + km.2 * (Z.getD km.1 0).2.2)) (0, 0, 0)

/-- The coefficients form a probability vector on valid indices. -/
def muOK (n : ℕ) (mu : List (ℕ × ℚ)) : Bool :=
  mu.all (fun km => decide (km.1 < n) && decide (0 ≤ km.2)) && decide ((mu.map Prod.snd).sum = 1)

/-- `P - s ∑ μ_k z_k ∈ 𝒦_cum`, the check of `verify_cert.dominated`. -/
def domQ (Z : List (ℚ × ℚ × ℚ)) (P : ℚ × ℚ × ℚ) (s : ℚ) (mu : List (ℕ × ℚ)) : Bool :=
  muOK Z.length mu &&
    cumOK (P.1 - s * (combQ Z mu).1, P.2.1 - s * (combQ Z mu).2.1, P.2.2 - s * (combQ Z mu).2.2)

/-- Condition (a) for every ordered pair. -/
def checkPairs (Z : List (ℚ × ℚ × ℚ)) (pairs : List (List (ℕ × ℚ))) : Bool :=
  (List.range Z.length).all fun i => (List.range Z.length).all fun j =>
    domQ Z (mergeQ (Z.getD i 0) (Z.getD j 0)) 1 (pairs.getD (i * Z.length + j) [])

def initQ (y : ℚ) (j : ℕ) : ℚ × ℚ × ℚ := (y / 2, 0, (1/2 : ℚ) ^ j)

/-- Condition (b) for `j ≤ m₀`, and the tail vector at scale `e₁ e₂^(m₀+1)`. -/
def checkInits (Z : List (ℚ × ℚ × ℚ)) (y e₁ e₂ : ℚ) (m₀ : ℕ) (inits : List (List (ℕ × ℚ)))
    (tail : List (ℕ × ℚ)) : Bool :=
  (List.range (m₀ + 1)).all (fun j => domQ Z (initQ y j) (e₁ * e₂ ^ j) (inits.getD j [])) &&
    domQ Z (y / 2, 0, 0) (e₁ * e₂ ^ (m₀ + 1)) tail

/-- `Z ≠ ∅`, `Z ≥ 0` and `fin z ≥ c` on `Z`. -/
def checkZ (Z : List (ℚ × ℚ × ℚ)) (c : ℚ) : Bool :=
  !Z.isEmpty && Z.all (fun z => decide (0 ≤ z.1) && decide (0 ≤ z.2.1) && decide (0 ≤ z.2.2) &&
    decide (c ≤ z.1 + z.2.1 + z.2.2 / 2))

/-- Coordinatewise cast `ℚ³ → ℝ³`. -/
def castT (P : ℚ × ℚ × ℚ) : ℝ × ℝ × ℝ := ((P.1 : ℝ), (P.2.1 : ℝ), (P.2.2 : ℝ))

/-- The real point set of a rational list. -/
def ZR (Z : List (ℚ × ℚ × ℚ)) : Finset (ℝ × ℝ × ℝ) := (Z.map castT).toFinset

theorem castT_merge (P Q : ℚ × ℚ × ℚ) : castT (mergeQ P Q) = merge (castT P) (castT Q) := by
  simp only [castT, mergeQ, merge]; push_cast; rfl

theorem cumOK_sound {P : ℚ × ℚ × ℚ} (h : cumOK P = true) : castT P ∈ Kcum := by
  simp only [cumOK, Bool.and_eq_true, decide_eq_true_eq] at h
  obtain ⟨⟨h1, h2⟩, h3⟩ := h
  refine ⟨?_, ?_, ?_⟩ <;> simp only [castT]
  · exact_mod_cast h1
  · exact_mod_cast h2
  · exact_mod_cast h3

theorem getD_mem_ZR {Z : List (ℚ × ℚ × ℚ)} {k : ℕ} (hk : k < Z.length) :
    castT (Z.getD k 0) ∈ ZR Z := by
  rw [ZR, List.mem_toFinset, List.getD_eq_getElem _ _ hk]
  exact List.mem_map_of_mem (List.getElem_mem hk)

theorem combQ_mem {Z : List (ℚ × ℚ × ℚ)} (hZ : Z ≠ []) :
    ∀ mu : List (ℕ × ℚ), (∀ km ∈ mu, km.1 < Z.length ∧ 0 ≤ km.2) →
      castT (combQ Z mu) ∈ (((mu.map Prod.snd).sum : ℚ) : ℝ) • convexHull ℝ (ZR Z : Set _) := by
  have hne : (convexHull ℝ (ZR Z : Set (ℝ × ℝ × ℝ))).Nonempty := by
    obtain ⟨z, hz⟩ := List.exists_mem_of_ne_nil Z hZ
    exact ⟨castT z, subset_convexHull ℝ _
      (mem_coe.2 (List.mem_toFinset.2 (List.mem_map_of_mem hz)))⟩
  intro mu
  induction mu with
  | nil =>
    intro _
    obtain ⟨z, hz⟩ := hne
    have : castT (combQ Z []) = (0 : ℝ) • z := by simp [castT, combQ]
    simpa [this] using Set.smul_mem_smul_set (a := (0 : ℝ)) hz
  | cons km mu ih =>
    intro hmu
    have hk := hmu km (List.mem_cons_self ..)
    have ih' := ih (fun x hx => hmu x (List.mem_cons_of_mem _ hx))
    have hs : (0 : ℝ) ≤ (((mu.map Prod.snd).sum : ℚ) : ℝ) := by
      exact_mod_cast List.sum_nonneg (fun x hx => by
        obtain ⟨km', hkm', rfl⟩ := List.mem_map.1 hx
        exact (hmu km' (List.mem_cons_of_mem _ hkm')).2)
    have hm : (0 : ℝ) ≤ (km.2 : ℝ) := by exact_mod_cast hk.2
    have hsplit : castT (combQ Z (km :: mu))
        = (km.2 : ℝ) • castT (Z.getD km.1 0) + castT (combQ Z mu) := by
      simp only [castT, combQ, List.foldr_cons]
      push_cast
      ext <;> simp <;> ring
    rw [hsplit, List.map_cons, List.sum_cons, Rat.cast_add,
      (convex_convexHull ℝ _).add_smul hm hs]
    exact Set.add_mem_add (Set.smul_mem_smul_set (subset_convexHull ℝ _ (getD_mem_ZR hk.1))) ih'

theorem domQ_sound {Z : List (ℚ × ℚ × ℚ)} (hZ : Z ≠ []) {P : ℚ × ℚ × ℚ} {s : ℚ} (hs : 0 < s)
    {mu : List (ℕ × ℚ)} (h : domQ Z P s mu = true) : castT P ∈ (s : ℝ) • PZ (ZR Z) := by
  simp only [domQ, muOK, Bool.and_eq_true, List.all_eq_true, decide_eq_true_eq] at h
  obtain ⟨⟨hmu, hsum⟩, hcum⟩ := h
  have hc := combQ_mem hZ mu (fun km hkm => hmu km hkm)
  rw [hsum, Rat.cast_one, one_smul] at hc
  have hΔ := cumOK_sound hcum
  have hsR : (0 : ℝ) < s := by exact_mod_cast hs
  refine ⟨castT (combQ Z mu) + (s : ℝ)⁻¹ • castT (P.1 - s * (combQ Z mu).1,
      P.2.1 - s * (combQ Z mu).2.1, P.2.2 - s * (combQ Z mu).2.2),
    ⟨_, hc, _, Kcum_smul (inv_nonneg.2 hsR.le) hΔ, rfl⟩, ?_⟩
  simp only [castT, smul_add, smul_smul, mul_inv_cancel₀ hsR.ne', one_smul]
  push_cast
  ext <;> simp

theorem checkPairs_sound {Z : List (ℚ × ℚ × ℚ)} (hZ : Z ≠ []) {pairs : List (List (ℕ × ℚ))}
    (h : checkPairs Z pairs = true) :
    ∀ z ∈ ZR Z, ∀ z' ∈ ZR Z, merge z z' ∈ PZ (ZR Z) := by
  intro z hz z' hz'
  simp only [ZR, List.mem_toFinset, List.mem_map] at hz hz'
  obtain ⟨a, ha, rfl⟩ := hz
  obtain ⟨b, hb, rfl⟩ := hz'
  obtain ⟨i, hi, rfl⟩ := List.getElem_of_mem ha
  obtain ⟨j, hj, rfl⟩ := List.getElem_of_mem hb
  simp only [checkPairs, List.all_eq_true, List.mem_range] at h
  have := domQ_sound hZ one_pos (h i hi j hj)
  rw [Rat.cast_one, one_smul, castT_merge, List.getD_eq_getElem _ _ hi,
    List.getD_eq_getElem _ _ hj] at this
  exact this

theorem castT_initQ (y : ℚ) (j : ℕ) : castT (initQ y j) = init (y : ℝ) j := by
  simp [castT, initQ, init]

theorem checkInits_sound {Z : List (ℚ × ℚ × ℚ)} (hZ : Z ≠ []) (hZ0 : ∀ z ∈ ZR Z, 0 ≤ z)
    {y e₁ e₂ : ℚ} (he₁ : 0 < e₁) (he₂ : 0 < e₂) (he₂1 : e₂ ≤ 1) {m₀ : ℕ}
    {inits : List (List (ℕ × ℚ))} {tail : List (ℕ × ℚ)}
    (h : checkInits Z y e₁ e₂ m₀ inits tail = true) :
    ∀ j : ℕ, init (y : ℝ) j ∈ ((e₁ : ℝ) * (e₂ : ℝ) ^ j) • PZ (ZR Z) := by
  simp only [checkInits, Bool.and_eq_true, List.all_eq_true, List.mem_range] at h
  obtain ⟨h1, h2⟩ := h
  have he₁R : (0 : ℝ) < e₁ := by exact_mod_cast he₁
  have he₂R : (0 : ℝ) < e₂ := by exact_mod_cast he₂
  refine init_all hZ0 he₁R he₂R (by exact_mod_cast he₂1) m₀ (fun j hj => ?_) ?_
  · have := domQ_sound hZ (by positivity) (h1 j (by omega))
    rwa [castT_initQ, Rat.cast_mul, Rat.cast_pow] at this
  · have := domQ_sound hZ (by positivity) h2
    rw [Rat.cast_mul, Rat.cast_pow] at this
    convert this using 1
    simp [castT]

theorem checkZ_nonempty {Z : List (ℚ × ℚ × ℚ)} {c : ℚ} (h : checkZ Z c = true) : Z ≠ [] := by
  intro hZ; simp [checkZ, hZ] at h

theorem ZR_nonempty {Z : List (ℚ × ℚ × ℚ)} (hZ : Z ≠ []) : (ZR Z).Nonempty := by
  obtain ⟨z, hz⟩ := List.exists_mem_of_ne_nil Z hZ
  exact ⟨castT z, List.mem_toFinset.2 (List.mem_map_of_mem hz)⟩

theorem checkZ_sound {Z : List (ℚ × ℚ × ℚ)} {c : ℚ} (h : checkZ Z c = true) :
    (∀ z ∈ ZR Z, 0 ≤ z) ∧ (c : ℝ) ≤ cZ (ZR Z) (ZR_nonempty (checkZ_nonempty h)) := by
  have h' := h
  simp only [checkZ, Bool.and_eq_true, List.all_eq_true, decide_eq_true_eq] at h'
  obtain ⟨-, hall⟩ := h'
  have key : ∀ z ∈ ZR Z, 0 ≤ z ∧ (c : ℝ) ≤ fin z := by
    intro z hz
    simp only [ZR, List.mem_toFinset, List.mem_map] at hz
    obtain ⟨a, ha, rfl⟩ := hz
    obtain ⟨⟨⟨h1, h2⟩, h3⟩, h4⟩ := hall a ha
    refine ⟨(nonneg_iff _).2 ⟨?_, ?_, ?_⟩, ?_⟩ <;> simp only [castT, fin]
    · exact_mod_cast h1
    · exact_mod_cast h2
    · exact_mod_cast h3
    · exact_mod_cast h4
  exact ⟨fun z hz => (key z hz).1, le_inf' _ _ (fun z hz => (key z hz).2)⟩

/-- Everything `tree_bound_of_certificate` needs, from the Boolean checks. -/
theorem tree_bound_of_checks {Z : List (ℚ × ℚ × ℚ)} {pairs inits : List (List (ℕ × ℚ))}
    {tail : List (ℕ × ℚ)} {y e₁ e₂ c : ℚ} {m₀ : ℕ} (hy : 0 ≤ y) (he₁ : 0 < e₁) (he₂ : 0 < e₂)
    (he₂1 : e₂ ≤ 1) (hZc : checkZ Z c = true) (hpairs : checkPairs Z pairs = true)
    (hinits : checkInits Z y e₁ e₂ m₀ inits tail = true)
    (T : SimpleGraph V) [DecidableRel T.Adj] (hT : T.IsTree) (ν : V → ℕ) :
    (c : ℝ) * (e₁ : ℝ) ^ Fintype.card V * (e₂ : ℝ) ^ (∑ v, ν v) ≤ treeW T ν (y : ℝ) := by
  have hZ := checkZ_nonempty hZc
  obtain ⟨hZ0, hcZ⟩ := checkZ_sound hZc
  have he₁R : (0 : ℝ) < e₁ := by exact_mod_cast he₁
  have he₂R : (0 : ℝ) < e₂ := by exact_mod_cast he₂
  refine le_trans ?_ (tree_bound_of_certificate (y : ℝ) e₁ e₂ (by exact_mod_cast hy) he₁R he₂R
    (ZR Z) (ZR_nonempty hZ) hZ0 (checkPairs_sound hZ hpairs)
    (checkInits_sound hZ hZ0 he₁ he₂ he₂1 hinits) T hT ν)
  have : (0 : ℝ) ≤ (e₁ : ℝ) ^ Fintype.card V * (e₂ : ℝ) ^ (∑ v, ν v) := by positivity
  rw [mul_assoc, mul_assoc]
  exact mul_le_mul_of_nonneg_right hcZ this

end Check

end

end Antinorm3

/-! ### `prop:rst-certs`: the two stored certificates, checked in the kernel -/

namespace RSThetaCert

open Antinorm3

theorem cert0_Z : checkZ Z0 (q 6212 10000) = true := by decide +kernel

theorem cert0_pairs : checkPairs Z0 pairs0 = true := by decide +kernel

theorem cert0_inits : checkInits Z0 y0 e1_0 e2_0 m0_0 inits0 tail0 = true := by decide +kernel

theorem cert1_Z : checkZ Z1 (q 6293 10000) = true := by decide +kernel

theorem cert1_pairs : checkPairs Z1 pairs1 = true := by decide +kernel

theorem cert1_inits : checkInits Z1 y1 e1_1 e2_1 m0_1 inits1 tail1 = true := by decide +kernel

end RSThetaCert

open Antinorm3 RSThetaCert in
/-- `prop:rst-certs` + `lem:rst-F`: the first RS-θ tree bound. -/
theorem rstheta_tree_bound_0 (T : SimpleGraph V) [DecidableRel T.Adj] (hT : T.IsTree)
    (ν : V → ℕ) :
    (6212/10000 : ℝ) * (747593601/960952792 : ℝ) ^ Fintype.card V
        * (512099210/652701491 : ℝ) ^ (∑ v, ν v)
      ≤ treeW T ν (69/200) := by
  have h := tree_bound_of_checks (by norm_num [y0, q]) (by norm_num [e1_0, q])
    (by norm_num [e2_0, q]) (by norm_num [e2_0, q]) cert0_Z cert0_pairs cert0_inits T hT ν
  convert h using 3 <;> norm_num [y0, e1_0, e2_0, q]

open Antinorm3 RSThetaCert in
/-- `prop:rst-certs` + `lem:rst-F`: the second RS-θ tree bound. -/
theorem rstheta_tree_bound_1 (T : SimpleGraph V) [DecidableRel T.Adj] (hT : T.IsTree)
    (ν : V → ℕ) :
    (6293/10000 : ℝ) * (248231700/312721579 : ℝ) ^ Fintype.card V
        * (568097827/739289481 : ℝ) ^ (∑ v, ν v)
      ≤ treeW T ν (17/50) := by
  have h := tree_bound_of_checks (by norm_num [y1, q]) (by norm_num [e1_1, q])
    (by norm_num [e2_1, q]) (by norm_num [e2_1, q]) cert1_Z cert1_pairs cert1_inits T hT ν
  convert h using 3 <;> norm_num [y1, e1_1, e2_1, q]

end MaxLeafFormal
Back to top