Skip to content

Commit

Permalink
feat(Analysis/Analytic): define meromorphic functions (#9590)
Browse files Browse the repository at this point in the history
This patch defines `MeromorphicAt`, for functions on nontrivially normed fields, and prove it is preserved by sums and products (routine) and inverses (much less trivial). Along the way, we define "order of vanishing" for a function analytic at a point (as an `ENat`).
  • Loading branch information
loefflerd committed Jan 10, 2024
1 parent b8dc366 commit 0788787
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 2 deletions.
1 change: 1 addition & 0 deletions Mathlib.lean
Expand Up @@ -572,6 +572,7 @@ import Mathlib.Analysis.Analytic.Constructions
import Mathlib.Analysis.Analytic.Inverse
import Mathlib.Analysis.Analytic.IsolatedZeros
import Mathlib.Analysis.Analytic.Linear
import Mathlib.Analysis.Analytic.Meromorphic
import Mathlib.Analysis.Analytic.Polynomial
import Mathlib.Analysis.Analytic.RadiusLiminf
import Mathlib.Analysis.Analytic.Uniqueness
Expand Down
72 changes: 70 additions & 2 deletions Mathlib/Analysis/Analytic/IsolatedZeros.lean
Expand Up @@ -3,10 +3,9 @@ Copyright (c) 2022 Vincent Beffara. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Vincent Beffara
-/
import Mathlib.Analysis.Analytic.Basic
import Mathlib.Analysis.Analytic.Constructions
import Mathlib.Analysis.Calculus.Dslope
import Mathlib.Analysis.Calculus.FDeriv.Analytic
import Mathlib.Analysis.Calculus.FormalMultilinearSeries
import Mathlib.Analysis.Analytic.Uniqueness

#align_import analysis.analytic.isolated_zeros from "leanprover-community/mathlib"@"a3209ddf94136d36e5e5c624b10b2a347cc9d090"
Expand Down Expand Up @@ -154,6 +153,75 @@ theorem frequently_eq_iff_eventually_eq (hf : AnalyticAt π•œ f zβ‚€) (hg : Anal
simpa [sub_eq_zero] using frequently_zero_iff_eventually_zero (hf.sub hg)
#align analytic_at.frequently_eq_iff_eventually_eq AnalyticAt.frequently_eq_iff_eventually_eq

/-- There exists at most one `n` such that locally around `zβ‚€` we have `f z = (z - zβ‚€) ^ n β€’ g z`,
with `g` analytic and nonvanishing at `zβ‚€`. -/
lemma unique_eventuallyEq_pow_smul_nonzero {m n : β„•}
(hm : βˆƒ g, AnalyticAt π•œ g zβ‚€ ∧ g zβ‚€ β‰  0 ∧ βˆ€αΆ  z in 𝓝 zβ‚€, f z = (z - zβ‚€) ^ m β€’ g z)
(hn : βˆƒ g, AnalyticAt π•œ g zβ‚€ ∧ g zβ‚€ β‰  0 ∧ βˆ€αΆ  z in 𝓝 zβ‚€, f z = (z - zβ‚€) ^ n β€’ g z) :
m = n := by
wlog h_le : n ≀ m generalizing m n
Β· exact ((this hn hm) (not_le.mp h_le).le).symm
let ⟨g, hg_an, _, hg_eq⟩ := hm
let ⟨j, hj_an, hj_ne, hj_eq⟩ := hn
contrapose! hj_ne
have : βˆƒαΆ  z in 𝓝[β‰ ] zβ‚€, j z = (z - zβ‚€) ^ (m - n) β€’ g z
Β· refine (eventually_nhdsWithin_iff.mpr ?_).frequently
filter_upwards [hg_eq, hj_eq] with z hfz hfz' hz
rwa [← Nat.add_sub_cancel' h_le, pow_add, mul_smul, hfz', smul_right_inj] at hfz
exact pow_ne_zero _ <| sub_ne_zero.mpr hz
rw [frequently_eq_iff_eventually_eq hj_an] at this
rw [EventuallyEq.eq_of_nhds this, sub_self, zero_pow, zero_smul]
Β· apply Nat.zero_lt_sub_of_lt (Nat.lt_of_le_of_ne h_le hj_ne.symm)
Β· exact (((analyticAt_id π•œ _).sub analyticAt_const).pow _).smul hg_an

/-- If `f` is analytic at `zβ‚€`, then exactly one of the following two possibilities occurs: either
`f` vanishes identically near `zβ‚€`, or locally around `zβ‚€` it has the form `z ↦ (z - zβ‚€) ^ n β€’ g z`
for some `n` and some `g` which is analytic and non-vanishing at `zβ‚€`. -/
theorem exists_eventuallyEq_pow_smul_nonzero_iff (hf : AnalyticAt π•œ f zβ‚€) :
(βˆƒ (n : β„•), βˆƒ (g : π•œ β†’ E), AnalyticAt π•œ g zβ‚€ ∧ g zβ‚€ β‰  0 ∧
βˆ€αΆ  z in 𝓝 zβ‚€, f z = (z - zβ‚€) ^ n β€’ g z) ↔ (Β¬βˆ€αΆ  z in 𝓝 zβ‚€, f z = 0) := by
constructor
· rintro ⟨n, g, hg_an, hg_ne, hg_eq⟩
contrapose! hg_ne
apply EventuallyEq.eq_of_nhds
rw [EventuallyEq, ← AnalyticAt.frequently_eq_iff_eventually_eq hg_an analyticAt_const]
refine (eventually_nhdsWithin_iff.mpr ?_).frequently
filter_upwards [hg_eq, hg_ne] with z hf_eq hf0 hz
rwa [hf0, eq_comm, smul_eq_zero_iff_right] at hf_eq
exact pow_ne_zero _ (sub_ne_zero.mpr hz)
Β· intro hf_ne
rcases hf with ⟨p, hp⟩
exact ⟨p.order, _, ⟨_, hp.has_fpower_series_iterate_dslope_fslope p.order⟩,
hp.iterate_dslope_fslope_ne_zero (hf_ne.imp hp.locally_zero_iff.mpr),
hp.eq_pow_order_mul_iterate_dslope⟩

/-- The order of vanishing of `f` at `zβ‚€`, as an element of `β„•βˆž`.
This is defined to be `∞` if `f` is identically 0 on a neighbourhood of `zβ‚€`, and otherwise the
unique `n` such that `f z = (z - zβ‚€) ^ n β€’ g z` with `g` analytic and non-vanishing at `zβ‚€`. See
`AnalyticAt.order_eq_top_iff` and `AnalyticAt.order_eq_nat_iff` for these equivalences. -/
noncomputable def order (hf : AnalyticAt π•œ f zβ‚€) : ENat :=
if h : βˆ€αΆ  z in 𝓝 zβ‚€, f z = 0 then ⊀
else ↑(hf.exists_eventuallyEq_pow_smul_nonzero_iff.mpr h).choose

lemma order_eq_top_iff (hf : AnalyticAt π•œ f zβ‚€) : hf.order = ⊀ ↔ βˆ€αΆ  z in 𝓝 zβ‚€, f z = 0 := by
unfold order
split_ifs with h
Β· rwa [eq_self, true_iff]
Β· simpa only [ne_eq, ENat.coe_ne_top, false_iff] using h

lemma order_eq_nat_iff (hf : AnalyticAt π•œ f zβ‚€) (n : β„•) : hf.order = ↑n ↔
βˆƒ (g : π•œ β†’ E), AnalyticAt π•œ g zβ‚€ ∧ g zβ‚€ β‰  0 ∧ βˆ€αΆ  z in 𝓝 zβ‚€, f z = (z - zβ‚€) ^ n β€’ g z := by
unfold order
split_ifs with h
Β· simp only [ENat.top_ne_coe, false_iff]
contrapose! h
rw [← hf.exists_eventuallyEq_pow_smul_nonzero_iff]
exact ⟨n, h⟩
Β· rw [← hf.exists_eventuallyEq_pow_smul_nonzero_iff] at h
refine ⟨fun hn ↦ (WithTop.coe_inj.mp hn : h.choose = n) β–Έ h.choose_spec, fun h' ↦ ?_⟩
rw [unique_eventuallyEq_pow_smul_nonzero h.choose_spec h']

end AnalyticAt

namespace AnalyticOn
Expand Down
125 changes: 125 additions & 0 deletions Mathlib/Analysis/Analytic/Meromorphic.lean
@@ -0,0 +1,125 @@
/-
Copyright (c) 2024 David Loeffler. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Loeffler
-/
import Mathlib.Analysis.Analytic.IsolatedZeros

/-!
# Meromorphic functions
-/

open scoped Topology

variable {π•œ : Type*} [NontriviallyNormedField π•œ]
{E : Type*} [NormedAddCommGroup E] [NormedSpace π•œ E]

/-- Meromorphy of `f` at `x` (more precisely, on a punctured neighbourhood of `x`; the value at
`x` itself is irrelevant). -/
def MeromorphicAt (f : π•œ β†’ E) (x : π•œ) :=
βˆƒ (n : β„•), AnalyticAt π•œ (fun z ↦ (z - x) ^ n β€’ f z) x

lemma AnalyticAt.meromorphicAt {f : π•œ β†’ E} {x : π•œ} (hf : AnalyticAt π•œ f x) :
MeromorphicAt f x :=
⟨0, by simpa only [pow_zero, one_smul]⟩

lemma meromorphicAt_id (x : π•œ) : MeromorphicAt id x := (analyticAt_id π•œ x).meromorphicAt

lemma meromorphicAt_const (e : E) (x : π•œ) : MeromorphicAt (fun _ ↦ e) x :=
analyticAt_const.meromorphicAt

namespace MeromorphicAt

lemma add {f g : π•œ β†’ E} {x : π•œ} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) :
MeromorphicAt (f + g) x := by
rcases hf with ⟨m, hf⟩
rcases hg with ⟨n, hg⟩
refine ⟨max m n, ?_⟩
have : (fun z ↦ (z - x) ^ max m n β€’ (f + g) z) = fun z ↦ (z - x) ^ (max m n - m) β€’
((z - x) ^ m β€’ f z) + (z - x) ^ (max m n - n) β€’ ((z - x) ^ n β€’ g z)
Β· simp_rw [← mul_smul, ← pow_add, Nat.sub_add_cancel (Nat.le_max_left _ _),
Nat.sub_add_cancel (Nat.le_max_right _ _), Pi.add_apply, smul_add]
rw [this]
exact ((((analyticAt_id π•œ x).sub analyticAt_const).pow _).smul hf).add
((((analyticAt_id π•œ x).sub analyticAt_const).pow _).smul hg)

lemma smul {f : π•œ β†’ π•œ} {g : π•œ β†’ E} {x : π•œ} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) :
MeromorphicAt (f β€’ g) x := by
rcases hf with ⟨m, hf⟩
rcases hg with ⟨n, hg⟩
refine ⟨m + n, ?_⟩
convert hf.smul hg using 2 with z
rw [smul_eq_mul, ← mul_smul, mul_assoc, mul_comm (f z), ← mul_assoc, pow_add,
← smul_eq_mul (a' := f z), smul_assoc, Pi.smul_apply']

lemma mul {f g : π•œ β†’ π•œ} {x : π•œ} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) :
MeromorphicAt (f * g) x :=
hf.smul hg

lemma neg {f : π•œ β†’ E} {x : π•œ} (hf : MeromorphicAt f x) : MeromorphicAt (-f) x := by
convert (meromorphicAt_const (-1 : π•œ) x).smul hf using 1
ext1 z
simp only [Pi.neg_apply, Pi.smul_apply', neg_smul, one_smul]

@[simp]
lemma neg_iff {f : π•œ β†’ E} {x : π•œ} :
MeromorphicAt (-f) x ↔ MeromorphicAt f x :=
⟨fun h ↦ by simpa only [neg_neg] using h.neg, MeromorphicAt.neg⟩

lemma sub {f g : π•œ β†’ E} {x : π•œ} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) :
MeromorphicAt (f - g) x := by
convert hf.add hg.neg using 1
ext1 z
simp_rw [Pi.sub_apply, Pi.add_apply, Pi.neg_apply, sub_eq_add_neg]

/-- With our definitions, `MeromorphicAt f x` depends only on the values of `f` on a punctured
neighbourhood of `x` (not on `f x`) -/
lemma congr {f g : π•œ β†’ E} {x : π•œ} (hf : MeromorphicAt f x) (hfg : f =αΆ [𝓝[β‰ ] x] g) :
MeromorphicAt g x := by
rcases hf with ⟨m, hf⟩
refine ⟨m + 1, ?_⟩
have : AnalyticAt π•œ (fun z ↦ z - x) x := (analyticAt_id π•œ x).sub analyticAt_const
refine (this.smul hf).congr ?_
rw [eventuallyEq_nhdsWithin_iff] at hfg
filter_upwards [hfg] with z hz
rcases eq_or_ne z x with rfl | hn
Β· simp
Β· rw [hz (Set.mem_compl_singleton_iff.mp hn), pow_succ, mul_smul]

lemma inv {f : π•œ β†’ π•œ} {x : π•œ} (hf : MeromorphicAt f x) : MeromorphicAt f⁻¹ x := by
rcases hf with ⟨m, hf⟩
by_cases h_eq : (fun z ↦ (z - x) ^ m β€’ f z) =αΆ [𝓝 x] 0
Β· -- silly case: f locally 0 near x
apply (meromorphicAt_const 0 x).congr
rw [eventuallyEq_nhdsWithin_iff]
filter_upwards [h_eq] with z hfz hz
rw [Pi.inv_apply, (smul_eq_zero_iff_right <| pow_ne_zero _ (sub_ne_zero.mpr hz)).mp hfz,
inv_zero]
Β· -- interesting case: use local formula for `f`
obtain ⟨n, g, hg_an, hg_ne, hg_eq⟩ := hf.exists_eventuallyEq_pow_smul_nonzero_iff.mpr h_eq
have : AnalyticAt π•œ (fun z ↦ (z - x) ^ (m + 1)) x :=
((analyticAt_id π•œ x).sub analyticAt_const).pow _
-- use `m + 1` rather than `m` to damp out any silly issues with the value at `z = x`
refine ⟨n + 1, (this.smul <| hg_an.inv hg_ne).congr ?_⟩
filter_upwards [hg_eq, hg_an.continuousAt.eventually_ne hg_ne] with z hfg hg_ne'
rcases eq_or_ne z x with rfl | hz_ne
Β· simp only [sub_self, pow_succ, zero_mul, zero_smul]
· simp_rw [smul_eq_mul] at hfg ⊒
have aux1 : f z β‰  0
Β· have : (z - x) ^ n * g z β‰  0 := mul_ne_zero (pow_ne_zero _ (sub_ne_zero.mpr hz_ne)) hg_ne'
rw [← hfg, mul_ne_zero_iff] at this
exact this.2
field_simp [sub_ne_zero.mpr hz_ne]
rw [pow_succ, mul_assoc, hfg]
ring

@[simp]
lemma inv_iff {f : π•œ β†’ π•œ} {x : π•œ} :
MeromorphicAt f⁻¹ x ↔ MeromorphicAt f x :=
⟨fun h ↦ by simpa only [inv_inv] using h.inv, MeromorphicAt.inv⟩

lemma div {f g : π•œ β†’ π•œ} {x : π•œ} (hf : MeromorphicAt f x) (hg : MeromorphicAt g x) :
MeromorphicAt (f / g) x :=
(div_eq_mul_inv f g).symm β–Έ (hf.mul hg.inv)

end MeromorphicAt

0 comments on commit 0788787

Please sign in to comment.