|
| 1 | +/- |
| 2 | +Copyright (c) 2025 Jeremy Tan. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Jeremy Tan |
| 5 | +-/ |
| 6 | +module |
| 7 | + |
| 8 | +public import Mathlib.Analysis.SpecificLimits.Basic |
| 9 | +public import Mathlib.Data.Real.Sqrt |
| 10 | + |
| 11 | +/-! |
| 12 | +# The arithmetic-geometric mean |
| 13 | +
|
| 14 | +Starting with two nonnegative real numbers, repeatedly replace them with their arithmetic and |
| 15 | +geometric means. By the AM-GM inequality, the smaller number (geometric mean) will monotonically |
| 16 | +increase and the larger number (arithmetic mean) will monotonically decrease. |
| 17 | +
|
| 18 | +The two monotone sequences converge to the same limit – the arithmetic-geometric mean (AGM). |
| 19 | +This file defines the AGM in the `NNReal` namespace and proves some of its basic properties. |
| 20 | +
|
| 21 | +## References |
| 22 | +
|
| 23 | +* https://en.wikipedia.org/wiki/Arithmetic–geometric_mean |
| 24 | +-/ |
| 25 | + |
| 26 | +@[expose] public section |
| 27 | + |
| 28 | +namespace NNReal |
| 29 | + |
| 30 | +/-- The AM–GM inequality for two `NNReal`s, with means in canonical form. -/ |
| 31 | +lemma sqrt_mul_le_half_add (x y : ℝ≥0) : sqrt (x * y) ≤ (x + y) / 2 := by |
| 32 | + rw [sqrt_le_iff_le_sq, div_pow, le_div_iff₀' (by positivity), ← mul_assoc] |
| 33 | + norm_num |
| 34 | + exact four_mul_le_sq_add .. |
| 35 | + |
| 36 | +/-- The strict AM–GM inequality for two `NNReal`s, with means in canonical form. -/ |
| 37 | +lemma sqrt_mul_lt_half_add_of_ne {x y : ℝ≥0} (h : x ≠ y) : sqrt (x * y) < (x + y) / 2 := by |
| 38 | + wlog hl : y < x generalizing x y |
| 39 | + · specialize this h.symm (h.gt_or_lt.resolve_left hl) |
| 40 | + rwa [mul_comm, add_comm] |
| 41 | + have key : 0 < (x - y) ^ 2 := sq_pos_iff.mpr (by rwa [← zero_lt_iff, tsub_pos_iff_lt]) |
| 42 | + rw [sq, tsub_mul, mul_tsub, mul_tsub, tsub_tsub_eq_add_tsub_of_le (by gcongr), |
| 43 | + tsub_add_eq_add_tsub (by gcongr), tsub_tsub, show x * y + y * x = 2 * x * y by ring, |
| 44 | + tsub_pos_iff_lt, ← sq, ← sq] at key |
| 45 | + rw [← sqrt_sq (_ / 2), sqrt_lt_sqrt, div_pow, lt_div_iff₀' (by positivity), |
| 46 | + show (2 : ℝ≥0) ^ 2 * (x * y) = 2 * x * y + 2 * x * y by ring, add_sq, add_right_comm] |
| 47 | + gcongr |
| 48 | + |
| 49 | +open Function Filter Topology |
| 50 | + |
| 51 | +/-- `agmSequences x y` is the sequence of (geometric, arithmetic) means |
| 52 | +converging to the arithmetic-geometric mean starting from `x` and `y`. -/ |
| 53 | +noncomputable def agmSequences (x y : ℝ≥0) : ℕ → ℝ≥0 × ℝ≥0 := |
| 54 | + fun n ↦ (fun p ↦ (sqrt (p.1 * p.2), (p.1 + p.2) / 2))^[n + 1] (x, y) |
| 55 | + |
| 56 | +variable {x y : ℝ≥0} {n : ℕ} |
| 57 | + |
| 58 | +@[simp] |
| 59 | +lemma agmSequences_zero : agmSequences x y 0 = (sqrt (x * y), (x + y) / 2) := rfl |
| 60 | + |
| 61 | +lemma agmSequences_succ : agmSequences x y (n + 1) = agmSequences (sqrt (x * y)) ((x + y) / 2) n := |
| 62 | + rfl |
| 63 | + |
| 64 | +lemma agmSequences_succ' : |
| 65 | + agmSequences x y (n + 1) = |
| 66 | + (sqrt ((agmSequences x y n).1 * (agmSequences x y n).2), |
| 67 | + ((agmSequences x y n).1 + (agmSequences x y n).2) / 2) := by |
| 68 | + nth_rw 1 [agmSequences] |
| 69 | + rw [iterate_succ', comp_apply] |
| 70 | + rfl |
| 71 | + |
| 72 | +lemma agmSequences_comm : agmSequences x y = agmSequences y x := by |
| 73 | + funext n |
| 74 | + cases n with |
| 75 | + | zero => simp [mul_comm, add_comm] |
| 76 | + | succ n => simp [agmSequences_succ, mul_comm, add_comm] |
| 77 | + |
| 78 | +lemma le_gm_and_am_le (h : x ≤ y) : x ≤ sqrt (x * y) ∧ (x + y) / 2 ≤ y := by |
| 79 | + constructor |
| 80 | + · rw [le_sqrt_iff_sq_le, sq] |
| 81 | + gcongr |
| 82 | + · apply div_le_of_le_mul' |
| 83 | + rw [two_mul] |
| 84 | + gcongr |
| 85 | + |
| 86 | +lemma dist_gm_am_le : dist (sqrt (x * y)) ((x + y) / 2) ≤ dist x y / 2 := by |
| 87 | + wlog h : x ≤ y generalizing x y |
| 88 | + · simpa [add_comm, mul_comm, dist_comm] using this (not_le.mp h).le |
| 89 | + rw [dist_comm, dist_eq, ← NNReal.coe_sub (sqrt_mul_le_half_add ..), abs_eq] |
| 90 | + calc |
| 91 | + _ ≤ ((x + y) / 2 - x).toReal := by |
| 92 | + gcongr |
| 93 | + rw [le_sqrt_iff_sq_le, sq] |
| 94 | + gcongr |
| 95 | + _ = _ := by |
| 96 | + nth_rw 2 [← add_halves x] |
| 97 | + rw [add_div, add_tsub_add_eq_tsub_left, ← tsub_div, NNReal.coe_div, NNReal.coe_two, dist_comm, |
| 98 | + dist_eq, ← NNReal.coe_sub h, abs_eq] |
| 99 | + |
| 100 | +lemma agmSequences_monotone_and_antitone : |
| 101 | + (Monotone fun n ↦ (agmSequences x y n).1) ∧ Antitone fun n ↦ (agmSequences x y n).2 := by |
| 102 | + suffices ∀ n, (agmSequences x y n).1 ≤ (agmSequences x y (n + 1)).1 ∧ |
| 103 | + (agmSequences x y (n + 1)).2 ≤ (agmSequences x y n).2 from |
| 104 | + ⟨monotone_nat_of_le_succ (this · |>.1), antitone_nat_of_succ_le (this · |>.2)⟩ |
| 105 | + intro n |
| 106 | + induction n generalizing x y with |
| 107 | + | zero => exact le_gm_and_am_le (sqrt_mul_le_half_add ..) |
| 108 | + | succ n ih => exact Prod.mk_le_mk.mp ih |
| 109 | + |
| 110 | +lemma agmSequences_fst_monotone : Monotone fun n ↦ (agmSequences x y n).1 := |
| 111 | + agmSequences_monotone_and_antitone.1 |
| 112 | + |
| 113 | +lemma agmSequences_snd_antitone : Antitone fun n ↦ (agmSequences x y n).2 := |
| 114 | + agmSequences_monotone_and_antitone.2 |
| 115 | + |
| 116 | +lemma agmSequences_fst_le_snd (n m : ℕ) : (agmSequences x y n).1 ≤ (agmSequences x y m).2 := by |
| 117 | + suffices ∀ {k}, (agmSequences x y k).1 ≤ (agmSequences x y k).2 by |
| 118 | + obtain h | h := le_total n m |
| 119 | + · exact (agmSequences_fst_monotone h).trans this |
| 120 | + · exact this.trans (agmSequences_snd_antitone h) |
| 121 | + intro k |
| 122 | + induction k generalizing x y with |
| 123 | + | zero => exact sqrt_mul_le_half_add .. |
| 124 | + | succ n ih => exact ih |
| 125 | + |
| 126 | +lemma agmSequences_fst_lt_snd_of_ne (h : x ≠ y) (n m : ℕ) : |
| 127 | + (agmSequences x y n).1 < (agmSequences x y m).2 := by |
| 128 | + suffices ∀ {k}, (agmSequences x y k).1 < (agmSequences x y k).2 by |
| 129 | + obtain h | h := le_total n m |
| 130 | + · exact (agmSequences_fst_monotone h).trans_lt this |
| 131 | + · exact this.trans_le (agmSequences_snd_antitone h) |
| 132 | + intro k |
| 133 | + induction k generalizing x y with |
| 134 | + | zero => exact sqrt_mul_lt_half_add_of_ne h |
| 135 | + | succ n ih => |
| 136 | + rw [agmSequences_succ'] |
| 137 | + exact sqrt_mul_lt_half_add_of_ne (ih h).ne |
| 138 | + |
| 139 | +lemma agmSequences_min_max : agmSequences (min x y) (max x y) = agmSequences x y := by |
| 140 | + obtain h | h := le_total x y |
| 141 | + · rw [min_eq_left h, max_eq_right h] |
| 142 | + · rw [min_eq_right h, max_eq_left h, agmSequences_comm] |
| 143 | + |
| 144 | +lemma dist_agmSequences_fst_snd (n : ℕ) : |
| 145 | + dist (agmSequences x y n).1 (agmSequences x y n).2 ≤ dist x y / 2 ^ (n + 1) := by |
| 146 | + induction n with |
| 147 | + | zero => simp [dist_gm_am_le] |
| 148 | + | succ n ih => |
| 149 | + rw [agmSequences_succ'] |
| 150 | + apply dist_gm_am_le.trans |
| 151 | + rw [pow_succ, ← div_div] |
| 152 | + gcongr |
| 153 | + |
| 154 | +lemma tendsto_dist_agmSequences_atTop_zero : |
| 155 | + Tendsto (fun n ↦ dist (agmSequences x y n).1 (agmSequences x y n).2) atTop (𝓝 0) := by |
| 156 | + apply squeeze_zero (fun _ ↦ dist_nonneg) dist_agmSequences_fst_snd |
| 157 | + conv => |
| 158 | + rw [← zero_mul (dist x y / 2)] |
| 159 | + enter [1, n] |
| 160 | + rw [pow_succ', ← div_div, div_eq_inv_mul, ← inv_pow] |
| 161 | + exact (_root_.tendsto_pow_atTop_nhds_zero_of_lt_one (by norm_num) (by norm_num)).mul_const _ |
| 162 | + |
| 163 | +/-- The arithmetic-geometric mean of two `NNReal`s, defined as the infimum of arithmetic means. -/ |
| 164 | +noncomputable def agm (x y : ℝ≥0) : ℝ≥0 := |
| 165 | + ⨅ n, (agmSequences x y n).2 |
| 166 | + |
| 167 | +lemma agm_comm : agm x y = agm y x := by |
| 168 | + unfold agm |
| 169 | + conv_rhs => |
| 170 | + enter [1, n] |
| 171 | + rw [agmSequences_comm] |
| 172 | + |
| 173 | +lemma agm_eq_ciInf : agm x y = ⨅ n, (agmSequences x y n).2 := rfl |
| 174 | + |
| 175 | +lemma tendsto_agmSequences_snd_agm : Tendsto (fun n ↦ (agmSequences x y n).2) atTop (𝓝 (agm x y)) := |
| 176 | + tendsto_atTop_ciInf agmSequences_snd_antitone (OrderBot.bddBelow _) |
| 177 | + |
| 178 | +lemma agm_le_agmSequences_snd (n : ℕ) : agm x y ≤ (agmSequences x y n).2 := ciInf_le' _ n |
| 179 | + |
| 180 | +lemma agm_le_max : agm x y ≤ max x y := by |
| 181 | + wlog h : x ≤ y generalizing x y |
| 182 | + · simpa [agm_comm, max_comm] using this (not_le.mp h).le |
| 183 | + rw [max_eq_right h] |
| 184 | + apply (agm_le_agmSequences_snd 0).trans |
| 185 | + rw [agmSequences_zero] |
| 186 | + exact (le_gm_and_am_le h).2 |
| 187 | + |
| 188 | +lemma bddAbove_range_agmSequences_fst : BddAbove (Set.range fun n ↦ (agmSequences x y n).1) := by |
| 189 | + rw [bddAbove_def] |
| 190 | + use (agmSequences x y 0).2 |
| 191 | + simp_rw [Set.mem_range, forall_exists_index, forall_apply_eq_imp_iff] |
| 192 | + exact fun _ ↦ agmSequences_fst_le_snd .. |
| 193 | + |
| 194 | +/-- The AGM is also the supremum of the geometric means. -/ |
| 195 | +lemma agm_eq_ciSup : agm x y = ⨆ n, (agmSequences x y n).1 := by |
| 196 | + refine tendsto_nhds_unique (tendsto_agmSequences_snd_agm.congr_dist ?_) |
| 197 | + (tendsto_atTop_ciSup agmSequences_fst_monotone bddAbove_range_agmSequences_fst) |
| 198 | + conv => |
| 199 | + enter [1, n] |
| 200 | + rw [dist_comm] |
| 201 | + exact tendsto_dist_agmSequences_atTop_zero |
| 202 | + |
| 203 | +lemma tendsto_agmSequences_fst_agm : |
| 204 | + Tendsto (fun n ↦ (agmSequences x y n).1) atTop (𝓝 (agm x y)) := by |
| 205 | + rw [agm_eq_ciSup] |
| 206 | + exact tendsto_atTop_ciSup agmSequences_fst_monotone bddAbove_range_agmSequences_fst |
| 207 | + |
| 208 | +lemma agmSequences_fst_le_agm (n : ℕ) : (agmSequences x y n).1 ≤ agm x y := by |
| 209 | + rw [agm_eq_ciSup] |
| 210 | + exact le_ciSup bddAbove_range_agmSequences_fst _ |
| 211 | + |
| 212 | +lemma min_le_agm : min x y ≤ agm x y := by |
| 213 | + wlog h : x ≤ y generalizing x y |
| 214 | + · simpa [agm_comm, min_comm] using this (not_le.mp h).le |
| 215 | + rw [min_eq_left h] |
| 216 | + refine le_trans ?_ (agmSequences_fst_le_agm 0) |
| 217 | + rw [agmSequences_zero] |
| 218 | + exact (le_gm_and_am_le h).1 |
| 219 | + |
| 220 | +@[simp] |
| 221 | +lemma agm_self : agm x x = x := by |
| 222 | + apply le_antisymm |
| 223 | + · nth_rw 3 [← max_self x] |
| 224 | + exact agm_le_max |
| 225 | + · nth_rw 1 [← min_self x] |
| 226 | + exact min_le_agm |
| 227 | + |
| 228 | +@[simp] |
| 229 | +lemma agm_zero_left : agm 0 y = 0 := by |
| 230 | + suffices ∀ n, (agmSequences 0 y n).1 = 0 by simp [agm_eq_ciSup, this] |
| 231 | + intro n |
| 232 | + induction n with |
| 233 | + | zero => simp [agmSequences] |
| 234 | + | succ n ih => |
| 235 | + rw [agmSequences_succ', ih, zero_mul, sqrt_zero] |
| 236 | + |
| 237 | +@[simp] |
| 238 | +lemma agm_zero_right : agm x 0 = 0 := by |
| 239 | + rw [agm_comm, agm_zero_left] |
| 240 | + |
| 241 | +lemma agm_pos (hx : 0 < x) (hy : 0 < y) : 0 < agm x y := (lt_min hx hy).trans_le min_le_agm |
| 242 | + |
| 243 | +lemma agm_eq_agm_agmSequences_fst_agmSequences_snd (n : ℕ) : |
| 244 | + agm x y = agm (agmSequences x y n).1 (agmSequences x y n).2 := by |
| 245 | + refine tendsto_nhds_unique ?_ tendsto_agmSequences_snd_agm |
| 246 | + have key := @tendsto_agmSequences_snd_agm x y |
| 247 | + rw [← tendsto_add_atTop_iff_nat (n + 1)] at key |
| 248 | + convert key using 2 with m |
| 249 | + simp_rw [agmSequences, Prod.mk.eta, ← iterate_add_apply, add_right_comm] |
| 250 | + |
| 251 | +lemma agm_eq_agm_gm_am : agm x y = agm (sqrt (x * y)) ((x + y) / 2) := by |
| 252 | + simpa using agm_eq_agm_agmSequences_fst_agmSequences_snd 0 |
| 253 | + |
| 254 | +lemma agmSequences_fst_lt_agm_of_pos_of_ne (hx : 0 < x) (hy : 0 < y) (hn : x ≠ y) (n : ℕ) : |
| 255 | + (agmSequences x y n).1 < agm x y := by |
| 256 | + rw [agm_eq_agm_agmSequences_fst_agmSequences_snd n] |
| 257 | + set p := (agmSequences x y n).1 |
| 258 | + set q := (agmSequences x y n).2 |
| 259 | + apply (?_ : p < sqrt (p * q)).trans_le (agmSequences_fst_le_agm 0) |
| 260 | + have ppos : 0 < p := |
| 261 | + (show 0 < sqrt (x * y) by positivity).trans_le (agmSequences_fst_monotone (zero_le n)) |
| 262 | + have plq : p < q := agmSequences_fst_lt_snd_of_ne hn .. |
| 263 | + nth_rw 1 [← mul_self_sqrt p, sqrt_mul] |
| 264 | + gcongr |
| 265 | + |
| 266 | +lemma agm_lt_agmSequences_snd_of_ne (hn : x ≠ y) (n : ℕ) : agm x y < (agmSequences x y n).2 := by |
| 267 | + rw [agm_eq_agm_agmSequences_fst_agmSequences_snd n] |
| 268 | + set p := (agmSequences x y n).1 |
| 269 | + set q := (agmSequences x y n).2 |
| 270 | + apply (agm_le_agmSequences_snd 0).trans_lt (?_ : (p + q) / 2 < q) |
| 271 | + have plq : p < q := agmSequences_fst_lt_snd_of_ne hn .. |
| 272 | + nth_rw 2 [← add_halves q] |
| 273 | + rw [add_div] |
| 274 | + gcongr |
| 275 | + |
| 276 | +lemma min_lt_agm_of_pos_of_ne (hx : 0 < x) (hy : 0 < y) (hn : x ≠ y) : min x y < agm x y := by |
| 277 | + wlog h : x < y generalizing x y |
| 278 | + · simpa [agm_comm, min_comm] using this hy hx hn.symm (hn.gt_or_lt.resolve_right h) |
| 279 | + rw [min_eq_left h.le] |
| 280 | + refine lt_of_le_of_lt ?_ (agmSequences_fst_lt_agm_of_pos_of_ne hx hy hn 0) |
| 281 | + rw [agmSequences_zero] |
| 282 | + exact (le_gm_and_am_le h.le).1 |
| 283 | + |
| 284 | +lemma agm_lt_max_of_ne (hn : x ≠ y) : agm x y < max x y := by |
| 285 | + wlog h : x < y generalizing x y |
| 286 | + · simpa [agm_comm, max_comm] using this hn.symm (hn.gt_or_lt.resolve_right h) |
| 287 | + rw [max_eq_right h.le] |
| 288 | + apply (agm_lt_agmSequences_snd_of_ne hn 0).trans_le |
| 289 | + rw [agmSequences_zero] |
| 290 | + exact (le_gm_and_am_le h.le).2 |
| 291 | + |
| 292 | +/-- The AGM distributes over multiplication. -/ |
| 293 | +lemma agm_mul_distrib {k : ℝ≥0} : agm (k * x) (k * y) = k * agm x y := by |
| 294 | + simp_rw [agm, mul_iInf] |
| 295 | + congr! with n |
| 296 | + induction n generalizing x y with |
| 297 | + | zero => simp [← mul_div_assoc, mul_add] |
| 298 | + | succ n ih => |
| 299 | + rw [agmSequences_succ, ← mul_add, mul_div_assoc, mul_mul_mul_comm, |
| 300 | + ← sq, sqrt_mul, sqrt_sq, ih, agmSequences_succ] |
| 301 | + |
| 302 | +end NNReal |
0 commit comments