Skip to content

Commit 25a4a33

Browse files
committed
feat(Analysis/SpecialFunctions): hide Gamma func implementation details (leanprover-community#38447)
The definition of the gamma function relies on an auxiliary declaration `gammaAux`, which is of no interest once the actual gamma function is built. This PR makes `gammaAux` and its cousins private, and un-`expose`'s the definition of the gamma function (which is fine because there are plenty of API lemmas about it, so we do not need to unfold its actual definition downstream).
1 parent d2bb6e2 commit 25a4a33

3 files changed

Lines changed: 49 additions & 67 deletions

File tree

Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ set it to be `0` by convention.)
3838
Gamma
3939
-/
4040

41-
@[expose] public section
41+
public section
4242

4343

4444
noncomputable section
@@ -107,7 +107,7 @@ theorem GammaIntegral_convergent {s : ℂ} (hs : 0 < s.re) :
107107
108108
See `Complex.GammaIntegral_convergent` for a proof of the convergence of the integral for
109109
`0 < re s`. -/
110-
def GammaIntegral (s : ℂ) : ℂ :=
110+
@[expose] def GammaIntegral (s : ℂ) : ℂ :=
111111
∫ x in Ioi (0 : ℝ), ↑(-x).exp * ↑x ^ (s - 1)
112112

113113
set_option backward.isDefEq.respectTransparency false in
@@ -145,7 +145,7 @@ namespace Complex
145145
section GammaRecurrence
146146

147147
/-- The indefinite version of the `Γ` function, `Γ(s, X) = ∫ x ∈ 0..X, exp(-x) x ^ (s - 1)`. -/
148-
def partialGamma (s : ℂ) (X : ℝ) : ℂ :=
148+
@[expose] def partialGamma (s : ℂ) (X : ℝ) : ℂ :=
149149
∫ x in 0..X, (-x).exp * x ^ (s - 1)
150150

151151
theorem tendsto_partialGamma {s : ℂ} (hs : 0 < s.re) :
@@ -248,11 +248,11 @@ end GammaRecurrence
248248
section GammaDef
249249

250250
/-- The `n`th function in this family is `Γ(s)` if `-n < s.re`, and junk otherwise. -/
251-
noncomputable def GammaAux : ℕ → ℂ → ℂ
251+
private noncomputable def GammaAux : ℕ → ℂ → ℂ
252252
| 0 => GammaIntegral
253253
| n + 1 => fun s : ℂ => GammaAux n (s + 1) / s
254254

255-
theorem GammaAux_recurrence1 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) :
255+
private theorem GammaAux_recurrence1 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) :
256256
GammaAux n s = GammaAux n (s + 1) / s := by
257257
induction n generalizing s with
258258
| zero =>
@@ -267,7 +267,7 @@ theorem GammaAux_recurrence1 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) :
267267
rw [add_re, one_re]; linarith
268268
rw [← hn (s + 1) hh1]
269269

270-
theorem GammaAux_recurrence2 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) :
270+
private theorem GammaAux_recurrence2 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) :
271271
GammaAux n s = GammaAux (n + 1) s := by
272272
rcases n with - | n
273273
· simp only [CharP.cast_eq_zero, Left.neg_neg_iff] at h1
@@ -284,12 +284,13 @@ theorem GammaAux_recurrence2 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) :
284284
rw [GammaAux_recurrence1 (s + 1) n hh1]
285285
rw [this]
286286

287+
/- This definition is deliberately not @[expose]'d, since `GammaAux` is not mathematically
288+
interesting. -/
287289
/-- The `Γ` function (of a complex variable `s`). -/
288-
@[pp_nodot]
289-
irreducible_def Gamma (s : ℂ) : ℂ :=
290+
@[irreducible, pp_nodot] def Gamma (s : ℂ) : ℂ :=
290291
GammaAux ⌊1 - s.re⌋₊ s
291292

292-
theorem Gamma_eq_GammaAux (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) : Gamma s = GammaAux n s := by
293+
private theorem Gamma_eq_GammaAux (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) : Gamma s = GammaAux n s := by
293294
have u : ∀ k : ℕ, GammaAux (⌊1 - s.re⌋₊ + k) s = Gamma s := fun k ↦ by
294295
induction k with
295296
| zero => simp [Gamma]
@@ -401,8 +402,7 @@ end Complex
401402
namespace Real
402403

403404
/-- The `Γ` function (of a real variable `s`). -/
404-
@[pp_nodot]
405-
def Gamma (s : ℝ) : ℝ :=
405+
@[pp_nodot, expose] def Gamma (s : ℝ) : ℝ :=
406406
(Complex.Gamma s).re
407407

408408
theorem Gamma_eq_integral {s : ℝ} (hs : 0 < s) :

Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -336,31 +336,30 @@ theorem approx_Gamma_integral_tendsto_Gamma_integral {s : ℂ} (hs : 0 < re s) :
336336

337337
/-- Euler's limit formula for the complex Gamma function. -/
338338
theorem GammaSeq_tendsto_Gamma (s : ℂ) : Tendsto (GammaSeq s) atTop (𝓝 <| Gamma s) := by
339-
suffices ∀ m : ℕ, -↑m < re s → Tendsto (GammaSeq s) atTop (𝓝 <| GammaAux m s) by
340-
rw [Gamma]
341-
apply this
342-
rw [neg_lt]
343-
rcases lt_or_ge 0 (re s) with (hs | hs)
344-
· exact (neg_neg_of_pos hs).trans_le (Nat.cast_nonneg _)
345-
· refine (Nat.lt_floor_add_one _).trans_le ?_
346-
rw [sub_eq_neg_add, Nat.floor_add_one (neg_nonneg.mpr hs), Nat.cast_add_one]
339+
suffices ∀ m : ℕ, ⌊1 - s.re⌋₊ = m → Tendsto (GammaSeq s) atTop (𝓝 <| Gamma s) by tauto
347340
intro m
348341
induction m generalizing s with intro hs
349342
| zero => -- Base case: `0 < re s`, so Gamma is given by the integral formula
350-
rw [Nat.cast_zero, neg_zero] at hs
351-
rw [← Gamma_eq_GammaAux]
352-
· refine Tendsto.congr' ?_ (approx_Gamma_integral_tendsto_Gamma_integral hs)
353-
refine (eventually_ne_atTop 0).mp (Eventually.of_forall fun n hn => ?_)
354-
exact (GammaSeq_eq_approx_Gamma_integral hs hn).symm
355-
· rwa [Nat.cast_zero, neg_lt_zero]
343+
rw [Nat.floor_eq_zero, sub_lt_self_iff] at hs
344+
apply (approx_Gamma_integral_tendsto_Gamma_integral hs).congr'
345+
filter_upwards [eventually_ne_atTop 0] with n hn using
346+
(GammaSeq_eq_approx_Gamma_integral hs hn).symm
356347
| succ m IH => -- Induction step: use recurrence formulae in `s` for Gamma and GammaSeq
357-
rw [Nat.cast_succ, neg_add, ← sub_eq_add_neg, sub_lt_iff_lt_add, ← one_re, ← add_re] at hs
358-
rw [GammaAux]
359-
have := @Tendsto.congr' _ _ _ ?_ _ _
360-
((eventually_ne_atTop 0).mp (Eventually.of_forall fun n hn => ?_)) ((IH _ hs).div_const s)
361-
pick_goal 3; · exact GammaSeq_add_one_left s hn -- doesn't work if inlined?
362-
conv at this => arg 1; intro n; rw [mul_comm]
363-
rwa [← mul_one (GammaAux m (s + 1) / s), tendsto_mul_iff_of_ne_zero _ (one_ne_zero' ℂ)] at this
348+
-- Silly case `s = 0`: both sides are zero
349+
rcases eq_or_ne s 0 with rfl | hsne
350+
· unfold GammaSeq
351+
simp [Finset.prod_range_succ']
352+
specialize IH (s + 1) ?_
353+
· rw [Nat.floor_eq_iff' (by lia)] at hs
354+
have : s.re ≤ -m := by grind
355+
rw [Nat.floor_eq_iff <| by simpa using (show s.re ≤ 0 by grind)]
356+
grind [add_re, one_re]
357+
rw [Gamma_add_one _ hsne] at IH
358+
have := (IH.div_const s).congr' <| by
359+
filter_upwards [eventually_ne_atTop 0] with n using GammaSeq_add_one_left s
360+
simp only [mul_comm _ (s.GammaSeq _)] at this
361+
rwa [mul_div_cancel_left₀ _ hsne, ← mul_one (Gamma s),
362+
tendsto_mul_iff_of_ne_zero _ (one_ne_zero' ℂ)] at this
364363
simp_rw [add_assoc]
365364
exact tendsto_natCast_div_add_atTop (1 + s)
366365

Mathlib/Analysis/SpecialFunctions/Gamma/Deriv.lean

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -61,43 +61,26 @@ theorem hasDerivAt_GammaIntegral {s : ℂ} (hs : 0 < s.re) :
6161
rw [(by simp : (1 : ℂ) = Real.exp (-0))]
6262
exact (continuous_ofReal.comp (Real.continuous_exp.comp continuous_neg)).continuousWithinAt
6363

64-
theorem differentiableAt_GammaAux (s : ℂ) (n : ℕ) (h1 : 1 - s.re < n) (h2 : ∀ m : ℕ, s ≠ -m) :
65-
DifferentiableAt ℂ (GammaAux n) s := by
66-
induction n generalizing s with
67-
| zero =>
68-
refine (hasDerivAt_GammaIntegral ?_).differentiableAt
69-
rw [Nat.cast_zero] at h1; linarith
70-
| succ n hn =>
71-
dsimp only [GammaAux]
72-
specialize hn (s + 1)
73-
have a : 1 - (s + 1).re < ↑n := by
74-
rw [Nat.cast_succ] at h1; rw [Complex.add_re, Complex.one_re]; linarith
75-
have b : ∀ m : ℕ, s + 1 ≠ -m := by
76-
intro m; have := h2 (1 + m)
77-
contrapose this
78-
rw [← eq_sub_iff_add_eq] at this
79-
simpa using this
80-
refine DifferentiableAt.div (DifferentiableAt.comp _ (hn a b) ?_) ?_ ?_
81-
· rw [differentiableAt_add_const_iff (1 : ℂ)]; exact differentiableAt_id
82-
· exact differentiableAt_id
83-
· simpa using h2 0
84-
8564
@[fun_prop]
8665
theorem differentiableAt_Gamma (s : ℂ) (hs : ∀ m : ℕ, s ≠ -m) : DifferentiableAt ℂ Gamma s := by
87-
let n := ⌊1 - s.re⌋₊ + 1
88-
have hn : 1 - s.re < n := mod_cast Nat.lt_floor_add_one (1 - s.re)
89-
apply (differentiableAt_GammaAux s n hn hs).congr_of_eventuallyEq
90-
let S := {t : ℂ | 1 - t.re < n}
91-
have : S ∈ 𝓝 s := by
92-
rw [mem_nhds_iff]; use S
93-
refine ⟨Subset.rfl, ?_, hn⟩
94-
have : S = re ⁻¹' Ioi (1 - n : ℝ) := by
95-
ext; rw [preimage, Ioi, mem_setOf_eq, mem_setOf_eq, mem_setOf_eq]; exact sub_lt_comm
96-
rw [this]
97-
exact Continuous.isOpen_preimage continuous_re _ isOpen_Ioi
98-
apply eventuallyEq_of_mem this
99-
intro t ht; rw [mem_setOf_eq] at ht
100-
apply Gamma_eq_GammaAux; linarith
66+
-- We will show, by induction on `n`, that `Gamma` is differentiable on `-n < Re s`.
67+
suffices ∀ (n : ℕ) (s : ℂ) (hsre : -n < s.re) (hs : ∀ m : ℕ, s ≠ -m), DifferentiableAt ℂ _ s from
68+
this (⌊-s.re⌋₊ + 1) s (by grind [Nat.lt_floor_add_one (-s.re)]) hs
69+
intro n s hsre hs
70+
induction n generalizing s with
71+
| zero =>
72+
-- Case `n = 0`: use relation to `gammaIntegral`
73+
replace hsre : 0 < s.re := by simpa using hsre
74+
have : IsOpen {s : ℂ | 0 < s.re} := continuous_re.isOpen_preimage _ isOpen_Ioi
75+
apply (hasDerivAt_GammaIntegral (by simpa using hsre)).differentiableAt.congr_of_eventuallyEq
76+
filter_upwards [this.mem_nhds hsre] with a using Gamma_eq_integral
77+
| succ n IH =>
78+
-- Induction step: use recurrence relation
79+
have hsne : s ≠ 0 := by grind [hs 0]
80+
specialize IH (s + 1) (by grind [add_re, one_re]) (fun m ↦ by grind [hs (m + 1)])
81+
have := IH.comp s (show DifferentiableAt ℂ (fun s ↦ s + 1) s by fun_prop)
82+
apply (this.fun_div differentiableAt_id hsne).congr_of_eventuallyEq
83+
filter_upwards [isOpen_ne.mem_nhds hsne] using by grind [Gamma_add_one]
10184

10285
theorem differentiableAt_Gamma_one : DifferentiableAt ℂ Gamma 1 :=
10386
differentiableAt_Gamma 1 (by norm_cast; simp)

0 commit comments

Comments
 (0)