Current task: —

← Session 28 — ii′-5e: partial-fraction identity (zero series + F entire)

#1491 assistant 2026-08-23 15:01:30.164 UTC · 1016→5591 tok open ⤢
thinking (13710 chars)
Excellent — Zeta23 ALREADY has the full classification: - `RvM.completedRiemannZeta_eq_zero_iff : completedRiemannZeta s = 0 ↔ IsNontrivialZero s` (Λ zeros = nontrivial zeros, everywhere). So my classification: ζ s = 0, re s ≤ 0, s ≠ 0, Gammaℝ s ≠ 0 ⟹ Λ s = ΓR s · ζ s = 0 (via `RvM.completedRiemannZeta_eq_Gammaℝ_mul (hs : s ≠ 0) (hG : Gammaℝ s ≠ 0)`) ⟹ IsNontrivialZero s ⟹ 0 < re — contra. So: `zeta_zero_classification : riemannZeta s = 0 → IsNontrivialZero s ∨ s = 0 ∨ ∃ n : ℕ, 1 ≤ n ∧ s = -2 * n`: - re ≥ 1: riemannZeta_ne_zero_of_one_le_re — check exact signature: used in LiDisc as `riemannZeta_ne_zero_of_one_le_re h h2` with h : 1 ≤ ρ.re (from push Not), h2 : ζ ρ = 0 giving False ⟹ signature (h : 1 ≤ s.re) : riemannZeta s ≠ 0 ✓ (Mathlib). - 0 < re < 1: nontrivial ✓. - re ≤ 0: s = 0? yes → middle disjunct. no: Gammaℝ s = 0? yes → Gammaℝ_eq_zero_iff: s = -2*↑m: m = 0: s = 0 — wait s ≠ 0 case... m = 0 gives s = 0 contradiction with h0 — so m ≥ 1 ⟹ third disjunct (s = −2·↑m — need the exact form: Gammaℝ_eq_zero_iff : Gammaℝ s = 0 ↔ ∃ m : ℕ, s = -2 * m — from LiDisc: `rw [Complex.Gammaℝ_eq_zero_iff] at hG; obtain ⟨n, hn⟩ := hG; rw [hn]; ...` and `hre' : ρ.re = -2 * (n:ℝ)` via simp [neg_re, mul_re] — so hn : ρ = -2 * (n:ℂ)?? with the cast -2 * ↑n: (-2 * ↑n).re = -2n ✓. The exact ℂ form: `s = -(2 * (m : ℂ))` or `s = -2 * (m : ℂ)` — adapt with whatever; my disjunct: ∃ n ≥ 1, s = -2 * (n : ℂ).) no: Λ s = 0 via the product ⟹ IsNontrivialZero s ⟹ 0 < re contra ✓. Wait — simpler: actually could I skip Gammaℝ_eq_zero_iff case: ζ s = 0, re ≤ 0, s ≠ 0: if Gammaℝ s ≠ 0: Λ s = 0 ⟹ nontrivial ⟹ contra re ≤ 0. So Gammaℝ s = 0 ⟹ s = −2m (m ≥ 1 since s ≠ 0 ⟹ m ≠ 0 ✓). ✓ as planned. integerComplement: `Complex.integerComplement := (Set.range ((↑) : ℤ → ℂ))ᶜ` — membership: z ∈ ℂ_ℤ... (notation ℂ_ℤ?) — `z ∈ Complex.integerComplement ↔ ∀ n : ℤ, z ≠ n` presumably via compl range: z ∉ range ⟺ ∀ n, (n:ℂ) ≠ z... direction care: `Set.mem_compl_iff`, `Set.mem_range`. There are helper lemmas: integerComplement.ne_zero, integerComplement_add_ne_zero, add_intCast_mem_integerComplement. For my use: s/2 ∈ integerComplement for s near 0 (s ≠ 0, ‖s‖ < 1): if s/2 = (n : ℤ) for some n: |n| = ‖s/2‖ < 1/2 ⟹ n = 0 ⟹ s = 0 contra ✓. And for w near −n (n ≥ 1): w = (k : ℤ) with ‖w+n‖ < 1/2 ⟹ |k + n| < 1/2 ⟹ k = −n ⟹ w = −n — excluded punctured... For the M-test at −n I need the domain (ball(−n, 1/2) minus the point −n?) — no wait: the M-test for H_n's series analyticity is on the open ball ball(−n, 1/2) INCLUDING −n: the terms of H_n are analytic AT −n too (the pole term j = n−1 removed) ✓ — the series for H_n is the digamma series MINUS its j = n−1 term: H_n(w) := −γ − 1/w + ∑' j, (if j = n−1 then 0 else (1/(j+1) − 1/(w+j+1)))... For the M-test on ball(−n, 1/2): terms j ≠ n−1: 1/(j+1) − 1/(w+j+1): poles at w = −(j+1): for j ≠ n−1, −(j+1) ≠ −n ✓ and ‖−(j+1) − (−n)‖ = |n−j−1| ≥ 1 ⟹ ball(−n, 1/2) avoids all of them ✓. Uniform bound: ‖1/(j+1) − 1/(w+j+1)‖ = ‖w‖/((j+1)·‖w+j+1‖): hmm this needs w ≠ 0 for the algebra but the bound is general: 1/(j+1) − 1/(w+j+1) = w/((j+1)(w+j+1)) ✓ (j+1 ≠ 0, w+j+1 ≠ 0 on the domain ✓). ‖w‖ ≤ n + 1/2; ‖w+j+1‖: for j ≠ n−1: ≥ |n − (j+1)| − 1/2 ≥ 1/2. That gives ‖term‖ ≤ (n+1/2)·2/(j+1) — NOT summable (harmonic)! Need better for large j: for j ≥ 2n: ‖w+j+1‖ ≥ (j+1) − ‖w‖ ≥ (j+1)/2 ✓ (since ‖w‖ ≤ n+1/2 ≤ (j+1)/2 when j+1 ≥ 2n+1 ✓): ‖term‖ ≤ 2(n+1/2)/(j+1)² ✓ summable. So use the EVENTUALLY-form M-test (of_norm_le_summable_eventually) with the finite head j < 2n unconstrained — but wait: uniform convergence needs every term individually... the eventually-form handles it: head terms just need to be finite functions (they are, on the domain — poles avoided ✓) — and for the DIFFERENTIABILITY of partial sums, each term differentiable on the domain ✓ (poles avoided). ✓. Similarly for the s=0 case: the full digamma series on ball(0, 1/2): terms 1/(j+1) − 1/(w+j+1): poles at −(j+1) ≤ −1: ball(0,1/2) avoids ✓; bound: ‖w‖ ≤ 1/2, ‖w+j+1‖ ≥ (j+1) − 1/2 ≥ (j+1)/2 ⟹ ‖term‖ ≤ 1/(j+1)²·... ‖w‖/((j+1)(j+1)/2) = 2‖w‖/(j+1)² ≤ 1/(j+1)² ✓ summable (summable_div_add_one_sq from LiDigamma ✓). ALL terms (no eventually needed) ✓ — matches LiDigamma's `summable_div_add_one_sq 1` usage. Now — plan the file LiFEntire.lean. Actually, name it per convention: the 5e files are LiGapCircles (5e-i), LiDigammaLeft (5e-ii), LiSeries (5e-iii) — 5e-iv: `LiFEntire.lean`. Structure: ```lean /- header: ii′-5e-iv (D-068 §4): F entire via principal-part splits + the limUnder extension -/ import Mathlib import Zeta23.Statement import Zeta23.Statement.SeamClosed import Zeta23.GammaFacts.Series (digamma_series) import Zeta23.RvM.CountByIntegral (?? — for completedRiemannZeta facts; check what LiDisc imports) import NguyenRH1.LiSeries import NguyenRH1.LiTrivialZeros (zeroMult_neg_two_mul) Definitions: def Fexpr (s : ℂ) : ℂ := logDeriv riemannZeta s - seriesFun s + 1/s + 1/(s-1) - (Real.log π)/2 + Complex.digamma (s/2)/2 Hmm wait — check the exact target identity signs once more (D-068 §0): ζ′/ζ(s) = B + Σ m(1/(s−ρ)+1/ρ) − 1/s − 1/(s−1) + ½log π − ½ψ(s/2) ⟹ F := ζ′/ζ − series + 1/s + 1/(s−1) − ½logπ + ½ψ(s/2) ≡ B. ✓ def badPoint (s : ℂ) : Prop := IsNontrivialZero s ∨ s = 0 ∨ s = 1 ∨ ∃ n : ℕ, 1 ≤ n ∧ s = -2 * (n : ℂ) Section A: helpers A1. analyticAt_digamma {w} (hw : ∀ m : ℕ, w ≠ -m) : AnalyticAt ℂ digamma w A2. zeta_zero_classification {s} (hs : riemannZeta s = 0) : IsNontrivialZero s ∨ s = 0 ∨ ∃ n ≥ 1... A3. logDeriv h analyticity at zeros: the NF punctured form — per nontrivial zero ρ₀: exists analytic W with (fun s => logDeriv ζ s − m/(s−ρ₀)) =ᶠ[𝓝[≠] ρ₀] W. From the NF: obtain ⟨h, hh, hh0, hfh⟩; W := logDeriv h... need h analytic on a BALL (not just at ρ₀): hh.eventually_analyticAt : ∀ᶠ z in 𝓝 ρ₀, AnalyticAt ℂ h z ✓ (AnalyticAt.eventually_analyticAt ✓ used in LiSides line 379) + hh.continuousAt.eventually_ne hh0 (h ≠ 0 nearby) ⟹ on a ball: logDeriv h = deriv h/h differentiable... AnalyticAt at the CENTER: logDeriv h analytic at ρ₀: (hh.deriv).div hh0 — AnalyticAt.deriv : AnalyticAt f x → AnalyticAt (deriv f) x ✓ check name; AnalyticAt.div : AnalyticAt f → AnalyticAt g → g x ≠ 0 → AnalyticAt (f/g) ✓. Punctured equality: logDeriv ζ s = m/(s−ρ₀) + logDeriv h s for s near ρ₀, s ≠ ρ₀, h s ≠ 0, h analytic at s: the LiSides Rfun_residue_at block has exactly this (hld : logDeriv riemannZeta s = m/(s−ρ) + logDeriv h s — lines 384-397) ✓ reuse pattern. A4. At 1: logDeriv_zetaA relation punctured. A5. At −2n: analyticOrderNatAt riemannZeta (−2n) = 1 — from zeroMult_neg_two_mul (zeroMult = analyticOrderNatAt? zeroMult ρ := (analyticOrderAt riemannZeta ρ).toNat; and analyticOrderNatAt = analyticOrderAt.toNat? check LiTrivialZeros: they proved zeroMult(−2n) = 1 via analyticOrderAt_eq_natCast — analyticOrderNatAt riemannZeta (−2n) = 1 — and zeroMult = analyticOrderNatAt? In LiSides line 401: `have hmz : (zeroMult ρ : ℂ) = (analyticOrderNatAt riemannZeta ρ : ℂ) := rfl` — zeroMult IS analyticOrderNatAt by rfl ✓. So analyticOrderNatAt ζ (−2n) = 1 ✓ from zeroMult_neg_two_mul by the rfl. Then the NF at −2n: logDeriv ζ s = 1/(s+2n) + logDeriv h s punctured; h analytic nonzero at −2n ✓. A6. Digamma splits: at 0: on ball(0, 1/2): digamma w = −γ − 1/w + S₀(w) where S₀ := ∑' j, (1/(j+1) − 1/(w+j+1)) — need this for w ∈ ball(0,1/2), w ≠ 0 (integerComplement ✓). S₀ analytic on the whole ball (M-test incl. w = 0 ✓ terms fine at 0: 1/(j+1) − 1/(j+1) = 0... at w = 0 the term is 0 ✓ analytic ✓). Define digammaSeriesPart (w) := ∑' j : ℕ, (1/(j+1) − 1/(w+j+1)); analytic on ball(0, 1/2) via M-test ✓ (5e-iii pattern); agreement: for w ∈ ball, w ≠ 0: digamma w = −γ − 1/w + digammaSeriesPart w (digamma_series, integerComplement: w ∈ ball(0,1/2), w ≠ 0 ⟹ w ∉ ℤ ✓). at −n (n ≥ 1): digammaSeriesPartSub n w := ∑' j, if j = n−1 then 0 else (1/(j+1) − 1/(w+j+1)); analytic on ball(−n, 1/2) (M-test eventually-form); agreement: for w ∈ ball, w ≠ −n: digamma w = −γ − 1/w + digammaSeriesPartSub n w + (1/n − 1/(w+n)) — hmm the single-term tsum split: ∑' full = ∑' sub + (1/n − 1/(w+n)) via tsum_eq_single-style as in 5e-iii §5 ✓ (single_summable pattern). So digamma w + 1/(w+n) = −γ − 1/w + digammaSeriesPartSub n w + 1/n (analytic at −n: 1/w fine (w near −n ≠ 0 ✓)) — define H_n w := −γ − 1/w + digammaSeriesPartSub n w + 1/n: analytic at −n, punctured agreement digamma w = −1/(w+n) + H_n w. Then for the F-expr at s near −2n: digamma(s/2)/2 = (−1/(s/2+n) + H_n(s/2))/2 = −1/(s+2n) + H_n(s/2)/2. A7. Generic analyticity of Fexpr at good points + continuity. A8. The per-bad-point witnesses A + punctured agreements. A9. G := fun s => limUnder (𝓝[≠] s) Fexpr; G_eq_Fexpr at good points; G analytic everywhere. Capstone theorem: theorem exists_entire_eq_Fexpr : ∃ G : ℂ → ℂ, (∀ s, AnalyticAt ℂ G s) ∧ ∀ s, ¬ badPoint s → G s = Fexpr s ``` Wait — one issue in A9's good-point case: G =ᶠ Fexpr near good s needs a ball of good points; the ball: ζ ≠ 0 ball (continuity at s, s ≠ 1) ∩ ball avoiding {0, 1} (s ≠ 0, s ≠ 1 — finite set distance) — every y in the ball: ζ y ≠ 0 ⟹ y not a zero ⟹ y not nontrivial (def .1), y not −2n (ζ(−2n) = 0), y ∉ {0,1} ⟹ y good ✓. ζ(−2n) = 0 — need: riemannZeta (−2n) = 0 for n ≥ 1: from zeroMult_neg_two_mul (zeroMult = order.toNat = 1 ≠ 0 ⟹ ζ(−2n) = 0? analyticOrderAt.toNat = 1 means the order is 1 — is there a direct lemma ζ(−2n) = 0? `riemannZeta_neg_two_mul`? hmm — Zeta23/Mathlib: `riemannZeta_neg_nat_eq...`? There might be `riemannZeta_neg_two_mul` or via the NF: ζ = (z+2n)¹·h near ⟹ ζ(−2n) = 0·h = 0 ✓ (evaluate the EventuallyEq at the point: self_of_nhds ✓). OK fine. Alternatively — for y to be NOT a bad point I need: ¬(IsNontrivialZero y ∨ y = 0 ∨ y = 1 ∨ ∃ n ≥ 1, y = −2n): nontrivial ⟹ ζ y = 0 contra ✓; y = 0/1 excluded by ball ✓; y = −2n ⟹ ζ y = 0 contra (needs ζ(−2n) = 0 ✓). ✓. Now — how big is this file? Estimating: A1 ~40, A2 ~60, A3 ~80, A4 ~50, A5 ~60, A6 ~200 (two M-tests + splits), A7 ~60, A8 ~80 (four witness assemblies), A9 ~120 (the limUnder gluing). Total ~700–800 lines. That's a full session or more. This is consistent with D-068's 0.5 estimate... maybe optimistic but fine. Sub-stage protocol: I could split 5e-iv into two commits: (a) helpers A1–A2 + digamma splits A6; (b) the zero/one/trivial splits + G assembly. Let me aim for one session with an intermediate commit. Let me check a few more API names before writing: - `AnalyticAt.deriv` — exists? grep. - `AnalyticAt.div` — exists? (used somewhere in Li files?) - `AnalyticAt.eventually_analyticAt` ✓ (LiSides 379). - `Tendsto.limUnder_eq` / how to compute limUnder: `tendsto_nhds_limUnder : (∃ x, Tendsto g f (𝓝 x)) → Tendsto g f (𝓝 (limUnder f g))` (line 232 above ✓!). So: if the punctured limit exists, limUnder is it: uniqueness: if Tendsto f (𝓝[≠]s) (𝓝 L) then limUnder = L: from tendsto_nhds_limUnder ⟨L, h⟩ : Tendsto f .. (𝓝 (limUnder)) + h + NeBot + T2 ⟹ tendsto_nhds_unique ✓ (needs NeBot (𝓝[≠] s) — ℂ: `nhdsWithin_neBot`? instance `NeBot (𝓝[≠] s)` for ℂ — (𝓝[≠] s).NeBot via `instNeBot...`? For a perfect space: `nhdsWithin_neBot_of...`. Mathlib has `NeBot (𝓝[≠] x)` instance for NontriviallyNormedField? or PerfectSpace: `PerfectSpace` ℂ? Hmm — there IS `instNeBotNhdsWithinCompl...`? Let me grep quickly for how Li files or Mathlib derive Tendsto within punctured ℂ. - logDeriv API: `logDeriv_apply : logDeriv f x = deriv f x / f x` ✓; `logDeriv_mul` (used in LiSides: `logDeriv_mul (f) (g) s (hfgs : f s ≠ 0) (hgs : g s ≠ 0) (hf : DifferentiableAt...) (hg)`? from LiSides line 389-390: `logDeriv_mul (f := ...) (g := h) s (pow_ne_zero _ hsρ') hhs (by fun_prop) hhas.differentiableAt` — so signature: logDeriv_mul (hfx : f x ≠ 0) (hgx : g x ≠ 0) (hf : DifferentiableAt...) (hg)?? order: (f g) s (h1 : f s ≠ 0) (h2 : g s ≠ 0) (h3 : DifferentiableAt f s) (h4 : DifferentiableAt g s)? The LiSides call: `logDeriv_mul (f := fun z => (z − ρ) ^ analyticOrderNatAt riemannZeta ρ) (g := h) s (pow_ne_zero _ hsρ') hhs (by fun_prop) hhas.differentiableAt` — so positional after s: (f s ≠ 0) (g s ≠ 0) (DifferentiableAt f) (DifferentiableAt g) — wait hhs : h s ≠ 0 ✓ second; (by fun_prop) : DifferentiableAt ℂ (fun z => (z−ρ)^m) s ✓ third; hhas.differentiableAt : hhas : AnalyticAt ℂ h s → .differentiableAt ✓ fourth. So logDeriv_mul x hfx hgx hfd hgd : logDeriv (f * g) x = logDeriv f x + logDeriv g x ✓. - logDeriv (fun z => z − ρ) = 1/(z−ρ): from LiSides e2 pattern: logDeriv_comp + logDeriv_pow... for (z−ρ): `logDeriv (fun z => z - ρ) s = 1/(s−ρ)`: logDeriv_sub_const? or via (differentiableAt_id.sub ...).logDeriv? There's `logDeriv_id`... I'll compute: logDeriv (fun z => z − ρ) s = deriv (z−ρ)/... = 1/(s−ρ): `(differentiableAt_id.sub (differentiableAt_const _)).logDeriv`?? logDeriv of a function at a point isn't from DifferentiableAt — logDeriv is DEFINED as deriv/f. So logDeriv (fun z => z−ρ) s = deriv (fun z => z−ρ) s / (s−ρ) = 1/(s−ρ): via logDeriv_apply + deriv of id.sub const = 1: `(differentiableAt_id.sub (differentiableAt_const ρ)).deriv` : deriv (fun z => z − ρ) s = 1... then simp [logDeriv_apply, that]. Fine. - For the +4 shift there's `logDeriv_Gammaℝ_shift` (5d) — not needed here. - zetaA logDeriv at 1: `AnalyticAt ℂ (logDeriv zetaA) 1`? hmm — I actually need the WITNESS function analytic at 1 agreeing with logDeriv ζ + 1/(s−1) punctured. W := logDeriv zetaA: analytic at 1 ✓ (zetaA analytic, zetaA 1 = 1 ≠ 0: AnalyticAt.deriv + AnalyticAt.div). Punctured: logDeriv ζ s + 1/(s−1) = logDeriv zetaA s for s ≠ 1 near 1: logDeriv zetaA s = logDeriv ((s−1)ζ s) (zetaA_apply) = 1/(s−1) + logDeriv ζ s (logDeriv_mul, needs ζ s ≠ 0: punctured near 1 via zetaA ≠ 0 ball: ζ s = zetaA s/(s−1) ≠ 0 ✓). Let me check `AnalyticAt.deriv` and `AnalyticAt.div` names.
Zeta23 already has the full classification fact (`completedRiemannZeta_eq_zero_iff`). Checking the last API pieces: `AnalyticAt.deriv`/`.div` and the limUnder uniqueness route.
tool: Bash
input
{
  "command": "cd D:/Python/Quantum/zeta-23-lean/.lake/packages/mathlib && grep -rn \"theorem AnalyticAt.deriv\\b\\|protected theorem AnalyticAt.deriv\\b\" Mathlib/Analysis/Analytic/*.lean Mathlib/Analysis/Calculus/*.lean -r | head -3; grep -rn \"theorem AnalyticAt.div\\b\\|AnalyticAt.div \" Mathlib/Analysis/Analytic/Constructions.lean | head -3; grep -rn \"tendsto_nhds_unique\\b\" Mathlib/Topology/Basic.lean | head -2; grep -rn \"NeBot.*nhdsWithin.*compl\\|instNeBot.*Punctured\\|nhdsWithin.*NeBot\" Mathlib/Analysis/ -r --include=*.lean | grep -i \"instance\\|theorem.*NeBot\" | head -5",
  "description": "Check AnalyticAt.deriv/div, tendsto_nhds_unique, NeBot punctured"
}
raw content_json (database row)
[{"type":"thinking","thinking":"Excellent — Zeta23 ALREADY has the full classification:\n- `RvM.completedRiemannZeta_eq_zero_iff : completedRiemannZeta s = 0 ↔ IsNontrivialZero s` (Λ zeros = nontrivial zeros, everywhere).\n\nSo my classification: ζ s = 0, re s ≤ 0, s ≠ 0, Gammaℝ s ≠ 0 ⟹ Λ s = ΓR s · ζ s = 0 (via `RvM.completedRiemannZeta_eq_Gammaℝ_mul (hs : s ≠ 0) (hG : Gammaℝ s ≠ 0)`) ⟹ IsNontrivialZero s ⟹ 0 < re — contra. So:\n\n`zeta_zero_classification : riemannZeta s = 0 → IsNontrivialZero s ∨ s = 0 ∨ ∃ n : ℕ, 1 ≤ n ∧ s = -2 * n`:\n- re ≥ 1: riemannZeta_ne_zero_of_one_le_re — check exact signature: used in LiDisc as `riemannZeta_ne_zero_of_one_le_re h h2` with h : 1 ≤ ρ.re (from push Not), h2 : ζ ρ = 0 giving False ⟹ signature (h : 1 ≤ s.re) : riemannZeta s ≠ 0 ✓ (Mathlib).\n- 0 < re < 1: nontrivial ✓.\n- re ≤ 0: s = 0? yes → middle disjunct. no: Gammaℝ s = 0? yes → Gammaℝ_eq_zero_iff: s = -2*↑m: m = 0: s = 0 — wait s ≠ 0 case... m = 0 gives s = 0 contradiction with h0 — so m ≥ 1 ⟹ third disjunct (s = −2·↑m — need the exact form: Gammaℝ_eq_zero_iff : Gammaℝ s = 0 ↔ ∃ m : ℕ, s = -2 * m — from LiDisc: `rw [Complex.Gammaℝ_eq_zero_iff] at hG; obtain ⟨n, hn⟩ := hG; rw [hn]; ...` and `hre' : ρ.re = -2 * (n:ℝ)` via simp [neg_re, mul_re] — so hn : ρ = -2 * (n:ℂ)?? with the cast -2 * ↑n: (-2 * ↑n).re = -2n ✓. The exact ℂ form: `s = -(2 * (m : ℂ))` or `s = -2 * (m : ℂ)` — adapt with whatever; my disjunct: ∃ n ≥ 1, s = -2 * (n : ℂ).)\n  no: Λ s = 0 via the product ⟹ IsNontrivialZero s ⟹ 0 < re contra ✓.\n\nWait — simpler: actually could I skip Gammaℝ_eq_zero_iff case: ζ s = 0, re ≤ 0, s ≠ 0: if Gammaℝ s ≠ 0: Λ s = 0 ⟹ nontrivial ⟹ contra re ≤ 0. So Gammaℝ s = 0 ⟹ s = −2m (m ≥ 1 since s ≠ 0 ⟹ m ≠ 0 ✓). ✓ as planned.\n\nintegerComplement: `Complex.integerComplement := (Set.range ((↑) : ℤ → ℂ))ᶜ` — membership: z ∈ ℂ_ℤ... (notation ℂ_ℤ?) — `z ∈ Complex.integerComplement ↔ ∀ n : ℤ, z ≠ n` presumably via compl range: z ∉ range ⟺ ∀ n, (n:ℂ) ≠ z... direction care: `Set.mem_compl_iff`, `Set.mem_range`. There are helper lemmas: integerComplement.ne_zero, integerComplement_add_ne_zero, add_intCast_mem_integerComplement. For my use: s/2 ∈ integerComplement for s near 0 (s ≠ 0, ‖s‖ < 1): if s/2 = (n : ℤ) for some n: |n| = ‖s/2‖ < 1/2 ⟹ n = 0 ⟹ s = 0 contra ✓. And for w near −n (n ≥ 1): w = (k : ℤ) with ‖w+n‖ < 1/2 ⟹ |k + n| < 1/2 ⟹ k = −n ⟹ w = −n — excluded punctured... For the M-test at −n I need the domain (ball(−n, 1/2) minus the point −n?) — no wait: the M-test for H_n's series analyticity is on the open ball ball(−n, 1/2) INCLUDING −n: the terms of H_n are analytic AT −n too (the pole term j = n−1 removed) ✓ — the series for H_n is the digamma series MINUS its j = n−1 term: H_n(w) := −γ − 1/w + ∑' j, (if j = n−1 then 0 else (1/(j+1) − 1/(w+j+1)))... For the M-test on ball(−n, 1/2): terms j ≠ n−1: 1/(j+1) − 1/(w+j+1): poles at w = −(j+1): for j ≠ n−1, −(j+1) ≠ −n ✓ and ‖−(j+1) − (−n)‖ = |n−j−1| ≥ 1 ⟹ ball(−n, 1/2) avoids all of them ✓. Uniform bound: ‖1/(j+1) − 1/(w+j+1)‖ = ‖w‖/((j+1)·‖w+j+1‖): hmm this needs w ≠ 0 for the algebra but the bound is general: 1/(j+1) − 1/(w+j+1) = w/((j+1)(w+j+1)) ✓ (j+1 ≠ 0, w+j+1 ≠ 0 on the domain ✓). ‖w‖ ≤ n + 1/2; ‖w+j+1‖: for j ≠ n−1: ≥ |n − (j+1)| − 1/2 ≥ 1/2. That gives ‖term‖ ≤ (n+1/2)·2/(j+1) — NOT summable (harmonic)! Need better for large j: for j ≥ 2n: ‖w+j+1‖ ≥ (j+1) − ‖w‖ ≥ (j+1)/2 ✓ (since ‖w‖ ≤ n+1/2 ≤ (j+1)/2 when j+1 ≥ 2n+1 ✓): ‖term‖ ≤ 2(n+1/2)/(j+1)² ✓ summable. So use the EVENTUALLY-form M-test (of_norm_le_summable_eventually) with the finite head j < 2n unconstrained — but wait: uniform convergence needs every term individually... the eventually-form handles it: head terms just need to be finite functions (they are, on the domain — poles avoided ✓) — and for the DIFFERENTIABILITY of partial sums, each term differentiable on the domain ✓ (poles avoided). ✓.\n\nSimilarly for the s=0 case: the full digamma series on ball(0, 1/2): terms 1/(j+1) − 1/(w+j+1): poles at −(j+1) ≤ −1: ball(0,1/2) avoids ✓; bound: ‖w‖ ≤ 1/2, ‖w+j+1‖ ≥ (j+1) − 1/2 ≥ (j+1)/2 ⟹ ‖term‖ ≤ 1/(j+1)²·... ‖w‖/((j+1)(j+1)/2) = 2‖w‖/(j+1)² ≤ 1/(j+1)² ✓ summable (summable_div_add_one_sq from LiDigamma ✓). ALL terms (no eventually needed) ✓ — matches LiDigamma's `summable_div_add_one_sq 1` usage.\n\nNow — plan the file LiFEntire.lean. Actually, name it per convention: the 5e files are LiGapCircles (5e-i), LiDigammaLeft (5e-ii), LiSeries (5e-iii) — 5e-iv: `LiFEntire.lean`.\n\nStructure:\n\n```lean\n/- header: ii′-5e-iv (D-068 §4): F entire via principal-part splits + the limUnder extension -/\n\nimport Mathlib\nimport Zeta23.Statement\nimport Zeta23.Statement.SeamClosed\nimport Zeta23.GammaFacts.Series   (digamma_series)\nimport Zeta23.RvM.CountByIntegral (?? — for completedRiemannZeta facts; check what LiDisc imports)\nimport NguyenRH1.LiSeries\nimport NguyenRH1.LiTrivialZeros  (zeroMult_neg_two_mul)\n\nDefinitions:\ndef Fexpr (s : ℂ) : ℂ := logDeriv riemannZeta s - seriesFun s + 1/s + 1/(s-1) - (Real.log π)/2 + Complex.digamma (s/2)/2\n\nHmm wait — check the exact target identity signs once more (D-068 §0):\nζ′/ζ(s) = B + Σ m(1/(s−ρ)+1/ρ) − 1/s − 1/(s−1) + ½log π − ½ψ(s/2)\n⟹ F := ζ′/ζ − series + 1/s + 1/(s−1) − ½logπ + ½ψ(s/2) ≡ B. ✓\n\ndef badPoint (s : ℂ) : Prop := IsNontrivialZero s ∨ s = 0 ∨ s = 1 ∨ ∃ n : ℕ, 1 ≤ n ∧ s = -2 * (n : ℂ)\n\nSection A: helpers\nA1. analyticAt_digamma {w} (hw : ∀ m : ℕ, w ≠ -m) : AnalyticAt ℂ digamma w\nA2. zeta_zero_classification {s} (hs : riemannZeta s = 0) : IsNontrivialZero s ∨ s = 0 ∨ ∃ n ≥ 1...\nA3. logDeriv h analyticity at zeros: the NF punctured form — per nontrivial zero ρ₀:\n    exists analytic W with (fun s => logDeriv ζ s − m/(s−ρ₀)) =ᶠ[𝓝[≠] ρ₀] W.\n    From the NF: obtain ⟨h, hh, hh0, hfh⟩; W := logDeriv h... need h analytic on a BALL (not just at ρ₀): hh.eventually_analyticAt : ∀ᶠ z in 𝓝 ρ₀, AnalyticAt ℂ h z ✓ (AnalyticAt.eventually_analyticAt ✓ used in LiSides line 379) + hh.continuousAt.eventually_ne hh0 (h ≠ 0 nearby) ⟹ on a ball: logDeriv h = deriv h/h differentiable... AnalyticAt at the CENTER: logDeriv h analytic at ρ₀: (hh.deriv).div hh0 — AnalyticAt.deriv : AnalyticAt f x → AnalyticAt (deriv f) x ✓ check name; AnalyticAt.div : AnalyticAt f → AnalyticAt g → g x ≠ 0 → AnalyticAt (f/g) ✓.\n    Punctured equality: logDeriv ζ s = m/(s−ρ₀) + logDeriv h s for s near ρ₀, s ≠ ρ₀, h s ≠ 0, h analytic at s: the LiSides Rfun_residue_at block has exactly this (hld : logDeriv riemannZeta s = m/(s−ρ) + logDeriv h s — lines 384-397) ✓ reuse pattern.\nA4. At 1: logDeriv_zetaA relation punctured.\nA5. At −2n: analyticOrderNatAt riemannZeta (−2n) = 1 — from zeroMult_neg_two_mul (zeroMult = analyticOrderNatAt? zeroMult ρ := (analyticOrderAt riemannZeta ρ).toNat; and analyticOrderNatAt = analyticOrderAt.toNat? check LiTrivialZeros: they proved zeroMult(−2n) = 1 via analyticOrderAt_eq_natCast — analyticOrderNatAt riemannZeta (−2n) = 1 — and zeroMult = analyticOrderNatAt? In LiSides line 401: `have hmz : (zeroMult ρ : ℂ) = (analyticOrderNatAt riemannZeta ρ : ℂ) := rfl` — zeroMult IS analyticOrderNatAt by rfl ✓. So analyticOrderNatAt ζ (−2n) = 1 ✓ from zeroMult_neg_two_mul by the rfl.\n    Then the NF at −2n: logDeriv ζ s = 1/(s+2n) + logDeriv h s punctured; h analytic nonzero at −2n ✓.\nA6. Digamma splits:\n    at 0: on ball(0, 1/2): digamma w = −γ − 1/w + S₀(w) where S₀ := ∑' j, (1/(j+1) − 1/(w+j+1)) — need this for w ∈ ball(0,1/2), w ≠ 0 (integerComplement ✓). S₀ analytic on the whole ball (M-test incl. w = 0 ✓ terms fine at 0: 1/(j+1) − 1/(j+1) = 0... at w = 0 the term is 0 ✓ analytic ✓).\n    Define digammaSeriesPart (w) := ∑' j : ℕ, (1/(j+1) − 1/(w+j+1)); analytic on ball(0, 1/2) via M-test ✓ (5e-iii pattern); agreement: for w ∈ ball, w ≠ 0: digamma w = −γ − 1/w + digammaSeriesPart w (digamma_series, integerComplement: w ∈ ball(0,1/2), w ≠ 0 ⟹ w ∉ ℤ ✓).\n    at −n (n ≥ 1): digammaSeriesPartSub n w := ∑' j, if j = n−1 then 0 else (1/(j+1) − 1/(w+j+1)); analytic on ball(−n, 1/2) (M-test eventually-form); agreement: for w ∈ ball, w ≠ −n: digamma w = −γ − 1/w + digammaSeriesPartSub n w + (1/n − 1/(w+n)) — hmm the single-term tsum split: ∑' full = ∑' sub + (1/n − 1/(w+n)) via tsum_eq_single-style as in 5e-iii §5 ✓ (single_summable pattern).\n    So digamma w + 1/(w+n) = −γ − 1/w + digammaSeriesPartSub n w + 1/n (analytic at −n: 1/w fine (w near −n ≠ 0 ✓)) — define H_n w := −γ − 1/w + digammaSeriesPartSub n w + 1/n: analytic at −n, punctured agreement digamma w = −1/(w+n) + H_n w.\n    Then for the F-expr at s near −2n: digamma(s/2)/2 = (−1/(s/2+n) + H_n(s/2))/2 = −1/(s+2n) + H_n(s/2)/2.\nA7. Generic analyticity of Fexpr at good points + continuity.\nA8. The per-bad-point witnesses A + punctured agreements.\nA9. G := fun s => limUnder (𝓝[≠] s) Fexpr; G_eq_Fexpr at good points; G analytic everywhere.\nCapstone theorem:\ntheorem exists_entire_eq_Fexpr : ∃ G : ℂ → ℂ, (∀ s, AnalyticAt ℂ G s) ∧ ∀ s, ¬ badPoint s → G s = Fexpr s\n```\n\nWait — one issue in A9's good-point case: G =ᶠ Fexpr near good s needs a ball of good points; the ball: ζ ≠ 0 ball (continuity at s, s ≠ 1) ∩ ball avoiding {0, 1} (s ≠ 0, s ≠ 1 — finite set distance) — every y in the ball: ζ y ≠ 0 ⟹ y not a zero ⟹ y not nontrivial (def .1), y not −2n (ζ(−2n) = 0), y ∉ {0,1} ⟹ y good ✓. ζ(−2n) = 0 — need: riemannZeta (−2n) = 0 for n ≥ 1: from zeroMult_neg_two_mul (zeroMult = order.toNat = 1 ≠ 0 ⟹ ζ(−2n) = 0? analyticOrderAt.toNat = 1 means the order is 1 — is there a direct lemma ζ(−2n) = 0? `riemannZeta_neg_two_mul`? hmm — Zeta23/Mathlib: `riemannZeta_neg_nat_eq...`? There might be `riemannZeta_neg_two_mul` or via the NF: ζ = (z+2n)¹·h near ⟹ ζ(−2n) = 0·h = 0 ✓ (evaluate the EventuallyEq at the point: self_of_nhds ✓). OK fine.\n\nAlternatively — for y to be NOT a bad point I need: ¬(IsNontrivialZero y ∨ y = 0 ∨ y = 1 ∨ ∃ n ≥ 1, y = −2n): nontrivial ⟹ ζ y = 0 contra ✓; y = 0/1 excluded by ball ✓; y = −2n ⟹ ζ y = 0 contra (needs ζ(−2n) = 0 ✓). ✓.\n\nNow — how big is this file? Estimating: A1 ~40, A2 ~60, A3 ~80, A4 ~50, A5 ~60, A6 ~200 (two M-tests + splits), A7 ~60, A8 ~80 (four witness assemblies), A9 ~120 (the limUnder gluing). Total ~700–800 lines. That's a full session or more. This is consistent with D-068's 0.5 estimate... maybe optimistic but fine. Sub-stage protocol: I could split 5e-iv into two commits: (a) helpers A1–A2 + digamma splits A6; (b) the zero/one/trivial splits + G assembly. Let me aim for one session with an intermediate commit.\n\nLet me check a few more API names before writing:\n- `AnalyticAt.deriv` — exists? grep.\n- `AnalyticAt.div` — exists? (used somewhere in Li files?)\n- `AnalyticAt.eventually_analyticAt` ✓ (LiSides 379).\n- `Tendsto.limUnder_eq` / how to compute limUnder: `tendsto_nhds_limUnder : (∃ x, Tendsto g f (𝓝 x)) → Tendsto g f (𝓝 (limUnder f g))` (line 232 above ✓!). So: if the punctured limit exists, limUnder is it: uniqueness: if Tendsto f (𝓝[≠]s) (𝓝 L) then limUnder = L: from tendsto_nhds_limUnder ⟨L, h⟩ : Tendsto f .. (𝓝 (limUnder)) + h + NeBot + T2 ⟹ tendsto_nhds_unique ✓ (needs NeBot (𝓝[≠] s) — ℂ: `nhdsWithin_neBot`? instance `NeBot (𝓝[≠] s)` for ℂ — (𝓝[≠] s).NeBot via `instNeBot...`? For a perfect space: `nhdsWithin_neBot_of...`. Mathlib has `NeBot (𝓝[≠] x)` instance for NontriviallyNormedField? or PerfectSpace: `PerfectSpace` ℂ? Hmm — there IS `instNeBotNhdsWithinCompl...`? Let me grep quickly for how Li files or Mathlib derive Tendsto within punctured ℂ.\n- logDeriv API: `logDeriv_apply : logDeriv f x = deriv f x / f x` ✓; `logDeriv_mul` (used in LiSides: `logDeriv_mul (f) (g) s (hfgs : f s ≠ 0) (hgs : g s ≠ 0) (hf : DifferentiableAt...) (hg)`? from LiSides line 389-390: `logDeriv_mul (f := ...) (g := h) s (pow_ne_zero _ hsρ') hhs (by fun_prop) hhas.differentiableAt` — so signature: logDeriv_mul (hfx : f x ≠ 0) (hgx : g x ≠ 0) (hf : DifferentiableAt...) (hg)?? order: (f g) s (h1 : f s ≠ 0) (h2 : g s ≠ 0) (h3 : DifferentiableAt f s) (h4 : DifferentiableAt g s)? The LiSides call: `logDeriv_mul (f := fun z => (z − ρ) ^ analyticOrderNatAt riemannZeta ρ) (g := h) s (pow_ne_zero _ hsρ') hhs (by fun_prop) hhas.differentiableAt` — so positional after s: (f s ≠ 0) (g s ≠ 0) (DifferentiableAt f) (DifferentiableAt g) — wait hhs : h s ≠ 0 ✓ second; (by fun_prop) : DifferentiableAt ℂ (fun z => (z−ρ)^m) s ✓ third; hhas.differentiableAt : hhas : AnalyticAt ℂ h s → .differentiableAt ✓ fourth. So logDeriv_mul x hfx hgx hfd hgd : logDeriv (f * g) x = logDeriv f x + logDeriv g x ✓.\n- logDeriv (fun z => z − ρ) = 1/(z−ρ): from LiSides e2 pattern: logDeriv_comp + logDeriv_pow... for (z−ρ): `logDeriv (fun z => z - ρ) s = 1/(s−ρ)`: logDeriv_sub_const? or via (differentiableAt_id.sub ...).logDeriv? There's `logDeriv_id`... I'll compute: logDeriv (fun z => z − ρ) s = deriv (z−ρ)/... = 1/(s−ρ): `(differentiableAt_id.sub (differentiableAt_const _)).logDeriv`?? logDeriv of a function at a point isn't from DifferentiableAt — logDeriv is DEFINED as deriv/f. So logDeriv (fun z => z−ρ) s = deriv (fun z => z−ρ) s / (s−ρ) = 1/(s−ρ): via logDeriv_apply + deriv of id.sub const = 1: `(differentiableAt_id.sub (differentiableAt_const ρ)).deriv` : deriv (fun z => z − ρ) s = 1... then simp [logDeriv_apply, that]. Fine.\n- For the +4 shift there's `logDeriv_Gammaℝ_shift` (5d) — not needed here.\n- zetaA logDeriv at 1: `AnalyticAt ℂ (logDeriv zetaA) 1`? hmm — I actually need the WITNESS function analytic at 1 agreeing with logDeriv ζ + 1/(s−1) punctured. W := logDeriv zetaA: analytic at 1 ✓ (zetaA analytic, zetaA 1 = 1 ≠ 0: AnalyticAt.deriv + AnalyticAt.div). Punctured: logDeriv ζ s + 1/(s−1) = logDeriv zetaA s for s ≠ 1 near 1: logDeriv zetaA s = logDeriv ((s−1)ζ s) (zetaA_apply) = 1/(s−1) + logDeriv ζ s (logDeriv_mul, needs ζ s ≠ 0: punctured near 1 via zetaA ≠ 0 ball: ζ s = zetaA s/(s−1) ≠ 0 ✓).\n\nLet me check `AnalyticAt.deriv` and `AnalyticAt.div` names.","signature":""},{"type":"text","text":"Zeta23 already has the full classification fact (`completedRiemannZeta_eq_zero_iff`). Checking the last API pieces: `AnalyticAt.deriv`/`.div` and the limUnder uniqueness route."},{"type":"tool_use","id":"Bash_107","name":"Bash","input":{"command":"cd D:/Python/Quantum/zeta-23-lean/.lake/packages/mathlib && grep -rn \"theorem AnalyticAt.deriv\\b\\|protected theorem AnalyticAt.deriv\\b\" Mathlib/Analysis/Analytic/*.lean Mathlib/Analysis/Calculus/*.lean -r | head -3; grep -rn \"theorem AnalyticAt.div\\b\\|AnalyticAt.div \" Mathlib/Analysis/Analytic/Constructions.lean | head -3; grep -rn \"tendsto_nhds_unique\\b\" Mathlib/Topology/Basic.lean | head -2; grep -rn \"NeBot.*nhdsWithin.*compl\\|instNeBot.*Punctured\\|nhdsWithin.*NeBot\" Mathlib/Analysis/ -r --include=*.lean | grep -i \"instance\\|theorem.*NeBot\" | head -5","description":"Check AnalyticAt.deriv/div, tendsto_nhds_unique, NeBot punctured"},"extra_content":null}]