← Session 22 — ii′-1: liCoeff pairing fix + residue machinery
thinking (7387 chars)
Part 1 committed (0b4133e). Now — the digamma series (Part 2). It's ~23:05. This is the heavy rock. Let me start it carefully.
Plan for Part 2 (the real digamma series):
```lean
/-- The summand of the digamma series: u_m(x) = 1/m − 1/(x+m) for m ≥ 1. -/
def digammaSummand (x : ℝ) (m : ℕ) : ℝ := if m = 0 then 0 else (1 / (m : ℝ) - 1 / (x + m))
```
Hmm — the indexing: the series is Σ_{m≥1} (1/m − 1/(x+m)). Cleaner: define on ℕ with the m=0 term = 0 (junk) or index from m+1. Let me use m+1 indexing: u x m := 1/(m+1) − 1/(x + m + 1) for m : ℕ. Then Σ_{m} u x m = Σ_{m≥1} (1/m − 1/(x+m)) ✓. Summability: |u x m| = x/((m+1)(x+m+1)) ≤ x/(m+1)² for x > 0 — vs summable_one_div_nat_pow-ish — need Σ 1/(m+1)² summable — the p-series at p = 2 shifted — `Real.summable_one_div_nat_pow.mpr (1 < 2)` gives Σ 1/n² over ℕ — with n = 0 term 1/0 = 0 junk fine. Comparison: u x m ≤ x/(m+1)²... the dominator x·(1/(m+1)²) — summable ✓ via the p-series + shift. Actually simpler: 1/(m+1)² vs 1/(m')² with m' = m+1: `summable_nat_add_iff`? — `summable_nat_add_iff (k) : Summable (fun n => f (n + k)) ↔ Summable f` ✓ exists. So Summable (fun m => 1/((m:ℝ)+1)^2) via summable_nat_add_iff 1 + the p-series ✓.
The main lemma (A2): the function sequence digammaRealSeq x n := Real.log n − Σ_{m ∈ range (n+1)} 1/(x+m) converges locally uniformly on (0,∞) to Dinf(x) := −γ − 1/x + Σ_{m≥1}(1/m − 1/(x+m)).
Decompose: digammaRealSeq x n = (log n − H_n) + Σ_{m=1}^n (1/m − 1/(x+m)) − 1/x.
- H_n = Σ_{m=1}^n 1/m = Σ_{m ∈ range(n+1)} 1/m (m=0 term is 1/0 = 0 junk — harmonic n := Σ_{i ∈ range n} 1/(i+1)? — Mathlib's `harmonic n := ∑ i ∈ Finset.range n, (i+1)⁻¹`? — harmonic n = Σ_{i<n} 1/(i+1) ✓. So Σ_{m ∈ range(n+1)} 1/(x+m) = 1/x + Σ_{m=1}^n 1/(x+m) = 1/x + Σ_{i ∈ range n} 1/(x + (i+1))... — the reindexings are fiddly but fine.
- The three pieces: (log n − H_n) → −γ (tendsto_harmonic_sub_log ✓); the series partial sums → tsum locally uniformly (M-test); −1/x constant.
TendstoLocallyUniformlyOn assembly from the pieces: TendstoLocallyUniformlyOn.add etc. ✓ (there are .add/.const lemmas for locally uniform — `TendstoLocallyUniformlyOn.add` ✓ exists presumably).
Then (A3): deriv (Real.log ∘ Real.Gamma) = D∞ on (0,∞) via hasDerivAt_of_tendstoLocallyUniformlyOn with:
- f_n := fun x => logGammaSeq x n; g := Real.log ∘ Real.Gamma; f'_n := digammaRealSeq · n; g' := Dinf.
- hfg : ∀ x ∈ Ioi 0, Tendsto (fun n => logGammaSeq x n) atTop (𝓝 (log (Gamma x))) ✓ = tendsto_log_gamma.
- hf : ∀ᶠ n, ∀ x ∈ Ioi 0, HasDerivAt (fun x => logGammaSeq x n) (digammaRealSeq x n) x — deriv of x·log n + log n! − Σ_{m≤n} log(x+m) = log n − Σ 1/(x+m) — termwise deriv of log(x+m) = 1/(x+m) (Real.deriv_log_comp or hasDerivAt_log... — `Real.hasDerivAt_log (hx : x ≠ 0) : HasDerivAt log (1/x) x` ✓ + comp with x+m ✓). logGammaSeq is defined with `∑ m ∈ Finset.range (n + 1), log (x + m)` ✓ deriv_sum ✓.
- hf' : TendstoLocallyUniformlyOn digammaRealSeq Dinf atTop (Ioi 0) — from (A2).
Then HasDerivAt (Real.log ∘ Real.Gamma) (Dinf x) x for x ∈ Ioi 0 — and deriv (Real.log ∘ Real.Gamma) x = Dinf x.
Hmm wait — one subtlety: hasDerivAt_of_tendstoLocallyUniformlyOn's g is the POINTWISE limit of f n — here g := fun x => log (Real.Gamma x) — hfg gives Tendsto (f n x) → (𝓝 (log (Gamma x))) — and g x := (Real.log ∘ Real.Gamma) x = log (Gamma x) ✓.
Then: deriv (Real.log ∘ Real.Gamma) x = Real.Gamma' x / Real.Gamma x — deriv of log∘Gamma: (Real.hasDerivAt_log (Gamma x ≠ 0)).comp-with-Gamma'... — need Real.Gamma differentiable at x (Real.differentiableAt_Gamma ✓ for x > 0 — the hypothesis ∀ m, x ≠ −m ✓ since x > 0) and log at Gamma x (Gamma x > 0 ≠ 0 ✓ Real.Gamma_pos_of_pos). So ψ_real x := deriv Real.Gamma x / Real.Gamma x = Dinf x ✓.
The complex bridge (Part 4): Complex.digamma ↑x = ↑(Dinf x):
digamma ↑x = deriv Complex.Gamma ↑x / Complex.Gamma ↑x.
Complex.Gamma ↑x = ↑(Real.Gamma x) (Complex.Gamma_ofReal ✓).
deriv Complex.Gamma ↑x = ↑(deriv Real.Gamma x)?? — the bridge: consider fun x : ℝ => Complex.Gamma ↑x = ↑∘ Real.Gamma — deriv: deriv (↑∘g) x = ↑(deriv g x) — via ofRealCLM: `Complex.ofRealCLM.hasDerivAt`... The statement: deriv (fun x : ℝ => (↑(g x) : ℂ)) x = ↑(deriv g x) — provable via HasDerivAt.comp: HasDerivAt g (g' x) x (real differentiability) + HasDerivAt ofReal 1 (g x)... hmm ofReal as a function ℝ → ℂ has derivative 1 (ofRealCLM 1 = 1): HasDerivAt ofReal 1 (g x)?? — ofReal : ℝ → ℂ — its derivative as a real-to-complex map: ofRealCLM — `Complex.ofRealCLM.hasDerivAt (x := g x)`? — from LiPrincipal: `Complex.ofRealCLM.hasDerivAt (x := x)` gave HasDerivAt (fun t : ℝ => (t:ℂ)) 1 x — hmm — ofRealCLM.hasDerivAt : HasDerivAt Complex.ofRealCLM (ofRealCLM) ... — the CLM's derivative is itself: HasDerivAt ofRealCLM (ofRealCLM) x?? and ofRealCLM vs ofReal: ofRealCLM_apply : ofRealCLM x = ↑x ✓ — so HasDerivAt (fun t => (↑t:ℂ)) 1 x ✓ (LiPrincipal's usage). Then comp: HasDerivAt (↑∘g) ((g' x) • 1)?? — order f'∘g': the comp for ℝ→ℝ→ℂ: HasDerivAt.comp — the algebra tower — result deriv = g' • (ofReal-deriv) = g' · 1... = ↑g' — via smul — the session-016 note: "HasDerivAt.comp handles mixed fields via NormedAlgebra/IsScalarTower" ✓. Result: HasDerivAt (fun x => ↑(g x)) (↑(g' x)) x — then .deriv ✓. There might be a slicker existing lemma (`Complex.deriv_ofReal`? `ofReal_deriv`?) — I'll try `Complex.deriv_ofReal` first; else the comp dance.
Then digamma ↑x = ↑(Real.Gamma' x)/↑(Real.Gamma x) = ↑(Real.Gamma' x / Real.Gamma x) = ↑(Dinf x) ✓.
Hmm wait — one more subtlety: deriv Complex.Gamma ↑x vs deriv (Complex.Gamma ∘ ofReal) x: I need the COMPLEX derivative of Complex.Gamma at ↑x — from the real-line: digamma is analytic at ↑x (x > 0, no poles) — the complex deriv at ↑x equals the real-line deriv: deriv (Complex.Gamma ∘ ofReal) x = deriv Complex.Gamma ↑x · deriv ofReal x = deriv Complex.Gamma ↑x · 1 — via HasDerivAt.comp the other direction: HasDerivAt (Complex.Gamma ∘ ofReal) (deriv Complex.Gamma ↑x * 1) x — so deriv (Complex.Gamma∘ofReal) x = deriv Complex.Gamma ↑x ✓ — combined with = ↑(Real.Gamma' x) — get deriv Complex.Gamma ↑x = ↑(Real.Gamma' x) ✓.
OK and Part 3 (the iterated derivatives of Dinf) and the reindexing... This is a big file. Let me build it incrementally — start with Part 2's infrastructure now: the summability + the uniform convergence. Let me carefully write the first chunk and compile.
Actually, let me reconsider the overall Lean encoding once more for the SERIES. There's a choice: model Dinf directly as a tsum:
`Dinf (x : ℝ) : ℝ := -Real.eulerMascheroniConstant - 1 / x + ∑' m : ℕ, (1 / (m + 1 : ℝ) - 1 / (x + m + 1))`
Summability of Σ_m (1/(m+1) − 1/(x+m+1)): |term| = x/((m+1)(x+m+1)) ≤ x/(m+1)² for x > 0. Dominator: x/(m+1)² — Summable: `Real.summable_one_div_nat_pow` is for fun n => 1/(n:ℝ)^p over ℕ — the (m+1) shift: summable_nat_add_iff 1 : Summable (fun n => f (n+1)) ↔ Summable f — with f n := x/(n:ℝ)² — f (m+1) = x/(m+1)² ✓ and f 0 = x/0 = 0 — Summable f ⟸ Real.summable_one_div_nat_pow.mpr (1<2) — that's for 1/n^p — x/(n)² = x·(1/n²) — Summable.mul_left ✓. Then comparison via `summable_of_nonneg_of_le`? — wait that's Summable.of_nonneg_of_le (from session 018: args (0 ≤ g) (g ≤ f) (Summable f) : Summable g ✓).
Uniform convergence of partial sums on compacts: `tendstoUniformlyOn_tsum`? — let me check the exact name in TsumUniformlyOn.lean. Then locally uniform on Ioi 0 via compacts.
Let me check TsumUniformlyOn names.
Part 1 committed (0b4133e). Starting Part 2 — the real digamma series. Checking the uniform-tsum lemma names first.
tool: Bash
input
{
"command": "cd \"D:/Python/Quantum/zeta-23-lean/.lake/packages/mathlib\" && grep -n \"theorem\\|lemma\" Mathlib/Topology/Algebra/InfiniteSum/TsumUniformlyOn.lean | head -12",
"description": "List TsumUniformlyOn lemmas"
}
raw content_json (database row)
[{"type":"thinking","thinking":"Part 1 committed (0b4133e). Now — the digamma series (Part 2). It's ~23:05. This is the heavy rock. Let me start it carefully. \n\nPlan for Part 2 (the real digamma series):\n\n```lean\n/-- The summand of the digamma series: u_m(x) = 1/m − 1/(x+m) for m ≥ 1. -/\ndef digammaSummand (x : ℝ) (m : ℕ) : ℝ := if m = 0 then 0 else (1 / (m : ℝ) - 1 / (x + m))\n```\nHmm — the indexing: the series is Σ_{m≥1} (1/m − 1/(x+m)). Cleaner: define on ℕ with the m=0 term = 0 (junk) or index from m+1. Let me use m+1 indexing: u x m := 1/(m+1) − 1/(x + m + 1) for m : ℕ. Then Σ_{m} u x m = Σ_{m≥1} (1/m − 1/(x+m)) ✓. Summability: |u x m| = x/((m+1)(x+m+1)) ≤ x/(m+1)² for x > 0 — vs summable_one_div_nat_pow-ish — need Σ 1/(m+1)² summable — the p-series at p = 2 shifted — `Real.summable_one_div_nat_pow.mpr (1 < 2)` gives Σ 1/n² over ℕ — with n = 0 term 1/0 = 0 junk fine. Comparison: u x m ≤ x/(m+1)²... the dominator x·(1/(m+1)²) — summable ✓ via the p-series + shift. Actually simpler: 1/(m+1)² vs 1/(m')² with m' = m+1: `summable_nat_add_iff`? — `summable_nat_add_iff (k) : Summable (fun n => f (n + k)) ↔ Summable f` ✓ exists. So Summable (fun m => 1/((m:ℝ)+1)^2) via summable_nat_add_iff 1 + the p-series ✓.\n\nThe main lemma (A2): the function sequence digammaRealSeq x n := Real.log n − Σ_{m ∈ range (n+1)} 1/(x+m) converges locally uniformly on (0,∞) to Dinf(x) := −γ − 1/x + Σ_{m≥1}(1/m − 1/(x+m)).\n\nDecompose: digammaRealSeq x n = (log n − H_n) + Σ_{m=1}^n (1/m − 1/(x+m)) − 1/x.\n- H_n = Σ_{m=1}^n 1/m = Σ_{m ∈ range(n+1)} 1/m (m=0 term is 1/0 = 0 junk — harmonic n := Σ_{i ∈ range n} 1/(i+1)? — Mathlib's `harmonic n := ∑ i ∈ Finset.range n, (i+1)⁻¹`? — harmonic n = Σ_{i<n} 1/(i+1) ✓. So Σ_{m ∈ range(n+1)} 1/(x+m) = 1/x + Σ_{m=1}^n 1/(x+m) = 1/x + Σ_{i ∈ range n} 1/(x + (i+1))... — the reindexings are fiddly but fine.\n- The three pieces: (log n − H_n) → −γ (tendsto_harmonic_sub_log ✓); the series partial sums → tsum locally uniformly (M-test); −1/x constant.\n\nTendstoLocallyUniformlyOn assembly from the pieces: TendstoLocallyUniformlyOn.add etc. ✓ (there are .add/.const lemmas for locally uniform — `TendstoLocallyUniformlyOn.add` ✓ exists presumably).\n\nThen (A3): deriv (Real.log ∘ Real.Gamma) = D∞ on (0,∞) via hasDerivAt_of_tendstoLocallyUniformlyOn with:\n- f_n := fun x => logGammaSeq x n; g := Real.log ∘ Real.Gamma; f'_n := digammaRealSeq · n; g' := Dinf.\n- hfg : ∀ x ∈ Ioi 0, Tendsto (fun n => logGammaSeq x n) atTop (𝓝 (log (Gamma x))) ✓ = tendsto_log_gamma.\n- hf : ∀ᶠ n, ∀ x ∈ Ioi 0, HasDerivAt (fun x => logGammaSeq x n) (digammaRealSeq x n) x — deriv of x·log n + log n! − Σ_{m≤n} log(x+m) = log n − Σ 1/(x+m) — termwise deriv of log(x+m) = 1/(x+m) (Real.deriv_log_comp or hasDerivAt_log... — `Real.hasDerivAt_log (hx : x ≠ 0) : HasDerivAt log (1/x) x` ✓ + comp with x+m ✓). logGammaSeq is defined with `∑ m ∈ Finset.range (n + 1), log (x + m)` ✓ deriv_sum ✓.\n- hf' : TendstoLocallyUniformlyOn digammaRealSeq Dinf atTop (Ioi 0) — from (A2).\nThen HasDerivAt (Real.log ∘ Real.Gamma) (Dinf x) x for x ∈ Ioi 0 — and deriv (Real.log ∘ Real.Gamma) x = Dinf x.\n\nHmm wait — one subtlety: hasDerivAt_of_tendstoLocallyUniformlyOn's g is the POINTWISE limit of f n — here g := fun x => log (Real.Gamma x) — hfg gives Tendsto (f n x) → (𝓝 (log (Gamma x))) — and g x := (Real.log ∘ Real.Gamma) x = log (Gamma x) ✓.\n\nThen: deriv (Real.log ∘ Real.Gamma) x = Real.Gamma' x / Real.Gamma x — deriv of log∘Gamma: (Real.hasDerivAt_log (Gamma x ≠ 0)).comp-with-Gamma'... — need Real.Gamma differentiable at x (Real.differentiableAt_Gamma ✓ for x > 0 — the hypothesis ∀ m, x ≠ −m ✓ since x > 0) and log at Gamma x (Gamma x > 0 ≠ 0 ✓ Real.Gamma_pos_of_pos). So ψ_real x := deriv Real.Gamma x / Real.Gamma x = Dinf x ✓.\n\nThe complex bridge (Part 4): Complex.digamma ↑x = ↑(Dinf x): \ndigamma ↑x = deriv Complex.Gamma ↑x / Complex.Gamma ↑x. \nComplex.Gamma ↑x = ↑(Real.Gamma x) (Complex.Gamma_ofReal ✓).\nderiv Complex.Gamma ↑x = ↑(deriv Real.Gamma x)?? — the bridge: consider fun x : ℝ => Complex.Gamma ↑x = ↑∘ Real.Gamma — deriv: deriv (↑∘g) x = ↑(deriv g x) — via ofRealCLM: `Complex.ofRealCLM.hasDerivAt`... The statement: deriv (fun x : ℝ => (↑(g x) : ℂ)) x = ↑(deriv g x) — provable via HasDerivAt.comp: HasDerivAt g (g' x) x (real differentiability) + HasDerivAt ofReal 1 (g x)... hmm ofReal as a function ℝ → ℂ has derivative 1 (ofRealCLM 1 = 1): HasDerivAt ofReal 1 (g x)?? — ofReal : ℝ → ℂ — its derivative as a real-to-complex map: ofRealCLM — `Complex.ofRealCLM.hasDerivAt (x := g x)`? — from LiPrincipal: `Complex.ofRealCLM.hasDerivAt (x := x)` gave HasDerivAt (fun t : ℝ => (t:ℂ)) 1 x — hmm — ofRealCLM.hasDerivAt : HasDerivAt Complex.ofRealCLM (ofRealCLM) ... — the CLM's derivative is itself: HasDerivAt ofRealCLM (ofRealCLM) x?? and ofRealCLM vs ofReal: ofRealCLM_apply : ofRealCLM x = ↑x ✓ — so HasDerivAt (fun t => (↑t:ℂ)) 1 x ✓ (LiPrincipal's usage). Then comp: HasDerivAt (↑∘g) ((g' x) • 1)?? — order f'∘g': the comp for ℝ→ℝ→ℂ: HasDerivAt.comp — the algebra tower — result deriv = g' • (ofReal-deriv) = g' · 1... = ↑g' — via smul — the session-016 note: \"HasDerivAt.comp handles mixed fields via NormedAlgebra/IsScalarTower\" ✓. Result: HasDerivAt (fun x => ↑(g x)) (↑(g' x)) x — then .deriv ✓. There might be a slicker existing lemma (`Complex.deriv_ofReal`? `ofReal_deriv`?) — I'll try `Complex.deriv_ofReal` first; else the comp dance.\n\nThen digamma ↑x = ↑(Real.Gamma' x)/↑(Real.Gamma x) = ↑(Real.Gamma' x / Real.Gamma x) = ↑(Dinf x) ✓.\n\nHmm wait — one more subtlety: deriv Complex.Gamma ↑x vs deriv (Complex.Gamma ∘ ofReal) x: I need the COMPLEX derivative of Complex.Gamma at ↑x — from the real-line: digamma is analytic at ↑x (x > 0, no poles) — the complex deriv at ↑x equals the real-line deriv: deriv (Complex.Gamma ∘ ofReal) x = deriv Complex.Gamma ↑x · deriv ofReal x = deriv Complex.Gamma ↑x · 1 — via HasDerivAt.comp the other direction: HasDerivAt (Complex.Gamma ∘ ofReal) (deriv Complex.Gamma ↑x * 1) x — so deriv (Complex.Gamma∘ofReal) x = deriv Complex.Gamma ↑x ✓ — combined with = ↑(Real.Gamma' x) — get deriv Complex.Gamma ↑x = ↑(Real.Gamma' x) ✓.\n\nOK and Part 3 (the iterated derivatives of Dinf) and the reindexing... This is a big file. Let me build it incrementally — start with Part 2's infrastructure now: the summability + the uniform convergence. Let me carefully write the first chunk and compile.\n\nActually, let me reconsider the overall Lean encoding once more for the SERIES. There's a choice: model Dinf directly as a tsum:\n`Dinf (x : ℝ) : ℝ := -Real.eulerMascheroniConstant - 1 / x + ∑' m : ℕ, (1 / (m + 1 : ℝ) - 1 / (x + m + 1))`\n\nSummability of Σ_m (1/(m+1) − 1/(x+m+1)): |term| = x/((m+1)(x+m+1)) ≤ x/(m+1)² for x > 0. Dominator: x/(m+1)² — Summable: `Real.summable_one_div_nat_pow` is for fun n => 1/(n:ℝ)^p over ℕ — the (m+1) shift: summable_nat_add_iff 1 : Summable (fun n => f (n+1)) ↔ Summable f — with f n := x/(n:ℝ)² — f (m+1) = x/(m+1)² ✓ and f 0 = x/0 = 0 — Summable f ⟸ Real.summable_one_div_nat_pow.mpr (1<2) — that's for 1/n^p — x/(n)² = x·(1/n²) — Summable.mul_left ✓. Then comparison via `summable_of_nonneg_of_le`? — wait that's Summable.of_nonneg_of_le (from session 018: args (0 ≤ g) (g ≤ f) (Summable f) : Summable g ✓).\n\nUniform convergence of partial sums on compacts: `tendstoUniformlyOn_tsum`? — let me check the exact name in TsumUniformlyOn.lean. Then locally uniform on Ioi 0 via compacts.\n\nLet me check TsumUniformlyOn names.","signature":""},{"type":"text","text":"Part 1 committed (0b4133e). Starting Part 2 — the real digamma series. Checking the uniform-tsum lemma names first."},{"type":"tool_use","id":"Bash_292","name":"Bash","input":{"command":"cd \"D:/Python/Quantum/zeta-23-lean/.lake/packages/mathlib\" && grep -n \"theorem\\|lemma\" Mathlib/Topology/Algebra/InfiniteSum/TsumUniformlyOn.lean | head -12","description":"List TsumUniformlyOn lemmas"},"extra_content":null}]