Skip to content

Commit 0dd53a2

Browse files
committed
feat(Analysis/SpecialFunctions): arithmetic-geometric mean (leanprover-community#32892)
Co-authored-by: Parcly Taxel <[email protected]>
1 parent ba0a0a1 commit 0dd53a2

File tree

2 files changed

+303
-0
lines changed

2 files changed

+303
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,6 +2126,7 @@ public import Mathlib.Analysis.Real.Pi.Wallis
21262126
public import Mathlib.Analysis.Real.Spectrum
21272127
public import Mathlib.Analysis.Seminorm
21282128
public import Mathlib.Analysis.SpecialFunctions.Arcosh
2129+
public import Mathlib.Analysis.SpecialFunctions.ArithmeticGeometricMean
21292130
public import Mathlib.Analysis.SpecialFunctions.Arsinh
21302131
public import Mathlib.Analysis.SpecialFunctions.Artanh
21312132
public import Mathlib.Analysis.SpecialFunctions.Bernstein
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
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

Comments
 (0)