diff --git a/LeanPool.lean b/LeanPool.lean index ddd609e9eb..c82b8fb1e3 100644 --- a/LeanPool.lean +++ b/LeanPool.lean @@ -7676,6 +7676,169 @@ public import LeanPool.SetTheory.Realize public import LeanPool.SetTheory.RealizeBuilders public import LeanPool.SetTheory.RealizeCore public import LeanPool.SetTheory.SimpAttr +public import LeanPool.SeveralComplexVariables +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.LinearFunctional +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.OpenMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.TaylorBounds +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoefficientPolynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoordinateChange +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Elimination +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Factorization +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Fiber +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.IntrinsicOrder +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Noetherian +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Order +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Polynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.RelativePrimality +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Units +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Weierstrass +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Codimension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.CoordinatePlane +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Hartogs +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Holomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Regular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Removable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.BallAutomorphisms +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.BiholomorphicRigidity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanThullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanUniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyDerivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyEstimates +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyPompeiu +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyRiemann +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchySeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyTransform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Circular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CircularContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CommonExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CompactHole +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ContourIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DomainOfHolomorphy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DominatedIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsLaurent +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsSeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.BoundaryDistance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Exhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Transport +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicLp +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitGraph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CorankOne +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CriticalSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.Immersion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Integral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Integral.Circle +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IsolatedSingularity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentApproximation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Annulus +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Coefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Convergence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Iterated +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Neighborhoods +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductExpansion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Uniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Independence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Invariance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Necessity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Peak +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm.Holomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyBounded +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.MaximumModulus +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Montel +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Osgood +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ParametricIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Plurisubharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscMeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscTaylor +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polynomial.OfFn +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolynomialDerivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Analytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Pseudoconvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RealUniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reindex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.GeometricConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.HolomorphicConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.MonomialSeparation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.PartialHull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.ExceptionalSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Geometry +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Gluing +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Local +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Runge +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Runge.Examples +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Baire +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.FiberExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.HartogsLemma +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.MeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Submean +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SphericalShell +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.Majorant +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.SmoothCriterion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.CompactExhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Frontier +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Graph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Path +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.UpperSemicontinuous +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Bochner +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Disc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Gluing +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.StarConvex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.CoordinatePower +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Picard +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassPreparation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Local +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Persistence +public import LeanPool.SeveralComplexVariables.Solution public import LeanPool.Shannon1948Formalization public import LeanPool.Shannon1948Formalization.Entropy public import LeanPool.Shannon1948Formalization.Entropy.Approx diff --git a/LeanPool/SeveralComplexVariables.lean b/LeanPool/SeveralComplexVariables.lean new file mode 100644 index 0000000000..744579b25f --- /dev/null +++ b/LeanPool/SeveralComplexVariables.lean @@ -0,0 +1,181 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.LinearFunctional +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.OpenMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.TaylorBounds +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoefficientPolynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoordinateChange +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Elimination +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Factorization +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Fiber +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.IntrinsicOrder +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Noetherian +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Order +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Polynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.RelativePrimality +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Units +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Weierstrass +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Codimension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.CoordinatePlane +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Hartogs +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Holomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Regular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Removable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.BallAutomorphisms +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.BiholomorphicRigidity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanThullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanUniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyDerivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyEstimates +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyPompeiu +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyRiemann +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchySeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyTransform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Circular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CircularContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CommonExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CompactHole +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ContourIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DomainOfHolomorphy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DominatedIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsLaurent +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsSeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.BoundaryDistance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Exhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Transport +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicLp +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitGraph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CorankOne +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CriticalSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.Immersion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Integral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Integral.Circle +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IsolatedSingularity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentApproximation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Annulus +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Coefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Convergence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Iterated +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Neighborhoods +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductExpansion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Uniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Independence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Invariance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Necessity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Peak +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm.Holomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyBounded +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.MaximumModulus +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Montel +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Osgood +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ParametricIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Plurisubharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscMeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscTaylor +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polynomial.OfFn +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolynomialDerivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Analytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Pseudoconvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RealUniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reindex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.GeometricConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.HolomorphicConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.MonomialSeparation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.PartialHull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.ExceptionalSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Geometry +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Gluing +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Local +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Runge +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Runge.Examples +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Baire +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.FiberExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.HartogsLemma +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.MeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Submean +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SphericalShell +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.Majorant +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.SmoothCriterion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.CompactExhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Frontier +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Graph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Path +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.UpperSemicontinuous +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Bochner +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Disc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Gluing +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.StarConvex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.CoordinatePower +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Picard +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassPreparation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Local +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Persistence +public import LeanPool.SeveralComplexVariables.Solution + +/-! +# Classical several complex variables + +Source: url:https://github.com/bjbraams/lean-scv +Authors: Bastiaan J Braams +Status: verified +Main declarations: `SeveralComplexVariables.analyticOnNhd_of_separately_analytic_locally_bounded` +Tags: complex-analysis, several-complex-variables, holomorphic-functions +MSC: 32A10, 32D05, 32E10 +-/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables.lean new file mode 100644 index 0000000000..b52e42b9f3 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables.lean @@ -0,0 +1,217 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.LinearFunctional +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.OpenMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.TaylorBounds +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoefficientPolynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoordinateChange +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Elimination +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Factorization +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Fiber +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.IntrinsicOrder +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Noetherian +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Order +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Polynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.RelativePrimality +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Units +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Weierstrass +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Codimension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.CoordinatePlane +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Hartogs +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Holomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Regular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Removable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.BallAutomorphisms +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.BiholomorphicRigidity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanThullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanUniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyDerivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyEstimates +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyPompeiu +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyRiemann +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchySeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyTransform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Circular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CircularContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CommonExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CompactHole +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ContourIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DomainOfHolomorphy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DominatedIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsLaurent +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsSeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.BoundaryDistance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Exhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Transport +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicLp +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitGraph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CorankOne +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CriticalSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.Immersion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Integral.Circle +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IsolatedSingularity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentApproximation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Annulus +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Coefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Convergence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Iterated +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Neighborhoods +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductExpansion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Uniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Independence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Invariance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Necessity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Peak +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm.Holomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyBounded +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.MaximumModulus +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Montel +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Osgood +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ParametricIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Plurisubharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscMeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscTaylor +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polynomial.OfFn +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolynomialDerivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Analytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Pseudoconvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RealUniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reindex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.GeometricConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.HolomorphicConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.MonomialSeparation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.PartialHull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.ExceptionalSet +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Geometry +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Gluing +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Local +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Runge +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Runge.Examples +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Baire +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.FiberExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.HartogsLemma +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.MeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Submean +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SphericalShell +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.Majorant +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.SmoothCriterion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.CompactExhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Frontier +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Graph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Path +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.UpperSemicontinuous +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Bochner +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Disc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Gluing +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.StarConvex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.CoordinatePower +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Picard +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassPreparation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Local +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Persistence + +/-! +# Several complex variables + +This umbrella imports the classical function theory of open subsets of finite-dimensional +complex normed spaces. Analytic maps use Mathlib's `AnalyticOnNhd ℂ`; holomorphic maps on open +sets use `DifferentiableOn ℂ`. Banach-valued targets are retained where appropriate. Finite +coordinate spaces carry the supremum norm, so their balls are polydiscs; Euclidean ball geometry +uses the inner-product norm explicitly. + +## Local analysis and function spaces + +The library provides polydisc Cauchy and Taylor formulas with separate radii, mixed derivative +estimates, the Cauchy–Riemann equations, the identity and maximum principles, analytic parameter +integrals, and the Cauchy–Pompeiu identity. Locally uniform convergence preserves analyticity +and derivatives. Holomorphic maps form compact-open function spaces, with continuous evaluation, +restriction, and coordinate differentiation. Montel and Vitali theorems use finite-dimensional +targets for compactness. Holomorphic `Lp` spaces are complete, including exponent infinity. + +## Mapping theory and continuation + +Inverse and implicit mapping theorems, regular zero-set graphs, injective holomorphic maps, +Cartan uniqueness, circular rigidity, and explicit ball automorphisms are included. Reinhardt, +circular, and Hartogs geometry support Taylor and Laurent continuation, unrestricted separate +holomorphy, and removable singularities. Hartogs' compact-hole theorem follows from Ehrenpreis' +argument with real derivatives and the Cauchy transform, without differential forms. + +## Germs and analytic sets + +Analytic germs form local integral domains with residue field `ℂ`. Weierstrass division and +preparation, Taylor uniqueness, coordinate-independent total order, Noetherianity, and unique +factorization support zero-set and relative-primality results. Analytic subsets have local +finite equations, interior rigidity, dense connected complements, and regular and singular loci. +The Riemann extension theorems include Banach-valued removal and the holomorphic restriction +algebra equivalence across sets of slice codimension at least two. + +## Convexity, boundary geometry, and approximation + +Holomorphic hulls, compact exhaustions, and escaping sequences lead to the Cartan–Thullen +equivalences on finite-dimensional complex normed spaces. Thullen's Banach-valued Taylor +continuation lemma gives the coordinate hull-radius statements and Bochner's tube theorem. +Subharmonicity and plurisubharmonicity use the local submean property; the Laplacian and Levi +form give their `C²` criteria. Domains of holomorphy are pseudoconvex and satisfy continuity +principles. Levi's necessary condition, independence of the defining function, holomorphic +supporting polynomials, normalized local peak functions, and local holomorphic blow-up are +proved. Runge pairs and domains use approximation on compact sets; polynomial hulls and +Reinhardt and circular examples are included. + +The Oka–Weil theorem, the Levi sufficiency problem, and abstract envelopes of holomorphy remain +outside this library's scope. The [upstream theorem catalogue][scvCatalogue] records the precise +mathematical statements at the imported revision. + +[scvCatalogue]: https://github.com/bjbraams/lean-scv/blob/caef1ae776ff79933718312357980d46628d3702/SCVMainTheorems.md +-/ + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis.lean new file mode 100644 index 0000000000..780a029df1 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis.lean @@ -0,0 +1,15 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.LinearFunctional +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.OpenMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.TaylorBounds + +/-! Supporting modules for Classical several complex variables. -/ + diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/Connected.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/Connected.lean new file mode 100644 index 0000000000..8dfd1adf14 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/Connected.lean @@ -0,0 +1,75 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Module.Connected + +/-! +# Connectedness of shells and exteriors of balls + +In a real normed space of dimension at least two, spherical shells and exteriors of closed balls +centered at the origin are preconnected. The proofs are radial: a shell is the image of the product +of an interval and the unit sphere. + +## Main results + +* `isPreconnected_ball_diff_closedBall_zero`: A shell in a real normed space of dimension at least + two is preconnected. +* `isPreconnected_compl_closedBall_zero`: The exterior of a closed norm ball is preconnected in + real dimension at least two. +-/ + +public section + +open Metric Set + +/-- A shell in a real normed space of dimension at least two is preconnected. This radial argument +is independent of any analytic extension theorem. -/ +theorem isPreconnected_ball_diff_closedBall_zero {E : Type*} [NormedAddCommGroup E] + [NormedSpace ℝ E] + (hdim : 1 < Module.rank ℝ E) {ρ R : ℝ} (hρ : 0 ≤ ρ) : + IsPreconnected (ball (0 : E) R \ closedBall 0 ρ) := by + let A : Set (ℝ × E) := Ioo ρ R ×ˢ sphere 0 1 + have hA : IsPreconnected A := isPreconnected_Ioo.prod + (isPreconnected_sphere hdim (0 : E) 1) + have hc : Continuous (fun p : ℝ × E => p.1 • p.2) := continuous_fst.smul continuous_snd + have he : (fun p : ℝ × E => p.1 • p.2) '' A = ball (0 : E) R \ closedBall 0 ρ := by + apply Subset.antisymm + · rintro z ⟨⟨t, v⟩, ⟨ht, hv⟩, rfl⟩ + have hvn : ‖v‖ = 1 := by simpa [mem_sphere, dist_zero_right] using hv + have htn : 0 < t := hρ.trans_lt ht.1 + simpa [mem_ball, mem_closedBall, dist_zero_right, norm_smul, + Real.norm_of_nonneg htn.le, hvn] using ⟨ht.2, ht.1⟩ + · intro z hz + have hzR : ‖z‖ < R := by simpa [mem_ball, dist_zero_right] using hz.1 + have hzρ : ρ < ‖z‖ := by simpa [mem_closedBall, dist_zero_right] using hz.2 + have hn : 0 < ‖z‖ := hρ.trans_lt hzρ + refine ⟨(‖z‖, ‖z‖⁻¹ • z), ⟨⟨hzρ, hzR⟩, ?_⟩, ?_⟩ + · simp [norm_smul, Real.norm_of_nonneg (inv_nonneg.mpr hn.le), + inv_mul_cancel₀ hn.ne'] + · simp [smul_smul, mul_inv_cancel₀ hn.ne'] + rw [← he] + exact hA.image _ hc.continuousOn + +/-- The exterior of a closed norm ball is preconnected in real dimension at least two. It is the +directed union of the finite shells. -/ +theorem isPreconnected_compl_closedBall_zero {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] + (hdim : 1 < Module.rank ℝ E) {ρ : ℝ} (hρ : 0 ≤ ρ) : + IsPreconnected ((closedBall (0 : E) ρ)ᶜ) := by + have h : IsPreconnected (⋃ n : ℕ, ball (0 : E) (n : ℝ) \ closedBall 0 ρ) := by + rw [← sUnion_range] + apply IsPreconnected.sUnion_directed + · rintro s ⟨n, rfl⟩ t ⟨m, rfl⟩ + refine ⟨ball (0 : E) ((max n m : ℕ) : ℝ) \ closedBall 0 ρ, ⟨max n m, rfl⟩, ?_, ?_⟩ + · exact sdiff_subset_sdiff_left (ball_subset_ball (by exact_mod_cast le_max_left n m)) + · exact sdiff_subset_sdiff_left (ball_subset_ball (by exact_mod_cast le_max_right n m)) + · rintro s ⟨n, rfl⟩ + exact isPreconnected_ball_diff_closedBall_zero hdim hρ + simpa only [← iUnion_sdiff, iUnion_ball_nat, ← compl_eq_univ_sdiff] using h + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/LinearFunctional.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/LinearFunctional.lean new file mode 100644 index 0000000000..acc575d112 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/LinearFunctional.lean @@ -0,0 +1,105 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Algebra.Module.LinearMap.DivisionRing +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.Analysis.Normed.Operator.Basic + +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.NormNum +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Push + +/-! +# Elementary facts on scalar actions and continuous linear functionals + +## Main results + +* `Complex.smul_eq_re_smul_add_im_smul`: A complex scalar acts on a vector of a complex module + through its real and imaginary parts. +* `ContinuousLinearMap.exists_apply_eq_one_of_ne_zero`: A nonzero continuous linear functional + attains the value `1` on a nonzero vector. +* `ContinuousLinearMap.exists_pos_smul_eq_of_neg_imp_nonpos`: Inclusion of negative half-spaces + forces two nonzero real continuous linear functionals to be positively proportional. +-/ + +public section + +/-- A complex scalar acts on a vector through its real and imaginary parts. -/ +theorem Complex.smul_eq_re_smul_add_im_smul {E : Type*} [AddCommGroup E] [Module ℂ E] + (ζ : ℂ) (c : E) : ζ • c = ζ.re • c + ζ.im • (Complex.I • c) := by + conv_lhs => rw [← Complex.re_add_im ζ] + rw [add_smul, mul_smul, Complex.coe_smul, Complex.coe_smul] + +/-- A nonzero continuous linear functional attains the value `1` on a nonzero vector. -/ +theorem ContinuousLinearMap.exists_apply_eq_one_of_ne_zero {𝕜 E : Type*} + [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] {ℓ : E →L[𝕜] 𝕜} + (hℓ : ℓ ≠ 0) : ∃ ν, ℓ ν = 1 ∧ 0 < ‖ν‖ := by + have hℓ' : (ℓ : E →ₗ[𝕜] 𝕜) ≠ 0 := fun h => hℓ (ContinuousLinearMap.coe_injective h) + obtain ⟨ν, hν⟩ := LinearMap.surjective hℓ' 1 + refine ⟨ν, hν, norm_pos_iff.mpr fun h0 => ?_⟩ + rw [h0, map_zero] at hν + exact zero_ne_one hν + +/-- A nonzero functional whose closed negative half-space contains the open negative half-space of +another nonzero functional is a positive multiple of it. -/ +theorem ContinuousLinearMap.exists_pos_smul_eq_of_neg_imp_nonpos + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {ℓ₁ ℓ₂ : E →L[ℝ] ℝ} + (h₁ : ℓ₁ ≠ 0) (h₂ : ℓ₂ ≠ 0) + (h : ∀ v, ℓ₂ v < 0 → ℓ₁ v ≤ 0) : ∃ c : ℝ, 0 < c ∧ ℓ₁ = c • ℓ₂ := by + obtain ⟨u, hu⟩ : ∃ u, ℓ₂ u ≠ 0 := by + by_contra hcon + push Not at hcon + exact h₂ (ContinuousLinearMap.ext hcon) + set u₀ : E := (1 / ℓ₂ u) • u with hu₀ + have hℓu₀ : ℓ₂ u₀ = 1 := by rw [hu₀, map_smul, smul_eq_mul, one_div, inv_mul_cancel₀ hu] + set c := ℓ₁ u₀ with hc + -- the kernel of `ℓ₂` is contained in the kernel of `ℓ₁` + have hker : ∀ v, ℓ₂ v = 0 → ℓ₁ v = 0 := by + intro v hv + have hle : ∀ ε : ℝ, 0 < ε → ℓ₁ v ≤ ε * c := by + intro ε hε + have := h (v - ε • u₀) (by rw [map_sub, map_smul, hv, hℓu₀, smul_eq_mul]; linarith) + rw [map_sub, map_smul, smul_eq_mul] at this + linarith + have hge : ∀ ε : ℝ, 0 < ε → -(ε * c) ≤ ℓ₁ v := by + intro ε hε + have := h (-v - ε • u₀) (by rw [map_sub, map_neg, map_smul, hv, hℓu₀, smul_eq_mul]; linarith) + rw [map_sub, map_neg, map_smul, smul_eq_mul] at this + linarith + have h1 : ℓ₁ v ≤ 0 := le_of_forall_pos_le_add fun ε hε => by + have := hle (ε / (|c| + 1)) (by positivity) + have hcb : ε / (|c| + 1) * c ≤ ε := by + rw [div_mul_eq_mul_div, div_le_iff₀ (by positivity)] + nlinarith [le_abs_self c, abs_nonneg c] + linarith + have h2 : 0 ≤ ℓ₁ v := by + by_contra hneg + push Not at hneg + have := hge (-ℓ₁ v / (2 * (|c| + 1))) (div_pos (by linarith) (by positivity)) + have hcb : -ℓ₁ v / (2 * (|c| + 1)) * c ≤ -ℓ₁ v / 2 := by + rw [div_mul_eq_mul_div, div_le_iff₀ (by positivity)] + nlinarith [le_abs_self c, abs_nonneg c] + linarith + exact le_antisymm h1 h2 + have heq : ℓ₁ = c • ℓ₂ := by + ext v + have hv : ℓ₂ (v - ℓ₂ v • u₀) = 0 := by rw [map_sub, map_smul, hℓu₀, smul_eq_mul, mul_one, + sub_self] + have := hker _ hv + rw [map_sub, map_smul, smul_eq_mul, sub_eq_zero] at this + rw [this, smul_apply, smul_eq_mul, hc, mul_comm] + have hc0 : 0 ≤ c := by + have := h (-u₀) (by rw [map_neg, hℓu₀]; norm_num) + rw [map_neg] at this + linarith + refine ⟨c, lt_of_le_of_ne hc0 fun hzero => h₁ ?_, heq⟩ + rw [heq, ← hzero, zero_smul] + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/OpenMapping.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/OpenMapping.lean new file mode 100644 index 0000000000..00b9c3990a --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/OpenMapping.lean @@ -0,0 +1,161 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.Analysis.SpecificLimits.Normed +public import Mathlib.Topology.Algebra.IsUniformGroup.Basic +public import Mathlib.Topology.Algebra.Module.Equiv +public import Mathlib.Topology.Baire.CompleteMetrizable +public import Mathlib.Topology.Baire.Lemmas + +/-! +# Open mapping for complete metrizable real or complex vector spaces + +This supplies the open-mapping argument needed for holomorphic function spaces with their +compact-open topology. Baire's theorem first gives neighborhoods in closures of images; +successive approximations and completeness remove the closure. The compatible metrics need not +arise from norms and scalar multiplication need not preserve them. + +## Main results + +`isOpenMap_of_surjective_complete` is the open mapping theorem for a surjective continuous +linear map from a complete metrizable space to a Hausdorff metrizable Baire space. Its proof goes +through a private neighborhood form: the image of every zero neighborhood is a zero neighborhood. +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace ContinuousLinearMap + +variable {𝕜 E F : Type*} [RCLike 𝕜] [AddCommGroup E] [Module 𝕜 E] [PseudoMetricSpace E] + [IsUniformAddGroup E] [ContinuousSMul 𝕜 E] + [AddCommGroup F] [Module 𝕜 F] [PseudoMetricSpace F] + [IsUniformAddGroup F] [ContinuousSMul 𝕜 F] + +/-- Baire's theorem gives a neighborhood in the closure of the image of any zero neighborhood under +a surjective continuous linear map. -/ +private theorem closure_image_mem_nhds_of_surjective [BaireSpace F] + (T : E →L[𝕜] F) (hs : Function.Surjective T) {W : Set E} (hW : W ∈ 𝓝 0) : + closure (T '' W) ∈ 𝓝 0 := by + classical + have hsub : {p : E × E | p.1 - p.2 ∈ W} ∈ 𝓝 (0, 0) := + (continuous_fst.sub continuous_snd).continuousAt.preimage_mem_nhds (by simpa using hW) + obtain ⟨D, hD, D', hD', hDD⟩ := mem_nhds_prod_iff.mp hsub + let B := D ∩ D' + have hB : B ∈ 𝓝 (0 : E) := inter_mem hD hD' + have hBW {x y : E} (hx : x ∈ B) (hy : y ∈ B) : x - y ∈ W := + hDD (show (x, y) ∈ D ×ˢ D' from ⟨hx.1, hy.2⟩) + let c (n : ℕ) : 𝕜 := (n + 1 : ℕ) + have hc (n : ℕ) : c n ≠ 0 := by dsimp [c]; exact_mod_cast Nat.succ_ne_zero n + let e (n : ℕ) : F ≃L[𝕜] F := + ContinuousLinearEquiv.smulLeft (R₁ := 𝕜) (M₁ := F) (Units.mk0 (c n) (hc n)) + let S := closure (T '' B) + have hcover : ⋃ n, e n '' S = univ := by + apply iUnion_eq_univ_iff.mpr + intro y + obtain ⟨x, rfl⟩ := hs y + have ht : Tendsto (fun n => (c n)⁻¹ • x) atTop (𝓝 (0 : E)) := by + simpa [c, one_div] using + (tendsto_one_div_add_atTop_nhds_zero_nat (𝕜 := 𝕜)).smul_const x + obtain ⟨n, hn⟩ := (ht.eventually hB).exists + refine ⟨n, T ((c n)⁻¹ • x), subset_closure ⟨_, hn, rfl⟩, ?_⟩ + simp [e, map_smul, smul_smul, hc] + obtain ⟨n, z, hz⟩ := nonempty_interior_of_iUnion_of_closed + (fun n => (e n).toHomeomorph.isClosedMap S isClosed_closure) hcover + let a := (e n).symm z + have hS : S ∈ 𝓝 a := by + have hh := (e n).continuous.continuousAt.preimage_mem_nhds + (show e n '' S ∈ 𝓝 (e n a) by + simpa [a] using mem_interior_iff_mem_nhds.mp hz) + simpa only [preimage_image_eq _ (e n).injective] using hh + have ha : a ∈ S := mem_of_mem_nhds hS + have hN : (fun y : F => y + a) ⁻¹' S ∈ 𝓝 0 := + (continuous_id.add continuous_const).continuousAt.preimage_mem_nhds (by simpa using hS) + apply mem_of_superset hN + intro y hy + have hh : (y + a) - a ∈ closure (T '' W) := + map_mem_closure₂ continuous_sub hy ha (by + rintro _ ⟨x, hx, rfl⟩ _ ⟨x', hx', rfl⟩ + exact ⟨x - x', hBW hx hx', T.map_sub x x'⟩) + simpa only [add_sub_cancel_right] using hh + +/-- Completeness removes the closure from the neighborhood conclusion in the Baire argument by +successively correcting the error with geometrically small increments. -/ +private theorem image_mem_nhds_of_surjective [CompleteSpace E] [BaireSpace F] [T2Space F] + (T : E →L[𝕜] F) (hs : Function.Surjective T) {W : Set E} (hW : W ∈ 𝓝 0) : + T '' W ∈ 𝓝 0 := by + classical + obtain ⟨r, hr, hrW⟩ := Metric.nhds_basis_closedBall.mem_iff.mp hW + have hsmall (n : ℕ) : ∃ B ∈ 𝓝 (0 : E), + ∀ x ∈ B, ∀ s : E, dist s (s + x) ≤ (r / 2) * (1 / 2 : ℝ) ^ n := by + have h := dist_mem_uniformity (α := E) (show 0 < (r / 2) * (1 / 2 : ℝ) ^ n by positivity) + rw [uniformity_eq_comap_nhds_zero E] at h + obtain ⟨B, hB, hsub⟩ := Filter.mem_comap.mp h + refine ⟨B, hB, fun x hx s => le_of_lt (hsub + (show (s, s + x) ∈ (fun p : E × E => p.2 - p.1) ⁻¹' B from ?_))⟩ + change (s + x) - s ∈ B + simpa only [add_sub_cancel_left] using hx + choose B hB hdist using hsmall + let V (n : ℕ) := interior (closure (T '' B n)) ∩ ball 0 (1 / ((n : ℝ) + 1)) + have hVo (n : ℕ) : IsOpen (V n) := isOpen_interior.inter isOpen_ball + have hV0 (n : ℕ) : (0 : F) ∈ V n := by + refine ⟨mem_interior_iff_mem_nhds.mpr + (closure_image_mem_nhds_of_surjective T hs (hB n)), ?_⟩ + simp only [mem_ball, dist_self] + positivity + have happrox (n : ℕ) (y : F) (hy : y ∈ V n) : + ∃ x ∈ B n, y - T x ∈ V (n + 1) := by + have hopen : IsOpen ((fun z : F => y - z) ⁻¹' V (n + 1)) := + (hVo _).preimage (continuous_const.sub continuous_id) + obtain ⟨z, hz, x, hx, rfl⟩ := + _root_.mem_closure_iff.mp (interior_subset hy.1) _ hopen (by simpa using hV0 (n + 1)) + exact ⟨x, hx, hz⟩ + apply mem_of_superset ((hVo 0).mem_nhds (hV0 0)) + intro y hy + let step (n : ℕ) (s : {s : E // y - T s ∈ V n}) : + {s : E // y - T s ∈ V (n + 1)} := + ⟨s.val + (happrox n (y - T s.val) s.property).choose, by + have h := (happrox n (y - T s.val) s.property).choose_spec.2 + simpa only [map_add, sub_sub] using h⟩ + let seq : (n : ℕ) → {s : E // y - T s ∈ V n} := + fun n => Nat.rec (motive := fun n => {s : E // y - T s ∈ V n}) + ⟨0, by simpa using hy⟩ step n + have hd (n : ℕ) : dist (seq n).val (seq (n + 1)).val ≤ (r / 2) * (1 / 2 : ℝ) ^ n := + hdist n _ (happrox n (y - T (seq n).val) (seq n).property).choose_spec.1 _ + obtain ⟨x, hx⟩ := cauchySeq_tendsto_of_complete + (cauchySeq_of_le_geometric (1 / 2) (r / 2) (by norm_num) hd) + have hxW : x ∈ W := by + apply hrW + have h := dist_le_of_le_geometric_of_tendsto₀ (1 / 2) (r / 2) (by norm_num) hd hx + change dist x 0 ≤ r + norm_num [seq, dist_comm, div_div] at h ⊢ + exact h + have herr : Tendsto (fun n => y - T (seq n).val) atTop (𝓝 0) := by + apply tendsto_iff_dist_tendsto_zero.mpr + apply squeeze_zero (fun _ => dist_nonneg) + (fun n => le_of_lt (show dist (y - T (seq n).val) 0 < 1 / ((n : ℝ) + 1) from + (seq n).property.2)) + exact tendsto_one_div_add_atTop_nhds_zero_nat + have heq : y - T x = 0 := tendsto_nhds_unique + (tendsto_const_nhds.sub (T.continuous.tendsto x |>.comp hx)) herr + exact ⟨x, hxW, (sub_eq_zero.mp heq).symm⟩ + +/-- A surjective continuous real- or complex-linear map from a complete metrizable topological +vector space to a Hausdorff metrizable Baire vector space is open. The metrics only need to +induce the additive uniformities; they need not arise from norms. -/ +theorem isOpenMap_of_surjective_complete [CompleteSpace E] [BaireSpace F] [T2Space F] + (T : E →L[𝕜] F) (hs : Function.Surjective T) : IsOpenMap T := by + apply IsTopologicalAddGroup.isOpenMap_iff_nhds_zero.mpr + intro S hS + exact mem_of_superset (image_mem_nhds_of_surjective T hs hS) (image_preimage_subset _ _) + +end ContinuousLinearMap + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/TaylorBounds.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/TaylorBounds.lean new file mode 100644 index 0000000000..1ce09152d7 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analysis/TaylorBounds.lean @@ -0,0 +1,77 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.SpecialFunctions.Pow.Real + +import Mathlib.Tactic.GCongr +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Elementary bounds for Taylor remainders + +These real inequalities choose a small radius and absorb a cubic error into a quadratic bound. + +## Main results + +* `le_one_and_mul_add_le_of_le_min`: Radius constraints used to absorb a cubic Taylor error into a + quadratic budget `η t ^ 2`. +* `taylor_remainder_add_cubic_le`: Combine a second-order remainder of size `O(t ^ 2)` with a cubic + error of size `O(t ^ 3)` into a single quadratic bound `η t ^ 2`. +-/ + +public section + +namespace SeveralComplexVariables.TaylorBounds + +/-- Radius constraints used to absorb a cubic Taylor error into a quadratic budget `η t ^ 2`. -/ +theorem le_one_and_mul_add_le_of_le_min {η M₀ M₁ δ' r : ℝ} (hM₀ : 0 ≤ M₀) + (hM₁ : 0 ≤ M₁) (hr : 0 < r) + (hr₀ : r ≤ min 1 (min (η / (2 * (M₁ + 1))) (δ' / (2 * (M₀ + 1))))) : + r ≤ 1 ∧ r * (M₁ + 1) ≤ η / 2 ∧ r * (M₀ + 1) < δ' := by + have hr1 : r ≤ 1 := hr₀.trans (min_le_left _ _) + have hrM₁ : r * (M₁ + 1) ≤ η / 2 := by + have := hr₀.trans ((min_le_right _ _).trans (min_le_left _ _)) + rw [le_div_iff₀ (by positivity)] at this + linarith + have hrδ' : r * (M₀ + 1) < δ' := by + have := hr₀.trans ((min_le_right _ _).trans (min_le_right _ _)) + rw [le_div_iff₀ (by positivity)] at this + have : 0 < r * (M₀ + 1) := by positivity + linarith + exact ⟨hr1, hrM₁, hrδ'⟩ + +/-- Combine a second-order remainder of size `O(t ^ 2)` with a cubic error of size `O(t ^ 3)` into a +single quadratic bound `η t ^ 2`. -/ +theorem taylor_remainder_add_cubic_le {η t M₀ M₁ rem cub : ℝ} (ht : 0 < t) (hη : 0 < η) + (htM₁ : t * (M₁ + 1) ≤ η / 2) + (hrem : |rem| ≤ η / (2 * (M₀ ^ 2 + 1)) * (t * M₀) ^ 2) (hcub : |cub| ≤ M₁ * t ^ 3) : + |rem + cub| ≤ η * t ^ 2 := by + have hR : |rem| ≤ η / 2 * t ^ 2 := by + refine hrem.trans ?_ + rw [mul_pow, div_mul_eq_mul_div, div_le_iff₀ (by positivity)] + have : M₀ ^ 2 ≤ M₀ ^ 2 + 1 := by linarith + calc η * (t ^ 2 * M₀ ^ 2) ≤ η * (t ^ 2 * (M₀ ^ 2 + 1)) := by gcongr + _ = η / 2 * t ^ 2 * (2 * (M₀ ^ 2 + 1)) := by ring + have hC : |cub| ≤ η / 2 * t ^ 2 := by + refine hcub.trans ?_ + calc M₁ * t ^ 3 = t * M₁ * t ^ 2 := by ring + _ ≤ η / 2 * t ^ 2 := by + refine mul_le_mul_of_nonneg_right ?_ (by positivity) + have : t * M₁ ≤ t * (M₁ + 1) := + mul_le_mul_of_nonneg_left (by linarith) ht.le + linarith + calc |rem + cub| ≤ |rem| + |cub| := abs_add_le _ _ + _ ≤ η / 2 * t ^ 2 + η / 2 * t ^ 2 := add_le_add hR hC + _ = η * t ^ 2 := by ring + +end SeveralComplexVariables.TaylorBounds + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm.lean new file mode 100644 index 0000000000..bb74e71fe2 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm.lean @@ -0,0 +1,345 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.RingTheory.Ideal.Quotient.Operations +public import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic +public import Mathlib.Topology.Germ +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Basic + +/-! +# The local ring of analytic germs + +An analytic germ is a Mathlib `Filter.Germ` with a representative analytic at the base point. +Equality is agreement on a neighborhood, rather than equality just at the base point. The scalar +field `𝕜` is an explicit argument, `AnalyticGerm 𝕜 x`, and may be any nontrivially normed field: +the scalar germs form a `𝕜`-algebra, evaluation detects its units, identifies its unique maximal +ideal with the germs vanishing at the base point, and identifies the quotient with `𝕜`, and +analytic maps act contravariantly by `𝕜`-algebra homomorphisms. Over `ℝ` or `ℂ` the germs form an +integral domain, by the identity principle on connected balls. The rest of the germ theory in this +library is developed for `𝕜 = ℂ`. + +The motivating references are [Suwa][Suwa2024] (2024), Section 1.4, Propositions 1.5--1.7, and +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Section 1.8. We use `AnalyticAt` for +convergent power series; on finite-dimensional complex domains this agrees with the project's +holomorphic convention. The construction works on arbitrary normed spaces, including the zero +space. Analytic Weierstrass division and preparation are not asserted here. + +## Main definitions + +* `analyticGermSubring`: The subring of germs admitting a representative analytic at the base point. +* `AnalyticGerm`: Scalar analytic germs at `x`, with the ring operations inherited from Mathlib + germs. +* `ofAnalyticAt`: The germ of a function analytic at the base point. +* `eval`: Evaluation of an analytic germ at its base point, as a ring homomorphism. +* `const`: Constant functions define a ring homomorphism into analytic germs. +* `evalAlgHom`: Evaluation also preserves the `𝕜`-algebra structure. +* `pullback`: Composition with an analytic map pulls scalar germs back as a `𝕜`-algebra + homomorphism. +* `pullbackOfEq`: Pullback along a map whose value at the source point is only known up to a stated + equation, letting the target germ's base point be phrased as any value equal to `f x`. +* `quotientKerEvalEquiv`: Quotienting analytic germs by the evaluation kernel gives the scalar + field. +* `quotientMaximalIdealEquiv`: The quotient by the unique maximal ideal is canonically the scalar + field. +* `equivScalarOfSubsingleton`: Analytic germs on a zero-dimensional domain form exactly the scalar + field. + +## Main results + +* `isUnit_iff`: An analytic germ is invertible exactly when its value at the base point is nonzero. +* `maximalIdeal_eq_ker_eval`: Evaluation has the unique maximal ideal as its kernel. +* `pullback_comp`: Pullbacks compose in the reverse order to their analytic maps. +* `eval_surjective`: Evaluation onto the scalar field is surjective. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [T. Suwa, *Complex Analytic Geometry: From the Localization Viewpoint*][Suwa2024] +-/ + +public noncomputable section + +open Filter Set Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {𝕜 E : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] + +variable (𝕜) in +/-- The subring of germs admitting a representative analytic at the base point. -/ +@[expose] def analyticGermSubring (x : E) : Subring (Germ (𝓝 x) 𝕜) where + carrier := {φ | ∃ f : E → 𝕜, AnalyticAt 𝕜 f x ∧ (f : Germ (𝓝 x) 𝕜) = φ} + zero_mem' := ⟨0, analyticAt_const, rfl⟩ + one_mem' := ⟨1, analyticAt_const, rfl⟩ + add_mem' := by + rintro _ _ ⟨f, hf, rfl⟩ ⟨g, hg, rfl⟩ + exact ⟨f + g, hf.add hg, rfl⟩ + neg_mem' := by + rintro _ ⟨f, hf, rfl⟩ + exact ⟨-f, hf.neg, rfl⟩ + mul_mem' := by + rintro _ _ ⟨f, hf, rfl⟩ ⟨g, hg, rfl⟩ + exact ⟨f * g, hf.mul hg, rfl⟩ + +/-- Membership of a represented germ is exactly analyticity of that representative. -/ +@[simp] theorem mem_analyticGermSubring {x : E} {f : E → 𝕜} : + (f : Germ (𝓝 x) 𝕜) ∈ analyticGermSubring 𝕜 x ↔ AnalyticAt 𝕜 f x := by + constructor + · rintro ⟨g, hg, heq⟩ + exact hg.congr (Germ.coe_eq.mp heq) + · intro hf + exact ⟨f, hf, rfl⟩ + +variable (𝕜) in +/-- Scalar analytic germs at `x` over the field `𝕜`, with the ring operations inherited from +Mathlib germs. -/ +abbrev AnalyticGerm (x : E) : Type _ := ↥(analyticGermSubring 𝕜 x) + +namespace AnalyticGerm + +variable {x : E} + +/-- The germ of a function analytic at the base point. -/ +@[expose] def ofAnalyticAt (f : E → 𝕜) (hf : AnalyticAt 𝕜 f x) : AnalyticGerm 𝕜 x := + ⟨f, f, hf, rfl⟩ + +/-- Every analytic germ has an analytic representative. -/ +theorem exists_rep (φ : AnalyticGerm 𝕜 x) : + ∃ (f : E → 𝕜) (hf : AnalyticAt 𝕜 f x), ofAnalyticAt f hf = φ := by + obtain ⟨f, hf, heq⟩ := φ.property + exact ⟨f, hf, Subtype.ext heq⟩ + +/-- Two analytic representatives define the same germ exactly when they agree nearby. -/ +@[simp] theorem ofAnalyticAt_eq_iff {f g : E → 𝕜} + {hf : AnalyticAt 𝕜 f x} {hg : AnalyticAt 𝕜 g x} : + ofAnalyticAt f hf = ofAnalyticAt g hg ↔ f =ᶠ[𝓝 x] g := by + rw [Subtype.ext_iff] + exact Germ.coe_eq + +/-- The zero germ is represented by the zero function. -/ +theorem ofAnalyticAt_zero : + ofAnalyticAt (0 : E → 𝕜) analyticAt_const = (0 : AnalyticGerm 𝕜 x) := rfl + +/-- Sums of analytic representatives compute sums of germs. -/ +theorem ofAnalyticAt_add (f g : E → 𝕜) (hf : AnalyticAt 𝕜 f x) (hg : AnalyticAt 𝕜 g x) : + ofAnalyticAt (f + g) (hf.add hg) = ofAnalyticAt f hf + ofAnalyticAt g hg := rfl + +/-- Products of analytic representatives compute products of germs. -/ +theorem ofAnalyticAt_mul (f g : E → 𝕜) (hf : AnalyticAt 𝕜 f x) (hg : AnalyticAt 𝕜 g x) : + ofAnalyticAt (f * g) (hf.mul hg) = ofAnalyticAt f hf * ofAnalyticAt g hg := rfl + +/-- Powers of analytic representatives compute powers of germs. -/ +theorem ofAnalyticAt_pow (f : E → 𝕜) (hf : AnalyticAt 𝕜 f x) (n : ℕ) : + ofAnalyticAt (f ^ n) (hf.pow n) = ofAnalyticAt f hf ^ n := rfl + +/-- Finite sums of analytic representatives compute finite sums of germs. -/ +theorem ofAnalyticAt_sum {κ : Type*} (s : Finset κ) (f : κ → E → 𝕜) + (hf : ∀ i, AnalyticAt 𝕜 (f i) x) (hs : AnalyticAt 𝕜 (∑ i ∈ s, f i) x) : + ofAnalyticAt (∑ i ∈ s, f i) hs = ∑ i ∈ s, ofAnalyticAt (f i) (hf i) := by + apply Subtype.ext + change ((∑ i ∈ s, f i : E → 𝕜) : Germ (𝓝 x) 𝕜) = + ((∑ i ∈ s, ofAnalyticAt (f i) (hf i) : AnalyticGerm 𝕜 x) : Germ (𝓝 x) 𝕜) + rw [AddSubmonoidClass.coe_finsetSum] + exact map_sum (Filter.Germ.coeRingHom (𝓝 x)) f s + +/-- Evaluation of an analytic germ at its base point, as a ring homomorphism. -/ +@[expose] def eval (x : E) : AnalyticGerm 𝕜 x →+* 𝕜 := + Germ.valueRingHom.comp (analyticGermSubring 𝕜 x).subtype + +/-- Evaluation of a represented germ is evaluation of its representative. -/ +@[simp] theorem eval_ofAnalyticAt (f : E → 𝕜) (hf : AnalyticAt 𝕜 f x) : + eval x (ofAnalyticAt f hf) = f x := rfl + +/-- Constant functions define a ring homomorphism into analytic germs. -/ +@[expose] def const (x : E) : 𝕜 →+* AnalyticGerm 𝕜 x where + toFun c := ofAnalyticAt (fun _ => c) analyticAt_const + map_zero' := rfl + map_one' := rfl + map_add' _ _ := rfl + map_mul' _ _ := rfl + +/-- Analytic germs form a `𝕜`-algebra via constant germs. -/ +instance : Algebra 𝕜 (AnalyticGerm 𝕜 x) := (const x).toAlgebra + +/-- Evaluation of a constant germ recovers its constant value. -/ +@[simp] theorem eval_const (c : 𝕜) : eval x (const x c) = c := rfl + +/-- Evaluation onto the scalar field is surjective. -/ +theorem eval_surjective (x : E) : Function.Surjective (eval (𝕜 := 𝕜) x) := + fun c => ⟨const x c, rfl⟩ + +/-- Evaluation also preserves the `𝕜`-algebra structure. -/ +def evalAlgHom (x : E) : AnalyticGerm 𝕜 x →ₐ[𝕜] 𝕜 where + __ := eval x + commutes' _ := rfl + +section Pullback + +variable {F G : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] + [NormedAddCommGroup G] [NormedSpace 𝕜 G] + +/-- Composition with an analytic map pulls scalar germs back as a `𝕜`-algebra homomorphism. +Mathlib's `compTendsto` makes the construction independent of representatives. -/ +@[expose] def pullback (f : E → F) (hf : AnalyticAt 𝕜 f x) : + AnalyticGerm 𝕜 (f x) →ₐ[𝕜] AnalyticGerm 𝕜 x where + toFun φ := ⟨φ.val.compTendsto f hf.continuousAt, by + obtain ⟨g, hg, heq⟩ := φ.property + refine ⟨g ∘ f, hg.comp hf, ?_⟩ + rw [← heq] + rfl⟩ + map_zero' := rfl + map_one' := rfl + map_add' a b := by + obtain ⟨g, hg, rfl⟩ := exists_rep a + obtain ⟨h, hh, rfl⟩ := exists_rep b + rfl + map_mul' a b := by + obtain ⟨g, hg, rfl⟩ := exists_rep a + obtain ⟨h, hh, rfl⟩ := exists_rep b + rfl + commutes' _ := rfl + +/-- Pullback of a represented germ is represented by composition. -/ +@[simp] theorem pullback_ofAnalyticAt (f : E → F) (hf : AnalyticAt 𝕜 f x) + (g : F → 𝕜) (hg : AnalyticAt 𝕜 g (f x)) : + pullback f hf (ofAnalyticAt g hg) = ofAnalyticAt (g ∘ f) (hg.comp hf) := rfl + +/-- Pullback along a map whose value at the source point is only known up to a stated equation, +letting the target germ's base point be phrased as any value equal to `f x`. Matches `pullback` +definitionally once the equation is substituted. -/ +def pullbackOfEq (f : E → F) (hf : AnalyticAt 𝕜 f x) {y : F} (hy : f x = y) : + AnalyticGerm 𝕜 y →ₐ[𝕜] AnalyticGerm 𝕜 x := + hy ▸ pullback f hf + +/-- Pullback along an equation-adjusted map of a represented germ is represented by composition. -/ +@[simp] theorem pullbackOfEq_ofAnalyticAt (f : E → F) (hf : AnalyticAt 𝕜 f x) {y : F} + (hy : f x = y) (g : F → 𝕜) (hg : AnalyticAt 𝕜 g y) : + pullbackOfEq f hf hy (ofAnalyticAt g hg) = ofAnalyticAt (g ∘ f) (hg.comp_of_eq hf hy) := by + subst hy + rfl + +/-- Evaluation commutes with pullback at the corresponding base points. -/ +@[simp] theorem eval_pullback (f : E → F) (hf : AnalyticAt 𝕜 f x) + (φ : AnalyticGerm 𝕜 (f x)) : eval x (pullback f hf φ) = eval (f x) φ := by + obtain ⟨g, hg, rfl⟩ := exists_rep φ + rfl + +/-- Pullback by the identity fixes every analytic germ. -/ +@[simp] theorem pullback_id (φ : AnalyticGerm 𝕜 x) : + pullback (fun y : E => y) analyticAt_id φ = φ := by + obtain ⟨f, hf, rfl⟩ := exists_rep φ + rfl + +/-- Pullbacks compose in the reverse order to their analytic maps. -/ +theorem pullback_comp (f : E → F) (hf : AnalyticAt 𝕜 f x) + (g : F → G) (hg : AnalyticAt 𝕜 g (f x)) (φ : AnalyticGerm 𝕜 (g (f x))) : + pullback (g ∘ f) (hg.comp hf) φ = pullback f hf (pullback g hg φ) := by + obtain ⟨h, hh, rfl⟩ := exists_rep φ + rfl + +end Pullback + +/-- An analytic germ is invertible exactly when its value at the base point is nonzero. -/ +theorem isUnit_iff (φ : AnalyticGerm 𝕜 x) : IsUnit φ ↔ eval x φ ≠ 0 := by + constructor + · intro h + exact (h.map (eval x)).ne_zero + · obtain ⟨f, hf, rfl⟩ := exists_rep φ + intro h + have hne : f x ≠ 0 := h + let ψ := ofAnalyticAt (fun y => (f y)⁻¹) (hf.inv hne) + have hmul : ofAnalyticAt f hf * ψ = 1 := by + apply Subtype.ext + apply Germ.coe_eq.mpr + filter_upwards [hf.continuousAt.eventually_ne hne] with y hy + exact mul_inv_cancel₀ hy + exact ⟨⟨ofAnalyticAt f hf, ψ, hmul, by rwa [mul_comm]⟩, rfl⟩ + +/-- Pullback preserves and reflects units, as required of a homomorphism of local rings. -/ +theorem isUnit_pullback_iff {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] + (f : E → F) (hf : AnalyticAt 𝕜 f x) (φ : AnalyticGerm 𝕜 (f x)) : + IsUnit (pullback f hf φ) ↔ IsUnit φ := by + simp only [isUnit_iff, eval_pullback] + +/-- The ring of analytic germs is local. -/ +instance : IsLocalRing (AnalyticGerm 𝕜 x) where + isUnit_or_isUnit_of_add_one {a b} h := by + rw [isUnit_iff, isUnit_iff] + by_cases ha : eval x a = 0 + · right + have hv := congrArg (eval x) h + have hb : eval x b = 1 := by simpa [ha] using hv + rw [hb] + exact one_ne_zero + · exact Or.inl ha + +/-- The unique maximal ideal consists precisely of germs vanishing at the base point. -/ +theorem mem_maximalIdeal_iff (φ : AnalyticGerm 𝕜 x) : + φ ∈ IsLocalRing.maximalIdeal (AnalyticGerm 𝕜 x) ↔ eval x φ = 0 := by + simp [IsLocalRing.mem_maximalIdeal, mem_nonunits_iff, isUnit_iff] + +/-- Evaluation has the unique maximal ideal as its kernel. -/ +theorem maximalIdeal_eq_ker_eval (x : E) : + IsLocalRing.maximalIdeal (AnalyticGerm 𝕜 x) = RingHom.ker (eval (𝕜 := 𝕜) x) := by + ext φ + exact mem_maximalIdeal_iff φ + +variable (𝕜) in +/-- Quotienting analytic germs by the evaluation kernel gives the scalar field. -/ +def quotientKerEvalEquiv (x : E) : + AnalyticGerm 𝕜 x ⧸ RingHom.ker (eval (𝕜 := 𝕜) x) ≃+* 𝕜 := + (eval (𝕜 := 𝕜) x).quotientKerEquivOfSurjective (eval_surjective x) + +variable (𝕜) in +/-- The quotient by the unique maximal ideal is canonically the scalar field. -/ +def quotientMaximalIdealEquiv (x : E) : + AnalyticGerm 𝕜 x ⧸ IsLocalRing.maximalIdeal (AnalyticGerm 𝕜 x) ≃+* 𝕜 := + (Ideal.quotEquivOfEq (maximalIdeal_eq_ker_eval x)).trans (quotientKerEvalEquiv 𝕜 x) + +/-- In dimension zero, every analytic germ is the constant germ of its value. -/ +theorem const_eval_of_subsingleton [Subsingleton E] (φ : AnalyticGerm 𝕜 x) : + const x (eval x φ) = φ := by + obtain ⟨f, hf, rfl⟩ := exists_rep φ + apply Subtype.ext + apply Germ.coe_eq.mpr + exact Eventually.of_forall fun y => congrArg f (Subsingleton.elim x y) + +variable (𝕜) in +/-- Analytic germs on a zero-dimensional domain form exactly the scalar field. -/ +def equivScalarOfSubsingleton [Subsingleton E] (x : E) : AnalyticGerm 𝕜 x ≃+* 𝕜 := + RingEquiv.ofBijective (eval x) ⟨fun a b h => by + rw [← const_eval_of_subsingleton a, ← const_eval_of_subsingleton b, h], + eval_surjective x⟩ + +section RCLike + +variable {𝕜 E : Type*} [RCLike 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] {x : E} + +/-- Analytic germs over `ℝ` or `ℂ` have no zero divisors, by the analytic identity principle on +connected balls. -/ +instance : NoZeroDivisors (AnalyticGerm 𝕜 x) where + eq_zero_or_eq_zero_of_mul_eq_zero {a b} hab := by + obtain ⟨f, hf, rfl⟩ := exists_rep a + obtain ⟨g, hg, rfl⟩ := exists_rep b + have hfg : (fun y => f y * g y) =ᶠ[𝓝 x] 0 := + Germ.coe_eq.mp (congrArg Subtype.val hab) + rcases eventuallyEq_zero_or_eventuallyEq_zero_of_mul hf hg hfg with h | h + · exact Or.inl (Subtype.ext (Germ.coe_eq.mpr h)) + · exact Or.inr (Subtype.ext (Germ.coe_eq.mpr h)) + +/-- The ring of scalar analytic germs over `ℝ` or `ℂ` is an integral domain. -/ +instance : IsDomain (AnalyticGerm 𝕜 x) := NoZeroDivisors.to_isDomain _ + +end RCLike + +end AnalyticGerm +end SeveralComplexVariables + + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/CoefficientPolynomial.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/CoefficientPolynomial.lean new file mode 100644 index 0000000000..169c0a9bbe --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/CoefficientPolynomial.lean @@ -0,0 +1,241 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Polynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polynomial.OfFn + +/-! +# Polynomials built from coefficient germs + +`ofCoefficients` and `remainderOfCoefficients` build a polynomial in `X` from a finite family of +coefficient germs indexed below a fixed degree `d`, with and without the extra monic `X ^ d` +term respectively. Evaluated in the last coordinate by `polynomialHom`, these match the analytic +`weierstrassPolynomial` and `weierstrassRemainder` built from representatives of the same +coefficients. Every monic polynomial of degree `d`, and every polynomial of degree below `d`, is +recovered from its own coefficients in one of these two shapes. The constructions are thin +wrappers around Mathlib's `Polynomial.ofFn`; the algebraic reconstruction results are proved +over arbitrary semirings in `SeveralComplexVariables.Polynomial.OfFn`. + +This coefficient-level bookkeeping underlies Weierstrass division and preparation in the +analytic germ ring, proved in `SeveralComplexVariables.AnalyticGerm.Weierstrass`. + +## Main definitions + +* `ofCoefficients`: The monic polynomial in `X` of degree `d` with prescribed coefficient germs + below `d`. +* `remainderOfCoefficients`: The polynomial in `X` of degree below `d` with prescribed coefficient + germs. + +## Main results + +* `isDistinguishedAt_ofCoefficients`: The distinguished-shape polynomial is distinguished + when its coefficients vanish at the parameter origin. +* `eq_ofCoefficients_of_monic`: Any monic polynomial of degree `d` is the distinguished-shape + polynomial built from its own coefficients. +* `polynomialHom_ofCoefficients`: Evaluating the distinguished-shape polynomial in the last + coordinate gives the Weierstrass polynomial built from analytic representatives of the coefficient + germs. +* `eq_remainderOfCoefficients_of_degree_lt`: Any polynomial of degree below `d` is the + remainder-shape polynomial built from its own coefficients. +-/ + +public noncomputable section + +namespace SeveralComplexVariables.AnalyticGerm + +open Filter +open scoped Topology + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +open Classical in +/-- The monic polynomial in `X` of degree `d` with prescribed coefficient germs below `d`. -/ +@[expose] def ofCoefficients {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) : + Polynomial (AnalyticGerm ℂ (0 : E)) := + Polynomial.X ^ d + Polynomial.ofFn d b + +open Classical in +/-- The lower-degree part of `ofCoefficients` has degree strictly below `d`. -/ +theorem degree_sum_lt {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) : + (∑ j : Fin d, Polynomial.C (b j) * Polynomial.X ^ (j : ℕ)).degree < (d : WithBot ℕ) := + Polynomial.degree_sum_fin_lt b + +open Classical in +/-- The distinguished-shape polynomial built from coefficient germs is monic. -/ +theorem monic_ofCoefficients {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) : + (ofCoefficients b).Monic := + Polynomial.monic_X_pow_add (Polynomial.ofFn_degree_lt b) + +open Classical in +/-- The distinguished-shape polynomial built from coefficient germs has degree `d`. -/ +theorem natDegree_ofCoefficients {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) : + (ofCoefficients b).natDegree = d := + Polynomial.natDegree_X_pow_add_ofFn b + +open Classical in +/-- Coefficients of `ofCoefficients` below `d` recover the prescribed germs. -/ +theorem coeff_ofCoefficients_of_lt {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) {i : ℕ} + (hi : i < d) : (ofCoefficients b).coeff i = b ⟨i, hi⟩ := + Polynomial.coeff_X_pow_add_ofFn_of_lt b hi + +open Classical in +/-- The distinguished-shape polynomial is distinguished when its coefficients vanish at the +parameter origin. -/ +theorem isDistinguishedAt_ofCoefficients {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) + (hb : ∀ j, eval 0 (b j) = 0) : + (ofCoefficients b).IsDistinguishedAt (IsLocalRing.maximalIdeal _) := by + rw [isDistinguishedAt_iff] + refine ⟨monic_ofCoefficients b, fun i hi => ?_⟩ + rw [natDegree_ofCoefficients] at hi + rw [coeff_ofCoefficients_of_lt b hi] + exact hb _ + +open Classical in +/-- Any monic polynomial of degree `d` is the distinguished-shape polynomial built from its own +coefficients. -/ +theorem eq_ofCoefficients_of_monic {w : Polynomial (AnalyticGerm ℂ (0 : E))} {d : ℕ} + (hm : w.Monic) (hd : w.natDegree = d) : + w = ofCoefficients (fun j : Fin d => w.coeff (j : ℕ)) := by + subst hd + exact hm.eq_X_pow_add_ofFn + +open Classical in +/-- Evaluating the distinguished-shape polynomial in the last coordinate gives the Weierstrass +polynomial built from analytic representatives of the coefficient germs. -/ +theorem polynomialHom_ofCoefficients {d : ℕ} (a : Fin d → E → ℂ) + (ha : ∀ j, AnalyticAt ℂ (a j) 0) : + polynomialHom (ofCoefficients (fun j => ofAnalyticAt (a j) (ha j))) = + ofAnalyticAt (weierstrassPolynomial a) (analyticAt_weierstrassPolynomial ha) := by + have hfst : AnalyticAt ℂ (Prod.fst : E × ℂ → E) 0 := analyticAt_fst + have hsnd : AnalyticAt ℂ (Prod.snd : E × ℂ → ℂ) 0 := analyticAt_snd + have hlc : (lastCoordinate : AnalyticGerm ℂ (0 : E × ℂ)) = ofAnalyticAt Prod.snd hsnd := rfl + rw [ofCoefficients, Polynomial.ofFn_eq_sum_monomial] + simp only [← Polynomial.C_mul_X_pow_eq_monomial] + simp only [map_add, map_sum, map_mul, map_pow, polynomialHom_C, polynomialHom_X, hlc] + have hstep : ∀ j : Fin d, parameterHom (ofAnalyticAt (a j) (ha j)) * + ofAnalyticAt Prod.snd hsnd ^ (j : ℕ) = + ofAnalyticAt (a j ∘ Prod.fst * Prod.snd ^ (j : ℕ)) + (((ha j).comp_of_eq hfst rfl).mul (hsnd.pow (j : ℕ))) := by + intro j + have hpar := pullback_ofAnalyticAt Prod.fst (analyticAt_fst (p := (0 : E × ℂ))) (a j) (ha j) + change pullback Prod.fst (analyticAt_fst (p := (0 : E × ℂ))) (ofAnalyticAt (a j) (ha j)) * + ofAnalyticAt Prod.snd hsnd ^ (j : ℕ) = _ + rw [hpar, ← ofAnalyticAt_pow, ofAnalyticAt_mul] + rw [Finset.sum_congr rfl (fun j _ => hstep j), + ← ofAnalyticAt_sum Finset.univ (fun j => a j ∘ Prod.fst * Prod.snd ^ (j : ℕ)) + (fun j => ((ha j).comp_of_eq hfst rfl).mul (hsnd.pow (j : ℕ))) + (Finset.analyticAt_sum _ fun j _ => ((ha j).comp_of_eq hfst rfl).mul (hsnd.pow (j : ℕ))), + ← ofAnalyticAt_pow, ← ofAnalyticAt_add] + congr 1 + funext z + simp [weierstrassPolynomial, weierstrassRemainder, Function.comp] + +open Classical in +/-- A distinguished polynomial's image is regular of order equal to its degree: the Weierstrass +polynomial built from representatives of its coefficients has central slice `t ↦ t ^ d`, whose +order at the origin is exactly `d`. -/ +theorem orderInLastVariable_polynomialHom_of_isDistinguishedAt + {w : Polynomial (AnalyticGerm ℂ (0 : E))} + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) : + orderInLastVariable (polynomialHom w) = w.natDegree := by + obtain ⟨hwmon, hwcoeff0⟩ := (isDistinguishedAt_iff w).mp hw + set d := w.natDegree with hd_def + have hweq : w = ofCoefficients (fun j : Fin d => w.coeff (j : ℕ)) := + eq_ofCoefficients_of_monic hwmon hd_def + choose a0 ha0 haeq using fun j : Fin d => exists_rep (w.coeff (j : ℕ)) + have ha00 : ∀ j : Fin d, a0 j 0 = 0 := by + intro j + have h0 := hwcoeff0 (j : ℕ) j.isLt + rw [← haeq j, eval_ofAnalyticAt] at h0 + exact h0 + have hweq2 : w = ofCoefficients (fun j : Fin d => ofAnalyticAt (a0 j) (ha0 j)) := by + rw [hweq]; congr 1; funext j; exact (haeq j).symm + have hwhom : polynomialHom w = ofAnalyticAt (weierstrassPolynomial a0) + (analyticAt_weierstrassPolynomial ha0) := by + rw [hweq2]; exact polynomialHom_ofCoefficients a0 ha0 + rw [hwhom, orderInLastVariable_ofAnalyticAt] + have hcentral : (fun t : ℂ => weierstrassPolynomial a0 (0, t)) = fun t : ℂ => t ^ d := + funext (weierstrassPolynomial_central ha00) + rw [hcentral] + change analyticOrderAt ((id : ℂ → ℂ) ^ d) 0 = d + rw [analyticOrderAt_pow (analyticAt_id (𝕜 := ℂ)) d, analyticOrderAt_id] + simp + +open Classical in +/-- The polynomial in `X` of degree below `d` with prescribed coefficient germs. -/ +@[expose] def remainderOfCoefficients {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) : + Polynomial (AnalyticGerm ℂ (0 : E)) := + Polynomial.ofFn d b + +open Classical in +/-- The remainder-shape polynomial has degree strictly below `d`. -/ +theorem degree_remainderOfCoefficients_lt {d : ℕ} (b : Fin d → AnalyticGerm ℂ (0 : E)) : + (remainderOfCoefficients b).degree < (d : WithBot ℕ) := Polynomial.ofFn_degree_lt b + +open Classical in +/-- Any polynomial of degree below `d` is the remainder-shape polynomial built from its own +coefficients. -/ +theorem eq_remainderOfCoefficients_of_degree_lt {r : Polynomial (AnalyticGerm ℂ (0 : E))} {d : ℕ} + (hr : r.degree < (d : WithBot ℕ)) : + r = remainderOfCoefficients (fun j : Fin d => r.coeff (j : ℕ)) := + (Polynomial.ofFn_toFn_eq_of_degree_lt hr).symm + +open Classical in +/-- Evaluating the remainder-shape polynomial in the last coordinate gives the Weierstrass remainder +built from analytic representatives of the coefficient germs. -/ +theorem polynomialHom_remainderOfCoefficients {d : ℕ} (a : Fin d → E → ℂ) + (ha : ∀ j, AnalyticAt ℂ (a j) 0) : + polynomialHom (remainderOfCoefficients (fun j => ofAnalyticAt (a j) (ha j))) = + ofAnalyticAt (weierstrassRemainder a) (analyticAt_weierstrassRemainder ha) := by + have hfst : AnalyticAt ℂ (Prod.fst : E × ℂ → E) 0 := analyticAt_fst + have hsnd : AnalyticAt ℂ (Prod.snd : E × ℂ → ℂ) 0 := analyticAt_snd + have hlc : (lastCoordinate : AnalyticGerm ℂ (0 : E × ℂ)) = ofAnalyticAt Prod.snd hsnd := rfl + rw [remainderOfCoefficients, Polynomial.ofFn_eq_sum_monomial] + simp only [← Polynomial.C_mul_X_pow_eq_monomial] + simp only [map_sum, map_mul, map_pow, polynomialHom_C, polynomialHom_X, hlc] + have hstep : ∀ j : Fin d, parameterHom (ofAnalyticAt (a j) (ha j)) * + ofAnalyticAt Prod.snd hsnd ^ (j : ℕ) = + ofAnalyticAt (a j ∘ Prod.fst * Prod.snd ^ (j : ℕ)) + (((ha j).comp_of_eq hfst rfl).mul (hsnd.pow (j : ℕ))) := by + intro j + have hpar := pullback_ofAnalyticAt Prod.fst (analyticAt_fst (p := (0 : E × ℂ))) (a j) (ha j) + change pullback Prod.fst (analyticAt_fst (p := (0 : E × ℂ))) (ofAnalyticAt (a j) (ha j)) * + ofAnalyticAt Prod.snd hsnd ^ (j : ℕ) = _ + rw [hpar, ← ofAnalyticAt_pow, ofAnalyticAt_mul] + rw [Finset.sum_congr rfl (fun j _ => hstep j), + ← ofAnalyticAt_sum Finset.univ (fun j => a j ∘ Prod.fst * Prod.snd ^ (j : ℕ)) + (fun j => ((ha j).comp_of_eq hfst rfl).mul (hsnd.pow (j : ℕ))) + (Finset.analyticAt_sum _ fun j _ => ((ha j).comp_of_eq hfst rfl).mul (hsnd.pow (j : ℕ)))] + congr 1 + funext z + simp [weierstrassRemainder, Function.comp] + +open Classical in +/-- `remainderOfCoefficients` is additive in the coefficient tuple. -/ +theorem remainderOfCoefficients_add {d : ℕ} (a b : Fin d → AnalyticGerm ℂ (0 : E)) : + remainderOfCoefficients (a + b) = remainderOfCoefficients a + remainderOfCoefficients b := + map_add (Polynomial.ofFn d) a b + +open Classical in +/-- `remainderOfCoefficients` scales by a constant-polynomial factor under a common germ multiplier +on the coefficient tuple. -/ +theorem remainderOfCoefficients_smul {d : ℕ} (c : AnalyticGerm ℂ (0 : E)) + (a : Fin d → AnalyticGerm ℂ (0 : E)) : + remainderOfCoefficients (c • a) = Polynomial.C c * remainderOfCoefficients a := by + simpa only [remainderOfCoefficients, Polynomial.smul_eq_C_mul] using + (Polynomial.ofFn d).map_smul c a + +open Classical in +/-- `remainderOfCoefficients` commutes with finite sums of coefficient tuples. -/ +theorem remainderOfCoefficients_sum {d : ℕ} {ι : Type*} (s : Finset ι) + (v : ι → Fin d → AnalyticGerm ℂ (0 : E)) : + remainderOfCoefficients (∑ i ∈ s, v i) = ∑ i ∈ s, remainderOfCoefficients (v i) := + map_sum (Polynomial.ofFn d) v s + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/CoordinateChange.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/CoordinateChange.lean new file mode 100644 index 0000000000..448c0bb10b --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/CoordinateChange.lean @@ -0,0 +1,272 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Order +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity + +/-! +# Coordinate changes and regular analytic germs + +Analytic changes of coordinates induce algebra isomorphisms on scalar germs. A nonzero germ on a +finite-dimensional parameter space times `ℂ` becomes regular in the scalar coordinate after a +complex linear change of coordinates. Finite families are normalized by applying the single-germ +theorem to their product. This includes the finite-family version discussed in [Suwa][Suwa2024] +§1.4; the unitary and countable-family refinements in [Jakóbczak–Jarnicki][JakobczakJarnicki2021], +Lemma 1.8.3 are not needed here. + +## Main definitions + +* `pullbackEquiv`: An analytic homeomorphism with analytic inverse induces an algebra isomorphism of + germs. +* `pullbackEquivOfEq`: Pullback equivalence along a map whose value at the source point is only + known up to a stated equation, letting the target germ's base point be phrased as any value equal + to `e x`. +* `linearEquivPullback`: Continuous linear coordinate changes act contravariantly on analytic germs. +* `translateEquiv`: Translation identifies the germs at any point with the germs at the origin. +* `linearEquivPullbackZero`: A linear change of coordinates fixes the origin and identifies the + corresponding germ rings. +* `orderInLastVariable`: Order of a scalar germ along the distinguished coordinate axis. +* `regularizingLinearEquiv`: A triangular linear coordinate change sends the last coordinate axis to + the line through `v`, provided the last coordinate of `v` is nonzero. + +## Main results + +* `exists_regular_coordinate_change`: A nonzero analytic germ can be made regular in the last + coordinate by an invertible complex linear change. +* `exists_regular_coordinate_change_finite`: One linear coordinate change makes every member of a + finite family of nonzero analytic germs regular in the last variable. +* `isUnit_iff_orderInLastVariable_eq_zero`: A germ is a unit exactly when it has order zero along + the distinguished coordinate. +* `orderInLastVariable_mul`: Order along the distinguished coordinate is additive under + multiplication of germs. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [T. Suwa, *Complex Analytic Geometry: From the Localization Viewpoint*][Suwa2024] +-/ + +public noncomputable section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables +namespace AnalyticGerm + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- An analytic homeomorphism with analytic inverse induces an algebra isomorphism of germs. -/ +@[expose] def pullbackEquiv (e : E ≃ₜ F) (x : E) (he : AnalyticAt ℂ e x) + (hi : AnalyticAt ℂ e.symm (e x)) : AnalyticGerm ℂ (e x) ≃ₐ[ℂ] AnalyticGerm ℂ x := + AlgEquiv.ofBijective (pullback e he) (by + constructor + · intro a b hab + obtain ⟨f, hf, rfl⟩ := exists_rep a + obtain ⟨g, hg, rfl⟩ := exists_rep b + have hh : (f ∘ e) =ᶠ[𝓝 x] (g ∘ e) := + Germ.coe_eq.mp (congrArg Subtype.val hab) + apply ofAnalyticAt_eq_iff.mpr + have ht : Tendsto e.symm (𝓝 (e x)) (𝓝 x) := by + simpa using e.symm.continuous.tendsto (e x) + simpa only [Function.comp_def, e.apply_symm_apply] using hh.comp_tendsto ht + · intro a + obtain ⟨f, hf, rfl⟩ := exists_rep a + refine ⟨ofAnalyticAt (f ∘ e.symm) (hf.comp_of_eq hi (e.symm_apply_apply x)), ?_⟩ + apply Subtype.ext + apply Germ.coe_eq.mpr + exact .of_forall fun y => by simp [Function.comp_def]) + +/-- Pullback equivalence along a map whose value at the source point is only known up to a stated +equation, letting the target germ's base point be phrased as any value equal to `e x`. Matches +`pullbackEquiv` definitionally once the equation is substituted. -/ +def pullbackEquivOfEq (e : E ≃ₜ F) (x : E) (he : AnalyticAt ℂ e x) + (hi : AnalyticAt ℂ e.symm (e x)) {y : F} (hy : e x = y) : + AnalyticGerm ℂ y ≃ₐ[ℂ] AnalyticGerm ℂ x := + hy ▸ pullbackEquiv e x he hi + +/-- Applying an equation-adjusted pullback equivalence to a represented germ is represented by +composition, matching the plain pullback. -/ +theorem pullbackEquivOfEq_ofAnalyticAt (e : E ≃ₜ F) (x : E) (he : AnalyticAt ℂ e x) + (hi : AnalyticAt ℂ e.symm (e x)) {y : F} (hy : e x = y) (g : F → ℂ) + (hg : AnalyticAt ℂ g y) : + pullbackEquivOfEq e x he hi hy (ofAnalyticAt g hg) = + ofAnalyticAt (g ∘ e) (hg.comp_of_eq he hy) := by + subst hy + rfl + +/-- An equation-adjusted pullback equivalence is bijective, like the plain pullback equivalence it +matches definitionally. -/ +theorem pullbackEquivOfEq_bijective (e : E ≃ₜ F) (x : E) (he : AnalyticAt ℂ e x) + (hi : AnalyticAt ℂ e.symm (e x)) {y : F} (hy : e x = y) : + Function.Bijective (pullbackEquivOfEq e x he hi hy) := by + subst hy + exact (pullbackEquiv e x he hi).bijective + +/-- Continuous linear coordinate changes act contravariantly on analytic germs. -/ +def linearEquivPullback (e : E ≃L[ℂ] F) (x : E) : + AnalyticGerm ℂ (e x) ≃ₐ[ℂ] AnalyticGerm ℂ x := + pullbackEquiv e.toHomeomorph x (e.toContinuousLinearMap.analyticAt x) + (e.symm.toContinuousLinearMap.analyticAt (e x)) + +/-- Translation identifies the germs at any point with the germs at the origin. -/ +def translateEquiv (x : E) : AnalyticGerm ℂ x ≃ₐ[ℂ] AnalyticGerm ℂ (0 : E) := by + have e : AnalyticGerm ℂ (0 + x) ≃ₐ[ℂ] AnalyticGerm ℂ (0 : E) := + pullbackEquiv (Homeomorph.addRight x) 0 + (analyticAt_id.add analyticAt_const) (by + change AnalyticAt ℂ (fun y : E => y + -x) _ + exact analyticAt_id.add analyticAt_const) + exact (zero_add x) ▸ e + +/-- A linear change of coordinates fixes the origin and identifies the corresponding germ rings. -/ +def linearEquivPullbackZero (e : E ≃L[ℂ] F) : + AnalyticGerm ℂ (0 : F) ≃ₐ[ℂ] AnalyticGerm ℂ (0 : E) := by + have h := linearEquivPullback e (0 : E) + exact (e.map_zero) ▸ h + +/-- Order of a scalar germ along the distinguished coordinate axis. The definition uses Mathlib's +one-variable analytic order and is independent of representatives. -/ +@[expose] def orderInLastVariable (φ : AnalyticGerm ℂ (0 : E × ℂ)) : ℕ∞ := + φ.val.liftOn (fun f => analyticOrderAt (fun w : ℂ => f (0, w)) 0) (by + intro f g h + have ht : Tendsto (fun w : ℂ => ((0 : E), w)) (𝓝 0) (𝓝 0) := + (continuous_const.prodMk continuous_id).tendsto 0 + exact analyticOrderAt_congr (h.comp_tendsto ht)) + +/-- The order of a represented germ is the order of its central scalar slice. -/ +@[simp] theorem orderInLastVariable_ofAnalyticAt (f : E × ℂ → ℂ) (hf : AnalyticAt ℂ f 0) : + orderInLastVariable (ofAnalyticAt f hf) = analyticOrderAt (fun w : ℂ => f (0, w)) 0 := rfl + +/-- The central slice of a represented germ is analytic at the scalar origin. -/ +theorem analyticAt_ofAnalyticAt_central (f : E × ℂ → ℂ) (hf : AnalyticAt ℂ f 0) : + AnalyticAt ℂ (fun w : ℂ => f (0, w)) 0 := + hf.comp_of_eq (analyticAt_const.prod analyticAt_id) rfl + +/-- Order along the distinguished coordinate is additive under multiplication of germs. -/ +theorem orderInLastVariable_mul (φ ψ : AnalyticGerm ℂ (0 : E × ℂ)) : + orderInLastVariable (φ * ψ) = orderInLastVariable φ + orderInLastVariable ψ := by + obtain ⟨f, hf, rfl⟩ := exists_rep φ + obtain ⟨g, hg, rfl⟩ := exists_rep ψ + rw [← ofAnalyticAt_mul] + simp only [orderInLastVariable_ofAnalyticAt] + exact analyticOrderAt_mul (analyticAt_ofAnalyticAt_central f hf) + (analyticAt_ofAnalyticAt_central g hg) + +/-- A germ is a unit exactly when it has order zero along the distinguished coordinate. -/ +theorem isUnit_iff_orderInLastVariable_eq_zero (φ : AnalyticGerm ℂ (0 : E × ℂ)) : + IsUnit φ ↔ orderInLastVariable φ = 0 := by + obtain ⟨f, hf, rfl⟩ := exists_rep φ + rw [isUnit_iff, eval_ofAnalyticAt, orderInLastVariable_ofAnalyticAt] + exact (analyticAt_ofAnalyticAt_central f hf).analyticOrderAt_eq_zero.symm + +end AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- A triangular linear coordinate change sends the last coordinate axis to the line through `v`, +provided the last coordinate of `v` is nonzero. -/ +def regularizingLinearEquiv (v : E × ℂ) (hv : v.2 ≠ 0) : (E × ℂ) ≃ₗ[ℂ] (E × ℂ) where + toFun z := (z.1 + z.2 • v.1, z.2 * v.2) + invFun z := (z.1 - (z.2 / v.2) • v.1, z.2 / v.2) + left_inv z := by simp [hv] + right_inv z := by simp [hv] + map_add' z w := by + ext <;> simp [add_smul, add_mul]; module + map_smul' c z := by + ext <;> simp [smul_add, mul_smul, smul_eq_mul, mul_assoc] + +/-- A nonzero analytic germ can be made regular in the last coordinate by an invertible complex +linear change. The resulting order is finite, including order zero for units. Empty parameter +spaces are allowed, since the scalar coordinate is always present. -/ +theorem exists_regular_coordinate_change [FiniteDimensional ℂ E] + {f : E × ℂ → ℂ} (hf : AnalyticAt ℂ f 0) (hne : ¬ f =ᶠ[𝓝 0] 0) : + ∃ (L : (E × ℂ) ≃L[ℂ] (E × ℂ)) (d : ℕ), + analyticOrderAt (fun w : ℂ => f (L (0, w))) 0 = d := by + have hsnd : ¬ (Prod.snd : E × ℂ → ℂ) =ᶠ[𝓝 0] 0 := by + intro h + have ht : Tendsto (fun w : ℂ => ((0 : E), w)) (𝓝 0) (𝓝 0) := by + exact (continuous_const.prodMk continuous_id).tendsto 0 + have hi : (id : ℂ → ℂ) =ᶠ[𝓝 0] 0 := h.comp_tendsto ht + have ho := analyticOrderAt_eq_top.mpr hi + simp at ho + have hprod : ¬ (fun z : E × ℂ => f z * z.2) =ᶠ[𝓝 0] 0 := by + intro h + exact (eventuallyEq_zero_or_eventuallyEq_zero_of_mul hf analyticAt_snd h).elim hne hsnd + obtain ⟨r, hr, hfa⟩ := hf.exists_ball_analyticOnNhd + obtain ⟨v, hvball, hfv⟩ : ∃ v ∈ ball (0 : E × ℂ) r, f v * v.2 ≠ 0 := by + by_contra! h + exact hprod (Filter.mem_of_superset (ball_mem_nhds 0 hr) (fun z hz => h z hz)) + have hv : v.2 ≠ 0 := (mul_ne_zero_iff.mp hfv).2 + have hvn : 0 < ‖v‖ := norm_pos_iff.mpr (fun h => hv (by simp [h])) + have hline : AnalyticOnNhd ℂ (fun w : ℂ => f (w • v)) (ball 0 (r / ‖v‖)) := by + intro w hw + have hmem : w • v ∈ ball (0 : E × ℂ) r := by + rw [mem_ball_zero_iff, norm_smul] + exact (lt_div_iff₀ hvn).mp (mem_ball_zero_iff.mp hw) + have hs : AnalyticAt ℂ (fun t : ℂ => t • v) w := analyticAt_id.smul analyticAt_const + exact (hfa _ hmem).comp_of_eq hs rfl + have hlinene : analyticOrderAt (fun w : ℂ => f (w • v)) 0 ≠ ⊤ := by + intro h + have heq := hline.eqOn_zero_of_preconnected_of_eventuallyEq_zero + (convex_ball (0 : ℂ) (r / ‖v‖)).isPreconnected (mem_ball_self (div_pos hr hvn)) + (analyticOrderAt_eq_top.mp h) + have h1 : (1 : ℂ) ∈ ball 0 (r / ‖v‖) := by + rw [mem_ball_zero_iff, norm_one, lt_div_iff₀ hvn, one_mul] + exact mem_ball_zero_iff.mp hvball + exact (mul_ne_zero_iff.mp hfv).1 (by simpa using heq h1) + obtain ⟨d, hd⟩ := ENat.ne_top_iff_exists.mp hlinene + refine ⟨(regularizingLinearEquiv v hv).toContinuousLinearEquiv, d, ?_⟩ + convert hd.symm using 1 + congr 1 + funext w + simp [regularizingLinearEquiv] + rfl + +/-- One linear coordinate change makes every member of a finite family of nonzero analytic germs +regular in the last variable. Empty families and unit germs are allowed. Apply single-germ +normalization to the product, then use that no factor slice can vanish. -/ +theorem exists_regular_coordinate_change_finite [FiniteDimensional ℂ E] + {κ : Type*} [Finite κ] {f : κ → E × ℂ → ℂ} + (hf : ∀ i, AnalyticAt ℂ (f i) 0) (hne : ∀ i, ¬ f i =ᶠ[𝓝 0] 0) : + ∃ (L : (E × ℂ) ≃L[ℂ] (E × ℂ)) (d : κ → ℕ), + ∀ i, analyticOrderAt (fun w : ℂ => f i (L (0, w))) 0 = d i := by + classical + let := Fintype.ofFinite κ + classical + have hp : ∀ s : Finset κ, ¬ (fun z => ∏ i ∈ s, f i z) =ᶠ[𝓝 0] 0 := by + intro s + induction s using Finset.induction_on with + | empty => + intro h + have h0 := h.self_of_nhds + simp at h0 + | @insert i s hi ih => + simp only [Finset.prod_insert hi] + intro h + exact (eventuallyEq_zero_or_eventuallyEq_zero_of_mul (hf i) + (s.analyticAt_fun_prod (fun j _ => hf j)) h).elim (hne i) ih + obtain ⟨L, d, hd⟩ := exists_regular_coordinate_change + (Finset.univ.analyticAt_fun_prod (fun i _ => hf i)) (hp Finset.univ) + have hfin : ∀ i, analyticOrderAt (fun w : ℂ => f i (L (0, w))) 0 ≠ ⊤ := by + intro i hi + have he := analyticOrderAt_eq_top.mp hi + have hz : (fun w : ℂ => ∏ j, f j (L (0, w))) =ᶠ[𝓝 0] 0 := by + filter_upwards [he] with w hw + exact Finset.prod_eq_zero (Finset.mem_univ i) hw + have ht := analyticOrderAt_eq_top.mpr hz + rw [hd] at ht + simp at ht + refine ⟨L, fun i => (analyticOrderAt (fun w : ℂ => f i (L (0, w))) 0).toNat, ?_⟩ + intro i + exact (ENat.natCast_toNat (hfin i)).symm + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Elimination.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Elimination.lean new file mode 100644 index 0000000000..c828bf70d6 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Elimination.lean @@ -0,0 +1,129 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.LinearAlgebra.Matrix.ToLinearEquiv +public import Mathlib.RingTheory.Polynomial.Resultant.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Fiber +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Weierstrass + +/-! +# Elimination of the scalar variable for relatively prime germs + +A distinguished polynomial and a relatively prime polynomial germ have nonzero resultant. The +proof uses Weierstrass division to show injectivity of the Sylvester map. Its adjugate then +supplies a nonzero parameter germ in the generated ideal. + +## Main results + +`resultant_ne_zero_of_isRelPrime_polynomialHom` is nonvanishing of the resultant of a +distinguished polynomial and a relatively prime polynomial germ. +`exists_base_combination_of_isRelPrime` produces a nonzero parameter germ in the generated +ideal. `sylvesterMap_injective_of_isRelPrime` is injectivity of the Sylvester map. +-/ + +public noncomputable section + +open Polynomial + +namespace SeveralComplexVariables.AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + +/-- A polynomial of smaller degree divisible as a germ by a distinguished polynomial is zero. -/ +theorem eq_zero_of_degree_lt_of_polynomialHom_dvd + {p w : Polynomial (AnalyticGerm ℂ (0 : E))} + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) + (hdeg : p.degree < (w.natDegree : WithBot ℕ)) + (hdiv : polynomialHom w ∣ polynomialHom p) : p = 0 := by + obtain ⟨q, hq⟩ := hdiv + obtain ⟨r, hr⟩ := exists_polynomial_quotient p w hw q (by rw [hq, mul_comm]) + have hd : w ∣ p := ⟨r, polynomialHom_injective (by rw [map_mul, hr, hq])⟩ + by_contra hp + have := Polynomial.degree_le_of_dvd hd hp + rw [Polynomial.degree_eq_natDegree hw.monic.ne_zero] at this + exact (not_lt_of_ge this) hdeg + +/-- Relative primality of the germs makes the Sylvester map injective. -/ +private theorem sylvesterMap_injective_of_isRelPrime + {w p : Polynomial (AnalyticGerm ℂ (0 : E))} + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) + (hrel : IsRelPrime (polynomialHom w) (polynomialHom p)) : + Function.Injective (Polynomial.sylvesterMap w p le_rfl le_rfl) := by + apply (injective_iff_map_eq_zero _).mpr + intro q hq + have he : w * q.2.val + p * q.1.val = 0 := congrArg Subtype.val hq + have he' : polynomialHom w * polynomialHom q.2.val + + polynomialHom p * polynomialHom q.1.val = 0 := by + simpa only [map_add, map_mul, map_zero] using congrArg polynomialHom he + have hd : polynomialHom w ∣ polynomialHom q.1.val := + hrel.dvd_of_dvd_mul_left ⟨-polynomialHom q.2.val, by linear_combination he'⟩ + have hq1 : q.1.val = 0 := eq_zero_of_degree_lt_of_polynomialHom_dvd hw + (Polynomial.mem_degreeLT.mp q.1.property) hd + have hq2 : q.2.val = 0 := by + simpa only [hq1, mul_zero, add_zero, mul_eq_zero, hw.monic.ne_zero, false_or] using he + exact Prod.ext (Subtype.ext hq1) (Subtype.ext hq2) + +/-- A distinguished polynomial relatively prime to another polynomial as an analytic germ has +nonzero resultant in the parameter germ ring. -/ +theorem resultant_ne_zero_of_isRelPrime_polynomialHom + {w p : Polynomial (AnalyticGerm ℂ (0 : E))} + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) + (hrel : IsRelPrime (polynomialHom w) (polynomialHom p)) : w.resultant p ≠ 0 := by + let R := AnalyticGerm ℂ (0 : E) + let T := Polynomial.sylvesterMap w p le_rfl le_rfl + let b₁ := ((Polynomial.degreeLT.basis R w.natDegree).prod + (Polynomial.degreeLT.basis R p.natDegree)).reindex finSumFinEquiv + let b₂ := Polynomial.degreeLT.basis R (w.natDegree + p.natDegree) + have hM : T.toMatrix b₁ b₂ = Polynomial.sylvester w p w.natDegree p.natDegree := + Polynomial.toMatrix_sylvesterMap' w p le_rfl le_rfl + intro hz + obtain ⟨v, hv, hMv⟩ := Matrix.exists_mulVec_eq_zero_iff.mpr hz + let q := b₁.equivFun.symm v + have hrepr : (b₁.repr q : Fin (w.natDegree + p.natDegree) → R) = v := + b₁.equivFun.apply_symm_apply v + have hTq : T q = 0 := by + apply b₂.equivFun.injective + change (b₂.repr (T q) : Fin (w.natDegree + p.natDegree) → R) = b₂.equivFun 0 + rw [← T.toMatrix_mulVec_repr b₁ b₂ q, hM, hrepr, hMv, map_zero] + have hq : q = 0 := (sylvesterMap_injective_of_isRelPrime hw hrel) (hTq.trans (map_zero T).symm) + exact hv (by rw [← hrepr, hq, map_zero]; rfl) + +/-- Eliminating the scalar variable puts a nonzero parameter germ in the ideal generated by two +relatively prime germs, the first of finite order in the scalar variable. -/ +theorem exists_base_combination_of_isRelPrime + {f g : AnalyticGerm ℂ (0 : E × ℂ)} {d : ℕ} (hd : orderInLastVariable f = d) + (hrel : IsRelPrime f g) : + ∃ h : AnalyticGerm ℂ (0 : E), h ≠ 0 ∧ + ∃ a b : AnalyticGerm ℂ (0 : E × ℂ), basePullback 0 h = a * f + b * g := by + obtain ⟨⟨u, w⟩, ⟨hw, _, hfact⟩, _⟩ := existsUnique_preparation f hd + have hrel' : IsRelPrime (polynomialHom w) g := by + rw [hfact] at hrel + exact hrel.of_mul_left_right + by_cases hw0 : w.natDegree = 0 + · have hw1 : w = 1 := Polynomial.eq_one_of_monic_natDegree_zero hw.monic hw0 + refine ⟨1, one_ne_zero, ↑u⁻¹, 0, ?_⟩ + simp [hfact, hw1] + obtain ⟨⟨q, p⟩, ⟨_, hdiv⟩, _⟩ := existsUnique_division w hw g + have hwp : IsRelPrime (polynomialHom w) (polynomialHom p) := by + rw [hdiv] at hrel' + exact hrel'.of_mul_add_right_right + have hres := resultant_ne_zero_of_isRelPrime_polynomialHom hw hwp + obtain ⟨a, b, _, _, hab⟩ := Polynomial.exists_mul_add_mul_eq_C_resultant + w p le_rfl le_rfl (Or.inl hw0) + have hcomb : basePullback 0 (w.resultant p) = + polynomialHom w * polynomialHom a + polynomialHom p * polynomialHom b := by + simpa only [map_add, map_mul, polynomialHom_C, parameterHom, basePullback] using + (congrArg polynomialHom hab).symm + refine ⟨w.resultant p, hres, ↑u⁻¹ * (polynomialHom a - q * polynomialHom b), + polynomialHom b, ?_⟩ + rw [hcomb, hfact, hdiv] + have hu : (↑u⁻¹ : AnalyticGerm ℂ (0 : E × ℂ)) * ↑u = 1 := u.inv_val + linear_combination -(polynomialHom a - q * polynomialHom b) * polynomialHom w * hu + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Factorization.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Factorization.lean new file mode 100644 index 0000000000..ba36c8f5a3 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Factorization.lean @@ -0,0 +1,124 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.RingTheory.Coprime.Basic +public import Mathlib.RingTheory.Noetherian.UniqueFactorizationDomain +public import Mathlib.RingTheory.UniqueFactorizationDomain.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Noetherian +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Polynomial + +/-! +# Elementary factorization of analytic germs + +[Jakóbczak–Jarnicki][JakobczakJarnicki2021], Proposition 1.8.4: scalar analytic germ rings in +finite dimension are unique factorization domains. The analytic ingredient is that an +irreducible germ is prime. Together with Noetherianity this supplies Mathlib's +`UniqueFactorizationMonoid` instance and its usual existence and uniqueness results. + +The source's “relatively prime” is expressed as `IsRelPrime`, meaning that common divisors are +units. It is not `IsCoprime`: two germs vanishing at the base point cannot generate the unit +ideal. No geometric conclusions from §1.8.5 are included. + +## Main results + +* `prime_of_irreducible`: Irreducible analytic germs are prime in finite dimension: transport to the + origin of a coordinate presentation using the induction on dimension above. +* `exists_prime_factors`: Every nonzero analytic germ is associated to a finite product of prime + germs. +* `factors_unique`: Irreducible factorizations agree up to reordering and multiplication by units. +* `isRelPrime_iff_common_divisors`: Relative primality of germs means that every common divisor is a + unit. +* `not_isCoprime_of_eval_eq_zero`: Two germs vanishing at the base point cannot generate the unit + ideal. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +namespace SeveralComplexVariables.AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {x : E} + +/-- Two germs vanishing at the base point cannot generate the unit ideal. This does not prevent them +from being relatively prime in the factorization sense. -/ +theorem not_isCoprime_of_eval_eq_zero {f g : AnalyticGerm ℂ x} + (hf : eval x f = 0) (hg : eval x g = 0) : ¬ IsCoprime f g := by + rintro ⟨a, b, h⟩ + have he := congrArg (eval x) h + simp [hf, hg] at he + +/-- Irreducible germs on `n` complex coordinates are prime, by induction using +`prime_of_irreducible_of_baseUFD`. Dimension zero has no irreducible elements, since the germ +ring there is a field. -/ +theorem prime_of_irreducible_coordinates (n : ℕ) : + ∀ {f : AnalyticGerm ℂ (0 : Fin n → ℂ)}, Irreducible f → Prime f := by + induction n with + | zero => + intro f hf + exfalso + set e := equivScalarOfSubsingleton ℂ (0 : Fin 0 → ℂ) + have hf' : Irreducible (e f) := hf.map e + rcases eq_or_ne (e f) 0 with h0 | h0 + · rw [h0] at hf' + exact (hf'.isUnit_or_isUnit (by ring)).elim not_isUnit_zero not_isUnit_zero + · exact hf'.not_isUnit (isUnit_iff_ne_zero.mpr h0) + | succ n ih => + intro f hf + have : UniqueFactorizationMonoid (AnalyticGerm ℂ (0 : Fin n → ℂ)) := + { irreducible_iff_prime := ⟨ih, Prime.irreducible⟩ } + let e : (Fin (n + 1) → ℂ) ≃ₗ[ℂ] (Fin n → ℂ) × ℂ := + (LinearEquiv.piCongrLeft ℂ (fun _ => ℂ) (finSuccEquiv n)).trans + ((LinearEquiv.piOptionEquivProd ℂ).trans (LinearEquiv.prodComm ℂ _ _)) + set eqv : AnalyticGerm ℂ (0 : Fin (n + 1) → ℂ) ≃ₐ[ℂ] AnalyticGerm ℂ (0 : (Fin n → ℂ) × ℂ) := + (linearEquivPullbackZero e.toContinuousLinearEquiv).symm with heqv + have hfe : Irreducible (eqv f) := hf.map eqv + have hpe : Prime (eqv f) := prime_of_irreducible_of_baseUFD hfe + exact (MulEquiv.prime_iff eqv).mp hpe + +/-- Irreducible analytic germs are prime in finite dimension: transport to the origin of a +coordinate presentation using the induction on dimension above. -/ +theorem prime_of_irreducible [FiniteDimensional ℂ E] {f : AnalyticGerm ℂ x} + (hf : Irreducible f) : Prime f := by + let e := (Module.finBasis ℂ E).equivFunL + set eqv0 : AnalyticGerm ℂ (0 : E) ≃ₐ[ℂ] AnalyticGerm ℂ (0 : Fin (Module.finrank ℂ E) → ℂ) := + (linearEquivPullbackZero e).symm with heqv0 + set eqvx : AnalyticGerm ℂ x ≃ₐ[ℂ] AnalyticGerm ℂ (0 : E) := translateEquiv x with heqvx + have hf1 : Irreducible (eqvx f) := hf.map eqvx + have hf2 : Irreducible (eqv0 (eqvx f)) := hf1.map eqv0 + have hp2 : Prime (eqv0 (eqvx f)) := prime_of_irreducible_coordinates _ hf2 + have hp1 : Prime (eqvx f) := (MulEquiv.prime_iff eqv0).mp hp2 + exact (MulEquiv.prime_iff eqvx).mp hp1 + +/-- The finite-dimensional analytic germ ring is a unique factorization domain. This instance +combines Noetherianity with the prime-germ lemma. -/ +instance [FiniteDimensional ℂ E] : UniqueFactorizationMonoid (AnalyticGerm ℂ x) where + irreducible_iff_prime := ⟨prime_of_irreducible, Prime.irreducible⟩ + +/-- Every nonzero analytic germ is associated to a finite product of prime germs. The empty product +accounts for units, including all nonzero zero-dimensional germs. -/ +theorem exists_prime_factors [FiniteDimensional ℂ E] (f : AnalyticGerm ℂ x) (hf : f ≠ 0) : + ∃ s : Multiset (AnalyticGerm ℂ x), (∀ p ∈ s, Prime p) ∧ Associated s.prod f := + UniqueFactorizationMonoid.exists_prime_factors f hf + +/-- Irreducible factorizations agree up to reordering and multiplication by units. -/ +theorem factors_unique [FiniteDimensional ℂ E] {s t : Multiset (AnalyticGerm ℂ x)} + (hs : ∀ p ∈ s, Irreducible p) (ht : ∀ p ∈ t, Irreducible p) + (h : Associated s.prod t.prod) : Multiset.Rel Associated s t := + UniqueFactorizationMonoid.factors_unique hs ht h + +/-- Relative primality of germs means that every common divisor is a unit. -/ +theorem isRelPrime_iff_common_divisors {f g : AnalyticGerm ℂ x} : + IsRelPrime f g ↔ ∀ d, d ∣ f → d ∣ g → IsUnit d := by + rfl + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Fiber.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Fiber.lean new file mode 100644 index 0000000000..220d6e8404 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Fiber.lean @@ -0,0 +1,135 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Factorization + +/-! +# Parameter germs and restriction to a fiber + +Adding an unused scalar variable preserves irreducible germs. Consequently a nonzero parameter +germ is relatively prime to every germ whose restriction to the scalar fiber is nonzero. This is +the local algebra needed for persistence of relative primality. + +## Main results + +`basePullback` pulls a parameter germ back along projection, adding an unused scalar variable; +`fiberPullback` restricts a germ to the scalar fiber. `irreducible_basePullback` preserves +irreducibility. `isRelPrime_basePullback_of_fiber_ne_zero` is relative primality of a nonzero +parameter germ to a germ with nonzero fiber restriction. `eventually_fiber_ne_zero_ofAnalyticAt` +is persistence of a nonzero fiber germ. +-/ + +public noncomputable section + +open Filter Set Metric +open scoped Topology + +namespace SeveralComplexVariables.AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Regard a parameter germ as a germ independent of the scalar variable. -/ +@[expose] def basePullback (y : E × ℂ) : AnalyticGerm ℂ y.1 →ₐ[ℂ] AnalyticGerm ℂ y := + pullback Prod.fst analyticAt_fst + +/-- Restrict a germ to the scalar fiber through its base point. -/ +def fiberPullback (y : E × ℂ) : AnalyticGerm ℂ y →ₐ[ℂ] AnalyticGerm ℂ y.2 := + pullback (fun w : ℂ => (y.1, w)) (analyticAt_const.prod analyticAt_id) + +/-- A parameter germ vanishing at its base point restricts to zero on the scalar fiber. -/ +theorem fiberPullback_basePullback_eq_zero (y : E × ℂ) {p : AnalyticGerm ℂ y.1} + (hp : ¬ IsUnit p) : fiberPullback y (basePullback y p) = 0 := by + obtain ⟨g, hg, rfl⟩ := exists_rep p + have h0 : g y.1 = 0 := by simpa only [isUnit_iff, eval_ofAnalyticAt, not_not] using hp + change ofAnalyticAt (fun _ : ℂ => g y.1) analyticAt_const = + ofAnalyticAt (0 : ℂ → ℂ) analyticAt_const + apply ofAnalyticAt_eq_iff.mpr + exact Filter.Eventually.of_forall (fun _ => h0) + +/-- Adding an unused scalar variable preserves irreducibility of a parameter germ. -/ +theorem irreducible_basePullback (y : E × ℂ) {p : AnalyticGerm ℂ y.1} (hp : Irreducible p) : + Irreducible (basePullback y p) := by + let s : AnalyticGerm ℂ y →ₐ[ℂ] AnalyticGerm ℂ y.1 := + pullback (fun z : E => (z, y.2)) (analyticAt_id.prod analyticAt_const) + have hs (q : AnalyticGerm ℂ y.1) : s (basePullback y q) = q := by + obtain ⟨g, hg, rfl⟩ := exists_rep q + rfl + refine ⟨fun hu => hp.not_isUnit ((isUnit_pullback_iff _ _ p).mp hu), ?_⟩ + intro a b hab + have he : p = s a * s b := by rw [← hs p, hab, map_mul] + have hu (q : AnalyticGerm ℂ y) : IsUnit (s q) ↔ IsUnit q := by + simp only [s, isUnit_iff, eval_pullback] + exact (hp.isUnit_or_isUnit he).imp (hu a).mp (hu b).mp + +/-- A nonzero parameter germ is relatively prime to a germ nonzero on its scalar fiber. -/ +theorem isRelPrime_basePullback_of_fiber_ne_zero [FiniteDimensional ℂ E] + (y : E × ℂ) {p : AnalyticGerm ℂ y.1} (hp : p ≠ 0) {f : AnalyticGerm ℂ y} + (hf : fiberPullback y f ≠ 0) : IsRelPrime (basePullback y p) f := by + induction p using UniqueFactorizationMonoid.induction_on_prime with + | h₁ => exact (hp rfl).elim + | h₂ p hu => exact (hu.map (basePullback y)).isRelPrime_left + | h₃ p q hp0 hq ih => + rw [map_mul] + apply IsRelPrime.mul_left _ (ih hp0) + apply (irreducible_basePullback y hq.irreducible).isRelPrime_iff_not_dvd.mpr + intro hdiv + have h := map_dvd (fiberPullback y) hdiv + rw [fiberPullback_basePullback_eq_zero y hq.not_isUnit] at h + exact hf (zero_dvd_iff.mp h) + +/-- A represented analytic germ is nonzero exactly when the representative is not locally zero. -/ +theorem ofAnalyticAt_ne_zero_iff {f : E → ℂ} {x : E} (hf : AnalyticAt ℂ f x) : + ofAnalyticAt f hf ≠ 0 ↔ ¬ f =ᶠ[𝓝 x] 0 := by + change ofAnalyticAt f hf ≠ ofAnalyticAt (0 : E → ℂ) analyticAt_const ↔ _ + exact not_congr ofAnalyticAt_eq_iff + +/-- A nonzero analytic germ has nonzero germs at all sufficiently nearby points. -/ +theorem eventually_ne_zero_ofAnalyticAt {f : E → ℂ} {x : E} (hf : AnalyticAt ℂ f x) + (hne : ofAnalyticAt f hf ≠ 0) : + ∀ᶠ y in 𝓝 x, ∃ hy : AnalyticAt ℂ f y, ofAnalyticAt f hy ≠ 0 := by + obtain ⟨r, hr, hfr⟩ := hf.exists_ball_analyticOnNhd + filter_upwards [ball_mem_nhds x hr] with y hy + refine ⟨hfr y hy, ?_⟩ + rw [ofAnalyticAt_ne_zero_iff] + intro hzero + have he := hfr.eqOn_zero_of_preconnected_of_eventuallyEq_zero isPreconnected_ball hy hzero + exact (ofAnalyticAt_ne_zero_iff hf).mp hne + (Filter.mem_of_superset (ball_mem_nhds x hr) (fun z hz => he hz)) + +/-- Nonvanishing of the central fiber germ persists for nearby scalar fiber germs. -/ +theorem eventually_fiber_ne_zero_ofAnalyticAt {f : E × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (hne : ¬ (fun w : ℂ => f (0, w)) =ᶠ[𝓝 0] 0) : + ∀ᶠ y in 𝓝 (0 : E × ℂ), ∃ hy : AnalyticAt ℂ f y, + fiberPullback y (ofAnalyticAt f hy) ≠ 0 := by + obtain ⟨r, hr, hfr⟩ := hf.exists_ball_analyticOnNhd + have hprod : AnalyticOnNhd ℂ f (ball (0 : E) r ×ˢ ball (0 : ℂ) r) := by + simpa only [ball_prod_same, Prod.mk_zero_zero] using hfr + obtain ⟨w, hw, hfw⟩ : ∃ w ∈ ball (0 : ℂ) r, f (0, w) ≠ 0 := by + by_contra! h + exact hne (Filter.mem_of_superset (ball_mem_nhds 0 hr) h) + have hc : ContinuousAt (fun a : E => f (a, w)) 0 := + (hprod (0, w) ⟨mem_ball_self hr, hw⟩).continuousAt.comp_of_eq + (continuousAt_id.prodMk continuousAt_const) rfl + have hb : ∀ᶠ y : E × ℂ in 𝓝 0, f (y.1, w) ≠ 0 := + (continuous_fst.continuousAt : Tendsto (Prod.fst : E × ℂ → E) (𝓝 0) (𝓝 0)).eventually + (hc.eventually_ne hfw) + filter_upwards [((isOpen_ball.prod isOpen_ball).mem_nhds + (show (0 : E × ℂ) ∈ ball (0 : E) r ×ˢ ball (0 : ℂ) r from + ⟨mem_ball_self hr, mem_ball_self hr⟩)), hb] with y hy hfyw + refine ⟨hprod y hy, ?_⟩ + have hslice : AnalyticOnNhd ℂ (fun t : ℂ => f (y.1, t)) (ball 0 r) := by + intro t ht + exact (hprod (y.1, t) ⟨hy.1, ht⟩).comp_of_eq (analyticAt_const.prod analyticAt_id) rfl + change ofAnalyticAt (fun t : ℂ => f (y.1, t)) (hslice y.2 hy.2) ≠ 0 + rw [ofAnalyticAt_ne_zero_iff] + intro hzero + exact hfyw (hslice.eqOn_zero_of_preconnected_of_eventuallyEq_zero + isPreconnected_ball hy.2 hzero hw) + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/IntrinsicOrder.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/IntrinsicOrder.lean new file mode 100644 index 0000000000..f282937fcb --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/IntrinsicOrder.lean @@ -0,0 +1,142 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.RingTheory.MvPowerSeries.Rename +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Order + +/-! +# Coordinate-independent order of analytic germs + +`inCoordinates` transports a germ to a finite coordinate space. `orderInCoordinates` is +independent of the continuous complex-linear coordinates, so `intrinsicOrder` defines total +order on every finite-dimensional complex normed space, including zero-dimensional spaces. The +coordinate Taylor implementation remains in `Order`. `finiteIndexTaylorSeries` supplies a Taylor +series indexed by any finite coordinate type. + +## Main definitions + +* `inCoordinates`: Express a germ in continuous complex-linear coordinates, by pulling back the + inverse map. +* `orderInCoordinates`: The total order computed in a chosen system of continuous linear + coordinates. +* `intrinsicOrder`: Total order of an analytic germ on a finite-dimensional complex normed space. +* `finiteIndexTaylorSeries`: Taylor series with variables indexed by an arbitrary finite coordinate + type. + +## Main results + +* `intrinsicOrder_eq_orderInCoordinates`: Intrinsic order can be computed using any continuous + complex-linear coordinate system. +* `intrinsicOrder_eq_order`: Intrinsic order agrees with the original order on finite coordinate + spaces. +* `intrinsicOrder_mul`: Intrinsic order is additive under multiplication. +* `intrinsicOrder_eq_top_iff`: A germ has infinite intrinsic order exactly when it is zero. +-/ + +public noncomputable section +open Filter +open scoped Topology +namespace SeveralComplexVariables.AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {x : E} {n m : ℕ} + +/-- Express a germ in continuous complex-linear coordinates, by pulling back the inverse map. -/ +def inCoordinates (L : E ≃L[ℂ] (Fin n → ℂ)) (x : E) : + AnalyticGerm ℂ x ≃ₐ[ℂ] AnalyticGerm ℂ (L x) := + pullbackEquivOfEq L.symm.toHomeomorph (L x) + (L.symm.toContinuousLinearMap.analyticAt _) (L.toContinuousLinearMap.analyticAt _) + (L.symm_apply_apply x) + +/-- A represented germ in coordinates is represented by composition with the inverse map. -/ +theorem inCoordinates_ofAnalyticAt (L : E ≃L[ℂ] (Fin n → ℂ)) + (f : E → ℂ) (hf : AnalyticAt ℂ f x) : + inCoordinates L x (ofAnalyticAt f hf) = + ofAnalyticAt (f ∘ L.symm) + (hf.comp_of_eq (L.symm.toContinuousLinearMap.analyticAt _) (L.symm_apply_apply x)) := + pullbackEquivOfEq_ofAnalyticAt _ _ _ _ _ _ _ + +/-- The total order computed in a chosen system of continuous linear coordinates. -/ +@[expose] def orderInCoordinates (L : E ≃L[ℂ] (Fin n → ℂ)) (f : AnalyticGerm ℂ x) : ℕ∞ := + order (inCoordinates L x f) + +/-- Comparing two coordinate systems cannot lower the computed order. -/ +private theorem orderInCoordinates_le (L : E ≃L[ℂ] (Fin n → ℂ)) + (M : E ≃L[ℂ] (Fin m → ℂ)) (f : AnalyticGerm ℂ x) : + orderInCoordinates L f ≤ orderInCoordinates M f := by + obtain ⟨f, hf, rfl⟩ := exists_rep f + let e := M.symm.trans L + have ha : AnalyticAt ℂ (f ∘ L.symm) (e (M x)) := by + simpa [e] using hf.comp_of_eq (L.symm.toContinuousLinearMap.analyticAt (L x)) + (L.symm_apply_apply x) + have h := order_le_order_pullback e (e.toContinuousLinearMap.analyticAt (M x)) + (ofAnalyticAt (f ∘ L.symm) ha) + change (holomorphicTaylorSeries (f ∘ L.symm) (e (M x))).order ≤ + (holomorphicTaylorSeries ((f ∘ L.symm) ∘ e) (M x)).order at h + unfold orderInCoordinates + rw [inCoordinates_ofAnalyticAt L f hf, inCoordinates_ofAnalyticAt M f hf] + simpa only [order, taylorSeries_ofAnalyticAt, e, ContinuousLinearEquiv.trans_apply, + ContinuousLinearEquiv.symm_apply_apply, Function.comp_def] using h + +/-- Total order is independent of the chosen continuous complex-linear coordinates. -/ +theorem orderInCoordinates_eq (L : E ≃L[ℂ] (Fin n → ℂ)) + (M : E ≃L[ℂ] (Fin m → ℂ)) (f : AnalyticGerm ℂ x) : + orderInCoordinates L f = orderInCoordinates M f := + le_antisymm (orderInCoordinates_le L M f) (orderInCoordinates_le M L f) + +variable [FiniteDimensional ℂ E] + +/-- Total order of an analytic germ on a finite-dimensional complex normed space. The chosen basis +in the implementation does not affect its value. -/ +@[expose] def intrinsicOrder (f : AnalyticGerm ℂ x) : ℕ∞ := + orderInCoordinates (Module.finBasis ℂ E).equivFunL f + +/-- Intrinsic order can be computed using any continuous complex-linear coordinate system. -/ +theorem intrinsicOrder_eq_orderInCoordinates (L : E ≃L[ℂ] (Fin n → ℂ)) + (f : AnalyticGerm ℂ x) : intrinsicOrder f = orderInCoordinates L f := + orderInCoordinates_eq _ _ f + +/-- Intrinsic order agrees with the original order on finite coordinate spaces. -/ +@[simp] theorem intrinsicOrder_eq_order {x : Fin n → ℂ} (f : AnalyticGerm ℂ x) : + intrinsicOrder f = order f := by + rw [intrinsicOrder_eq_orderInCoordinates (ContinuousLinearEquiv.refl ℂ (Fin n → ℂ))] + obtain ⟨g, hg, rfl⟩ := exists_rep f + unfold orderInCoordinates + rw [inCoordinates_ofAnalyticAt _ g hg] + rfl + +/-- A germ has infinite intrinsic order exactly when it is zero. -/ +@[simp] theorem intrinsicOrder_eq_top_iff (f : AnalyticGerm ℂ x) : + intrinsicOrder f = ⊤ ↔ f = 0 := by + rw [intrinsicOrder, orderInCoordinates, order_eq_top_iff] + exact (inCoordinates (Module.finBasis ℂ E).equivFunL x).map_eq_zero_iff + +/-- Intrinsic order is additive under multiplication. -/ +theorem intrinsicOrder_mul (f g : AnalyticGerm ℂ x) : + intrinsicOrder (f * g) = intrinsicOrder f + intrinsicOrder g := by + simp only [intrinsicOrder, orderInCoordinates, map_mul, order_mul] + +/-- Cancellation can only raise the intrinsic order of a sum. -/ +theorem min_intrinsicOrder_le_intrinsicOrder_add (f g : AnalyticGerm ℂ x) : + min (intrinsicOrder f) (intrinsicOrder g) ≤ intrinsicOrder (f + g) := by + simpa only [intrinsicOrder, orderInCoordinates, map_add] using + min_order_le_order_add (inCoordinates (Module.finBasis ℂ E).equivFunL x f) + (inCoordinates (Module.finBasis ℂ E).equivFunL x g) + +/-- Taylor series with variables indexed by an arbitrary finite coordinate type. A finite +enumeration is used for the ordered derivative implementation, then the formal variables are +renamed back to the original coordinate type. -/ +def finiteIndexTaylorSeries {ι : Type*} [Fintype ι] {x : ι → ℂ} + (f : AnalyticGerm ℂ x) : MvPowerSeries ι ℂ := + MvPowerSeries.renameEquiv ℂ (Fintype.equivFin ι).symm + (taylorSeries (inCoordinates + (ContinuousLinearEquiv.piCongrLeft ℂ (fun _ : Fin (Fintype.card ι) => ℂ) + (Fintype.equivFin ι)) x f)) + +end SeveralComplexVariables.AnalyticGerm +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Noetherian.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Noetherian.lean new file mode 100644 index 0000000000..c17e9a2b6b --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Noetherian.lean @@ -0,0 +1,236 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.RingTheory.Finiteness.Ideal +public import Mathlib.RingTheory.Noetherian.Basic +public import Mathlib.RingTheory.Polynomial.UniqueFactorization +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoordinateChange +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Weierstrass + +/-! +# Noetherianity of analytic germ rings + +[Jakóbczak–Jarnicki][JakobczakJarnicki2021], Proposition 1.8.6: scalar analytic germs on +finite-dimensional complex spaces form Noetherian rings. The analytic induction step normalizes +a nonzero element of an ideal, divides by it, and uses finite generation of the resulting +submodule of the finite module of remainder coefficients. The dimension induction, +zero-dimensional base case, and coordinate transport are proved here from that step. No claim is +made for infinite-dimensional source spaces. + +## Main results + +`ideal_fg` is finite generation of ideals of finite-dimensional analytic germs. `ideal_fg_prod` +is the analytic induction step. `isNoetherianRing_coordinates` is Noetherianity on coordinate +spaces, from which the general instance is transported. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Filter +open scoped Topology + +namespace SeveralComplexVariables.AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Given an ideal element regular in the distinguished coordinate, division against its Weierstrass +preparation shows the ideal is finitely generated: every element reduces, modulo the ideal +element, to a polynomial remainder of degree below the order; those remainders occurring in the +ideal form a submodule of the finite free module of degree-bounded coefficient tuples, finitely +generated since the coefficient ring is Noetherian. -/ +theorem ideal_fg_of_orderInLastVariable_eq_nat [FiniteDimensional ℂ E] + [IsNoetherianRing (AnalyticGerm ℂ (0 : E))] (J : Ideal (AnalyticGerm ℂ (0 : E × ℂ))) + {g : AnalyticGerm ℂ (0 : E × ℂ)} (hgJ : g ∈ J) {d : ℕ} (hd : orderInLastVariable g = d) : + J.FG := by + classical + obtain ⟨⟨u, w⟩, ⟨hwdist, hwdeg, hgeq⟩, -⟩ := existsUnique_preparation g hd + simp only at hwdist hwdeg hgeq + have hgu : polynomialHom w = (↑u⁻¹ : AnalyticGerm ℂ (0 : E × ℂ)) * g := by + rw [hgeq, ← mul_assoc, ← Units.val_mul, inv_mul_cancel, Units.val_one, one_mul] + let M : Submodule (AnalyticGerm ℂ (0 : E)) (Fin d → AnalyticGerm ℂ (0 : E)) := + { carrier := {a | polynomialHom (remainderOfCoefficients a) ∈ J} + zero_mem' := by + change polynomialHom (remainderOfCoefficients 0) ∈ J + simp [remainderOfCoefficients] + add_mem' := by + intro a b ha hb + simp only [Set.mem_ofPred_eq, remainderOfCoefficients_add, map_add] at ha hb ⊢ + exact J.add_mem ha hb + smul_mem' := by + intro c a ha + simp only [Set.mem_ofPred_eq, remainderOfCoefficients_smul, map_mul, + polynomialHom_C] at ha ⊢ + exact J.mul_mem_left _ ha } + have hMfg : M.FG := IsNoetherian.noetherian M + obtain ⟨S, hS⟩ := hMfg + refine ⟨insert g (S.image (fun a => polynomialHom (remainderOfCoefficients a))), ?_⟩ + apply le_antisymm + · rw [Ideal.span_le] + intro x hx + simp only [Finset.coe_insert, Set.mem_insert_iff, Finset.coe_image, Set.mem_image, + Finset.mem_coe] at hx + rcases hx with rfl | ⟨a, haS, rfl⟩ + · exact hgJ + · change a ∈ M + rw [← hS] + exact Submodule.subset_span haS + · intro h hhJ + obtain ⟨⟨q, r⟩, ⟨hrdeg, heq⟩, -⟩ := existsUnique_division w hwdist h + simp only at hrdeg heq + rw [hwdeg] at hrdeg + have hreq : polynomialHom r = h - q * (↑u⁻¹ : AnalyticGerm ℂ (0 : E × ℂ)) * g := by + rw [heq, hgu]; ring + have hmem : polynomialHom r ∈ J := by + rw [hreq] + exact J.sub_mem hhJ (J.mul_mem_left _ hgJ) + have har : r = remainderOfCoefficients (fun j : Fin d => r.coeff (j : ℕ)) := + eq_remainderOfCoefficients_of_degree_lt hrdeg + have hmemM : (fun j : Fin d => r.coeff (j : ℕ)) ∈ M := by + change polynomialHom (remainderOfCoefficients _) ∈ J + rwa [← har] + rw [← hS] at hmemM + obtain ⟨f, hf⟩ := Submodule.mem_span_finset'.mp hmemM + have hrsum : r = + ∑ a : S, f a • remainderOfCoefficients (a : Fin d → AnalyticGerm ℂ (0 : E)) := by + rw [har, ← hf, remainderOfCoefficients_sum] + refine Finset.sum_congr rfl fun a _ => ?_ + rw [Polynomial.smul_eq_C_mul] + exact remainderOfCoefficients_smul (f a) (a : Fin d → AnalyticGerm ℂ (0 : E)) + have hpolyr : polynomialHom r = ∑ a : S, parameterHom (f a) * + polynomialHom (remainderOfCoefficients (a : Fin d → AnalyticGerm ℂ (0 : E))) := by + rw [hrsum, map_sum] + refine Finset.sum_congr rfl fun a _ => ?_ + rw [Polynomial.smul_eq_C_mul, map_mul, polynomialHom_C] + have hheq : h = q * ((↑u⁻¹ : AnalyticGerm ℂ (0 : E × ℂ)) * g) + + ∑ a : S, parameterHom (f a) * + polynomialHom (remainderOfCoefficients (a : Fin d → AnalyticGerm ℂ (0 : E))) := by + rw [heq, hgu, hpolyr] + rw [hheq] + apply Ideal.add_mem + · exact Ideal.mul_mem_left _ q (Ideal.mul_mem_left _ _ + (Ideal.subset_span (Finset.mem_coe.mpr (Finset.mem_insert_self g _)))) + · apply Ideal.sum_mem + intro a _ + apply Ideal.mul_mem_left + apply Ideal.subset_span + exact Finset.mem_coe.mpr (Finset.mem_insert_of_mem + (Finset.mem_image.mpr ⟨(a : Fin d → AnalyticGerm ℂ (0 : E)), a.2, rfl⟩)) + +/-- Analytic induction step for Noetherianity. A nonzero element becomes regular in the +distinguished coordinate after a linear coordinate change; finite generation transports back +along the induced ring automorphism of the germ ring. -/ +theorem ideal_fg_prod [FiniteDimensional ℂ E] + [IsNoetherianRing (AnalyticGerm ℂ (0 : E))] + (I : Ideal (AnalyticGerm ℂ (0 : E × ℂ))) : I.FG := by + rcases eq_or_ne I ⊥ with hI0 | hI0 + · exact hI0 ▸ Submodule.fg_bot + · obtain ⟨g, hgI, hg0⟩ := Submodule.exists_mem_ne_zero_of_ne_bot hI0 + obtain ⟨g0, hg0A, rfl⟩ := exists_rep g + have hg0ne : ¬ g0 =ᶠ[𝓝 0] 0 := fun h => hg0 (Subtype.ext (Germ.coe_eq.mpr h)) + obtain ⟨L, d, hd⟩ := exists_regular_coordinate_change hg0A hg0ne + have hL0 : L (0 : E × ℂ) = 0 := L.map_zero + have hΦ : AnalyticAt ℂ L (0 : E × ℂ) := L.toContinuousLinearMap.analyticAt 0 + have hΦsymm0 : AnalyticAt ℂ L.symm (L (0 : E × ℂ)) := by + rw [hL0]; exact L.symm.toContinuousLinearMap.analyticAt 0 + set Φ : AnalyticGerm ℂ (0 : E × ℂ) ≃ₐ[ℂ] AnalyticGerm ℂ (0 : E × ℂ) := + pullbackEquivOfEq L.toHomeomorph 0 hΦ hΦsymm0 hL0 with hΦdef + have hΦg : Φ (ofAnalyticAt g0 hg0A) = ofAnalyticAt (g0 ∘ L) (hg0A.comp_of_eq hΦ hL0) := + pullbackEquivOfEq_ofAnalyticAt L.toHomeomorph 0 hΦ hΦsymm0 hL0 g0 hg0A + have hΦbij : Function.Bijective (Φ : AnalyticGerm ℂ (0 : E × ℂ) → AnalyticGerm ℂ (0 : E × ℂ)) := + pullbackEquivOfEq_bijective L.toHomeomorph 0 hΦ hΦsymm0 hL0 + have hΦorder : orderInLastVariable (Φ (ofAnalyticAt g0 hg0A)) = d := by + rw [hΦg, orderInLastVariable_ofAnalyticAt] + exact hd + have hFG : (I.map (Φ.toRingEquiv : AnalyticGerm ℂ (0 : E × ℂ) →+* + AnalyticGerm ℂ (0 : E × ℂ))).FG := + ideal_fg_of_orderInLastVariable_eq_nat _ (Ideal.mem_map_of_mem _ hgI) hΦorder + have hcomap : (I.map (Φ.toRingEquiv : AnalyticGerm ℂ (0 : E × ℂ) →+* + AnalyticGerm ℂ (0 : E × ℂ))).comap + (Φ.toRingEquiv : AnalyticGerm ℂ (0 : E × ℂ) →+* AnalyticGerm ℂ (0 : E × ℂ)) = I := + Ideal.comap_map_of_bijective _ hΦbij + have hI : I = (I.map (Φ.toRingEquiv : AnalyticGerm ℂ (0 : E × ℂ) →+* + AnalyticGerm ℂ (0 : E × ℂ))).map + (Φ.toRingEquiv.symm : AnalyticGerm ℂ (0 : E × ℂ) →+* AnalyticGerm ℂ (0 : E × ℂ)) := by + conv_lhs => rw [← hcomap] + rw [Ideal.map_comap_of_equiv Φ.toRingEquiv.symm, RingEquiv.symm_symm] + rfl + rw [hI] + exact Ideal.FG.map hFG _ + +/-- Analytic induction step for factorization: an irreducible germ becomes regular in the +distinguished coordinate after a linear change, Weierstrass-prepares to a distinguished +polynomial, and irreducibility of the polynomial (hence, given a unique factorization base ring, +its primality) transports back to primality of the germ. -/ +theorem prime_of_irreducible_of_baseUFD [FiniteDimensional ℂ E] + [UniqueFactorizationMonoid (AnalyticGerm ℂ (0 : E))] + {g : AnalyticGerm ℂ (0 : E × ℂ)} (hg : Irreducible g) : Prime g := by + obtain ⟨g0, hg0A, rfl⟩ := exists_rep g + have hg0ne : ¬ g0 =ᶠ[𝓝 0] 0 := fun h => hg.ne_zero (Subtype.ext (Germ.coe_eq.mpr h)) + obtain ⟨L, d, hd⟩ := exists_regular_coordinate_change hg0A hg0ne + have hL0 : L (0 : E × ℂ) = 0 := L.map_zero + have hΦ : AnalyticAt ℂ L (0 : E × ℂ) := L.toContinuousLinearMap.analyticAt 0 + have hΦsymm0 : AnalyticAt ℂ L.symm (L (0 : E × ℂ)) := by + rw [hL0]; exact L.symm.toContinuousLinearMap.analyticAt 0 + set Φ : AnalyticGerm ℂ (0 : E × ℂ) ≃ₐ[ℂ] AnalyticGerm ℂ (0 : E × ℂ) := + pullbackEquivOfEq L.toHomeomorph 0 hΦ hΦsymm0 hL0 with hΦdef + have hΦg : Φ (ofAnalyticAt g0 hg0A) = ofAnalyticAt (g0 ∘ L) (hg0A.comp_of_eq hΦ hL0) := + pullbackEquivOfEq_ofAnalyticAt L.toHomeomorph 0 hΦ hΦsymm0 hL0 g0 hg0A + have hΦorder : orderInLastVariable (Φ (ofAnalyticAt g0 hg0A)) = d := by + rw [hΦg, orderInLastVariable_ofAnalyticAt] + exact hd + have hΦirr : Irreducible (Φ (ofAnalyticAt g0 hg0A)) := hg.map Φ + obtain ⟨⟨u, w⟩, ⟨hwdist, hwdeg, hgeq⟩, -⟩ := + existsUnique_preparation (Φ (ofAnalyticAt g0 hg0A)) hΦorder + simp only at hwdist hwdeg hgeq + have hpolyirr : Irreducible (polynomialHom w) := + (irreducible_isUnit_mul u.isUnit).mp (hgeq ▸ hΦirr) + have hwirr : Irreducible w := (irreducible_polynomialHom_iff w hwdist).mp hpolyirr + have hwp : Prime w := UniqueFactorizationMonoid.irreducible_iff_prime.mp hwirr + have hpw : Prime (polynomialHom w) := prime_polynomialHom_of_isDistinguishedAt hwdist hwp + have hpΦg : Prime (Φ (ofAnalyticAt g0 hg0A)) := by + rw [hgeq]; exact (prime_units_mul u).mpr hpw + exact (MulEquiv.prime_iff Φ).mp hpΦg + +/-- The origin germ ring in `n` complex coordinates is Noetherian, by induction using +`ideal_fg_prod`. In dimension zero it is the scalar field. -/ +theorem isNoetherianRing_coordinates (n : ℕ) : + IsNoetherianRing (AnalyticGerm ℂ (0 : Fin n → ℂ)) := by + induction n with + | zero => + exact isNoetherianRing_of_ringEquiv ℂ (equivScalarOfSubsingleton ℂ (0 : Fin 0 → ℂ)).symm + | succ n ih => + let := ih + let : IsNoetherianRing (AnalyticGerm ℂ (0 : (Fin n → ℂ) × ℂ)) := + (isNoetherianRing_iff_ideal_fg _).mpr ideal_fg_prod + let e : (Fin (n + 1) → ℂ) ≃ₗ[ℂ] (Fin n → ℂ) × ℂ := + (LinearEquiv.piCongrLeft ℂ (fun _ => ℂ) (finSuccEquiv n)).trans + ((LinearEquiv.piOptionEquivProd ℂ).trans (LinearEquiv.prodComm ℂ _ _)) + exact isNoetherianRing_of_ringEquiv _ + (linearEquivPullbackZero e.toContinuousLinearEquiv).toRingEquiv + +/-- Scalar analytic germs at any point of a finite-dimensional complex normed space form a +Noetherian ring. This instance combines the analytic induction step with the dimension +induction. -/ +instance [FiniteDimensional ℂ E] (x : E) : IsNoetherianRing (AnalyticGerm ℂ x) := by + let e := (Module.finBasis ℂ E).equivFunL + let := isNoetherianRing_coordinates (Module.finrank ℂ E) + let : IsNoetherianRing (AnalyticGerm ℂ (0 : E)) := + isNoetherianRing_of_ringEquiv _ (linearEquivPullbackZero e).toRingEquiv + exact isNoetherianRing_of_ringEquiv _ (translateEquiv x).symm.toRingEquiv + +/-- Every ideal of finite-dimensional analytic germs has finitely many generators. -/ +theorem ideal_fg [FiniteDimensional ℂ E] {x : E} (I : Ideal (AnalyticGerm ℂ x)) : I.FG := + (isNoetherianRing_iff_ideal_fg _).mp inferInstance I + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Order.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Order.lean new file mode 100644 index 0000000000..6e828d67ca --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Order.lean @@ -0,0 +1,724 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Algebra.MvPolynomial.Funext +public import Mathlib.Analysis.Analytic.Polynomial +public import Mathlib.RingTheory.MvPowerSeries.Derivative +public import Mathlib.RingTheory.MvPowerSeries.NoZeroDivisors +public import Mathlib.RingTheory.MvPowerSeries.Trunc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoordinateChange +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscTaylor + +/-! +# Total order of analytic germs + +The Taylor series of a scalar germ in finite complex coordinates is a Mathlib `MvPowerSeries`. +Its `order` is the least total degree with a nonzero coefficient, with infinity for the zero +series. This is different from order along a chosen axis. The empty coordinate type `Fin 0` is +included. + +The basic order characterization and sum rules use Mathlib directly. Taylor uniqueness and the +infinite-order criterion follow from the convergent polydisc expansion. The product rule follows +from multiplicativity of Taylor series. The coordinate chain rule proves that analytic pullback +cannot lower order; applying this to a map and its inverse gives coordinate invariance. Exact +total order along the last axis after a linear change follows [Suwa][Suwa2024], Lemma 1.2: the +leading homogeneous part is a nonzero polynomial, hence nonvanishing at some point. An +invertible shear sends the last basis vector to a suitable such point. These are classical local +analytic facts, as in [Suwa][Suwa2024] §1.4, rather than a development of local algebra. + +## Main definitions + +* `taylorSeries`: Taylor series of a scalar analytic germ, independent of its representative. +* `order`: Total order of vanishing: the least total degree in the germ's Taylor series. +* `shearToLastAxis`: A linear automorphism sending the last coordinate axis to the line through `c`, + provided the `i`-th coordinate of `c` is nonzero. + +## Main results + +* `taylorSeries_injective`: The multivariate Taylor-series map is injective on analytic germs. +* `taylorSeries_mul`: Taylor series preserve multiplication of analytic germs. +* `order_mul`: The order of a product is the sum of the orders, including zero germs. +* `min_order_le_order_add`: Cancellation can only raise the order of a sum. +* `order_eq_zero_iff`: A germ has order zero exactly when it is a unit. +* `order_eq_top_iff`: Infinite order is equivalent to being the zero germ, by uniqueness of the + convergent multivariate Taylor expansion. +* `order_pullbackEquiv`: An analytic change of coordinates preserves total order. +* `exists_coordinate_change_order`: **[Suwa][Suwa2024], Lemma 1.2.** A linear change makes the order + on the last axis equal to the total order. + +## References + +* [T. Suwa, *Complex Analytic Geometry: From the Localization Viewpoint*][Suwa2024] +-/ + +public noncomputable section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables.AnalyticGerm + +variable {n m : ℕ} {x : Fin n → ℂ} + +/-- The multivariate Taylor series depends only on the function germ. -/ +theorem holomorphicTaylorSeries_congr {f g : (Fin n → ℂ) → ℂ} + (h : f =ᶠ[𝓝 x] g) : holomorphicTaylorSeries f x = holomorphicTaylorSeries g x := by + obtain ⟨U, hU, ho, hx⟩ := _root_.eventually_nhds_iff.mp h + funext k + dsimp [holomorphicTaylorSeries, multiIndexDeriv] + rw [iteratedPartialDeriv_congrOn ho hU (multiIndexList k) hx] + +/-- Taylor series of a scalar analytic germ, independent of its representative. -/ +@[expose] def taylorSeries (f : AnalyticGerm ℂ x) : MvPowerSeries (Fin n) ℂ := + f.val.liftOn (fun g => holomorphicTaylorSeries g x) + (fun _ _ h => holomorphicTaylorSeries_congr h) + +/-- Taylor series of a represented germ is the existing Taylor series of the function. -/ +@[simp] theorem taylorSeries_ofAnalyticAt (f : (Fin n → ℂ) → ℂ) (hf : AnalyticAt ℂ f x) : + taylorSeries (ofAnalyticAt f hf) = holomorphicTaylorSeries f x := rfl + +/-- Taylor series preserve addition of analytic germs. -/ +theorem taylorSeries_add (f g : AnalyticGerm ℂ x) : + taylorSeries (f + g) = taylorSeries f + taylorSeries g := by + obtain ⟨f, hf, rfl⟩ := exists_rep f + obtain ⟨g, hg, rfl⟩ := exists_rep g + obtain ⟨U, hsub, hU, hx⟩ := _root_.eventually_nhds_iff.mp + (hf.eventually_analyticAt.and hg.eventually_analyticAt) + have hA : ∀ b ∈ (Finset.univ : Finset Bool), + AnalyticOnNhd ℂ (if b then f else g) U := by + intro b _ z hz + cases b + · exact (hsub z hz).2 + · exact (hsub z hz).1 + change holomorphicTaylorSeries (f + g) x = + holomorphicTaylorSeries f x + holomorphicTaylorSeries g x + funext k + have hD : iteratedPartialDeriv (multiIndexList k) (f + g) x = + iteratedPartialDeriv (multiIndexList k) f x + + iteratedPartialDeriv (multiIndexList k) g x := by + simpa [Fintype.sum_bool, Pi.add_def] using + (iteratedPartialDeriv_finset_sum Finset.univ hA hU (multiIndexList k) hx) + change (∏ i, (k i).factorial : ℂ)⁻¹ * iteratedPartialDeriv (multiIndexList k) (f + g) x = + (∏ i, (k i).factorial : ℂ)⁻¹ * iteratedPartialDeriv (multiIndexList k) f x + + (∏ i, (k i).factorial : ℂ)⁻¹ * iteratedPartialDeriv (multiIndexList k) g x + rw [hD, mul_add] + +/-- The zero germ has zero Taylor series, including in dimension zero. -/ +@[simp] theorem taylorSeries_zero : taylorSeries (0 : AnalyticGerm ℂ x) = 0 := by + have hz : ∀ l : List (Fin n), iteratedPartialDeriv l (0 : (Fin n → ℂ) → ℂ) = 0 := by + intro l + induction l with + | nil => rfl + | cons i l ih => + change partialDeriv i (iteratedPartialDeriv l 0) = 0 + rw [ih] + funext z + simp [partialDeriv] + change holomorphicTaylorSeries (0 : (Fin n → ℂ) → ℂ) x = 0 + funext k + change holomorphicTaylorSeries (0 : (Fin n → ℂ) → ℂ) x k = 0 + simp [holomorphicTaylorSeries, multiIndexDeriv, hz] + +/-- The Taylor series of a coordinate derivative is the formal partial derivative. -/ +theorem holomorphicTaylorSeries_partialDeriv {f : (Fin n → ℂ) → ℂ} + (hf : AnalyticAt ℂ f x) (i : Fin n) : + holomorphicTaylorSeries (partialDeriv i f) x = + MvPowerSeries.pderiv i (holomorphicTaylorSeries f x) := by + obtain ⟨U, hU, ho, hx⟩ := _root_.eventually_nhds_iff.mp hf.eventually_analyticAt + ext k + rw [MvPowerSeries.coeff_pderiv] + have happ (l : List (Fin n)) : + iteratedPartialDeriv (l ++ [i]) f = iteratedPartialDeriv l (partialDeriv i f) := by + induction l with + | nil => rfl + | cons j l ih => + simpa only [List.cons_append, iteratedPartialDeriv] using congrArg (partialDeriv j) ih + have hD : multiIndexDeriv k (partialDeriv i f) x = + multiIndexDeriv (k + Finsupp.single i 1 : Fin n →₀ ℕ) f x := by + rw [multiIndexDeriv, ← happ] + apply iteratedPartialDeriv_eq_multiIndexDeriv hU ho hx + intro j + by_cases hji : j = i + · subst j; simp + · simp [hji, Ne.symm hji] + have hfac : (∏ j, ((k + Finsupp.single i 1 : Fin n →₀ ℕ) j).factorial : ℂ) = + (∏ j, (k j).factorial : ℂ) * (k i + 1) := by + rw [← Finset.prod_erase_mul _ _ (Finset.mem_univ i), + ← Finset.prod_erase_mul _ _ (Finset.mem_univ i)] + have he : (∏ j ∈ Finset.univ.erase i, (((k + Finsupp.single i 1 : Fin n →₀ ℕ) j).factorial : + ℂ)) = + ∏ j ∈ Finset.univ.erase i, ((k j).factorial : ℂ) := by + apply Finset.prod_congr rfl + intro j hj + simp [Finsupp.single_eq_of_ne (Finset.ne_of_mem_erase hj)] + rw [he] + simp [Nat.factorial_succ] + ring + change (∏ j, (k j).factorial : ℂ)⁻¹ * multiIndexDeriv k (partialDeriv i f) x = + (∏ j, ((k + Finsupp.single i 1 : Fin n →₀ ℕ) j).factorial : ℂ)⁻¹ * + multiIndexDeriv (k + Finsupp.single i 1 : Fin n →₀ ℕ) f x * (k i + 1) + rw [hD, hfac] + have hk : (k i : ℂ) + 1 ≠ 0 := by exact_mod_cast Nat.succ_ne_zero (k i) + field_simp + +/-- Total order of vanishing: the least total degree in the germ's Taylor series. -/ +@[expose] def order (f : AnalyticGerm ℂ x) : ℕ∞ := (taylorSeries f).order + +/-- The total order is computed by Mathlib's multivariate power-series order. -/ +theorem order_eq_taylorSeries_order (f : AnalyticGerm ℂ x) : + order f = (taylorSeries f).order := rfl + +/-- The constant Taylor coefficient is evaluation at the base point. -/ +@[simp] theorem constantCoeff_taylorSeries (f : AnalyticGerm ℂ x) : + (taylorSeries f).constantCoeff = eval x f := by + obtain ⟨g, hg, rfl⟩ := exists_rep f + change holomorphicTaylorSeries g x 0 = g x + simp [holomorphicTaylorSeries, multiIndexDeriv, multiIndexList, iteratedPartialDeriv] + +/-- A germ has order zero exactly when it is a unit. -/ +@[simp] theorem order_eq_zero_iff (f : AnalyticGerm ℂ x) : order f = 0 ↔ IsUnit f := by + rw [isUnit_iff, order] + have h := MvPowerSeries.order_ne_zero_iff_constCoeff_eq_zero (f := taylorSeries f) + simpa using not_congr h + +/-- The zero germ has infinite total order. -/ +@[simp] theorem order_zero : order (0 : AnalyticGerm ℂ x) = ⊤ := by + simp [order] + +/-- Distinct orders prevent cancellation of the leading terms of a sum. -/ +theorem order_add_of_ne {f g : AnalyticGerm ℂ x} (h : order f ≠ order g) : + order (f + g) = min (order f) (order g) := by + simpa only [order, taylorSeries_add] using MvPowerSeries.order_add_of_order_ne h + +/-- A scalar analytic germ is determined to be zero by its Taylor coefficients. The proof uses the +convergent polydisc Taylor expansion, including dimension zero. -/ +@[simp] theorem taylorSeries_eq_zero_iff (f : AnalyticGerm ℂ x) : + taylorSeries f = 0 ↔ f = 0 := by + classical + constructor + · intro hzero + obtain ⟨g, hg, rfl⟩ := exists_rep f + change holomorphicTaylorSeries g x = 0 at hzero + have hb : ∀ᶠ z in 𝓝 x, ‖g z‖ < ‖g x‖ + 1 := + hg.continuousAt.norm.eventually_lt_const (by linarith) + obtain ⟨r, hr, hball⟩ := Metric.mem_nhds_iff.mp (hg.eventually_analyticAt.and hb) + have hr₂ : 0 < r / 2 := half_pos hr + have hsub : closedPolydisc x (fun _ => r / 2) ⊆ ball x r := by + rw [closedPolydisc_eq_closedBall hr₂.le] + exact closedBall_subset_ball (half_lt_self hr) + have hA : AnalyticOnNhd ℂ g (closedPolydisc x (fun _ => r / 2)) := + fun z hz => (hball (hsub hz)).1 + have hslice : ∀ z ∈ closedPolydisc x (fun _ => r / 2), ∀ i, + AnalyticAt ℂ (fun w => g (Function.update z i w)) (z i) := by + intro z hz i + exact hA.analyticAt_update hz i + have hcoeff : ∀ m : Fin n → ℕ, + polydiscCauchyCoeffWithRadii g x (fun _ => r / 2) m = 0 := by + intro m + have h := (coeff_holomorphicTaylorSeries (fun _ => hr₂) hA.continuousOn hslice + (Finsupp.equivFunOnFinite.symm m)).symm + rw [hzero, Finsupp.coe_equivFunOnFinite_symm] at h + exact h + have he : g =ᶠ[𝓝 x] 0 := by + filter_upwards [ball_mem_nhds x hr₂] with z hz + have hh : ∀ i, ‖(z - x) i‖ < r / 2 := by + intro i + exact lt_of_le_of_lt (norm_le_pi_norm (z - x) i) + (by simpa only [mem_ball, dist_eq_norm] using hz) + have hsum := hasSum_polydiscTaylor (fun _ => hr₂) hh hA.continuousOn hslice + (fun z hz => (hball (hsub hz)).2.le) + have hxz : x + (z - x) = z := by abel + have hsum0 : HasSum (fun _ : Fin n → ℕ => (0 : ℂ)) (g z) := by + simpa only [hcoeff, smul_zero, hxz] using hsum + exact hsum0.unique hasSum_zero + exact Subtype.ext (Germ.coe_eq.mpr he) + · rintro rfl + exact taylorSeries_zero + +/-- The multivariate Taylor-series map is injective on analytic germs. -/ +theorem taylorSeries_injective : Function.Injective (taylorSeries (x := x)) := by + let T : AnalyticGerm ℂ x →+ MvPowerSeries (Fin n) ℂ := + { toFun := taylorSeries + map_zero' := taylorSeries_zero + map_add' := taylorSeries_add } + intro f g h + have hs : taylorSeries (f - g) = 0 := by + change T (f - g) = 0 + rw [map_sub] + exact sub_eq_zero.mpr h + exact sub_eq_zero.mp ((taylorSeries_eq_zero_iff _).mp hs) + +/-- Infinite order is equivalent to being the zero germ, by uniqueness of the convergent +multivariate Taylor expansion. -/ +@[simp] theorem order_eq_top_iff (f : AnalyticGerm ℂ x) : order f = ⊤ ↔ f = 0 := by + rw [order, MvPowerSeries.order_eq_top_iff, taylorSeries_eq_zero_iff] + +/-- Taylor series preserve multiplication of analytic germs. The proof compares coefficients +inductively, using the analytic and formal coordinate product rules. -/ +theorem taylorSeries_mul (f g : AnalyticGerm ℂ x) : + taylorSeries (f * g) = taylorSeries f * taylorSeries g := by + let P (k : Fin n →₀ ℕ) : Prop := ∀ f g : AnalyticGerm ℂ x, + MvPowerSeries.coeff k (taylorSeries (f * g)) = + MvPowerSeries.coeff k (taylorSeries f * taylorSeries g) + have hzero : P 0 := by + intro f g + simp only [MvPowerSeries.coeff_zero_eq_constantCoeff, map_mul, + constantCoeff_taylorSeries] + have hstep (k : Fin n →₀ ℕ) (i : Fin n) (ih : P k) : P (k + Finsupp.single i 1) := by + intro f g + obtain ⟨f, hf, rfl⟩ := exists_rep f + obtain ⟨g, hg, rfl⟩ := exists_rep g + obtain ⟨U, hU, ho, hx⟩ := _root_.eventually_nhds_iff.mp + (hf.eventually_analyticAt.and hg.eventually_analyticAt) + have hAf : AnalyticOnNhd ℂ f U := fun y hy => (hU y hy).1 + have hAg : AnalyticOnNhd ℂ g U := fun y hy => (hU y hy).2 + have hdf := (hAf.partialDeriv ho i) x hx + have hdg := (hAg.partialDeriv ho i) x hx + have hdm := ((hAf.mul hAg).partialDeriv ho i) x hx + have heq : ofAnalyticAt (partialDeriv i (f * g)) hdm = + ofAnalyticAt (partialDeriv i f) hdf * ofAnalyticAt g hg + + ofAnalyticAt f hf * ofAnalyticAt (partialDeriv i g) hdg := by + rw [← ofAnalyticAt_mul, ← ofAnalyticAt_mul, ← ofAnalyticAt_add] + apply ofAnalyticAt_eq_iff.mpr + filter_upwards [ho.eventually_mem hx] with y hy + exact partialDeriv_mul (hAf y hy).differentiableAt (hAg y hy).differentiableAt i + have hD : MvPowerSeries.coeff k + (MvPowerSeries.pderiv i (holomorphicTaylorSeries (f * g) x)) = + MvPowerSeries.coeff k (MvPowerSeries.pderiv i + (holomorphicTaylorSeries f x * holomorphicTaylorSeries g x)) := by + rw [← holomorphicTaylorSeries_partialDeriv (hf.mul hg) i] + change MvPowerSeries.coeff k (taylorSeries (ofAnalyticAt (partialDeriv i (f * g)) hdm)) = _ + rw [heq, taylorSeries_add, map_add, ih, ih] + simp only [taylorSeries_ofAnalyticAt, holomorphicTaylorSeries_partialDeriv hf i, + holomorphicTaylorSeries_partialDeriv hg i, Derivation.leibniz, smul_eq_mul, map_add] + rw [mul_comm (MvPowerSeries.pderiv i (holomorphicTaylorSeries f x))] + exact add_comm _ _ + simp only [MvPowerSeries.coeff_pderiv] at hD + exact mul_right_cancel₀ (by exact_mod_cast Nat.succ_ne_zero (k i)) hD + have hall (k : Fin n →₀ ℕ) : P k := by + induction k using Finsupp.induction₂ with + | zero => exact hzero + | add_single i b k _ _ ih => + have h (b : ℕ) : P (k + Finsupp.single i b) := by + induction b with + | zero => simpa using ih + | succ b hb => + simpa only [Finsupp.single_add, add_assoc] using hstep (k + Finsupp.single i b) i hb + exact h b + exact MvPowerSeries.ext fun k => hall k f g + +/-- The order of a product is the sum of the orders, including zero germs. This follows from +multiplicativity of Taylor series and `MvPowerSeries.order_mul`. -/ +theorem order_mul (f g : AnalyticGerm ℂ x) : order (f * g) = order f + order g := by + simpa only [order, taylorSeries_mul] using MvPowerSeries.order_mul (taylorSeries f) + (taylorSeries g) + +/-- Cancellation can only raise the order of a sum. -/ +theorem min_order_le_order_add (f g : AnalyticGerm ℂ x) : + min (order f) (order g) ≤ order (f + g) := by + simpa only [order, taylorSeries_add] using + (MvPowerSeries.min_order_le_add (f := taylorSeries f) (g := taylorSeries g)) + +/-- Order at least `d + 1` is equivalent to a zero constant term and order at least `d` for every +formal coordinate derivative. -/ +private theorem nat_succ_le_series_order_iff (p : MvPowerSeries (Fin n) ℂ) (d : ℕ) : + (d + 1 : ℕ) ≤ p.order ↔ p.constantCoeff = 0 ∧ + ∀ i, (d : ℕ∞) ≤ (MvPowerSeries.pderiv i p).order := by + constructor + · intro h + constructor + · exact MvPowerSeries.one_le_order_iff_constCoeff_eq_zero.mp + (le_trans (by exact_mod_cast Nat.succ_pos d) h) + · intro i + apply MvPowerSeries.nat_le_order + intro k hk + rw [MvPowerSeries.coeff_pderiv] + have hdeg : (k + Finsupp.single i 1).degree < d + 1 := by simpa using hk + rw [MvPowerSeries.coeff_of_lt_order + (lt_of_lt_of_le (by exact_mod_cast hdeg) h), zero_mul] + · rintro ⟨hzero, hd⟩ + apply MvPowerSeries.nat_le_order + intro k hk + by_cases hk0 : k = 0 + · simpa [hk0] using hzero + obtain ⟨i, hi⟩ := Finsupp.support_nonempty_iff.mpr hk0 + have hip : 0 < k i := Nat.pos_of_ne_zero (Finsupp.mem_support_iff.mp hi) + have hsingle : Finsupp.single i 1 ≤ k := Finsupp.single_le_iff.mpr hip + let l := k - Finsupp.single i 1 + have hl : l + Finsupp.single i 1 = k := tsub_add_cancel_of_le hsingle + have hdeg : l.degree < d := by + have := congrArg Finsupp.degree hl + simp only [map_add, Finsupp.degree_single] at this + omega + have hh := MvPowerSeries.coeff_of_lt_order (f := MvPowerSeries.pderiv i p) + (lt_of_lt_of_le (by exact_mod_cast hdeg) (hd i)) + rw [MvPowerSeries.coeff_pderiv, hl] at hh + exact (mul_eq_zero.mp hh).resolve_right (by exact_mod_cast Nat.succ_ne_zero (l i)) + +/-- A common lower bound on orders is preserved by finite sums of analytic germs. -/ +theorem le_order_sum {κ : Type*} (s : Finset κ) (f : κ → AnalyticGerm ℂ x) {d : ℕ∞} + (h : ∀ i ∈ s, d ≤ order (f i)) : d ≤ order (∑ i ∈ s, f i) := by + classical + induction s using Finset.induction_on with + | empty => simp + | @insert i s hi ih => + rw [Finset.sum_insert hi] + exact le_trans (le_min (h i (Finset.mem_insert_self _ _)) + (ih fun j hj => h j (Finset.mem_insert_of_mem hj))) (min_order_le_order_add _ _) + +/-- Coordinate differentiation preserves analyticity at a point. -/ +private theorem analyticAt_partialDeriv {f : (Fin n → ℂ) → ℂ} + (hf : AnalyticAt ℂ f x) (i : Fin n) : AnalyticAt ℂ (partialDeriv i f) x := by + obtain ⟨r, hr, hfa⟩ := hf.exists_ball_analyticOnNhd + exact (hfa.partialDeriv isOpen_ball i) x (mem_ball_self hr) + +/-- Analytic pullback cannot lower the total order of a scalar germ. This includes maps between +spaces of different dimensions and empty coordinate types. -/ +theorem order_le_order_pullback (e : (Fin n → ℂ) → (Fin m → ℂ)) (he : AnalyticAt ℂ e x) + (f : AnalyticGerm ℂ (e x)) : order f ≤ order (pullback e he f) := by + apply ENat.forall_natCast_le_iff_le.mp + intro d + obtain ⟨f, hf, rfl⟩ := exists_rep f + induction d generalizing f with + | zero => exact fun _ => bot_le + | succ d ih => + intro hd + obtain ⟨hzero, hderiv⟩ := (nat_succ_le_series_order_iff + (holomorphicTaylorSeries f (e x)) d).mp hd + change ((d + 1 : ℕ) : ℕ∞) ≤ (holomorphicTaylorSeries (f ∘ e) x).order + apply (nat_succ_le_series_order_iff _ d).mpr + constructor + · have h0 : f (e x) = 0 := by + simpa only [← taylorSeries_ofAnalyticAt f hf, constantCoeff_taylorSeries, + eval_ofAnalyticAt] using hzero + simpa only [← taylorSeries_ofAnalyticAt (f ∘ e) (hf.comp he), + constantCoeff_taylorSeries, eval_ofAnalyticAt, Function.comp_apply] using h0 + · intro i + let a (j : Fin m) := partialDeriv i (fun z => e z j) + let b (j : Fin m) := partialDeriv j f ∘ e + have ha (j : Fin m) : AnalyticAt ℂ (a j) x := + analyticAt_partialDeriv (analyticAt_pi_iff.mp he j) i + have hb (j : Fin m) : AnalyticAt ℂ (b j) x := + (analyticAt_partialDeriv hf j).comp he + have hsum := Finset.univ.analyticAt_sum (fun j _ => (ha j).mul (hb j)) + have heq : ofAnalyticAt (partialDeriv i (f ∘ e)) + (analyticAt_partialDeriv (hf.comp he) i) = + ∑ j, ofAnalyticAt (a j) (ha j) * ofAnalyticAt (b j) (hb j) := by + simp_rw [← ofAnalyticAt_mul] + rw [← ofAnalyticAt_sum Finset.univ (fun j => a j * b j) + (fun j => (ha j).mul (hb j)) hsum] + apply ofAnalyticAt_eq_iff.mpr + filter_upwards [he.eventually_analyticAt, + he.continuousAt.eventually hf.eventually_analyticAt] with z hez hfz + simpa [a, b, complexJacobian, smul_eq_mul] using + partialDeriv_comp hfz.differentiableAt hez.differentiableAt i + rw [← holomorphicTaylorSeries_partialDeriv (hf.comp he) i] + change (d : ℕ∞) ≤ order (ofAnalyticAt (partialDeriv i (f ∘ e)) + (analyticAt_partialDeriv (hf.comp he) i)) + rw [heq] + apply le_order_sum + intro j _ + rw [order_mul] + apply le_trans _ (le_add_left (le_refl _)) + apply ih (partialDeriv j f) (analyticAt_partialDeriv hf j) + simpa only [order, taylorSeries_ofAnalyticAt, + holomorphicTaylorSeries_partialDeriv hf j] using hderiv j + +/-- An analytic change of coordinates preserves total order. Apply order monotonicity to the +coordinate map and its analytic inverse. -/ +theorem order_pullbackEquiv (e : (Fin n → ℂ) ≃ₜ (Fin m → ℂ)) + (he : AnalyticAt ℂ e x) (hi : AnalyticAt ℂ e.symm (e x)) + (f : AnalyticGerm ℂ (e x)) : order (pullbackEquiv e x he hi f) = order f := by + apply le_antisymm + · obtain ⟨f, hf, rfl⟩ := exists_rep f + have hc : AnalyticAt ℂ (f ∘ e) (e.symm (e x)) := by simpa using hf.comp he + have h := order_le_order_pullback e.symm hi (ofAnalyticAt (f ∘ e) hc) + have heq : ofAnalyticAt ((f ∘ e) ∘ e.symm) (hc.comp hi) = ofAnalyticAt f hf := by + apply ofAnalyticAt_eq_iff.mpr + exact .of_forall fun z => by simp + rw [pullback_ofAnalyticAt, heq] at h + change (holomorphicTaylorSeries (f ∘ e) (e.symm (e x))).order ≤ + (holomorphicTaylorSeries f (e x)).order at h + change (holomorphicTaylorSeries (f ∘ e) x).order ≤ + (holomorphicTaylorSeries f (e x)).order + simpa only [Homeomorph.symm_apply_apply] using h + · exact order_le_order_pullback e he f + +/-- Exact order is characterized by the first nonzero total-degree Taylor coefficient. -/ +theorem order_eq_nat_iff (f : AnalyticGerm ℂ x) (d : ℕ) : + order f = d ↔ + (∃ k, MvPowerSeries.coeff k (taylorSeries f) ≠ 0 ∧ k.degree = d) ∧ + ∀ k, k.degree < d → MvPowerSeries.coeff k (taylorSeries f) = 0 := + MvPowerSeries.order_eq_nat + +/-- A linear automorphism sending the last coordinate axis to the line through `c`, provided the +`i`-th coordinate of `c` is nonzero. This is the shear used in [Suwa][Suwa2024], Lemma 1.2, +after swapping `i` with the last index. -/ +def shearToLastAxis (c : Fin (n + 1) → ℂ) (i : Fin (n + 1)) (hi : c i ≠ 0) : + (Fin (n + 1) → ℂ) ≃ₗ[ℂ] (Fin (n + 1) → ℂ) where + toFun z j := if j = i then z i * c i else z j + z i * c j + invFun z j := if j = i then z i / c i else z j - (z i / c i) * c j + left_inv z := by + ext j + by_cases hj : j = i + · subst hj + simp [hi] + · simp [hj]; field_simp [hi]; ring + right_inv z := by + ext j + by_cases hj : j = i + · subst hj + simp [hi] + · simp [hj] + map_add' z w := by + ext j + by_cases hj : j = i + · simp [hj]; ring + · simp [hj]; ring + map_smul' a z := by + ext j + by_cases hj : j = i + · simp [hj, smul_eq_mul]; ring + · simp [hj, smul_eq_mul]; ring + +/-- The shear sends the `i`-th axis to the line through `c`. -/ +theorem shearToLastAxis_single (c : Fin (n + 1) → ℂ) (i : Fin (n + 1)) (hi : c i ≠ 0) + (w : ℂ) : shearToLastAxis c i hi (Pi.single i w) = w • c := by + ext j + by_cases hj : j = i + · subst j; simp [shearToLastAxis, Pi.single_eq_same, smul_eq_mul] + · simp [shearToLastAxis, hj, smul_eq_mul] + +/-- Constant functions have constant multivariate Taylor series. -/ +theorem holomorphicTaylorSeries_const (a : ℂ) (x : Fin n → ℂ) : + holomorphicTaylorSeries (fun _ => a) x = MvPowerSeries.C a := by + ext k + by_cases hk : k = 0 + · subst k + change holomorphicTaylorSeries (fun _ => a) x 0 = a + simp [holomorphicTaylorSeries, multiIndexDeriv, multiIndexList, iteratedPartialDeriv] + · have hzero (l : List (Fin n)) (hl : l ≠ []) : + iteratedPartialDeriv l (fun _ : (Fin n → ℂ) => a) = 0 := by + induction l with + | nil => exact (hl rfl).elim + | cons i l ih => + by_cases hl0 : l = [] + · subst l + funext z + simp [iteratedPartialDeriv, partialDeriv] + · funext z + simp [iteratedPartialDeriv, ih hl0, partialDeriv] + rw [MvPowerSeries.coeff_C_of_ne_zero hk] + have hlist : multiIndexList k ≠ [] := by + intro h + have hcount := congrArg (fun l => l.count) h + have : k = 0 := by + ext i + have := congrFun hcount i + simpa only [count_multiIndexList, List.count_nil, Finsupp.zero_apply] using this + exact hk this + change holomorphicTaylorSeries (fun _ => a) x k = 0 + simp [holomorphicTaylorSeries, multiIndexDeriv, hzero _ hlist] + +/-- Coordinate functions have the corresponding formal variable as their Taylor series at zero. -/ +theorem holomorphicTaylorSeries_coord (i : Fin n) : + holomorphicTaylorSeries (fun z : Fin n → ℂ => z i) 0 = MvPowerSeries.X i := by + have hder (j : Fin n) : partialDeriv j (fun z : Fin n → ℂ => z i) = + fun _ => if j = i then (1 : ℂ) else 0 := by + funext z + by_cases hji : j = i + · subst j; simp [partialDeriv] + · simp [partialDeriv, hji, Ne.symm hji] + have hai : AnalyticAt ℂ (fun z : Fin n → ℂ => z i) 0 := + analyticAt_pi_iff.mp analyticAt_id i + have hd (j : Fin n) : MvPowerSeries.pderiv j + (holomorphicTaylorSeries (fun z : Fin n → ℂ => z i) 0) = + MvPowerSeries.pderiv j (MvPowerSeries.X i) := by + rw [← holomorphicTaylorSeries_partialDeriv hai j, hder, + holomorphicTaylorSeries_const] + by_cases hji : j = i <;> simp [MvPowerSeries.pderiv_X, hji] + ext k + by_cases hk : k = 0 + · subst k + simp only [MvPowerSeries.coeff_zero_eq_constantCoeff, MvPowerSeries.constantCoeff_X] + change holomorphicTaylorSeries (fun z : Fin n → ℂ => z i) 0 0 = 0 + simp [holomorphicTaylorSeries, multiIndexDeriv, multiIndexList, iteratedPartialDeriv] + · obtain ⟨j, hj⟩ := Finsupp.support_nonempty_iff.mpr hk + have hjp : 0 < k j := Nat.pos_of_ne_zero (Finsupp.mem_support_iff.mp hj) + let l := k - Finsupp.single j 1 + have hl : l + Finsupp.single j 1 = k := + tsub_add_cancel_of_le (Finsupp.single_le_iff.mpr hjp) + have hh := congrArg (MvPowerSeries.coeff l) (hd j) + simp only [MvPowerSeries.coeff_pderiv, hl] at hh + exact mul_right_cancel₀ (by exact_mod_cast Nat.succ_ne_zero (l j)) hh + +/-- The Taylor series at zero of polynomial evaluation is the polynomial itself. -/ +theorem holomorphicTaylorSeries_eval (p : MvPolynomial (Fin n) ℂ) : + holomorphicTaylorSeries (fun z => MvPolynomial.eval z p) 0 = p := by + have ha (q : MvPolynomial (Fin n) ℂ) : AnalyticAt ℂ (fun z => MvPolynomial.eval z q) 0 := + AnalyticAt.aeval_mvPolynomial (fun i => analyticAt_pi_iff.mp analyticAt_id i) q + induction p using MvPolynomial.induction_on with + | C a => simpa using holomorphicTaylorSeries_const a (0 : Fin n → ℂ) + | add p q hp hq => + change taylorSeries (ofAnalyticAt (fun z => MvPolynomial.eval z (p + q)) (ha _)) = _ + have heq : ofAnalyticAt (fun z => MvPolynomial.eval z (p + q)) (ha _) = + ofAnalyticAt (fun z => MvPolynomial.eval z p) (ha _) + + ofAnalyticAt (fun z => MvPolynomial.eval z q) (ha _) := by + rw [← ofAnalyticAt_add] + apply ofAnalyticAt_eq_iff.mpr + exact .of_forall fun z => map_add _ _ _ + rw [heq, taylorSeries_add] + simp only [taylorSeries_ofAnalyticAt, hp, hq, MvPolynomial.coe_add] + | mul_X p i hp => + change taylorSeries (ofAnalyticAt (fun z => MvPolynomial.eval z (p * MvPolynomial.X i)) + (ha _)) = _ + have heq : ofAnalyticAt (fun z => MvPolynomial.eval z (p * MvPolynomial.X i)) (ha _) = + ofAnalyticAt (fun z => MvPolynomial.eval z p) (ha _) * + ofAnalyticAt (fun z : Fin n → ℂ => z i) (analyticAt_pi_iff.mp analyticAt_id i) := by + rw [← ofAnalyticAt_mul] + apply ofAnalyticAt_eq_iff.mpr + exact .of_forall fun z => by simp + rw [heq, taylorSeries_mul] + simp only [taylorSeries_ofAnalyticAt, hp, holomorphicTaylorSeries_coord, + MvPolynomial.coe_mul, MvPolynomial.coe_X] + +/-- Total Taylor order in one coordinate agrees with Mathlib's scalar analytic order. -/ +theorem order_one_coordinate {g : ℂ → ℂ} (hg : AnalyticAt ℂ g 0) : + order (ofAnalyticAt (fun z : Fin 1 → ℂ => g (z 0)) + (hg.comp_of_eq + ((ContinuousLinearMap.proj (0 : Fin 1) : (Fin 1 → ℂ) →L[ℂ] ℂ).analyticAt 0) rfl)) = + analyticOrderAt g 0 := by + have ha {g : ℂ → ℂ} (hg : AnalyticAt ℂ g 0) : + AnalyticAt ℂ (fun z : Fin 1 → ℂ => g (z 0)) 0 := + hg.comp_of_eq ((ContinuousLinearMap.proj (0 : Fin 1) : (Fin 1 → ℂ) →L[ℂ] ℂ).analyticAt 0) rfl + apply ENat.eq_of_forall_natCast_le_iff + intro d + change (d : ℕ∞) ≤ (holomorphicTaylorSeries (fun z : Fin 1 → ℂ => g (z 0)) 0).order ↔ _ + induction d generalizing g with + | zero => simp + | succ d ih => + rw [nat_succ_le_series_order_iff] + have hc : (holomorphicTaylorSeries (fun z : Fin 1 → ℂ => g (z 0)) 0).constantCoeff = g 0 := + constantCoeff_taylorSeries (ofAnalyticAt _ (ha hg)) + rw [hc] + by_cases hz : g 0 = 0 + · rw [and_iff_right hz, Fin.forall_fin_one] + rw [← holomorphicTaylorSeries_partialDeriv (ha hg) 0] + have hd : partialDeriv 0 (fun z : Fin 1 → ℂ => g (z 0)) = + fun z => deriv g (z 0) := by + funext z + simp [partialDeriv] + rw [hd, ih hg.deriv] + simpa only [Nat.cast_add, Nat.cast_one] using analyticOrderAt_deriv_ge_iff hg hz + · simp [hz, hg.analyticOrderAt_eq_zero.mpr hz] + +/-- Restriction to a complex line cannot lower total order. -/ +theorem order_le_analyticOrderAt_line {f : (Fin n → ℂ) → ℂ} + (hf : AnalyticAt ℂ f 0) (v : Fin n → ℂ) : + order (ofAnalyticAt f hf) ≤ analyticOrderAt (fun w : ℂ => f (w • v)) 0 := by + let e : (Fin 1 → ℂ) → (Fin n → ℂ) := fun z => z 0 • v + have he : AnalyticAt ℂ e 0 := + ((ContinuousLinearMap.proj (0 : Fin 1) : (Fin 1 → ℂ) →L[ℂ] ℂ).analyticAt 0).smul + analyticAt_const + have hf' : AnalyticAt ℂ f (e 0) := by simpa [e] using hf + have h := order_le_order_pullback e he (ofAnalyticAt f hf') + rw [pullback_ofAnalyticAt] at h + have hl : AnalyticAt ℂ (fun w : ℂ => f (w • v)) 0 := + hf.comp_of_eq (analyticAt_id.smul analyticAt_const) (zero_smul _ _) + have hscalar := order_one_coordinate hl + simp only [order, taylorSeries_ofAnalyticAt] at h hscalar ⊢ + simpa [e, Function.comp_def, hscalar] using h + +/-- **[Suwa][Suwa2024], Lemma 1.2.** A linear change makes the order on the last axis equal to the +total order. Positive ambient dimension is explicit; units are permitted and give +order zero. Evaluate the leading homogeneous part at a point with nonzero last +coordinate; the higher-order remainder cannot cancel it along the resulting line. -/ +theorem exists_coordinate_change_order {f : (Fin (n + 1) → ℂ) → ℂ} + (hf : AnalyticAt ℂ f 0) (hne : ofAnalyticAt f hf ≠ 0) : + ∃ L : (Fin (n + 1) → ℂ) ≃L[ℂ] (Fin (n + 1) → ℂ), + analyticOrderAt (fun w : ℂ => f (L (Pi.single (Fin.last n) w))) 0 = + order (ofAnalyticAt f hf) := by + obtain ⟨d, hd⟩ := ENat.ne_top_iff_exists.mp + (show order (ofAnalyticAt f hf) ≠ ⊤ from fun h => hne ((order_eq_top_iff _).mp h)) + let p := taylorSeries (ofAnalyticAt f hf) + let q := MvPowerSeries.truncTotal (d + 1) p + have hp : p.order = d := hd.symm + have hqcoeff (k : Fin (n + 1) →₀ ℕ) : q.coeff k = + if k.degree < d + 1 then MvPowerSeries.coeff k p else 0 := + MvPowerSeries.coeff_truncTotal_eq_ite p + have hqdeg (k : Fin (n + 1) →₀ ℕ) (hk : k ∈ q.support) : k.degree = d := by + have hn := MvPolynomial.mem_support_iff.mp hk + rw [hqcoeff] at hn + split_ifs at hn with hlt + · have hge : d ≤ k.degree := by + by_contra! h + exact hn (MvPowerSeries.coeff_of_lt_order (by simpa [hp] using h)) + omega + · exact (hn rfl).elim + have hqne : q ≠ 0 := by + obtain ⟨k, hk, hkd⟩ := (order_eq_nat_iff (ofAnalyticAt f hf) d).mp hd.symm |>.1 + intro hq + have h := congrArg (fun q : MvPolynomial (Fin (n + 1)) ℂ => q.coeff k) hq + simp only [hqcoeff, hkd, Nat.lt_succ_self, ite_true, AddMonoidAlgebra.coeff_zero] at h + exact hk h + obtain ⟨v, hv⟩ : ∃ v : Fin (n + 1) → ℂ, + MvPolynomial.eval v (q * MvPolynomial.X (Fin.last n)) ≠ 0 := by + by_contra! h + exact (mul_ne_zero hqne (MvPolynomial.X_ne_zero _)) + (MvPolynomial.funext fun z => by simpa using h z) + have hvq : MvPolynomial.eval v q ≠ 0 := (mul_ne_zero_iff.mp (by simpa using hv)).1 + have hvi : v (Fin.last n) ≠ 0 := (mul_ne_zero_iff.mp (by simpa using hv)).2 + have hqline (w : ℂ) : MvPolynomial.eval (w • v) q = w ^ d * MvPolynomial.eval v q := by + simp only [MvPolynomial.eval_eq', Pi.smul_apply, smul_eq_mul, mul_pow, + Finset.prod_mul_distrib, Finset.prod_pow_eq_pow_sum, ← Finsupp.degree_eq_sum, + Finset.mul_sum] + apply Finset.sum_congr rfl + intro k hk + rw [hqdeg k hk] + ring + let g : (Fin (n + 1) → ℂ) → ℂ := fun z => MvPolynomial.eval z q + have hg : AnalyticAt ℂ g 0 := + AnalyticAt.aeval_mvPolynomial (fun i => analyticAt_pi_iff.mp analyticAt_id i) q + have ht : taylorSeries (ofAnalyticAt g hg) = q := holomorphicTaylorSeries_eval q + have hr : (d + 1 : ℕ) ≤ order (ofAnalyticAt (f - g) (hf.sub hg)) := by + have hs : taylorSeries (ofAnalyticAt (f - g) (hf.sub hg)) = p - q := by + have heq : ofAnalyticAt (f - g) (hf.sub hg) + ofAnalyticAt g hg = + ofAnalyticAt f hf := by + rw [← ofAnalyticAt_add] + apply ofAnalyticAt_eq_iff.mpr + exact .of_forall fun z => sub_add_cancel _ _ + have h := congrArg taylorSeries heq + rw [taylorSeries_add, ht] at h + exact eq_sub_of_add_eq h + apply MvPowerSeries.nat_le_order + intro k hk + rw [hs, map_sub, MvPolynomial.coeff_coe, hqcoeff, ite_eq_left hk, sub_self] + have hrem := le_trans hr (order_le_analyticOrderAt_line (hf.sub hg) v) + have hgo : analyticOrderAt (fun w : ℂ => g (w • v)) 0 = d := by + apply (AnalyticAt.analyticOrderAt_eq_natCast + (hg.comp_of_eq (analyticAt_id.smul analyticAt_const) (by simp))).mpr + refine ⟨fun _ => MvPolynomial.eval v q, analyticAt_const, hvq, ?_⟩ + exact .of_forall fun w => by simpa [g, sub_zero, smul_eq_mul] using hqline w + have hlt : analyticOrderAt (fun w : ℂ => g (w • v)) 0 < + analyticOrderAt (fun w : ℂ => (f - g) (w • v)) 0 := by + rw [hgo] + exact lt_of_lt_of_le (by exact_mod_cast Nat.lt_succ_self d) hrem + have hsum := analyticOrderAt_add_eq_left_of_lt hlt + have hfo : analyticOrderAt (fun w : ℂ => f (w • v)) 0 = d := by + have heq : (fun w : ℂ => g (w • v)) + (fun w : ℂ => (f - g) (w • v)) = + fun w : ℂ => f (w • v) := by + funext w + dsimp + ring + rw [heq, hgo] at hsum + exact hsum + refine ⟨(shearToLastAxis v (Fin.last n) hvi).toContinuousLinearEquiv, ?_⟩ + simpa only [LinearEquiv.coe_toContinuousLinearEquiv', shearToLastAxis_single, hd] using hfo + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Polynomial.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Polynomial.lean new file mode 100644 index 0000000000..027bbb8cde --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Polynomial.lean @@ -0,0 +1,221 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.RingTheory.Polynomial.Eisenstein.Distinguished +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoordinateChange +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassPreparation + +/-! +# Polynomials with analytic-germ coefficients + +Evaluation in the last coordinate maps `Polynomial (AnalyticGerm ℂ 0)` into the analytic germs on +the product with `ℂ`. Weierstrass polynomials are expressed using Mathlib's +`Polynomial.IsDistinguishedAt` at the coefficient ring's maximal ideal. + +Polynomial injectivity is proved by restriction to the zero section and Horner induction. +Normalization of factors of distinguished polynomials (Lemma 1.8.2) is proved by reduction +modulo the maximal ideal. Irreducibility (Lemma 1.8.1(b)) is proved in `Weierstrass.lean`; the +coefficient bookkeeping behind Weierstrass division and preparation, and the resulting quotient +comparison (Lemma 1.8.1(a)), are in `CoefficientPolynomial.lean` and `Weierstrass.lean`. The +irreducibility statement explicitly excludes units in the analytic germ ring: without that +hypothesis the source's Lemma 1.8.1(b) fails, for example for `X - 1`. + +## Main definitions + +* `parameterHom`: Parameter germs pull back to the product by forgetting its last coordinate. +* `lastCoordinate`: The analytic germ of the last coordinate. +* `polynomialHom`: Evaluate a polynomial in the last coordinate, pulling back its coefficient germs. + +## Main results + +* `polynomialHom_injective`: Polynomial expressions in the last coordinate have unique coefficient + germs. +* `isDistinguishedAt_iff`: Distinguished polynomials have precisely the usual Weierstrass + coefficient conditions. +* `isDistinguishedAt_of_monic_dvd`: A monic divisor of a distinguished polynomial is distinguished. +* `exists_distinguished_factors`: Factors of a distinguished polynomial become distinguished after + multiplying by reciprocal coefficient units (Lemma 1.8.2). +-/ + +public noncomputable section + +namespace SeveralComplexVariables.AnalyticGerm + +open Filter +open scoped Topology + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Parameter germs pull back to the product by forgetting its last coordinate. -/ +@[expose] def parameterHom : AnalyticGerm ℂ (0 : E) →ₐ[ℂ] AnalyticGerm ℂ (0 : E × ℂ) := + pullback (x := (0 : E × ℂ)) Prod.fst analyticAt_fst + +/-- The analytic germ of the last coordinate. -/ +@[expose] def lastCoordinate : AnalyticGerm ℂ (0 : E × ℂ) := + ofAnalyticAt Prod.snd analyticAt_snd + +/-- Evaluate a polynomial in the last coordinate, pulling back its coefficient germs. -/ +@[expose] def polynomialHom : Polynomial (AnalyticGerm ℂ (0 : E)) →+* AnalyticGerm ℂ (0 : E × ℂ) := + Polynomial.eval₂RingHom parameterHom.toRingHom lastCoordinate + +/-- A constant polynomial gives the corresponding parameter germ on the product. -/ +@[simp] theorem polynomialHom_C (a : AnalyticGerm ℂ (0 : E)) : + polynomialHom (Polynomial.C a) = parameterHom a := by + simp [polynomialHom] + +/-- The indeterminate gives the last-coordinate germ. -/ +@[simp] theorem polynomialHom_X : + polynomialHom (Polynomial.X : Polynomial (AnalyticGerm ℂ (0 : E))) = lastCoordinate := by + simp [polynomialHom] + +/-- Distinguished polynomials have precisely the usual Weierstrass coefficient conditions. -/ +theorem isDistinguishedAt_iff (p : Polynomial (AnalyticGerm ℂ (0 : E))) : + p.IsDistinguishedAt (IsLocalRing.maximalIdeal _) ↔ + p.Monic ∧ ∀ i < p.natDegree, eval 0 (p.coeff i) = 0 := by + constructor + · intro h + exact ⟨h.monic, fun i hi => (mem_maximalIdeal_iff _).mp (h.mem hi)⟩ + · rintro ⟨hm, h⟩ + exact ⟨⟨fun {i} hi => (mem_maximalIdeal_iff _).mpr (h i hi)⟩, hm⟩ + +/-- Restricting a polynomial germ to the zero section recovers its constant coefficient. -/ +@[simp] theorem pullback_zeroSection_polynomialHom + (p : Polynomial (AnalyticGerm ℂ (0 : E))) : + pullback (fun z : E => (z, (0 : ℂ))) (analyticAt_id.prod analyticAt_const) + (polynomialHom p) = p.coeff 0 := by + have h : (pullback (fun z : E => (z, (0 : ℂ))) + (analyticAt_id.prod analyticAt_const)).toRingHom.comp polynomialHom = + Polynomial.constantCoeff := by + apply Polynomial.ringHom_ext + · intro a + obtain ⟨f, hf, rfl⟩ := exists_rep a + change pullback (fun z : E => (z, (0 : ℂ))) (analyticAt_id.prod analyticAt_const) + (polynomialHom (Polynomial.C (ofAnalyticAt f hf))) = + (Polynomial.C (ofAnalyticAt f hf)).coeff 0 + rw [polynomialHom_C, Polynomial.coeff_C_zero] + rfl + · change pullback (fun z : E => (z, (0 : ℂ))) (analyticAt_id.prod analyticAt_const) + (polynomialHom (Polynomial.X : Polynomial (AnalyticGerm ℂ (0 : E)))) = + (Polynomial.X : Polynomial (AnalyticGerm ℂ (0 : E))).coeff 0 + rw [polynomialHom_X, Polynomial.coeff_X_zero] + rfl + exact DFunLike.congr_fun h p + +/-- The distinguished coordinate is a nonzero germ, even with no parameter variables. -/ +theorem lastCoordinate_ne_zero : (lastCoordinate (E := E)) ≠ 0 := by + intro h + have he : (Prod.snd : E × ℂ → ℂ) =ᶠ[𝓝 0] 0 := + Germ.coe_eq.mp (congrArg Subtype.val h) + have ht : Tendsto (fun w : ℂ => ((0 : E), w)) (𝓝 0) (𝓝 0) := + continuous_const.prodMk continuous_id |>.tendsto 0 + have hi : (id : ℂ → ℂ) =ᶠ[𝓝 0] 0 := he.comp_tendsto ht + exact one_ne_zero ((hasDerivAt_id (0 : ℂ)).congr_of_eventuallyEq hi.symm |>.unique + (hasDerivAt_const (0 : ℂ) (0 : ℂ))) + +/-- Polynomial expressions in the last coordinate have unique coefficient germs. Restriction to the +zero section detects constants; Horner induction and cancellation of the nonzero last-coordinate +germ detect all remaining coefficients. -/ +theorem polynomialHom_injective : Function.Injective (polynomialHom (E := E)) := by + have hker : ∀ p : Polynomial (AnalyticGerm ℂ (0 : E)), polynomialHom p = 0 → p = 0 := by + intro p + induction p using Polynomial.recOnHorner with + | M0 => exact fun _ => rfl + | MC p a hp ha ih => + intro h + have hc := congrArg (pullback (fun z : E => (z, (0 : ℂ))) + (analyticAt_id.prod analyticAt_const)) h + have : a = 0 := by + simpa only [pullback_zeroSection_polynomialHom, map_zero, + Polynomial.coeff_add, Polynomial.coeff_C_zero, hp, zero_add] using hc + exact (ha this).elim + | MX p hp ih => + intro h + have hz : polynomialHom p = 0 := + (mul_eq_zero.mp (by simpa using h)).resolve_right lastCoordinate_ne_zero + simp [ih hz] + intro p q h + have hz := hker (p - q) (by simp [h]) + exact sub_eq_zero.mp hz + +/-- A monic divisor of a distinguished polynomial is distinguished. Reduction modulo the maximal +ideal makes it a monic divisor of a power of `X`, hence itself a power of `X`. -/ +theorem isDistinguishedAt_of_monic_dvd {p w : Polynomial (AnalyticGerm ℂ (0 : E))} + (hp : p.Monic) (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) (hd : p ∣ w) : + p.IsDistinguishedAt (IsLocalRing.maximalIdeal _) := by + classical + let I := IsLocalRing.maximalIdeal (AnalyticGerm ℂ (0 : E)) + let π := Ideal.Quotient.mk I + have hdiv : p.map π ∣ Polynomial.X ^ w.natDegree := by + rw [← hw.map_eq_X_pow] + exact Polynomial.map_dvd π hd + obtain ⟨k, _, hk⟩ := (dvd_prime_pow Polynomial.prime_X w.natDegree).mp hdiv + have he : p.map π = Polynomial.X ^ k := + Polynomial.eq_of_monic_of_associated (hp.map π) (Polynomial.monic_X_pow k) hk + have hdeg : p.natDegree = k := by + simpa only [hp.natDegree_map, Polynomial.natDegree_X_pow] using congrArg Polynomial.natDegree he + refine ⟨⟨fun {j} hj => ?_⟩, hp⟩ + have hc := congrArg (fun r => Polynomial.coeff r j) he + have hjk : j ≠ k := ne_of_lt (hdeg ▸ hj) + have hz : π (p.coeff j) = 0 := by + simpa only [Polynomial.coeff_map, Polynomial.coeff_X_pow, ite_eq_right hjk] using hc + exact Ideal.Quotient.eq_zero_iff_mem.mp hz + +/-- Factors of a distinguished polynomial become distinguished after multiplying by reciprocal +coefficient units (Lemma 1.8.2). Normalize leading coefficients and use that monic divisors +remain distinguished after reduction modulo the maximal ideal. -/ +theorem exists_distinguished_factors (p q : Polynomial (AnalyticGerm ℂ (0 : E))) + (h : (p * q).IsDistinguishedAt (IsLocalRing.maximalIdeal _)) : + ∃ u : (AnalyticGerm ℂ (0 : E))ˣ, + (Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p).IsDistinguishedAt + (IsLocalRing.maximalIdeal _) ∧ + (Polynomial.C (↑(u⁻¹) : AnalyticGerm ℂ (0 : E)) * q).IsDistinguishedAt + (IsLocalRing.maximalIdeal _) := by + have hlc : p.leadingCoeff * q.leadingCoeff = 1 := by + rw [← Polynomial.leadingCoeff_mul] + exact h.monic + let u : (AnalyticGerm ℂ (0 : E))ˣ := + ⟨q.leadingCoeff, p.leadingCoeff, by simpa only [mul_comm] using hlc, hlc⟩ + have hp : (Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p).Monic := + Polynomial.monic_C_mul_of_mul_leadingCoeff_eq_one u.val_inv + have hq : (Polynomial.C (↑(u⁻¹) : AnalyticGerm ℂ (0 : E)) * q).Monic := + Polynomial.monic_C_mul_of_mul_leadingCoeff_eq_one u.inv_val + have he : (Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p) * + (Polynomial.C (↑(u⁻¹) : AnalyticGerm ℂ (0 : E)) * q) = p * q := by + calc + _ = Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * + Polynomial.C (↑(u⁻¹) : AnalyticGerm ℂ (0 : E)) * (p * q) := by ring + _ = _ := by rw [← Polynomial.C_mul]; simp + refine ⟨u, isDistinguishedAt_of_monic_dvd hp h ?_, + isDistinguishedAt_of_monic_dvd hq h ?_⟩ + · rw [← he] + exact dvd_mul_right _ _ + · rw [← he] + exact dvd_mul_left _ _ + +/-- The product of two distinguished polynomials is distinguished, of the sum of their degrees. +Reduction modulo the maximal ideal sends the product to a product of powers of `X`, hence to a +power of `X` of the total degree. -/ +theorem isDistinguishedAt_mul {p q : Polynomial (AnalyticGerm ℂ (0 : E))} + (hp : p.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) + (hq : q.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) : + (p * q).IsDistinguishedAt (IsLocalRing.maximalIdeal _) := by + have hpq : (p * q).Monic := hp.monic.mul hq.monic + have hdeg : (p * q).natDegree = p.natDegree + q.natDegree := hp.monic.natDegree_mul hq.monic + refine ⟨⟨fun {j} hj => ?_⟩, hpq⟩ + have he : (p * q).map (Ideal.Quotient.mk (IsLocalRing.maximalIdeal (AnalyticGerm ℂ (0 : E)))) = + Polynomial.X ^ (p * q).natDegree := by + rw [Polynomial.map_mul, hp.map_eq_X_pow, hq.map_eq_X_pow, hdeg, pow_add] + have hc := congrArg (fun r => Polynomial.coeff r j) he + have hz : (Ideal.Quotient.mk (IsLocalRing.maximalIdeal (AnalyticGerm ℂ (0 : E)))) + ((p * q).coeff j) + = 0 := by + simpa only [Polynomial.coeff_map, Polynomial.coeff_X_pow, ite_eq_right hj.ne] using hc + exact Ideal.Quotient.eq_zero_iff_mem.mp hz + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/RelativePrimality.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/RelativePrimality.lean new file mode 100644 index 0000000000..141d6deb1c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/RelativePrimality.lean @@ -0,0 +1,187 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.Elimination + +/-! +# Persistence of relative primality + +Relative primality is an open condition on the base point for two fixed analytic representatives +in finite dimension. We use `IsRelPrime`, not the stronger Bezout condition `IsCoprime`. A germ +at one point is not evaluated at other points; instead, the statement explicitly takes the germs +of the same representatives nearby. Weierstrass preparation and a resultant identity eliminate +one variable. The resulting nonzero parameter germ is relatively prime to the first germ on +every nearby scalar fiber, which excludes a common nonunit divisor. Analytic coordinate changes +reduce the general case to this argument; openness is its direct consequence. + +## Main results + +* `eventually_isRelPrime_of_orderInLastVariable`: Relative primality persists when the first germ + has finite order on the central fiber. +* `eventually_isRelPrime_of_comp_homeomorph`: Persistence of relative primality transports through + analytic changes of coordinates. +* `eventually_isRelPrime_ofAnalyticAt_prod`: Relative primality persists on a parameter space times + the scalar line. +* `eventually_isRelPrime_ofAnalyticAt`: Relatively prime germs of two analytic representatives + remain relatively prime nearby. +* `isOpen_isRelPrime_locus`: The locus where two functions are analytic and their germs are + relatively prime is open. +-/ + +public section + +open Filter Set +open scoped Topology + +namespace SeveralComplexVariables.AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + +/-- Relative primality persists when the first germ has finite order on the central fiber. -/ +theorem eventually_isRelPrime_of_orderInLastVariable {f g : E × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (hg : AnalyticAt ℂ g 0) {d : ℕ} + (hd : orderInLastVariable (ofAnalyticAt f hf) = d) + (hrel : IsRelPrime (ofAnalyticAt f hf) (ofAnalyticAt g hg)) : + ∀ᶠ y in 𝓝 (0 : E × ℂ), ∃ (hfy : AnalyticAt ℂ f y) (hgy : AnalyticAt ℂ g y), + IsRelPrime (ofAnalyticAt f hfy) (ofAnalyticAt g hgy) := by + obtain ⟨h, hne, a, b, hab⟩ := exists_base_combination_of_isRelPrime hd hrel + obtain ⟨h, hh, rfl⟩ := exists_rep h + obtain ⟨a, ha, rfl⟩ := exists_rep a + obtain ⟨b, hb, rfl⟩ := exists_rep b + change ofAnalyticAt (fun y : E × ℂ => h y.1) (hh.comp_of_eq analyticAt_fst rfl) = + ofAnalyticAt (fun y => a y * f y + b y * g y) ((ha.mul hf).add (hb.mul hg)) at hab + have heq : (fun y : E × ℂ => h y.1) =ᶠ[𝓝 0] + (fun y => a y * f y + b y * g y) := ofAnalyticAt_eq_iff.mp hab + have hfiber : ¬ (fun w : ℂ => f (0, w)) =ᶠ[𝓝 0] 0 := by + intro hz + have ht := analyticOrderAt_eq_top.mpr hz + rw [← orderInLastVariable_ofAnalyticAt f hf, hd] at ht + exact ENat.natCast_ne_top d ht + have hbase : ∀ᶠ y : E × ℂ in 𝓝 0, + ∃ hy : AnalyticAt ℂ h y.1, ofAnalyticAt h hy ≠ 0 := + (continuous_fst.continuousAt : Tendsto (Prod.fst : E × ℂ → E) (𝓝 0) (𝓝 0)).eventually + (eventually_ne_zero_ofAnalyticAt hh hne) + filter_upwards [heq.eventually_nhds, hbase, + eventually_fiber_ne_zero_ofAnalyticAt hf hfiber, hg.eventually_analyticAt, + ha.eventually_analyticAt, hb.eventually_analyticAt] with y he hyh hyf hyg hya hyb + obtain ⟨hyh, hyhne⟩ := hyh + obtain ⟨hyf, hyfiber⟩ := hyf + refine ⟨hyf, hyg, ?_⟩ + have hcomb : basePullback y (ofAnalyticAt h hyh) = + ofAnalyticAt a hya * ofAnalyticAt f hyf + ofAnalyticAt b hyb * ofAnalyticAt g hyg := by + change ofAnalyticAt (fun z : E × ℂ => h z.1) (hyh.comp_of_eq analyticAt_fst rfl) = + ofAnalyticAt (fun z => a z * f z + b z * g z) ((hya.mul hyf).add (hyb.mul hyg)) + exact ofAnalyticAt_eq_iff.mpr he + have hp := isRelPrime_basePullback_of_fiber_ne_zero y hyhne hyfiber + intro c hcf hcg + apply hp _ hcf + rw [hcomb] + exact dvd_add (dvd_mul_of_dvd_right hcf _) (dvd_mul_of_dvd_right hcg _) + +omit [FiniteDimensional ℂ E] in +/-- Persistence of relative primality transports through analytic changes of coordinates. -/ +theorem eventually_isRelPrime_of_comp_homeomorph + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + (e : E ≃ₜ F) (he : ∀ z, AnalyticAt ℂ e z) (hi : ∀ y, AnalyticAt ℂ e.symm y) + {f g : F → ℂ} {x : E} + (h : ∀ᶠ z in 𝓝 x, ∃ (hf : AnalyticAt ℂ (f ∘ e) z) + (hg : AnalyticAt ℂ (g ∘ e) z), IsRelPrime (ofAnalyticAt (f ∘ e) hf) + (ofAnalyticAt (g ∘ e) hg)) : + ∀ᶠ y in 𝓝 (e x), ∃ (hf : AnalyticAt ℂ f y) (hg : AnalyticAt ℂ g y), + IsRelPrime (ofAnalyticAt f hf) (ofAnalyticAt g hg) := by + have ht : Tendsto e.symm (𝓝 (e x)) (𝓝 x) := by + simpa only [e.symm_apply_apply] using e.symm.continuous.tendsto (e x) + filter_upwards [ht.eventually h] with y hy + obtain ⟨hf, hg, hrel⟩ := hy + have hfy : AnalyticAt ℂ f y := by + simpa only [Function.comp_def, e.apply_symm_apply] using + hf.comp_of_eq (hi y) rfl + have hgy : AnalyticAt ℂ g y := by + simpa only [Function.comp_def, e.apply_symm_apply] using + hg.comp_of_eq (hi y) rfl + let q := pullbackEquivOfEq e (e.symm y) (he _) (hi _) (e.apply_symm_apply y) + refine ⟨hfy, hgy, IsRelPrime.of_map q ?_⟩ + simpa only [q, pullbackEquivOfEq_ofAnalyticAt] using hrel + +/-- Relative primality persists on a parameter space times the scalar line. -/ +theorem eventually_isRelPrime_ofAnalyticAt_prod {f g : E × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (hg : AnalyticAt ℂ g 0) + (h : IsRelPrime (ofAnalyticAt f hf) (ofAnalyticAt g hg)) : + ∀ᶠ y in 𝓝 (0 : E × ℂ), ∃ (hfy : AnalyticAt ℂ f y) (hgy : AnalyticAt ℂ g y), + IsRelPrime (ofAnalyticAt f hfy) (ofAnalyticAt g hgy) := by + by_cases hzero : ofAnalyticAt f hf = 0 + · have hunit : g 0 ≠ 0 := by + simpa only [hzero, isRelPrime_zero_left, isUnit_iff, eval_ofAnalyticAt] using h + filter_upwards [hf.eventually_analyticAt, hg.eventually_analyticAt, + hg.continuousAt.eventually_ne hunit] with y hfy hgy hy + exact ⟨hfy, hgy, ((isUnit_iff (ofAnalyticAt g hgy)).mpr hy).isRelPrime_right⟩ + obtain ⟨L, d, hd⟩ := exists_regular_coordinate_change hf + ((ofAnalyticAt_ne_zero_iff hf).mp hzero) + have hfL : AnalyticAt ℂ (f ∘ L) 0 := hf.comp_of_eq (L.analyticAt 0) L.map_zero + have hgL : AnalyticAt ℂ (g ∘ L) 0 := hg.comp_of_eq (L.analyticAt 0) L.map_zero + let q := pullbackEquivOfEq L.toHomeomorph 0 (L.analyticAt 0) + (L.symm.analyticAt (L 0)) L.map_zero + have hq : IsRelPrime (q (ofAnalyticAt f hf)) (q (ofAnalyticAt g hg)) := + IsRelPrime.of_map q.symm (by simpa only [AlgEquiv.symm_apply_apply] using h) + have hL : IsRelPrime (ofAnalyticAt (f ∘ L) hfL) (ofAnalyticAt (g ∘ L) hgL) := by + have hqf : q (ofAnalyticAt f hf) = ofAnalyticAt (f ∘ L) hfL := + pullbackEquivOfEq_ofAnalyticAt L.toHomeomorph 0 (L.analyticAt 0) + (L.symm.analyticAt (L 0)) L.map_zero f hf + have hqg : q (ofAnalyticAt g hg) = ofAnalyticAt (g ∘ L) hgL := + pullbackEquivOfEq_ofAnalyticAt L.toHomeomorph 0 (L.analyticAt 0) + (L.symm.analyticAt (L 0)) L.map_zero g hg + rwa [hqf, hqg] at hq + have hp := eventually_isRelPrime_of_orderInLastVariable hfL hgL hd hL + simpa only [ContinuousLinearEquiv.coe_toHomeomorph, map_zero] using + eventually_isRelPrime_of_comp_homeomorph L.toHomeomorph L.analyticAt L.symm.analyticAt hp + +/-- Relatively prime germs of two analytic representatives remain relatively prime nearby. Neither +germ is required to be nonzero: the relatively prime zero case forces a unit. -/ +theorem eventually_isRelPrime_ofAnalyticAt {f g : E → ℂ} {x : E} + (hf : AnalyticAt ℂ f x) (hg : AnalyticAt ℂ g x) + (h : IsRelPrime (ofAnalyticAt f hf) (ofAnalyticAt g hg)) : + ∀ᶠ y in 𝓝 x, ∃ (hfy : AnalyticAt ℂ f y) (hgy : AnalyticAt ℂ g y), + IsRelPrime (ofAnalyticAt f hfy) (ofAnalyticAt g hgy) := by + classical + rcases hdim : Module.finrank ℂ E with _ | n + · have : Subsingleton E := Module.finrank_zero_iff.mp hdim + exact Filter.Eventually.of_forall (fun y => by + obtain rfl := Subsingleton.elim y x + exact ⟨hf, hg, h⟩) + · let en : E ≃L[ℂ] (Fin (n + 1) → ℂ) := by + rw [← hdim] + exact (Module.finBasis ℂ E).equivFunL + let ep : (Fin (n + 1) → ℂ) ≃ₗ[ℂ] (Fin n → ℂ) × ℂ := + (LinearEquiv.piCongrLeft ℂ (fun _ => ℂ) (finSuccEquiv n)).trans + ((LinearEquiv.piOptionEquivProd ℂ).trans (LinearEquiv.prodComm ℂ _ _)) + let e := en.trans ep.toContinuousLinearEquiv + let H := e.symm.toHomeomorph.trans (Homeomorph.addRight x) + have hH : ∀ z, AnalyticAt ℂ H z := fun z => (e.symm.analyticAt z).add analyticAt_const + have hHi : ∀ y, AnalyticAt ℂ H.symm y := fun y => + (e.analyticAt (y + -x)).comp_of_eq (analyticAt_id.add analyticAt_const) rfl + have hH0 : H 0 = x := by simp [H] + have hfH : AnalyticAt ℂ (f ∘ H) 0 := hf.comp_of_eq (hH 0) hH0 + have hgH : AnalyticAt ℂ (g ∘ H) 0 := hg.comp_of_eq (hH 0) hH0 + let q := pullbackEquivOfEq H 0 (hH 0) (hHi _) hH0 + have hq : IsRelPrime (q (ofAnalyticAt f hf)) (q (ofAnalyticAt g hg)) := + IsRelPrime.of_map q.symm (by simpa only [AlgEquiv.symm_apply_apply] using h) + have hHrel : IsRelPrime (ofAnalyticAt (f ∘ H) hfH) (ofAnalyticAt (g ∘ H) hgH) := by + simpa only [q, pullbackEquivOfEq_ofAnalyticAt] using hq + have hp := eventually_isRelPrime_ofAnalyticAt_prod hfH hgH hHrel + simpa only [hH0] using eventually_isRelPrime_of_comp_homeomorph H hH hHi hp + +/-- The locus where two functions are analytic and their germs are relatively prime is open. -/ +theorem isOpen_isRelPrime_locus (f g : E → ℂ) : + IsOpen {x | ∃ (hf : AnalyticAt ℂ f x) (hg : AnalyticAt ℂ g x), + IsRelPrime (ofAnalyticAt f hf) (ofAnalyticAt g hg)} := by + apply isOpen_iff_mem_nhds.mpr + rintro x ⟨hf, hg, h⟩ + exact eventually_isRelPrime_ofAnalyticAt hf hg h + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Units.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Units.lean new file mode 100644 index 0000000000..6d49d6a938 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Units.lean @@ -0,0 +1,65 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.SpecialFunctions.Complex.Analytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm + +/-! +# Roots of unit germs + +Every scalar analytic unit germ has an analytic root of each positive integral degree. We +normalize the value to one before using Mathlib's analytic complex power function; no global +choice of logarithm on the domain is required. These elementary local facts are used, for +example, when absorbing units into irreducible factorizations. + +## Main results + +`exists_isUnit_pow_eq` produces an analytic unit root of each positive integral degree. +`exists_analyticAt_pow_eq` is the corresponding statement for representatives. +-/ + +public noncomputable section + +open Filter +open scoped Topology + +namespace SeveralComplexVariables.AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {x : E} + +/-- A nonvanishing analytic function has a local analytic root of every positive degree. -/ +theorem exists_analyticAt_pow_eq {f : E → ℂ} (hf : AnalyticAt ℂ f x) + (hx : f x ≠ 0) {n : ℕ} (hn : n ≠ 0) : + ∃ g : E → ℂ, AnalyticAt ℂ g x ∧ (fun y => g y ^ n) =ᶠ[𝓝 x] f := by + let g : E → ℂ := fun y => (f x ^ ((n : ℂ)⁻¹)) * ((f y / f x) ^ ((n : ℂ)⁻¹)) + refine ⟨g, ?_, .of_forall fun y => ?_⟩ + · apply AnalyticAt.mul analyticAt_const + apply hf.div_const.cpow analyticAt_const + simp [hx] + · dsimp [g] + rw [mul_pow, Complex.cpow_nat_inv_pow _ hn, Complex.cpow_nat_inv_pow _ hn] + exact mul_div_cancel₀ _ hx + +/-- Every unit germ has an `n`-th root which is itself a unit, for `n ≠ 0`. -/ +theorem exists_isUnit_pow_eq (u : AnalyticGerm ℂ x) (hu : IsUnit u) + {n : ℕ} (hn : n ≠ 0) : ∃ v : AnalyticGerm ℂ x, IsUnit v ∧ v ^ n = u := by + obtain ⟨f, hf, rfl⟩ := exists_rep u + obtain ⟨g, hg, he⟩ := exists_analyticAt_pow_eq hf ((isUnit_iff _).mp hu) hn + have hp : ofAnalyticAt g hg ^ n = ofAnalyticAt f hf := by + apply Subtype.ext + exact Germ.coe_eq.mpr he + refine ⟨ofAnalyticAt g hg, ?_, hp⟩ + apply (isUnit_iff _).mpr + intro hz + have hval := congrArg (eval x) hp + have hnonzero := (isUnit_iff _).mp hu + rw [map_pow, hz, zero_pow hn] at hval + exact hnonzero hval.symm + +end SeveralComplexVariables.AnalyticGerm + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Weierstrass.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Weierstrass.lean new file mode 100644 index 0000000000..c3a41e66c0 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticGerm/Weierstrass.lean @@ -0,0 +1,428 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm.CoefficientPolynomial + +/-! +# Weierstrass theorems in the germ ring + +These interfaces express division and preparation directly in the analytic germ ring, using +ordinary polynomials over parameter germs and Mathlib's distinguished-polynomial predicate. +Polynomial degree (rather than natural degree) handles the zero remainder and degree-zero +divisors uniformly. Units are represented by the existing units group. + +Existence and uniqueness of both division and preparation are proved by choosing analytic +representatives, applying the analytic Weierstrass theorems on any finite-dimensional parameter +space, and reassembling the polynomial coefficients using the bookkeeping in +`CoefficientPolynomial.lean`. Polynomial preservation under division (Lemma 1.8.1(a)) follows by +comparing ordinary Euclidean division of polynomials with germ division uniqueness. The +irreducibility equivalence is proved. Finite simultaneous preparation follows from the proved +finite normalization theorem and the existing analytic preparation theorem. + +## Main results + +* `existsUnique_division`: Division by a distinguished polynomial has a unique germ quotient and + polynomial remainder of smaller degree. +* `existsUnique_preparation`: Preparation has a unique unit and distinguished polynomial of the + prescribed order. +* `irreducible_polynomialHom_iff`: A distinguished polynomial is irreducible exactly when its + analytic germ is. +* `prime_polynomialHom_of_isDistinguishedAt`: The image of a prime distinguished polynomial is + itself prime. +* `exists_equiv_forall_isWeierstrassPreparationAt`: One coordinate system permits preparation of all + members of a finite family. +-/ + +public noncomputable +section + +open Filter +open scoped Topology + +namespace SeveralComplexVariables +namespace AnalyticGerm + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Division by a distinguished polynomial has a unique germ quotient and polynomial remainder of +smaller degree. Choose representatives and apply analytic Weierstrass division, then identify +the germ quotient and coefficient germs by uniqueness. -/ +theorem existsUnique_division [FiniteDimensional ℂ E] + (w : Polynomial (AnalyticGerm ℂ (0 : E))) + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) (f : AnalyticGerm ℂ (0 : E × ℂ)) : + ∃! qr : AnalyticGerm ℂ (0 : E × ℂ) × Polynomial (AnalyticGerm ℂ (0 : E)), + qr.2.degree < (w.natDegree : WithBot ℕ) ∧ + f = qr.1 * polynomialHom w + polynomialHom qr.2 := by + set d := w.natDegree with hd_def + obtain ⟨hwmon, hwcoeff0⟩ := (isDistinguishedAt_iff w).mp hw + have hweq : w = ofCoefficients (fun j : Fin d => w.coeff (j : ℕ)) := + eq_ofCoefficients_of_monic hwmon hd_def + choose a0 ha0 haeq using fun j : Fin d => exists_rep (w.coeff (j : ℕ)) + have ha00 : ∀ j : Fin d, a0 j 0 = 0 := by + intro j + have h0 := hwcoeff0 (j : ℕ) (hd_def ▸ j.isLt) + rw [← haeq j, eval_ofAnalyticAt] at h0 + exact h0 + have hweq2 : w = ofCoefficients (fun j : Fin d => ofAnalyticAt (a0 j) (ha0 j)) := by + rw [hweq]; congr 1; funext j; exact (haeq j).symm + have hwhom : polynomialHom w = ofAnalyticAt (weierstrassPolynomial a0) + (analyticAt_weierstrassPolynomial ha0) := by + rw [hweq2]; exact polynomialHom_ofCoefficients a0 ha0 + have horder : analyticOrderAt (fun t : ℂ => weierstrassPolynomial a0 (0, t)) 0 = d := by + have hcentral : (fun t : ℂ => weierstrassPolynomial a0 (0, t)) = fun t : ℂ => t ^ d := + funext (weierstrassPolynomial_central ha00) + rw [hcentral] + change analyticOrderAt ((id : ℂ → ℂ) ^ d) 0 = d + rw [analyticOrderAt_pow (analyticAt_id (𝕜 := ℂ)) d, analyticOrderAt_id]; simp + obtain ⟨f0, hf0, rfl⟩ := exists_rep f + obtain ⟨q, a, Hdiv, huniqdiv⟩ := + exists_isWeierstrassDivisionAt_of_finiteDimensional + (analyticAt_weierstrassPolynomial ha0) hf0 horder + set r : Polynomial (AnalyticGerm ℂ (0 : E)) := + remainderOfCoefficients (fun j => ofAnalyticAt (a j) (Hdiv.analyticAt_coeff j)) with hr_def + have hrdeg : r.degree < (d : WithBot ℕ) := degree_remainderOfCoefficients_lt _ + have hrhom : polynomialHom r = ofAnalyticAt (weierstrassRemainder a) + (analyticAt_weierstrassRemainder Hdiv.analyticAt_coeff) := + polynomialHom_remainderOfCoefficients a Hdiv.analyticAt_coeff + refine ⟨(ofAnalyticAt q Hdiv.analyticAt_quotient, r), ⟨hrdeg, ?_⟩, ?_⟩ + · have hgerm : ofAnalyticAt f0 hf0 = ofAnalyticAt q Hdiv.analyticAt_quotient * + ofAnalyticAt (weierstrassPolynomial a0) (analyticAt_weierstrassPolynomial ha0) + + ofAnalyticAt (weierstrassRemainder a) + (analyticAt_weierstrassRemainder Hdiv.analyticAt_coeff) := by + rw [← ofAnalyticAt_mul, ← ofAnalyticAt_add] + exact ofAnalyticAt_eq_iff.mpr Hdiv.eq + simp only + rw [hgerm, hwhom, hrhom] + · rintro ⟨q', r'⟩ ⟨hr'deg, hfeq⟩ + simp only at hr'deg hfeq ⊢ + have hr'eq : r' = remainderOfCoefficients (fun j : Fin d => r'.coeff (j : ℕ)) := + eq_remainderOfCoefficients_of_degree_lt hr'deg + choose a' ha' haeq' using fun j : Fin d => exists_rep (r'.coeff (j : ℕ)) + have hr'eq2 : r' = remainderOfCoefficients (fun j : Fin d => ofAnalyticAt (a' j) (ha' j)) := by + rw [hr'eq]; congr 1; funext j; exact (haeq' j).symm + have hr'hom : polynomialHom r' = ofAnalyticAt (weierstrassRemainder a') + (analyticAt_weierstrassRemainder ha') := by + rw [hr'eq2]; exact polynomialHom_remainderOfCoefficients a' ha' + obtain ⟨q0', hq0', hq0'eq⟩ := exists_rep q' + have Hdiv' : IsWeierstrassDivisionAt (weierstrassPolynomial a0) f0 q0' a' := by + refine ⟨hq0', ha', ?_⟩ + have hgerm : ofAnalyticAt f0 hf0 = ofAnalyticAt q0' hq0' * + ofAnalyticAt (weierstrassPolynomial a0) (analyticAt_weierstrassPolynomial ha0) + + ofAnalyticAt (weierstrassRemainder a') (analyticAt_weierstrassRemainder ha') := by + rw [hq0'eq, ← hwhom, ← hr'hom]; exact hfeq + exact (ofAnalyticAt_eq_iff (hg := (hq0'.mul (analyticAt_weierstrassPolynomial ha0)).add + (analyticAt_weierstrassRemainder ha'))).mp hgerm + obtain ⟨hqeqq0', haeqa'⟩ := huniqdiv q0' a' Hdiv' + have hqeq : ofAnalyticAt q Hdiv.analyticAt_quotient = q' := by + rw [(ofAnalyticAt_eq_iff (hg := hq0')).mpr hqeqq0', hq0'eq] + have hreq : r = r' := by + rw [hr_def, hr'eq2] + congr 1 + funext j + exact ofAnalyticAt_eq_iff.mpr (haeqa' j) + rw [Prod.mk.injEq] + exact ⟨hqeq.symm, hreq.symm⟩ + +/-- Preparation has a unique unit and distinguished polynomial of the prescribed order. Order zero +gives polynomial one. The proof converts the analytic preparation and uniqueness theorems into +polynomial and unit equalities in the germ ring. -/ +theorem existsUnique_preparation [FiniteDimensional ℂ E] + (f : AnalyticGerm ℂ (0 : E × ℂ)) {d : ℕ} (hd : orderInLastVariable f = d) : + ∃! up : (AnalyticGerm ℂ (0 : E × ℂ))ˣ × Polynomial (AnalyticGerm ℂ (0 : E)), + up.2.IsDistinguishedAt (IsLocalRing.maximalIdeal _) ∧ up.2.natDegree = d ∧ + f = ↑up.1 * polynomialHom up.2 := by + obtain ⟨f0, hf0, rfl⟩ := exists_rep f + rw [orderInLastVariable_ofAnalyticAt] at hd + obtain ⟨u, a, H, huniq⟩ := exists_isWeierstrassPreparationAt_of_finiteDimensional hf0 hd + obtain ⟨hunit, hfact⟩ := H.germ_factorization hf0 + set w : Polynomial (AnalyticGerm ℂ (0 : E)) := + ofCoefficients (fun j => ofAnalyticAt (a j) (H.analyticAt_coeff j)) with hw_def + have hwdist : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _) := + isDistinguishedAt_ofCoefficients _ (fun j => by + rw [eval_ofAnalyticAt]; exact H.coeff_zero j) + have hwdeg : w.natDegree = d := natDegree_ofCoefficients _ + have hwhom : polynomialHom w = ofAnalyticAt (weierstrassPolynomial a) + (analyticAt_weierstrassPolynomial H.analyticAt_coeff) := + polynomialHom_ofCoefficients a H.analyticAt_coeff + refine ⟨(hunit.unit, w), ⟨hwdist, hwdeg, ?_⟩, ?_⟩ + · rw [hunit.unit_spec, hwhom]; exact hfact + · rintro ⟨u', w'⟩ ⟨hw'dist, hw'deg, hfeq⟩ + simp only at hw'dist hw'deg hfeq ⊢ + obtain ⟨hw'mon, hw'coeff0⟩ := (isDistinguishedAt_iff w').mp hw'dist + have hw'eq : w' = ofCoefficients (fun j : Fin d => w'.coeff (j : ℕ)) := + eq_ofCoefficients_of_monic hw'mon hw'deg + choose a' ha' haeq using fun j : Fin d => exists_rep (w'.coeff (j : ℕ)) + obtain ⟨v0, hv0, hveq⟩ := exists_rep (↑u' : AnalyticGerm ℂ (0 : E × ℂ)) + have hv0ne : v0 0 ≠ 0 := by + have hu' := (isUnit_iff (↑u' : AnalyticGerm ℂ (0 : E × ℂ))).mp u'.isUnit + rwa [← hveq, eval_ofAnalyticAt] at hu' + have ha'0 : ∀ j : Fin d, a' j 0 = 0 := by + intro j + have hlt : (j : ℕ) < w'.natDegree := by rw [hw'deg]; exact j.isLt + have h0 := hw'coeff0 (j : ℕ) hlt + rw [← haeq j, eval_ofAnalyticAt] at h0 + exact h0 + have hw'eq2 : w' = ofCoefficients (fun j : Fin d => ofAnalyticAt (a' j) (ha' j)) := by + rw [hw'eq]; congr 1; funext j; exact (haeq j).symm + have Hprep' : IsWeierstrassPreparationAt f0 v0 a' := by + refine ⟨hv0, hv0ne, ha', ha'0, ?_⟩ + have hgerm : ofAnalyticAt f0 hf0 = ofAnalyticAt (v0 * weierstrassPolynomial a') + (hv0.mul (analyticAt_weierstrassPolynomial ha')) := by + rw [hfeq, ← hveq, hw'eq2, polynomialHom_ofCoefficients, ← ofAnalyticAt_mul] + exact ofAnalyticAt_eq_iff.mp hgerm + obtain ⟨hueqv0, haeqa'⟩ := huniq v0 a' Hprep' + have hueq : hunit.unit = u' := Units.ext (by + rw [hunit.unit_spec, (ofAnalyticAt_eq_iff (hg := hv0)).mpr hueqv0, hveq]) + have hweq : w = w' := by + rw [hw_def, hw'eq2] + congr 1 + funext j + exact ofAnalyticAt_eq_iff.mpr (haeqa' j) + rw [Prod.mk.injEq] + exact ⟨hueq.symm, hweq.symm⟩ + +/-- Division by a distinguished polynomial preserves polynomial germs (Lemma 1.8.1(a)). The +Euclidean remainder of ordinary polynomial division by the monic divisor gives a second +decomposition; germ division uniqueness identifies it with the hypothesised one. -/ +theorem exists_polynomial_quotient [FiniteDimensional ℂ E] + (p w : Polynomial (AnalyticGerm ℂ (0 : E))) + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) + (g : AnalyticGerm ℂ (0 : E × ℂ)) (h : polynomialHom p = g * polynomialHom w) : + ∃ q : Polynomial (AnalyticGerm ℂ (0 : E)), polynomialHom q = g := by + have hwne : w ≠ 0 := hw.monic.ne_zero + have hrdeg : (p %ₘ w).degree < (w.natDegree : WithBot ℕ) := by + rw [← Polynomial.degree_eq_natDegree hwne] + exact Polynomial.degree_modByMonic_lt p hw.monic + have hpeq : polynomialHom p = polynomialHom (p /ₘ w) * polynomialHom w + + polynomialHom (p %ₘ w) := by + conv_lhs => rw [← Polynomial.modByMonic_add_div p w] + rw [map_add, map_mul] + ring + have hveq : polynomialHom p = g * polynomialHom w + + polynomialHom (0 : Polynomial (AnalyticGerm ℂ (0 : E))) := by simp [h] + have hzerodeg : (0 : Polynomial (AnalyticGerm ℂ (0 : E))).degree < (w.natDegree : WithBot ℕ) := by + rw [Polynomial.degree_zero]; exact WithBot.bot_lt_coe w.natDegree + have hp1 : (p %ₘ w).degree < (w.natDegree : WithBot ℕ) ∧ + polynomialHom p = polynomialHom (p /ₘ w) * polynomialHom w + polynomialHom (p %ₘ w) := + ⟨hrdeg, hpeq⟩ + have hp2 : (0 : Polynomial (AnalyticGerm ℂ (0 : E))).degree < (w.natDegree : WithBot ℕ) ∧ + polynomialHom p = g * polynomialHom w + + polynomialHom (0 : Polynomial (AnalyticGerm ℂ (0 : E))) := + ⟨hzerodeg, hveq⟩ + obtain ⟨y, _, huniq⟩ := existsUnique_division w hw (polynomialHom p) + have h1 := huniq (polynomialHom (p /ₘ w), p %ₘ w) hp1 + have h2 := huniq (g, 0) hp2 + exact ⟨p /ₘ w, (Prod.mk.injEq ..).mp (h1.trans h2.symm) |>.1⟩ + +/-- If the numerator in a distinguished division is polynomial, so is the quotient. This applies +with a nonzero remainder as well as to exact divisibility. -/ +theorem exists_polynomial_division_quotient [FiniteDimensional ℂ E] + (p w r : Polynomial (AnalyticGerm ℂ (0 : E))) + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) + (q : AnalyticGerm ℂ (0 : E × ℂ)) + (h : polynomialHom p = q * polynomialHom w + polynomialHom r) : + ∃ s : Polynomial (AnalyticGerm ℂ (0 : E)), polynomialHom s = q := by + apply exists_polynomial_quotient (p - r) w hw q + rw [map_sub, h, add_sub_cancel_right] + +/-- A distinguished polynomial of positive degree that is irreducible has irreducible image. Any +factorization of the image has orders adding to the degree; a factor of positive order would +prepare to a nonunit distinguished polynomial, and comparing the resulting polynomial +factorization of `w` with irreducibility of `w` forces the other factor to be a unit, +contradicting positivity of both orders. -/ +theorem irreducible_polynomialHom_of_isDistinguishedAt [FiniteDimensional ℂ E] + {w : Polynomial (AnalyticGerm ℂ (0 : E))} + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) (hd : w.natDegree ≠ 0) + (hirr : Irreducible w) : Irreducible (polynomialHom w) := by + have hworder : orderInLastVariable (polynomialHom w) = (w.natDegree : ℕ∞) := + orderInLastVariable_polynomialHom_of_isDistinguishedAt hw + constructor + · rw [isUnit_iff_orderInLastVariable_eq_zero, hworder] + exact_mod_cast hd + · intro A B hAB + have horder : orderInLastVariable A + orderInLastVariable B = (w.natDegree : ℕ∞) := by + rw [← orderInLastVariable_mul, ← hAB, hworder] + rcases eq_or_ne (orderInLastVariable A) 0 with hA0 | hA0 + · exact Or.inl ((isUnit_iff_orderInLastVariable_eq_zero A).mpr hA0) + rcases eq_or_ne (orderInLastVariable B) 0 with hB0 | hB0 + · exact Or.inr ((isUnit_iff_orderInLastVariable_eq_zero B).mpr hB0) + exfalso + have hAfin : orderInLastVariable A ≠ ⊤ := by + intro h; rw [h] at horder; simp at horder + have hBfin : orderInLastVariable B ≠ ⊤ := by + intro h; rw [h] at horder; simp at horder + lift orderInLastVariable A to ℕ using hAfin with dA hdA + lift orderInLastVariable B to ℕ using hBfin with dB hdB + have hdA0 : dA ≠ 0 := by exact_mod_cast hA0 + have hdB0 : dB ≠ 0 := by exact_mod_cast hB0 + obtain ⟨⟨uA, wA⟩, ⟨hwAdist, hwAdeg, hAeq⟩, -⟩ := existsUnique_preparation A hdA.symm + obtain ⟨⟨uB, wB⟩, ⟨hwBdist, hwBdeg, hBeq⟩, -⟩ := existsUnique_preparation B hdB.symm + simp only at hwAdist hwAdeg hAeq hwBdist hwBdeg hBeq + have heq2 : polynomialHom w = ((uA : AnalyticGerm ℂ (0 : E × ℂ)) * uB) * + polynomialHom (wA * wB) := by + rw [hAB, hAeq, hBeq, map_mul]; ring + obtain ⟨q, hq⟩ := exists_polynomial_quotient w (wA * wB) (isDistinguishedAt_mul hwAdist hwBdist) + ((uA : AnalyticGerm ℂ (0 : E × ℂ)) * uB) heq2 + have heq3 : w = (q * wA) * wB := by + apply polynomialHom_injective + rw [heq2, ← hq] + simp only [map_mul] + ring + have hwAnu : ¬ IsUnit wA := fun h => + hdA0 (by rw [← hwAdeg]; exact Polynomial.natDegree_eq_zero_of_isUnit h) + have hwBnu : ¬ IsUnit wB := fun h => + hdB0 (by rw [← hwBdeg]; exact Polynomial.natDegree_eq_zero_of_isUnit h) + rcases hirr.isUnit_or_isUnit heq3 with hqwA | hwBu + · exact hwAnu (isUnit_of_mul_isUnit_right hqwA) + · exact hwBnu hwBu + +/-- A distinguished polynomial is irreducible exactly when its analytic germ is. Degree zero is +allowed: `w = 1` and both sides are then false. Positive degree splits into the forward +direction above and, for the converse, comparing a germ factorization against a distinguished +normalization (Lemma 1.8.2) of any polynomial factorization. -/ +theorem irreducible_polynomialHom_iff [FiniteDimensional ℂ E] + (w : Polynomial (AnalyticGerm ℂ (0 : E))) + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) : + Irreducible (polynomialHom w) ↔ Irreducible w := by + rcases eq_or_ne w.natDegree 0 with hd0 | hd0 + · have hw1 : w = 1 := Polynomial.eq_one_of_monic_natDegree_zero hw.monic hd0 + subst hw1 + simp only [map_one] + exact ⟨fun h => absurd isUnit_one h.not_isUnit, fun h => absurd isUnit_one h.not_isUnit⟩ + · refine ⟨fun hirrHom => ⟨fun hu => hirrHom.not_isUnit (hu.map (polynomialHom (E := E))), + fun p q hpq => ?_⟩, fun hirr => irreducible_polynomialHom_of_isDistinguishedAt hw hd0 hirr⟩ + obtain ⟨u, hup, huq⟩ := exists_distinguished_factors p q (hpq ▸ hw) + have hp'q' : Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p * + (Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) * q) = w := by + rw [hpq] + calc + _ = Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * + Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) * (p * q) := by ring + _ = _ := by rw [← Polynomial.C_mul]; simp + have hhom : polynomialHom w = polynomialHom (Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p) * + polynomialHom (Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) * q) := by + rw [← map_mul, hp'q'] + rcases hirrHom.isUnit_or_isUnit hhom with h1 | h2 + · left + have hord : orderInLastVariable + (polynomialHom (Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p)) = 0 := + (isUnit_iff_orderInLastVariable_eq_zero _).mp h1 + rw [orderInLastVariable_polynomialHom_of_isDistinguishedAt hup] at hord + have hdeg0 : (Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p).natDegree = 0 := by + exact_mod_cast hord + have h1' : Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * p = 1 := + Polynomial.eq_one_of_monic_natDegree_zero hup.monic hdeg0 + have hp1 : p = Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) := by + have hc := congrArg (fun r => Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) * r) h1' + simpa [← mul_assoc, ← Polynomial.C_mul] using hc + rw [hp1] + exact Polynomial.isUnit_C.mpr u⁻¹.isUnit + · right + have hord : orderInLastVariable + (polynomialHom (Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) * q)) = 0 := + (isUnit_iff_orderInLastVariable_eq_zero _).mp h2 + rw [orderInLastVariable_polynomialHom_of_isDistinguishedAt huq] at hord + have hdeg0 : (Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) * q).natDegree = 0 := by + exact_mod_cast hord + have h2' : Polynomial.C (↑u⁻¹ : AnalyticGerm ℂ (0 : E)) * q = 1 := + Polynomial.eq_one_of_monic_natDegree_zero huq.monic hdeg0 + have hq1 : q = Polynomial.C (u : AnalyticGerm ℂ (0 : E)) := by + have hc := congrArg (fun r => Polynomial.C (u : AnalyticGerm ℂ (0 : E)) * r) h2' + simpa [← mul_assoc, ← Polynomial.C_mul] using hc + rw [hq1] + exact Polynomial.isUnit_C.mpr u.isUnit + +/-- A common factor of two germs that is the image of a prime distinguished polynomial divides one +of them: Weierstrass-divide each factor, reduce the product of the two polynomial remainders by +ordinary division against the distinguishing polynomial, and match the resulting decomposition +of the germ product against germ division uniqueness to reduce to primality of the +distinguishing polynomial itself. -/ +theorem dvd_or_dvd_of_isDistinguishedAt [FiniteDimensional ℂ E] + {w : Polynomial (AnalyticGerm ℂ (0 : E))} + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) (hwp : Prime w) + {f g : AnalyticGerm ℂ (0 : E × ℂ)} (hfg : polynomialHom w ∣ f * g) : + polynomialHom w ∣ f ∨ polynomialHom w ∣ g := by + obtain ⟨⟨qf, rf⟩, ⟨hrfdeg, hfeq⟩, -⟩ := existsUnique_division w hw f + obtain ⟨⟨qg, rg⟩, ⟨hrgdeg, hgeq⟩, -⟩ := existsUnique_division w hw g + simp only at hrfdeg hfeq hrgdeg hgeq + have hr0eq : rf * rg = (rf * rg) %ₘ w + w * ((rf * rg) /ₘ w) := + (Polynomial.modByMonic_add_div (rf * rg) w).symm + have hr0deg : ((rf * rg) %ₘ w).degree < (w.natDegree : WithBot ℕ) := by + rw [← Polynomial.degree_eq_natDegree hw.monic.ne_zero] + exact Polynomial.degree_modByMonic_lt (rf * rg) hw.monic + set bigC : AnalyticGerm ℂ (0 : E × ℂ) := + qf * qg * polynomialHom w + qf * polynomialHom rg + qg * polynomialHom rf + + polynomialHom ((rf * rg) /ₘ w) with hbigC_def + have hfg2 : f * g = bigC * polynomialHom w + polynomialHom ((rf * rg) %ₘ w) := by + have hmul : polynomialHom rf * polynomialHom rg = polynomialHom (rf * rg) := + (map_mul polynomialHom rf rg).symm + have hM : polynomialHom (rf * rg) = polynomialHom ((rf * rg) %ₘ w) + + polynomialHom w * polynomialHom ((rf * rg) /ₘ w) := by + conv_lhs => rw [hr0eq] + rw [map_add, map_mul] + rw [hbigC_def, hfeq, hgeq] + rw [show (qf * polynomialHom w + polynomialHom rf) * (qg * polynomialHom w + + polynomialHom rg) = qf * qg * polynomialHom w * polynomialHom w + + qf * polynomialHom w * polynomialHom rg + polynomialHom rf * qg * polynomialHom w + + polynomialHom rf * polynomialHom rg from by ring] + rw [hmul, hM]; ring + obtain ⟨c, hc⟩ := hfg + obtain ⟨⟨qfg, rfg⟩, ⟨hrfgdeg, hfgeq⟩, huniqfg⟩ := existsUnique_division w hw (f * g) + simp only at hrfgdeg hfgeq huniqfg + have hzerodeg : (0 : Polynomial (AnalyticGerm ℂ (0 : E))).degree < (w.natDegree : WithBot ℕ) := by + rw [Polynomial.degree_zero]; exact WithBot.bot_lt_coe w.natDegree + have hceq : f * g = c * polynomialHom w + polynomialHom (0 : Polynomial (AnalyticGerm ℂ (0 : E))) + := by + rw [hc, map_zero, add_zero]; ring + have heq1 := huniqfg (bigC, (rf * rg) %ₘ w) ⟨hr0deg, hfg2⟩ + have heq2 := huniqfg (c, 0) ⟨hzerodeg, hceq⟩ + have hr0 : (rf * rg) %ₘ w = 0 := ((Prod.mk.injEq ..).mp (heq1.trans heq2.symm)).2 + have hwdvd : w ∣ rf * rg := ⟨(rf * rg) /ₘ w, hr0eq.trans (by rw [hr0, zero_add])⟩ + rcases hwp.2.2 rf rg hwdvd with hwrf | hwrg + · obtain ⟨c0, hc0⟩ := hwrf + refine Or.inl ⟨qf + polynomialHom c0, ?_⟩ + rw [hfeq, hc0, map_mul]; ring + · obtain ⟨c0, hc0⟩ := hwrg + refine Or.inr ⟨qg + polynomialHom c0, ?_⟩ + rw [hgeq, hc0, map_mul]; ring + +/-- The image of a prime distinguished polynomial is itself prime. Non-vanishing and +non-invertibility come from irreducibility of the image; the dividing property comes from +`dvd_or_dvd_of_isDistinguishedAt`. -/ +theorem prime_polynomialHom_of_isDistinguishedAt [FiniteDimensional ℂ E] + {w : Polynomial (AnalyticGerm ℂ (0 : E))} + (hw : w.IsDistinguishedAt (IsLocalRing.maximalIdeal _)) (hwp : Prime w) : + Prime (polynomialHom w) := by + have hd0 : w.natDegree ≠ 0 := fun h0 => + hwp.not_isUnit (Polynomial.eq_one_of_monic_natDegree_zero hw.monic h0 ▸ isUnit_one) + have hpolyirr : Irreducible (polynomialHom w) := + irreducible_polynomialHom_of_isDistinguishedAt hw hd0 hwp.irreducible + exact ⟨hpolyirr.ne_zero, hpolyirr.not_isUnit, fun f g => dvd_or_dvd_of_isDistinguishedAt hw hwp⟩ + +end AnalyticGerm + +/-- One coordinate system permits preparation of all members of a finite family. This depends on the +preparation theorem and hence on analytic division. Empty parameter types, empty families, and +unit germs are all included. -/ +theorem exists_equiv_forall_isWeierstrassPreparationAt {ι κ : Type*} [Fintype ι] [Finite κ] + {f : κ → (ι → ℂ) × ℂ → ℂ} (hf : ∀ i, AnalyticAt ℂ (f i) 0) + (hne : ∀ i, ¬ f i =ᶠ[𝓝 0] 0) : + ∃ (L : ((ι → ℂ) × ℂ) ≃L[ℂ] ((ι → ℂ) × ℂ)) (d : κ → ℕ), ∀ i, + ∃ (u : (ι → ℂ) × ℂ → ℂ) (a : Fin (d i) → (ι → ℂ) → ℂ), + IsWeierstrassPreparationAt (fun z => f i (L z)) u a := by + classical + let := Fintype.ofFinite κ + obtain ⟨L, d, hd⟩ := exists_regular_coordinate_change_finite hf hne + refine ⟨L, d, fun i => ?_⟩ + have ha : AnalyticAt ℂ (fun z => f i (L z)) 0 := + (hf i).comp_of_eq (L.toContinuousLinearMap.analyticAt 0) L.map_zero + obtain ⟨u, a, h, _⟩ := exists_isWeierstrassPreparationAt ha (hd i) + exact ⟨u, a, h⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet.lean new file mode 100644 index 0000000000..893c9f2a52 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet.lean @@ -0,0 +1,19 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Codimension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.CoordinatePlane +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Hartogs +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Holomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Regular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Removable + +/-! Supporting modules for Classical several complex variables. -/ + diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Basic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Basic.lean new file mode 100644 index 0000000000..7e116bfcae --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Basic.lean @@ -0,0 +1,249 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Constructions +public import Mathlib.Analysis.Complex.Basic + +/-! +# Analytic subsets of open complex domains + +An analytic subset is locally the common zero set of finitely many scalar analytic functions. +Equations are required near every point of the ambient set, so relative closedness follows. The +local neighborhood requirement also implies that the ambient domain is open. No connectedness, +nonemptiness, or positive dimension is built in. Empty families define the whole domain. + +Holomorphic defining equations and biholomorphic transport are treated separately in +`SeveralComplexVariables.AnalyticSet.Holomorphic`. This file uses analytic predicates directly +and does not depend on the SCV holomorphy–analyticity equivalence. + +References: [Range][Range1986] I §3.2; [Fritzsche–Grauert][FritzscheGrauert2002] I §8; +[Scheidemann][Scheidemann2005] §4.1. No abstract analytic spaces or sheaf structures are +introduced. + +## Main definitions + +* `IsAnalyticSet`: `A` is an analytic subset of `U` if it is contained in `U` and is locally cut out + by finitely many scalar analytic equations. + +## Main results + +* `isAnalyticSet_zeroSet`: A scalar analytic zero set, restricted to its domain, is analytic. +* `IsAnalyticSet.isOpen_sdiff`: Analytic subsets are relatively closed, expressed by their open + complement in `U`. +* `IsAnalyticSet.inter`: Finite intersections of analytic subsets are analytic. +* `IsAnalyticSet.union`: Finite unions are defined by pairwise products of the local equations. +* `IsAnalyticSet.preimage`: Holomorphic preimages preserve analytic subsets. +* `IsAnalyticSet.prod`: Products of analytic subsets are analytic. +* `isAnalyticSet_of_local`: Analyticity of a subset can be checked on an open cover of its ambient + domain. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- `A` is an analytic subset of `U` if it is contained in `U` and is locally cut out by finitely +many scalar analytic equations. The equations need not extend throughout `U`. -/ +@[expose] def IsAnalyticSet (U A : Set E) : Prop := + A ⊆ U ∧ ∀ a ∈ U, ∃ V : Set E, IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ + ∃ s : Finset (E → ℂ), (∀ f ∈ s, AnalyticOnNhd ℂ f V) ∧ + ∀ z ∈ V, z ∈ A ↔ ∀ f ∈ s, f z = 0 + +/-- An analytic subset is contained in its ambient domain. -/ +theorem IsAnalyticSet.subset {U A : Set E} (h : IsAnalyticSet U A) : A ⊆ U := h.1 + +/-- The local open neighborhoods in the definition cover the ambient domain. -/ +theorem IsAnalyticSet.isOpen_domain {U A : Set E} (h : IsAnalyticSet U A) : IsOpen U := by + rw [isOpen_iff_mem_nhds] + intro a ha + obtain ⟨V, hV, haV, hVU, _⟩ := h.2 a ha + exact mem_of_superset (hV.mem_nhds haV) hVU + +/-- A finite family of analytic equations defines an analytic subset. -/ +theorem isAnalyticSet_commonZeroSet {U : Set E} (hU : IsOpen U) + (s : Finset (E → ℂ)) (hs : ∀ f ∈ s, AnalyticOnNhd ℂ f U) : + IsAnalyticSet U {z | z ∈ U ∧ ∀ f ∈ s, f z = 0} := by + refine ⟨fun _ hz => hz.1, fun a ha => ⟨U, hU, ha, Subset.rfl, s, hs, ?_⟩⟩ + intro z hz + exact and_iff_right hz + +/-- A scalar analytic zero set, restricted to its domain, is analytic. -/ +theorem isAnalyticSet_zeroSet {U : Set E} (hU : IsOpen U) {f : E → ℂ} + (hf : AnalyticOnNhd ℂ f U) : IsAnalyticSet U (U ∩ f ⁻¹' {0}) := by + classical + change IsAnalyticSet U {z | z ∈ U ∧ f z = 0} + simpa using isAnalyticSet_commonZeroSet hU {f} (by simpa using hf) + +/-- The zero set of a finite-coordinate analytic map is analytic, including an empty coordinate +index type, when the zero set is the whole domain. -/ +theorem isAnalyticSet_zeroSet_pi {ι : Type*} [Fintype ι] {U : Set E} (hU : IsOpen U) + {f : E → (ι → ℂ)} (hf : AnalyticOnNhd ℂ f U) : + IsAnalyticSet U (U ∩ f ⁻¹' {0}) := by + classical + let s : Finset (E → ℂ) := Finset.univ.image (fun i z => f z i) + have hs : ∀ g ∈ s, AnalyticOnNhd ℂ g U := by + intro g hg + obtain ⟨i, _, rfl⟩ := Finset.mem_image.mp hg + exact analyticOnNhd_pi_iff.mp hf i + have h := isAnalyticSet_commonZeroSet hU s hs + convert h using 1 + ext z + constructor + · rintro ⟨hzU, hfz⟩ + refine ⟨hzU, ?_⟩ + intro g hg + obtain ⟨i, _, rfl⟩ := Finset.mem_image.mp hg + exact congrFun hfz i + · rintro ⟨hzU, hsz⟩ + refine ⟨hzU, ?_⟩ + funext i + exact hsz (fun z => f z i) (Finset.mem_image.mpr ⟨i, Finset.mem_univ i, rfl⟩) + +/-- The whole open domain is analytic, using no equations. -/ +theorem isAnalyticSet_self {U : Set E} (hU : IsOpen U) : IsAnalyticSet U U := by + simpa using isAnalyticSet_commonZeroSet hU ∅ (by simp) + +/-- The empty set is analytic, using the constant equation `1 = 0`. -/ +theorem isAnalyticSet_empty {U : Set E} (hU : IsOpen U) : IsAnalyticSet U ∅ := by + simpa using isAnalyticSet_zeroSet hU (f := fun _ => 1) analyticOnNhd_const + +/-- Analytic subsets restrict to smaller open domains. -/ +theorem IsAnalyticSet.restrict {U A W : Set E} (h : IsAnalyticSet U A) + (hW : IsOpen W) (hWU : W ⊆ U) : IsAnalyticSet W (W ∩ A) := by + refine ⟨inter_subset_left, ?_⟩ + intro a ha + obtain ⟨V, hV, haV, hVU, s, hs, he⟩ := h.2 a (hWU ha) + refine ⟨W ∩ V, hW.inter hV, ⟨ha, haV⟩, inter_subset_left, s, + fun f hf => (hs f hf).mono inter_subset_right, ?_⟩ + intro z hz + exact (and_iff_right hz.1).trans (he z hz.2) + +/-- Analyticity of a subset can be checked on an open cover of its ambient domain. -/ +theorem isAnalyticSet_of_local {U A : Set E} (hAU : A ⊆ U) + (h : ∀ a ∈ U, ∃ V, IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ IsAnalyticSet V (V ∩ A)) : + IsAnalyticSet U A := by + refine ⟨hAU, ?_⟩ + intro a ha + obtain ⟨V, _, haV, hVU, hAV⟩ := h a ha + obtain ⟨W, hW, haW, hWV, s, hs, he⟩ := hAV.2 a haV + refine ⟨W, hW, haW, hWV.trans hVU, s, hs, ?_⟩ + intro z hz + exact (and_iff_right (hWV hz)).symm.trans (he z hz) + +/-- Analytic subsets are relatively closed, expressed by their open complement in `U`. -/ +theorem IsAnalyticSet.isOpen_sdiff {U A : Set E} (h : IsAnalyticSet U A) : + IsOpen (U \ A) := by + classical + rw [isOpen_iff_mem_nhds] + rintro a ⟨haU, haA⟩ + obtain ⟨V, hV, haV, hVU, s, hs, he⟩ := h.2 a haU + have hn : ¬ ∀ f ∈ s, f a = 0 := fun hall => haA ((he a haV).mpr hall) + push Not at hn + obtain ⟨f, hfs, hfa⟩ := hn + filter_upwards [hV.mem_nhds haV, (hs f hfs a haV).continuousAt.eventually_ne hfa] with z hz hnz + exact ⟨hVU hz, fun hzA => hnz ((he z hz).mp hzA f hfs)⟩ + +/-- Finite intersections of analytic subsets are analytic. -/ +theorem IsAnalyticSet.inter {U A B : Set E} (hA : IsAnalyticSet U A) + (hB : IsAnalyticSet U B) : IsAnalyticSet U (A ∩ B) := by + classical + refine ⟨inter_subset_left.trans hA.subset, ?_⟩ + intro a ha + obtain ⟨V, hV, haV, hVU, s, hs, he⟩ := hA.2 a ha + obtain ⟨W, hW, haW, _, t, ht, hk⟩ := hB.2 a ha + refine ⟨V ∩ W, hV.inter hW, ⟨haV, haW⟩, inter_subset_left.trans hVU, + s ∪ t, ?_, ?_⟩ + · intro f hf + rcases Finset.mem_union.mp hf with hf | hf + · exact (hs f hf).mono inter_subset_left + · exact (ht f hf).mono inter_subset_right + · intro z hz + simp only [mem_inter_iff, he z hz.1, hk z hz.2, Finset.mem_union] + exact ⟨fun h f hf => hf.elim (h.1 f) (h.2 f), + fun h => ⟨fun f hf => h f (Or.inl hf), fun f hf => h f (Or.inr hf)⟩⟩ + +/-- Finite unions are defined by pairwise products of the local equations. -/ +theorem IsAnalyticSet.union {U A B : Set E} (hA : IsAnalyticSet U A) + (hB : IsAnalyticSet U B) : IsAnalyticSet U (A ∪ B) := by + classical + refine ⟨union_subset hA.subset hB.subset, ?_⟩ + intro a ha + obtain ⟨V, hV, haV, hVU, s, hs, he⟩ := hA.2 a ha + obtain ⟨W, hW, haW, _, t, ht, hk⟩ := hB.2 a ha + refine ⟨V ∩ W, hV.inter hW, ⟨haV, haW⟩, inter_subset_left.trans hVU, + (s ×ˢ t).image (fun p => p.1 * p.2), ?_, ?_⟩ + · intro f hf + obtain ⟨⟨g, k⟩, hp, rfl⟩ := Finset.mem_image.mp hf + exact ((hs g (Finset.mem_product.mp hp).1).mono inter_subset_left).mul + ((ht k (Finset.mem_product.mp hp).2).mono inter_subset_right) + · intro z hz + constructor + · intro hzAB f hf + obtain ⟨⟨g, k⟩, hp, rfl⟩ := Finset.mem_image.mp hf + rcases hzAB with hzA | hzB + · exact mul_eq_zero.mpr (Or.inl ((he z hz.1).mp hzA g (Finset.mem_product.mp hp).1)) + · exact mul_eq_zero.mpr (Or.inr ((hk z hz.2).mp hzB k (Finset.mem_product.mp hp).2)) + · intro h + by_cases hzA : z ∈ A + · exact Or.inl hzA + · right + apply (hk z hz.2).mpr + have hn : ¬ ∀ g ∈ s, g z = 0 := fun hall => hzA ((he z hz.1).mpr hall) + push Not at hn + obtain ⟨g, hg, hgz⟩ := hn + intro k hkt + exact (mul_eq_zero.mp (h (g * k) + (Finset.mem_image.mpr ⟨(g, k), Finset.mem_product.mpr ⟨hg, hkt⟩, rfl⟩))).resolve_left hgz + +/-- Holomorphic preimages preserve analytic subsets. -/ +theorem IsAnalyticSet.preimage {U : Set E} {V B : Set F} (hB : IsAnalyticSet V B) + (hU : IsOpen U) {f : E → F} (hf : AnalyticOnNhd ℂ f U) (hm : MapsTo f U V) : + IsAnalyticSet U (U ∩ f ⁻¹' B) := by + classical + refine ⟨inter_subset_left, ?_⟩ + intro a ha + obtain ⟨W, hW, hfaW, hWV, s, hs, he⟩ := hB.2 (f a) (hm ha) + refine ⟨U ∩ f ⁻¹' W, hf.continuousOn.isOpen_inter_preimage hU hW, + ⟨ha, hfaW⟩, inter_subset_left, s.image (fun g => g ∘ f), ?_, ?_⟩ + · intro g hg + obtain ⟨k, hk, rfl⟩ := Finset.mem_image.mp hg + exact (hs k hk).comp (hf.mono inter_subset_left) (fun _ hz => hz.2) + · intro z hz + simpa [hz.1] using he (f z) hz.2 + +/-- Products of analytic subsets are analytic. -/ +theorem IsAnalyticSet.prod {U A : Set E} {V B : Set F} (hA : IsAnalyticSet U A) + (hB : IsAnalyticSet V B) : IsAnalyticSet (U ×ˢ V) (A ×ˢ B) := by + have ho := hA.isOpen_domain.prod hB.isOpen_domain + have h₁ := hA.preimage ho (f := Prod.fst) (fun _ _ => analyticAt_fst) (fun _ hz => hz.1) + have h₂ := hB.preimage ho (f := Prod.snd) (fun _ _ => analyticAt_snd) (fun _ hz => hz.2) + convert h₁.inter h₂ using 1 + ext z + constructor + · rintro ⟨hzA, hzB⟩ + exact ⟨⟨⟨hA.subset hzA, hB.subset hzB⟩, hzA⟩, + ⟨⟨hA.subset hzA, hB.subset hzB⟩, hzB⟩⟩ + · rintro ⟨⟨_, hzA⟩, ⟨_, hzB⟩⟩ + exact ⟨hzA, hzB⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Codimension.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Codimension.lean new file mode 100644 index 0000000000..0e8d02af75 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Codimension.lean @@ -0,0 +1,175 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Hartogs + +/-! +# Complex slices and removal in codimension at least two + +Following [Scheidemann][Scheidemann2005] §4.1, codimension at least `q` is expressed by an +injective complex linear `q`-plane on which each point of the subset is an isolated +intersection. We retain the pointwise slice witness instead of introducing a general dimension +theory. The empty set satisfies every bound; at a point the bound cannot exceed ambient +dimension. + +Hartogs figures around isolated two-dimensional slices give local holomorphic extensions, and +hence automatic local boundedness across the analytic set. The first Riemann extension theorem +then gives the global second Riemann extension theorem. Reference: +[Scheidemann][Scheidemann2005] 4.1.4 and 4.2.3. + +## Main definitions + +* `HasIsolatedComplexSlice`: An affine complex `q`-plane through `a` meets `A` only at `a` near that + point. +* `HasComplexSliceCodimensionAtLeast`: The slice formulation of complex codimension at least `q`, at + every point of `A`. + +## Main results + +* `IsAnalyticSet.locally_bounded_of_codimension_two`: **Automatic local boundedness in codimension + at least two.** Hartogs continuation around isolated two-dimensional slices gives a local + holomorphic extension, whose continuity supplies the bound. +* `IsAnalyticSet.exists_extension_of_codimension_two`: **Second Riemann extension theorem.** No + boundedness or connectedness assumption is imposed. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- An affine complex `q`-plane through `a` meets `A` only at `a` near that point. Membership of `a` +in `A` is separate, so this predicate also applies outside `A`. -/ +@[expose] def HasIsolatedComplexSlice (A : Set E) (a : E) (q : ℕ) : Prop := + ∃ L : (Fin q → ℂ) →L[ℂ] E, Function.Injective L ∧ + ∀ᶠ z in 𝓝 (0 : Fin q → ℂ), a + L z ∈ A → z = 0 + +/-- The slice formulation of complex codimension at least `q`, at every point of `A`. Analyticity is +a separate assumption. -/ +@[expose] def HasComplexSliceCodimensionAtLeast (A : Set E) (q : ℕ) : Prop := + ∀ a ∈ A, HasIsolatedComplexSlice A a q + +/-- The empty set satisfies every slice-codimension bound. -/ +theorem hasComplexSliceCodimensionAtLeast_empty (q : ℕ) : + HasComplexSliceCodimensionAtLeast (∅ : Set E) q := by + simp [HasComplexSliceCodimensionAtLeast] + +/-- Every subset has slice codimension at least zero; the zero-dimensional slice is a point. -/ +theorem hasComplexSliceCodimensionAtLeast_zero (A : Set E) : + HasComplexSliceCodimensionAtLeast A 0 := by + intro a _ + exact ⟨0, fun _ _ _ => Subsingleton.elim _ _, + Filter.Eventually.of_forall (fun _ _ => Subsingleton.elim _ _)⟩ + +/-- Isolated slice intersections are preserved on subsets. -/ +theorem HasIsolatedComplexSlice.mono {A B : Set E} {a : E} {q : ℕ} + (h : HasIsolatedComplexSlice A a q) (hBA : B ⊆ A) : HasIsolatedComplexSlice B a q := by + obtain ⟨L, hi, he⟩ := h + exact ⟨L, hi, he.mono (fun _ hz hb => hz (hBA hb))⟩ + +/-- Slice-codimension bounds pass to subsets, in particular to restrictions to open sets. -/ +theorem HasComplexSliceCodimensionAtLeast.mono {A B : Set E} {q : ℕ} + (h : HasComplexSliceCodimensionAtLeast A q) (hBA : B ⊆ A) : + HasComplexSliceCodimensionAtLeast B q := fun a ha => (h a (hBA ha)).mono hBA + +/-- A slice cannot have larger dimension than the ambient finite-dimensional space. -/ +theorem HasIsolatedComplexSlice.le_finrank [FiniteDimensional ℂ E] + {A : Set E} {a : E} {q : ℕ} (h : HasIsolatedComplexSlice A a q) : + q ≤ Module.finrank ℂ E := by + obtain ⟨L, hi, _⟩ := h + simpa using LinearMap.finrank_le_finrank_of_injective (f := L.toLinearMap) hi + +/-- A codimension bound exceeding ambient dimension forces the set to be empty. -/ +theorem HasComplexSliceCodimensionAtLeast.eq_empty_of_finrank_lt [FiniteDimensional ℂ E] + {A : Set E} {q : ℕ} (h : HasComplexSliceCodimensionAtLeast A q) + (hq : Module.finrank ℂ E < q) : A = ∅ := by + apply Set.eq_empty_iff_forall_notMem.mpr + intro a ha + exact (not_le_of_gt hq) (h a ha).le_finrank + +/-- A positive-dimensional isolated slice excludes an interior point. -/ +theorem HasIsolatedComplexSlice.notMem_interior {A : Set E} {a : E} {q : ℕ} + (h : HasIsolatedComplexSlice A a q) (hq : 0 < q) : a ∉ interior A := by + let : Nonempty (Fin q) := ⟨⟨0, hq⟩⟩ + obtain ⟨L, _, he⟩ := h + intro ha + have hc : ContinuousAt (fun z => a + L z) (0 : Fin q → ℂ) := + continuousAt_const.add L.continuous.continuousAt + have hn : ∀ᶠ z in 𝓝 (0 : Fin q → ℂ), a + L z ∈ A := + hc.preimage_mem_nhds (by simpa using mem_interior_iff_mem_nhds.mp ha) + have hz : ({0} : Set (Fin q → ℂ)) ∈ 𝓝 0 := by + filter_upwards [he, hn] with z hze hza + exact hze hza + have hzero : (0 : Fin q → ℂ) ∈ interior ({0} : Set (Fin q → ℂ)) := + mem_interior_iff_mem_nhds.mpr hz + simp at hzero + +/-- Positive slice codimension implies empty interior, also on disconnected domains. -/ +theorem HasComplexSliceCodimensionAtLeast.interior_eq_empty {A : Set E} {q : ℕ} + (h : HasComplexSliceCodimensionAtLeast A q) (hq : 0 < q) : interior A = ∅ := by + apply Set.eq_empty_iff_forall_notMem.mpr + intro a ha + exact (h a (interior_subset ha)).notMem_interior hq ha + +/-- **Automatic local boundedness in codimension at least two.** Hartogs continuation +around isolated two-dimensional slices gives a local holomorphic extension, whose +continuity supplies the bound. This allows arbitrary complex Banach targets. -/ +theorem IsAnalyticSet.locally_bounded_of_codimension_two [FiniteDimensional ℂ E] + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {U A : Set E} (hA : IsAnalyticSet U A) (hcodim : HasComplexSliceCodimensionAtLeast A 2) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ A)) : + ∀ a ∈ A, ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ (U \ A), ‖f z‖ ≤ C := by + intro a ha + obtain ⟨L, _, hisol⟩ := hcodim a ha + let e := (ContinuousLinearEquiv.finTwoArrow ℂ ℂ).symm + have hisol' : ∀ᶠ p in 𝓝 (0 : ℂ × ℂ), a + (L.comp e.toContinuousLinearMap) p ∈ A → p = 0 := by + have ht : Tendsto e (𝓝 (0 : ℂ × ℂ)) (𝓝 0) := by + simpa using e.continuous.tendsto (0 : ℂ × ℂ) + filter_upwards [ht.eventually hisol] with p hp hpA + apply e.injective + simpa using hp hpA + obtain ⟨r, hr, g, hg, heq⟩ := hA.exists_local_extension_of_isolated_two_slice + (hA.subset ha) (L.comp e.toContinuousLinearMap) hisol' hf + have hb : ∀ᶠ z in 𝓝 a, ‖g z‖ < ‖g a‖ + 1 := + ((hg a (mem_ball_self hr)).continuousAt.norm).eventually_lt_const (by linarith) + obtain ⟨δ, hδ, hδsub⟩ := Metric.mem_nhds_iff.mp (inter_mem (ball_mem_nhds a hr) hb) + refine ⟨δ, hδ, ‖g a‖ + 1, fun z hz => ?_⟩ + have hz' := hδsub hz.1 + rw [← heq ⟨hz'.1, hz.2.2⟩] + exact hz'.2.le + +/-- **Second Riemann extension theorem.** No boundedness or connectedness assumption +is imposed. The proof depends on automatic local boundedness in codimension two. -/ +theorem IsAnalyticSet.exists_extension_of_codimension_two [FiniteDimensional ℂ E] + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {U A : Set E} (hA : IsAnalyticSet U A) (hcodim : HasComplexSliceCodimensionAtLeast A 2) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ A)) : + ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ A) := + hA.exists_extension_of_locally_bounded (hcodim.interior_eq_empty (by decide)) hf + (hA.locally_bounded_of_codimension_two hcodim hf) + +/-- Extensions in the second Riemann theorem are unique on the ambient domain. This uniqueness proof +uses density and does not require the existence argument. -/ +theorem IsAnalyticSet.extension_unique_of_codimension_two + {F : Type*} [TopologicalSpace F] [T2Space F] {U A : Set E} + (hA : IsAnalyticSet U A) (hcodim : HasComplexSliceCodimensionAtLeast A 2) + {f g h : E → F} (hg : ContinuousOn g U) (hh : ContinuousOn h U) + (hgf : EqOn g f (U \ A)) (hhf : EqOn h f (U \ A)) : EqOn g h U := + hA.extension_unique (hcodim.interior_eq_empty (by decide)) hg hh hgf hhf + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/CoordinatePlane.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/CoordinatePlane.lean new file mode 100644 index 0000000000..7d65a80019 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/CoordinatePlane.lean @@ -0,0 +1,137 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Codimension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsContinuation + +/-! +# Removal across a coordinate subspace of codimension two + +The model subspace has two final coordinates equal to zero and arbitrary remaining parameters. +Hartogs continuation on cylinders proves removal on any open domain, with Banach-valued targets, +independently of the general analytic-set theorem. The parameter space may have dimension zero, +recovering isolated-point removal in `ℂ²`. + +## Main definitions + +* `complexCoordinatePlane`: The coordinate subspace obtained by setting the last two complex + coordinates to zero. + +## Main results + +* `exists_extension_across_coordinatePlane`: **Coordinate-subspace removal.** The proof uses the + already proved Hartogs cylinder theorem and gluing, with no dependence on general codimension-two + removal or local algebra. +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {P : Type*} [NormedAddCommGroup P] [NormedSpace ℂ P] + +/-- The coordinate subspace obtained by setting the last two complex coordinates to zero. -/ +@[expose] def complexCoordinatePlane : Set ((P × ℂ) × ℂ) := {z | z.1.2 = 0 ∧ z.2 = 0} + +/-- The model coordinate subspace is analytic on every open domain. -/ +theorem isAnalyticSet_coordinatePlane {U : Set ((P × ℂ) × ℂ)} (hU : IsOpen U) : + IsAnalyticSet U (U ∩ complexCoordinatePlane) := by + have h₁ := isAnalyticSet_zeroSet hU + (f := fun z : (P × ℂ) × ℂ => z.1.2) + (fun _ _ => analyticAt_snd.comp analyticAt_fst) + have h₂ := isAnalyticSet_zeroSet hU + (f := fun z : (P × ℂ) × ℂ => z.2) (fun _ _ => analyticAt_snd) + convert h₁.inter h₂ using 1 + ext z + simp only [mem_inter_iff, mem_preimage, mem_singleton_iff, complexCoordinatePlane, mem_ofPred_eq] + tauto + +/-- The last two coordinate directions provide the isolated two-plane slice. -/ +theorem hasComplexSliceCodimensionAtLeast_coordinatePlane : + HasComplexSliceCodimensionAtLeast (complexCoordinatePlane (P := P)) 2 := by + intro a ha + let L : (Fin 2 → ℂ) →L[ℂ] ((P × ℂ) × ℂ) := + ((0 : (Fin 2 → ℂ) →L[ℂ] P).prod (ContinuousLinearMap.proj 0)).prod + (ContinuousLinearMap.proj 1) + have hL (z : Fin 2 → ℂ) : L z = ((0, z 0), z 1) := rfl + refine ⟨L, ?_, Filter.Eventually.of_forall ?_⟩ + · intro x y he + have h₀ := congrArg (fun z : (P × ℂ) × ℂ => z.1.2) he + have h₁ := congrArg (fun z : (P × ℂ) × ℂ => z.2) he + funext i + fin_cases i + · exact h₀ + · exact h₁ + · intro z hz + have hz₀ : z 0 = 0 := by simpa [complexCoordinatePlane, hL, ha.1] using hz.1 + have hz₁ : z 1 = 0 := by simpa [complexCoordinatePlane, hL, ha.2] using hz.2 + funext i + fin_cases i + · exact hz₀ + · exact hz₁ + +/-- **Coordinate-subspace removal.** The proof uses the already proved Hartogs cylinder +theorem and gluing, with no dependence on general codimension-two removal or local algebra. -/ +theorem exists_extension_across_coordinatePlane [FiniteDimensional ℂ P] + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {U : Set ((P × ℂ) × ℂ)} (hU : IsOpen U) {f : ((P × ℂ) × ℂ) → F} + (hf : AnalyticOnNhd ℂ f (U \ complexCoordinatePlane)) : + ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ complexCoordinatePlane) := by + let : NormedSpace ℝ P := NormedSpace.restrictScalars ℝ ℂ P + have hA := isAnalyticSet_coordinatePlane hU + have hcodim := hasComplexSliceCodimensionAtLeast_coordinatePlane (P := P) + have hi := (hcodim.mono (inter_subset_right (s := U))).interior_eq_empty (by decide) + have hdiff : U \ (U ∩ complexCoordinatePlane) = U \ complexCoordinatePlane := by + ext z + simp only [Set.mem_sdiff, mem_inter_iff] + tauto + have hdense : U ⊆ closure (U \ complexCoordinatePlane) := by + simpa only [hdiff] using hA.subset_closure_sdiff hi + have hopen : IsOpen (U \ complexCoordinatePlane) := by + simpa only [hdiff] using hA.isOpen_sdiff + apply exists_analyticOnNhd_extension_of_local sdiff_subset hdense + intro a ha + by_cases haA : a ∈ complexCoordinatePlane + · obtain ⟨r, hr, hrU⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds ha) + let D : Set (P × ℂ) := ball a.1.1 r ×ˢ ball 0 r + let D₀ : Set (P × ℂ) := ball a.1.1 r ×ˢ (ball 0 r \ {0}) + let V : Set ((P × ℂ) × ℂ) := D ×ˢ ball 0 r + have haeq : a = ((a.1.1, 0), 0) := by + ext <;> simp_all [complexCoordinatePlane] + have hVU : V ⊆ U := by + apply Subset.trans _ hrU + rw [haeq] + simp only [← ball_prod_same, V, D] + exact Subset.rfl + have hne : D₀.Nonempty := by + have hz : (0 : ℂ) ∈ closure ({0}ᶜ : Set ℂ) := by simp + obtain ⟨z, hzne, hzr⟩ := Metric.mem_closure_iff.mp hz r hr + exact ⟨(a.1.1, z), mem_ball_self hr, by simpa [dist_comm] using hzr, hzne⟩ + have hcyl : hartogsCylinder D D₀ 0 r = V \ complexCoordinatePlane := by + ext z + simp only [hartogsCylinder, D, D₀, V, complexCoordinatePlane, + mem_union, mem_prod, Set.mem_sdiff, mem_ofPred_eq, closedBall_zero, + mem_singleton_iff] + tauto + obtain ⟨g, hg, he⟩ := exists_extension_hartogsCylinder (D := D) (D₀ := D₀) (ρ := 0) (R := r) + (isOpen_ball.prod isOpen_ball) (isPreconnected_ball.prod isPreconnected_ball) + (isOpen_ball.prod (isOpen_ball.sdiff isClosed_singleton)) hne + (fun _ hz => ⟨hz.1, hz.2.1⟩) le_rfl hr + (hf.mono (by rw [hcyl]; exact sdiff_subset_sdiff_left hVU)) + refine ⟨V, g, (isOpen_ball.prod isOpen_ball).prod isOpen_ball, ?_, hVU, hg, ?_⟩ + · exact ⟨⟨mem_ball_self hr, haA.1 ▸ mem_ball_self hr⟩, haA.2 ▸ mem_ball_self hr⟩ + · intro z hz + exact he (hcyl.symm ▸ ⟨hz.1, hz.2.2⟩) + · exact ⟨U \ complexCoordinatePlane, f, hopen, ⟨ha, haA⟩, sdiff_subset, hf, + fun _ _ => rfl⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/FunctionSpace.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/FunctionSpace.lean new file mode 100644 index 0000000000..1ece960725 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/FunctionSpace.lean @@ -0,0 +1,77 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Codimension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace.Extension + +/-! +# Restriction across analytic sets of codimension at least two + +[Scheidemann][Scheidemann2005]'s second Riemann theorem is stated as an isomorphism of +holomorphic algebras. The forward map below is restriction. Injectivity uses density; +surjectivity uses the proved second Riemann extension theorem. Disconnected and empty domains +are allowed. No assertion about continuity of the inverse is needed for this algebraic +formulation. + +## Main results + +`analyticSetRestrictionAlgEquiv` is [Scheidemann][Scheidemann2005]'s second Riemann theorem as +an isomorphism of holomorphic algebras across an analytic set of slice codimension at least two. +`analyticSetRestrictionAlgEquiv_apply` is restriction of representatives. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set + +namespace SeveralComplexVariables + +/-- **Second Riemann extension theorem, algebraic form.** Restriction across an analytic +subset of slice codimension at least two is an isomorphism of complex algebras. +Surjectivity follows from automatic local boundedness and the first Riemann theorem. -/ +def analyticSetRestrictionAlgEquiv {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] + {U V : TopologicalSpace.Opens E} {A : Set E} + (hA : IsAnalyticSet U A) (hcodim : HasComplexSliceCodimensionAtLeast A 2) + (hV : (V : Set E) = (U : Set E) \ A) : + HolomorphicAlgebra U ≃ₐ[ℂ] HolomorphicAlgebra V := by + have hVU : V ≤ U := by + change (V : Set E) ⊆ (U : Set E) + rw [hV] + exact sdiff_subset + have hd : (U : Set E) ⊆ closure (V : Set E) := by + rw [hV] + exact hA.subset_closure_sdiff (hcodim.interior_eq_empty (by decide)) + have hi := holomorphicRestrict_injective_of_subset_closure (F := ℂ) hVU hd + have hs : Function.Surjective (holomorphicRestrict (F := ℂ) hVU) := by + apply holomorphicRestrict_surjective hVU + intro f hf + obtain ⟨g, hg, he⟩ := hA.exists_extension_of_codimension_two hcodim (hV ▸ hf) + exact ⟨g, hg, hV ▸ he⟩ + exact AlgEquiv.ofBijective (holomorphicRestrictAlgHom hVU) + (by simpa only [holomorphicRestrictAlgHom_coe, Function.Bijective] using And.intro hi hs) + +/-- The forward algebra equivalence is exactly restriction to the complement. -/ +@[simp] theorem analyticSetRestrictionAlgEquiv_apply {E : Type*} [NormedAddCommGroup E] + [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U V : TopologicalSpace.Opens E} {A : Set E} + (hA : IsAnalyticSet U A) (hcodim : HasComplexSliceCodimensionAtLeast A 2) + (hV : (V : Set E) = (U : Set E) \ A) (f : HolomorphicAlgebra U) : + analyticSetRestrictionAlgEquiv hA hcodim hV f = + holomorphicRestrict (show V ≤ U from by + change (V : Set E) ⊆ (U : Set E) + rw [hV] + exact sdiff_subset) f := by + simp [analyticSetRestrictionAlgEquiv] + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Hartogs.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Hartogs.lean new file mode 100644 index 0000000000..0ce886a008 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Hartogs.lean @@ -0,0 +1,200 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Removable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsContinuation + +/-! +# Hartogs extension across analytic subsets + +A Hartogs figure avoiding an analytic exceptional set determines an extension on the whole +cylinder. The complement of a proper analytic subset is connected, so the identity principle +identifies this extension with the original function. Isolated two-dimensional slices supply +such figures near the exceptional set. + +## Main results + +`IsAnalyticSet.exists_extension_of_hartogsCylinder_subset` extends across a Hartogs figure that +avoids the analytic set. `exists_hartogs_neighborhood` produces such a figure near an isolated +two-dimensional slice. `IsAnalyticSet.exists_local_extension_of_isolated_two_slice` is local +extension from that figure. +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- A Hartogs cylinder avoiding an analytic subset gives an extension across that subset. +Connectedness of its complement ensures agreement everywhere it is defined. -/ +theorem IsAnalyticSet.exists_extension_of_hartogsCylinder_subset + {D D₀ : Set E} {ρ R : ℝ} {A : Set (E × ℂ)} + (hA : IsAnalyticSet (D ×ˢ ball 0 R) A) + (hD : IsOpen D) (hc : IsPreconnected D) (hD₀ : IsOpen D₀) (hne : D₀.Nonempty) + (hsub : D₀ ⊆ D) (hρ : 0 ≤ ρ) (hρR : ρ < R) + (hHA : hartogsCylinder D D₀ ρ R ⊆ (D ×ˢ ball 0 R) \ A) + {f : E × ℂ → F} (hf : AnalyticOnNhd ℂ f ((D ×ˢ ball 0 R) \ A)) : + ∃ g, AnalyticOnNhd ℂ g (D ×ˢ ball 0 R) ∧ EqOn g f ((D ×ˢ ball 0 R) \ A) := by + obtain ⟨g, hg, heq⟩ := exists_extension_hartogsCylinder hD hc hD₀ hne hsub hρ hρR + (hf.mono hHA) + obtain ⟨b, hb⟩ := hne + have hbH : (b, (0 : ℂ)) ∈ hartogsCylinder D D₀ ρ R := + Or.inr ⟨hb, mem_ball_self (hρ.trans_lt hρR)⟩ + have hproper : A ≠ D ×ˢ ball 0 R := by + intro h + exact (hHA hbH).2 (h.symm ▸ (hHA hbH).1) + have hconn := hA.isConnected_sdiff + ⟨⟨(b, 0), (hHA hbH).1⟩, hc.prod isPreconnected_ball⟩ hproper + have hH : IsOpen (hartogsCylinder D D₀ ρ R) := + (hD.prod (isOpen_ball.sdiff isClosed_closedBall)).union (hD₀.prod isOpen_ball) + exact ⟨g, hg, (hg.mono sdiff_subset).eqOn_of_preconnected_of_eventuallyEq hf + hconn.isPreconnected (hHA hbH) ((hH.eventually_mem hbH).mono (fun _ hz => heq hz))⟩ + +/-- The small base disc of an off-center Hartogs figure lies in the large base disc. -/ +private theorem offCenter_ball_subset {R : ℝ} (hR : 0 < R) : + ball ((R / 2 : ℝ) : ℂ) (R / 4) ⊆ ball 0 R := by + apply ball_subset_ball' + simp only [dist_zero_right, Complex.norm_real, Real.norm_eq_abs, abs_of_pos (half_pos hR)] + linarith + +/-- An off-center Hartogs figure fits inside a compact shell avoiding the origin. -/ +private theorem offCenter_hartogsCylinder_subset_shell {R : ℝ} (hR : 0 < R) : + hartogsCylinder (ball (0 : ℂ) R) (ball ((R / 2 : ℝ) : ℂ) (R / 4)) (R / 2) R ⊆ + closedBall (0 : ℂ × ℂ) R \ ball 0 (R / 4) := by + intro p hp + have hpR : p ∈ ball (0 : ℂ × ℂ) R := by + rw [← ball_prod_same] + rcases hp with hp | hp + · exact ⟨hp.1, hp.2.1⟩ + · exact ⟨offCenter_ball_subset hR hp.1, hp.2⟩ + refine ⟨ball_subset_closedBall hpR, ?_⟩ + intro hp0 + have hsmall : p ∈ ball (0 : ℂ) (R / 4) ×ˢ ball 0 (R / 4) := by + rwa [ball_prod_same] + rcases hp with hp | hp + · exact hp.2.2 (ball_subset_closedBall ((ball_subset_ball (by linarith)) hsmall.2)) + · have hd := dist_triangle ((R / 2 : ℝ) : ℂ) p.1 0 + have h₁ := mem_ball.mp hp.1 + have h₂ := mem_ball.mp hsmall.1 + rw [dist_comm p.1 ((R / 2 : ℝ) : ℂ)] at h₁ + simp only [dist_zero_right] at h₂ + simp only [dist_zero_right, Complex.norm_real, Real.norm_eq_abs, + abs_of_pos (half_pos hR)] at hd + linarith + +omit [FiniteDimensional ℂ E] in +/-- Compact subsets of an open set remain in it under small translations of a fixed continuous +linear image. -/ +private theorem eventually_add_image_subset {P : Type*} [NormedAddCommGroup P] + [NormedSpace ℂ P] {K : Set P} (hK : IsCompact K) {V : Set E} (hV : IsOpen V) + {a : E} (L : P →L[ℂ] E) (hsub : ∀ p ∈ K, a + L p ∈ V) : + ∀ᶠ z in 𝓝 a, ∀ p ∈ K, z + L p ∈ V := by + apply hK.eventually_forall_of_forall_eventually + intro p hp + exact (continuous_fst.add (L.continuous.comp continuous_snd)).continuousAt.preimage_mem_nhds + (hV.mem_nhds (hsub p hp)) + +omit [FiniteDimensional ℂ E] in +/-- An isolated two-dimensional slice supplies a Hartogs figure, together with nearby parallel +translates, that avoids the exceptional set. -/ +private theorem exists_hartogs_neighborhood {U A : Set E} + (hU : IsOpen U) (hUA : IsOpen (U \ A)) {a : E} (ha : a ∈ U) + (L : (ℂ × ℂ) →L[ℂ] E) + (hisol : ∀ᶠ p in 𝓝 (0 : ℂ × ℂ), a + L p ∈ A → p = 0) : + ∃ δ R : ℝ, 0 < δ ∧ 0 < R ∧ + (∀ q ∈ (ball a δ ×ˢ ball (0 : ℂ) R) ×ˢ ball (0 : ℂ) R, + q.1.1 + L (q.1.2, q.2) ∈ U) ∧ + (∀ q ∈ hartogsCylinder (ball a δ ×ˢ ball (0 : ℂ) R) + (ball a δ ×ˢ ball ((R / 2 : ℝ) : ℂ) (R / 4)) (R / 2) R, + q.1.1 + L (q.1.2, q.2) ∈ U \ A) := by + have hstay : ∀ᶠ p in 𝓝 (0 : ℂ × ℂ), a + L p ∈ U := + (continuous_const.add L.continuous).continuousAt.preimage_mem_nhds + (by simpa using hU.mem_nhds ha) + obtain ⟨ε, hε, hεsub⟩ := Metric.mem_nhds_iff.mp (hstay.and hisol) + let R := ε / 2 + have hR : 0 < R := half_pos hε + have hcentral (p : ℂ × ℂ) (hp : p ∈ closedBall 0 R) : + a + L p ∈ U ∧ (a + L p ∈ A → p = 0) := + hεsub (closedBall_subset_ball (half_lt_self hε) hp) + let K := closedBall (0 : ℂ × ℂ) R \ ball 0 (R / 4) + have hK : IsCompact K := (isCompact_closedBall _ _).diff isOpen_ball + have hcentralK (p : ℂ × ℂ) (hp : p ∈ K) : a + L p ∈ U \ A := by + refine ⟨(hcentral p hp.1).1, fun hpA => ?_⟩ + have hp0 := (hcentral p hp.1).2 hpA + exact hp.2 (hp0 ▸ mem_ball_self (by dsimp [R]; positivity)) + have hfull := eventually_add_image_subset (isCompact_closedBall (0 : ℂ × ℂ) R) + hU L (fun p hp => (hcentral p hp).1) + have hshell := eventually_add_image_subset hK hUA L hcentralK + obtain ⟨δ, hδ, hδsub⟩ := Metric.mem_nhds_iff.mp (hfull.and hshell) + refine ⟨δ, R, hδ, hR, ?_, ?_⟩ + · intro q hq + apply (hδsub hq.1.1).1 (q.1.2, q.2) + rw [← closedBall_prod_same] + exact ⟨ball_subset_closedBall hq.1.2, ball_subset_closedBall hq.2⟩ + · intro q hq + have hz : q.1.1 ∈ ball a δ := by rcases hq with hq | hq <;> exact hq.1.1 + apply (hδsub hz).2 (q.1.2, q.2) + apply offCenter_hartogsCylinder_subset_shell hR + rcases hq with hq | hq + · exact Or.inl ⟨hq.1.2, hq.2⟩ + · exact Or.inr ⟨hq.1.2, hq.2⟩ + +/-- An analytic subset with an isolated two-dimensional slice admits local extension of every +holomorphic function on its complement. No boundedness is assumed. -/ +theorem IsAnalyticSet.exists_local_extension_of_isolated_two_slice + {U A : Set E} (hA : IsAnalyticSet U A) {a : E} (ha : a ∈ U) + (L : (ℂ × ℂ) →L[ℂ] E) + (hisol : ∀ᶠ p in 𝓝 (0 : ℂ × ℂ), a + L p ∈ A → p = 0) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ A)) : + ∃ r : ℝ, 0 < r ∧ ∃ g : E → F, + AnalyticOnNhd ℂ g (ball a r) ∧ EqOn g f (ball a r \ A) := by + obtain ⟨δ, R, hδ, hR, hfull, hshell⟩ := + exists_hartogs_neighborhood hA.isOpen_domain hA.isOpen_sdiff ha L hisol + let D := ball a δ ×ˢ ball (0 : ℂ) R + let D₀ := ball a δ ×ˢ ball ((R / 2 : ℝ) : ℂ) (R / 4) + let B := D ×ˢ ball (0 : ℂ) R + let T : (E × ℂ) × ℂ → E := fun q => q.1.1 + L (q.1.2, q.2) + have hT : AnalyticOnNhd ℂ T B := fun q _ => + (analyticAt_fst.comp analyticAt_fst).add ((L.analyticAt _).comp + ((analyticAt_snd.comp analyticAt_fst).prod analyticAt_snd)) + have hD : IsOpen D := isOpen_ball.prod isOpen_ball + have hB : IsOpen B := hD.prod isOpen_ball + have hpre : IsAnalyticSet B (B ∩ T ⁻¹' A) := hA.preimage hB hT hfull + have hfT : AnalyticOnNhd ℂ (f ∘ T) (B \ (B ∩ T ⁻¹' A)) := by + intro q hq + exact (hf (T q) ⟨hfull q hq.1, fun hqA => hq.2 ⟨hq.1, hqA⟩⟩).comp (hT q hq.1) + have hH : hartogsCylinder D D₀ (R / 2) R ⊆ B \ (B ∩ T ⁻¹' A) := by + intro q hq + have hqB : q ∈ B := by + rcases hq with hq | hq + · exact ⟨hq.1, hq.2.1⟩ + · exact ⟨⟨hq.1.1, offCenter_ball_subset hR hq.1.2⟩, hq.2⟩ + exact ⟨hqB, fun hqA => (hshell q hq).2 hqA.2⟩ + obtain ⟨G, hG, hGF⟩ := hpre.exists_extension_of_hartogsCylinder_subset hD + (isPreconnected_ball.prod isPreconnected_ball) (isOpen_ball.prod isOpen_ball) + ⟨(a, ((R / 2 : ℝ) : ℂ)), mem_ball_self hδ, mem_ball_self (by positivity)⟩ + (prod_mono_right (offCenter_ball_subset hR)) (half_pos hR).le (half_lt_self hR) hH hfT + refine ⟨δ, hδ, fun z => G ((z, 0), 0), ?_, ?_⟩ + · intro z hz + exact (hG ((z, 0), 0) ⟨⟨hz, mem_ball_self hR⟩, mem_ball_self hR⟩).comp + (f := fun z : E => ((z, (0 : ℂ)), (0 : ℂ))) + ((analyticAt_id.prod analyticAt_const).prod analyticAt_const) + · intro z hz + have hzB : ((z, (0 : ℂ)), (0 : ℂ)) ∈ B := + ⟨⟨hz.1, mem_ball_self hR⟩, mem_ball_self hR⟩ + have hL0 : L ((0 : ℂ), (0 : ℂ)) = 0 := L.map_zero + have heq := hGF ⟨hzB, fun hp => hz.2 (by simpa [T, hL0] using hp.2)⟩ + simpa [T, hL0] using heq + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Holomorphic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Holomorphic.lean new file mode 100644 index 0000000000..e9ec130fab --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Holomorphic.lean @@ -0,0 +1,77 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic + +/-! +# Holomorphic equations and biholomorphic transport of analytic sets + +On open finite-dimensional complex domains, holomorphic finite-coordinate equations define +analytic subsets. Biholomorphic changes of ambient coordinates preserve analytic subsets. These +results use the holomorphy–analyticity equivalence and are separated from `AnalyticSet.Basic` so +that the definition and elementary analytic-set operations do not import holomorphic mapping +theory. + +References: [Range][Range1986] I §3.2; [Fritzsche–Grauert][FritzscheGrauert2002] I §8; +[Scheidemann][Scheidemann2005] §4.1. + +## Main results + +* `isAnalyticSet_zeroSet_pi_of_differentiableOn`: Holomorphic finite-coordinate equations on an open + finite-dimensional domain define an analytic subset, using Mathlib's equivalence of holomorphy and + analyticity. +* `IsAnalyticSet.image_biholomorphic`: Biholomorphic changes of ambient coordinates preserve + analytic subsets. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- Holomorphic finite-coordinate equations on an open finite-dimensional domain define an analytic +subset, using Mathlib's equivalence of holomorphy and analyticity. -/ +theorem isAnalyticSet_zeroSet_pi_of_differentiableOn [FiniteDimensional ℂ E] + {ι : Type*} [Finite ι] {U : Set E} (hU : IsOpen U) + {f : E → (ι → ℂ)} (hf : DifferentiableOn ℂ f U) : + IsAnalyticSet U (U ∩ f ⁻¹' {0}) := by + classical + let := Fintype.ofFinite ι + exact + isAnalyticSet_zeroSet_pi hU (hf.analyticOnNhd_of_finiteDimensional hU) + +/-- Biholomorphic changes of ambient coordinates preserve analytic subsets. -/ +theorem IsAnalyticSet.image_biholomorphic [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] + {e : OpenPartialHomeomorph E F} (he : IsBiholomorphic e) + {A : Set E} (hA : IsAnalyticSet e.source A) : IsAnalyticSet e.target (e '' A) := by + let := FiniteDimensional.complete ℂ E + have h := hA.preimage e.open_target + (he.2.analyticOnNhd_of_finiteDimensional e.open_target) e.symm.mapsTo + convert h using 1 + ext y + constructor + · rintro ⟨x, hx, rfl⟩ + exact ⟨e.map_source (hA.subset hx), by simpa [e.left_inv (hA.subset hx)] using hx⟩ + · rintro ⟨hy, hx⟩ + exact ⟨e.symm y, hx, e.right_inv hy⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Regular.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Regular.lean new file mode 100644 index 0000000000..efaf3f50b9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Regular.lean @@ -0,0 +1,297 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitGraph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Local + +/-! +# Regular points of analytic subsets + +Regularity means that local biholomorphic ambient coordinates identify the subset with the +kernel of a surjective complex linear map. This is intrinsic to the subset: `z₁² = 0` and `z₁ = +0` define the same regular hyperplane. No manifold structure is used. The full-rank-equations +criterion is proved by a linear right inverse and the holomorphic inverse mapping theorem. A +minimal nonvanishing derivative and persistence of zeros prove existence of regular hypersurface +points. Relative openness of the regular locus and relative closedness of the singular locus +follow from the definition. + +Reference: [Fritzsche–Grauert][FritzscheGrauert2002] I, 8.3–8.4; [Range][Range1986] I §3.2. + +## Main definitions + +* `IsRegularAnalyticSetAt`: Intrinsic regularity of codimension `q`: local biholomorphic coordinates + flatten `A` to the kernel of a surjective map to `ℂ^q`. +* `analyticRegularLocus`: The regular locus includes all local codimensions, including codimension + zero. +* `analyticSingularLocus`: Singular points are the points of the subset that are not regular. + +## Main results + +* `isRegularAnalyticSetAt_iff_exists_equations`: **Local coordinate characterization.** Regularity + is equivalent to the existence of full-rank defining equations, not a rank condition on an + arbitrary presentation. +* `exists_regularPoint_zeroSet`: **Regular points of a hypersurface.** A nonempty proper scalar zero + set in a preconnected domain contains a regular point of codimension one. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Intrinsic regularity of codimension `q`: local biholomorphic coordinates flatten `A` to the +kernel of a surjective map to `ℂ^q`. Membership in `A` is included. -/ +@[expose] def IsRegularAnalyticSetAt (A : Set E) (a : E) (q : ℕ) : Prop := + a ∈ A ∧ ∃ (e : OpenPartialHomeomorph E E) (L : E →L[ℂ] (Fin q → ℂ)), + IsBiholomorphic e ∧ a ∈ e.source ∧ Function.Surjective L ∧ + ∀ z ∈ e.source, z ∈ A ↔ L (e z) = 0 + +/-- The regular locus includes all local codimensions, including codimension zero. -/ +@[expose] def analyticRegularLocus (A : Set E) : Set E := {a | ∃ q, IsRegularAnalyticSetAt A a q} + +/-- Singular points are the points of the subset that are not regular. -/ +@[expose] def analyticSingularLocus (A : Set E) : Set E := A \ analyticRegularLocus A + +/-- Every regular point belongs to the subset. -/ +theorem analyticRegularLocus_subset (A : Set E) : analyticRegularLocus A ⊆ A := by + rintro a ⟨q, h⟩ + exact h.1 + +/-- The local codimension of a regular point is bounded by the ambient dimension. -/ +theorem IsRegularAnalyticSetAt.le_finrank [FiniteDimensional ℂ E] + {A : Set E} {a : E} {q : ℕ} (h : IsRegularAnalyticSetAt A a q) : + q ≤ Module.finrank ℂ E := by + obtain ⟨_, _, L, _, _, hL, _⟩ := h + simpa using LinearMap.finrank_le_finrank_of_surjective (f := L.toLinearMap) hL + +/-- A flattening chart witnesses the same codimension at every nearby point of the set. -/ +theorem IsRegularAnalyticSetAt.exists_open {A : Set E} {a : E} {q : ℕ} + (h : IsRegularAnalyticSetAt A a q) : + ∃ V, IsOpen V ∧ a ∈ V ∧ ∀ b ∈ V ∩ A, IsRegularAnalyticSetAt A b q := by + obtain ⟨_, e, L, he, ha, hL, hEq⟩ := h + exact ⟨e.source, e.open_source, ha, fun b hb => ⟨hb.2, e, L, he, hb.1, hL, hEq⟩⟩ + +/-- The regular locus is relatively open in the subset, without any global analyticity +assumption. -/ +theorem isOpen_relative_analyticRegularLocus (A : Set E) : + IsOpen {a : A | a.val ∈ analyticRegularLocus A} := by + rw [isOpen_iff_mem_nhds] + rintro a ⟨q, hq⟩ + obtain ⟨V, hV, haV, hreg⟩ := hq.exists_open + apply Filter.mem_of_superset ((hV.preimage continuous_subtype_val).mem_nhds haV) + intro b hb + exact ⟨q, hreg b ⟨hb, b.property⟩⟩ + +/-- The singular locus is relatively closed in the subset. This does not assert that it is +analytic. -/ +theorem isClosed_relative_analyticSingularLocus (A : Set E) : + IsClosed {a : A | a.val ∈ analyticSingularLocus A} := by + have he : {a : A | a.val ∈ analyticSingularLocus A} = + {a : A | a.val ∈ analyticRegularLocus A}ᶜ := by + ext a + simp [analyticSingularLocus] + rw [he] + exact (isOpen_relative_analyticRegularLocus A).isClosed_compl + +/-- On an analytic subset of `U`, the singular locus is relatively closed also in `U`. -/ +theorem IsAnalyticSet.isOpen_sdiff_singularLocus {U A : Set E} (hA : IsAnalyticSet U A) : + IsOpen (U \ analyticSingularLocus A) := by + classical + rw [isOpen_iff_mem_nhds] + rintro a ⟨haU, has⟩ + by_cases haA : a ∈ A + · have har : a ∈ analyticRegularLocus A := by + by_contra hn + exact has ⟨haA, hn⟩ + obtain ⟨q, hq⟩ := har + obtain ⟨V, hV, haV, hreg⟩ := hq.exists_open + apply Filter.mem_of_superset ((hA.isOpen_domain.inter hV).mem_nhds ⟨haU, haV⟩) + intro b hb + exact ⟨hb.1, fun hbs => hbs.2 ⟨q, hreg b ⟨hb.2, hbs.1⟩⟩⟩ + · exact Filter.mem_of_superset (hA.isOpen_sdiff.mem_nhds ⟨haU, haA⟩) + (fun b hb => ⟨hb.1, fun hbs => hb.2 hbs.1⟩) + +/-- Flattening coordinates supply local defining equations with surjective derivative. -/ +theorem IsRegularAnalyticSetAt.exists_equations [FiniteDimensional ℂ E] + {A : Set E} {a : E} {q : ℕ} (h : IsRegularAnalyticSetAt A a q) : + ∃ (V : Set E) (f : E → (Fin q → ℂ)), IsOpen V ∧ a ∈ V ∧ + AnalyticOnNhd ℂ f V ∧ (∀ z ∈ V, z ∈ A ↔ f z = 0) ∧ + Function.Surjective (fderiv ℂ f a) := by + let := FiniteDimensional.complete ℂ E + obtain ⟨_, e, L, he, ha, hL, hEq⟩ := h + refine ⟨e.source, L ∘ e, e.open_source, ha, ?_, hEq, ?_⟩ + · intro z hz + exact (L.analyticAt (e z)).comp + ((he.1.analyticOnNhd_of_finiteDimensional e.open_source) z hz) + · rw [fderiv_comp a L.differentiableAt (he.differentiableAt ha), L.fderiv] + obtain ⟨M, hM⟩ := he.isInvertible_fderiv ha + rw [← hM] + exact hL.comp M.surjective + +/-- Full-rank local defining equations admit flattening biholomorphic coordinates. A linear right +inverse corrects the defining map to have identity derivative, so the holomorphic inverse +mapping theorem supplies the required coordinates. -/ +theorem isRegularAnalyticSetAt_of_equations [FiniteDimensional ℂ E] + {A V : Set E} {a : E} {q : ℕ} (haA : a ∈ A) (hV : IsOpen V) (haV : a ∈ V) + {f : E → (Fin q → ℂ)} (hf : AnalyticOnNhd ℂ f V) + (hEq : ∀ z ∈ V, z ∈ A ↔ f z = 0) (hs : Function.Surjective (fderiv ℂ f a)) : + IsRegularAnalyticSetAt A a q := by + let L := fderiv ℂ f a + obtain ⟨R, hR⟩ := L.toLinearMap.exists_rightInverse_of_surjective + (LinearMap.range_eq_top.mpr hs) + let B : (Fin q → ℂ) →L[ℂ] E := R.toContinuousLinearMap + have hLB (y : Fin q → ℂ) : L (B y) = y := DFunLike.congr_fun hR y + let g : E → E := fun x => x + B (f x - L x) + have hg : DifferentiableOn ℂ g V := + differentiableOn_id.add (B.differentiable.comp_differentiableOn + (hf.differentiableOn.sub L.differentiable.differentiableOn)) + have hd : HasFDerivAt g (ContinuousLinearMap.id ℂ E) a := by + simpa only [g, L, Pi.add_def, Pi.sub_def, Function.comp_def, id_eq, + sub_self, ContinuousLinearMap.comp_zero, add_zero] using + (hasFDerivAt_id a).add (B.hasFDerivAt.comp a + ((hf a haV).differentiableAt.hasFDerivAt.sub L.hasFDerivAt)) + have hinv : (fderiv ℂ g a).IsInvertible := by + rw [hd.fderiv] + exact ⟨ContinuousLinearEquiv.refl ℂ E, rfl⟩ + obtain ⟨e, he, hae, heV, heq⟩ := exists_biholomorphic_of_isInvertible_fderiv hV hg haV hinv + refine ⟨haA, e, L, he, hae, hs, ?_⟩ + intro z hz + rw [hEq z (heV hz), heq] + have hLg : L (g z) = f z := by + dsimp [g] + rw [map_add, hLB] + abel + rw [hLg] + +/-- **Local coordinate characterization.** Regularity is equivalent to the existence +of full-rank defining equations, not a rank condition on an arbitrary presentation. +Both directions follow from the holomorphic inverse mapping theorem and the chain rule. -/ +theorem isRegularAnalyticSetAt_iff_exists_equations [FiniteDimensional ℂ E] + {A : Set E} {a : E} {q : ℕ} : + IsRegularAnalyticSetAt A a q ↔ a ∈ A ∧ + ∃ (V : Set E) (f : E → (Fin q → ℂ)), IsOpen V ∧ a ∈ V ∧ + AnalyticOnNhd ℂ f V ∧ (∀ z ∈ V, z ∈ A ↔ f z = 0) ∧ + Function.Surjective (fderiv ℂ f a) := by + refine ⟨fun h => ⟨h.1, h.exists_equations⟩, ?_⟩ + rintro ⟨haA, V, f, hV, haV, hf, hEq, hs⟩ + exact isRegularAnalyticSetAt_of_equations haA hV haV hf hEq hs + +/-- A surjective linear equation defines a regular linear subspace of the expected codimension. -/ +theorem isRegularAnalyticSetAt_linear_zeroSet (q : ℕ) (L : E →L[ℂ] (Fin q → ℂ)) + (hL : Function.Surjective L) {a : E} (ha : L a = 0) : + IsRegularAnalyticSetAt (L ⁻¹' {0}) a q := by + exact ⟨ha, OpenPartialHomeomorph.refl E, L, isBiholomorphic_refl, + Set.mem_univ a, hL, fun _ _ => Iff.rfl⟩ + +/-- A scalar defining equation with nonzero derivative defines a regular hypersurface. -/ +theorem isRegularAnalyticSetAt_of_scalar_equation [FiniteDimensional ℂ E] + {A V : Set E} {a : E} (haA : a ∈ A) (hV : IsOpen V) (haV : a ∈ V) + {f : E → ℂ} (hf : AnalyticOnNhd ℂ f V) + (hEq : ∀ z ∈ V, z ∈ A ↔ f z = 0) (hd : fderiv ℂ f a ≠ 0) : + IsRegularAnalyticSetAt A a 1 := by + have hs : Function.Surjective (fderiv ℂ f a) := by + apply LinearMap.surjective (f := (fderiv ℂ f a).toLinearMap) + intro h + apply hd + ext z + exact congrArg (fun L : E →ₗ[ℂ] ℂ => L z) h + apply isRegularAnalyticSetAt_of_equations (f := fun z (_ : Fin 1) => f z) + haA hV haV (AnalyticOnNhd.pi (fun _ => hf)) + · intro z hz + simpa [funext_iff] using hEq z hz + · rw [fderiv_pi (fun _ => (hf a haV).differentiableAt)] + intro y + obtain ⟨z, hz⟩ := hs (y 0) + refine ⟨z, ?_⟩ + ext i + fin_cases i + exact hz + +/-- A scalar zero set contained in a regular hypersurface is itself regular at each of its points on +that hypersurface. Persistence of zeros gives local equality. -/ +theorem IsRegularAnalyticSetAt.of_zeroSet_subset [FiniteDimensional ℂ E] + {A U : Set E} {a : E} (hA : IsRegularAnalyticSetAt A a 1) + (hU : IsOpen U) (haU : a ∈ U) {f : E → ℂ} (hf : AnalyticOnNhd ℂ f U) + (hfa : f a = 0) (hsub : ∀ z ∈ U, f z = 0 → z ∈ A) : + IsRegularAnalyticSetAt (U ∩ f ⁻¹' {0}) a 1 := by + obtain ⟨haA, e, L, he, hae, hL, hEq⟩ := hA + let l : E →L[ℂ] ℂ := (ContinuousLinearMap.proj (0 : Fin 1)).comp L + have hl (z : E) : l z = 0 ↔ L z = 0 := by + constructor + · intro hz + ext i + fin_cases i + exact hz + · intro hz + simp [l, hz] + have hls : Function.Surjective l := by + intro c + obtain ⟨z, hz⟩ := hL (fun _ => c) + exact ⟨z, by simp [l, hz]⟩ + let V := e.target ∩ e.symm ⁻¹' U + have hV : IsOpen V := e.isOpen_inter_preimage_symm hU + have hea : e a ∈ V := ⟨e.map_source hae, by simpa [e.left_inv hae] using haU⟩ + have hF : AnalyticOnNhd ℂ (f ∘ e.symm) V := by + intro y hy + exact (hf (e.symm y) hy.2).comp + ((he.2.analyticOnNhd_of_finiteDimensional e.open_target) y hy.1) + have hlocal := eventually_zeroSet_eq_linear_zeroSet hV hF hls hea + (by simpa [Function.comp_def, e.left_inv hae] using hfa) + ((hl (e a)).2 ((hEq a hae).1 haA)) (by + intro y hy hfy + apply (hl y).2 + have hAy := hsub (e.symm y) hy.2 hfy + simpa [e.right_inv hy.1] using (hEq (e.symm y) (e.map_target hy.1)).1 hAy) + have hnear : ∀ᶠ z in 𝓝 a, z ∈ U ∧ z ∈ e.source ∧ (f z = 0 ↔ L (e z) = 0) := by + filter_upwards [hU.eventually_mem haU, e.open_source.eventually_mem hae, + (e.continuousAt hae).eventually hlocal] with z hz hze heq + have heq' : f z = 0 ↔ l (e z) = 0 := by + simpa only [Function.comp_apply, e.left_inv hze] using heq + exact ⟨hz, hze, heq'.trans (hl (e z))⟩ + obtain ⟨T, hTsub, hT, haT⟩ := mem_nhds_iff.mp hnear + refine ⟨⟨haU, hfa⟩, e.restr T, L, he.restr T, ?_, hL, ?_⟩ + · rw [e.restr_source' T hT] + exact ⟨hae, haT⟩ + · intro z hz + rw [e.restr_source' T hT] at hz + have hzT := hTsub hz.2 + change (z ∈ U ∧ f z = 0) ↔ L (e z) = 0 + exact (and_iff_right hzT.1).trans hzT.2.2 + +/-- **Regular points of a hypersurface.** A nonempty proper scalar zero set in a +preconnected domain contains a regular point of codimension one. The nonempty zero-set +hypothesis repairs its omission in the printed [Fritzsche–Grauert][FritzscheGrauert2002] I, +Proposition 8.4. +Choose a minimal nonvanishing derivative, straighten its preceding derivative, +and use persistence of zeros to identify the two hypersurfaces locally. -/ +theorem exists_regularPoint_zeroSet [FiniteDimensional ℂ E] + {U : Set E} (hU : IsOpen U) (hc : IsPreconnected U) {f : E → ℂ} + (hf : AnalyticOnNhd ℂ f U) (hne : ∃ b ∈ U, f b ≠ 0) (hz : ∃ a ∈ U, f a = 0) : + ∃ a, IsRegularAnalyticSetAt (U ∩ f ⁻¹' {0}) a 1 := by + obtain ⟨a, g, ha, hfa, hg, hsub, hd⟩ := + exists_analytic_zeroSet_superset_fderiv_ne_zero hU hc hf hne hz + have hreg : IsRegularAnalyticSetAt (U ∩ g ⁻¹' {0}) a 1 := + isRegularAnalyticSetAt_of_scalar_equation ⟨ha, hsub a ha hfa⟩ hU ha hg + (fun z hz => and_iff_right hz) hd + exact ⟨a, hreg.of_zeroSet_subset hU ha hf hfa (fun z hz hfz => ⟨hz, hsub z hz hfz⟩)⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Removable.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Removable.lean new file mode 100644 index 0000000000..aa263ee677 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/AnalyticSet/Removable.lean @@ -0,0 +1,138 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Connected + +/-! +# Proper analytic subsets and the first Riemann extension theorem + +An analytic subset with empty interior is locally contained in proper scalar zero sets. In a +preconnected domain, properness suffices. This connects local finite equations with the existing +Banach-valued removability and connected-complement theory. For disconnected domains we retain +the empty-interior condition explicitly. + +References: [Range][Range1986] I, Theorem 3.8; [Fritzsche–Grauert][FritzscheGrauert2002] I, +8.1–8.2; [Scheidemann][Scheidemann2005] 4.1.6, 4.2.1–4.2.2. + +## Main results + +`IsAnalyticSet.interior_eq_empty` is emptiness of the interior of a proper analytic subset of a +preconnected domain. `IsAnalyticSet.locallyContainedInAnalyticZeroSet` places a proper analytic +subset in proper scalar zero sets. `IsAnalyticSet.exists_extension_of_locally_bounded` is the +first Riemann extension theorem for locally bounded Banach-valued maps. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- An analytic subset with interior in a preconnected ambient domain is the whole domain. -/ +theorem IsAnalyticSet.eq_domain_of_interior_nonempty {U A : Set E} + (hA : IsAnalyticSet U A) (hc : IsPreconnected U) (hne : (interior A).Nonempty) : + A = U := by + let : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ ℂ E + apply Subset.antisymm hA.subset + apply Subset.trans _ interior_subset + apply hc.subset_of_closure_inter_subset isOpen_interior + · obtain ⟨a, ha⟩ := hne + exact ⟨a, hA.subset (interior_subset ha), ha⟩ + · rintro a ⟨haC, haU⟩ + obtain ⟨V, hV, haV, _, s, hs, he⟩ := hA.2 a haU + obtain ⟨r, hr, hBV⟩ := Metric.mem_nhds_iff.mp (hV.mem_nhds haV) + obtain ⟨b, hbI, hbr⟩ := Metric.mem_closure_iff.mp haC r hr + have hbB : b ∈ ball a r := by simpa [dist_comm] using hbr + have hzero : ∀ f ∈ s, EqOn f 0 (ball a r) := by + intro f hfs + apply ((hs f hfs).mono hBV).eqOn_zero_of_preconnected_of_eventuallyEq_zero + isPreconnected_ball hbB + filter_upwards [isOpen_interior.mem_nhds hbI, isOpen_ball.mem_nhds hbB] with z hzI hzB + exact (he z (hBV hzB)).mp (interior_subset hzI) f hfs + apply mem_interior_iff_mem_nhds.mpr + filter_upwards [ball_mem_nhds a hr] with z hz + exact (he z (hBV hz)).mpr (fun f hf => hzero f hf hz) + +/-- A proper analytic subset of a preconnected domain has empty interior. -/ +theorem IsAnalyticSet.interior_eq_empty {U A : Set E} (hA : IsAnalyticSet U A) + (hc : IsPreconnected U) (hp : A ≠ U) : interior A = ∅ := by + by_contra hn + exact hp (hA.eq_domain_of_interior_nonempty hc (Set.nonempty_iff_ne_empty.mpr hn)) + +/-- An analytic subset with empty interior is locally contained in a proper scalar zero set. -/ +theorem IsAnalyticSet.locallyContainedInAnalyticZeroSet {U A : Set E} + (hA : IsAnalyticSet U A) (hi : interior A = ∅) : LocallyContainedInAnalyticZeroSet U A := by + classical + unfold LocallyContainedInAnalyticZeroSet + intro a ha + obtain ⟨V, hV, haV, hVU, s, hs, he⟩ := hA.2 a ha + have hn : ∃ f ∈ s, ¬ f =ᶠ[𝓝 a] 0 := by + by_contra! hall + have hz : ∀ᶠ z in 𝓝 a, ∀ f ∈ s, f z = 0 := (eventually_all_finset s).mpr hall + have haI : a ∈ interior A := by + apply mem_interior_iff_mem_nhds.mpr + filter_upwards [hV.mem_nhds haV, hz] with z hzV hzall + exact (he z hzV).mpr hzall + simp [hi] at haI + obtain ⟨f, hfs, hfn⟩ := hn + exact ⟨V, f, hV, haV, hVU, hs f hfs, hfn, + fun z hz => (he z hz.1).mp hz.2 f hfs⟩ + +/-- The complement of an analytic subset with empty interior is dense in the ambient domain. -/ +theorem IsAnalyticSet.subset_closure_sdiff {U A : Set E} (hA : IsAnalyticSet U A) + (hi : interior A = ∅) : U ⊆ closure (U \ A) := + (hA.locallyContainedInAnalyticZeroSet hi).subset_closure + +/-- Continuous extensions across a proper analytic exceptional set are unique on the domain. -/ +theorem IsAnalyticSet.extension_unique {F : Type*} [TopologicalSpace F] [T2Space F] + {U A : Set E} (hA : IsAnalyticSet U A) (hi : interior A = ∅) + {f g h : E → F} (hg : ContinuousOn g U) (hh : ContinuousOn h U) + (hgf : EqOn g f (U \ A)) (hhf : EqOn h f (U \ A)) : EqOn g h U := + (hA.locallyContainedInAnalyticZeroSet hi).extension_unique hg hh hgf hhf + +/-- A proper analytic subset cannot disconnect a connected open domain. -/ +theorem IsAnalyticSet.isConnected_sdiff [FiniteDimensional ℂ E] + {U A : Set E} (hA : IsAnalyticSet U A) (hc : IsConnected U) (hp : A ≠ U) : + IsConnected (U \ A) := + isConnected_sdiff_of_locallyContainedInAnalyticZeroSet hc hA.isOpen_sdiff + (hA.locallyContainedInAnalyticZeroSet (hA.interior_eq_empty hc.isPreconnected hp)) + +/-- **First Riemann extension theorem.** Local boundedness is required only near the +exceptional set. Empty interior replaces componentwise properness on a disconnected domain. +The extension is unique on `U` by `IsAnalyticSet.extension_unique`. -/ +theorem IsAnalyticSet.exists_extension_of_locally_bounded [FiniteDimensional ℂ E] + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {U A : Set E} (hA : IsAnalyticSet U A) (hi : interior A = ∅) {f : E → F} + (hf : AnalyticOnNhd ℂ f (U \ A)) + (hb : ∀ a ∈ A, ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ (U \ A), ‖f z‖ ≤ C) : + ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ A) := by + apply exists_analyticOnNhd_extension_across_locallyContainedZeroSet hA.isOpen_sdiff + (hA.locallyContainedInAnalyticZeroSet hi) hf + intro a ha + by_cases haA : a ∈ A + · exact hb a haA + · have hn : ∀ᶠ z in 𝓝 a, ‖f z‖ < ‖f a‖ + 1 := + ((hf a ⟨ha, haA⟩).continuousAt.norm).eventually_lt_const (by linarith) + obtain ⟨r, hr, hbound⟩ := Metric.mem_nhds_iff.mp hn + exact ⟨r, hr, ‖f a‖ + 1, fun z hz => (hbound hz.1).le⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analyticity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analyticity.lean new file mode 100644 index 0000000000..a8b5d086cc --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Analyticity.lean @@ -0,0 +1,106 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Constructions +public import Mathlib.Analysis.Calculus.Deriv.Pi +public import Mathlib.Analysis.Complex.CauchyIntegral +public import Mathlib.Analysis.Normed.Module.FiniteDimension +public import Mathlib.LinearAlgebra.FiniteDimensional.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Osgood + +/-! +# Analyticity of holomorphic maps in finite dimension + +This file proves the several-complex-variables theorem that a complex Fréchet-differentiable map on +an open subset of a finite-dimensional complex normed space is analytic. The general theorem uses +coordinates only inside its proof. The file is a temporary project home for material ultimately +intended for a Mathlib location such as `Mathlib.Analysis.Complex.SeveralVariables.Analyticity`. It +builds on the polydisc Cauchy-series and Osgood theorems; the underlying predicates are Mathlib +definitions. + +## Main results + +`DifferentiableOn.analyticOnNhd_of_finiteDimensional` and +`differentiableOn_iff_analyticOnNhd_of_finiteDimensional` give the coordinate-free interface for +arbitrary finite-dimensional complex normed domains and complete complex normed codomains. + +`DifferentiableOn.analyticOnNhd_pi` and `differentiableOn_iff_analyticOnNhd_pi` give the +corresponding interface for finite coordinate spaces `ι → ℂ`. Such spaces are natural for +separate holomorphy, coordinate derivatives, and polydisc expansions. The coordinate theorem is +proved first and then transported along a linear equivalence; this proof order imposes no choice +of coordinates on the general statements. +-/ + +public section + +open Set + +section Coordinates + +variable {ι F : Type*} [Fintype ι] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- A complex Fréchet-differentiable map on an open subset of a finite complex coordinate space is +analytic there. -/ +theorem DifferentiableOn.analyticOnNhd_pi {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : DifferentiableOn ℂ f U) (hU : IsOpen U) : AnalyticOnNhd ℂ f U := by + classical + apply SeveralComplexVariables.analyticOnNhd_pi_of_analyticOnNhd_update hU hf.continuousOn + intro z hz i + let V : Set ℂ := {w | Function.update z i w ∈ U} + have hupdate : Continuous (fun w : ℂ ↦ Function.update z i w) := by fun_prop + have hupdate_diff : Differentiable ℂ (fun w : ℂ ↦ Function.update z i w) := + fun w => (hasDerivAt_update z i w).differentiableAt + have hV : IsOpen V := hU.preimage hupdate + have hd : DifferentiableOn ℂ (fun w ↦ f (Function.update z i w)) V := by + intro w hw + exact (((hf _ hw).differentiableAt (hU.mem_nhds hw)).comp w + hupdate_diff.differentiableAt).differentiableWithinAt + exact hd.analyticAt (hV.mem_nhds (by simpa [V] using hz)) + +/-- On an open subset of a finite complex coordinate space, complex Fréchet differentiability and +analyticity are equivalent. -/ +theorem differentiableOn_iff_analyticOnNhd_pi {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hU : IsOpen U) : DifferentiableOn ℂ f U ↔ AnalyticOnNhd ℂ f U := + ⟨fun hf ↦ hf.analyticOnNhd_pi hU, fun hf ↦ hf.differentiableOn⟩ + +end Coordinates + +section FiniteDimensional + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Complex differentiability on an open finite-dimensional domain implies analyticity. No choice of +coordinates occurs in the statement. -/ +theorem DifferentiableOn.analyticOnNhd_of_finiteDimensional {U : Set E} {f : E → F} + (hf : DifferentiableOn ℂ f U) (hU : IsOpen U) : AnalyticOnNhd ℂ f U := by + let e := (Module.finBasis ℂ E).equivFunL + have hg : DifferentiableOn ℂ (f ∘ e.symm) (e.symm ⁻¹' U) := + hf.comp e.symm.differentiable.differentiableOn (fun _ hx => hx) + have ha := hg.analyticOnNhd_pi (hU.preimage e.symm.continuous) + intro x hx + have hmem : e x ∈ e.symm ⁻¹' U := by simpa using hx + simpa [Function.comp_def] using + (ha (e x) hmem).comp_of_eq (e.toContinuousLinearMap.analyticAt x) rfl + +/-- On an open finite-dimensional domain, holomorphy may be expressed using either complex Fréchet +differentiability or Mathlib's analytic predicate. -/ +theorem differentiableOn_iff_analyticOnNhd_of_finiteDimensional {U : Set E} {f : E → F} + (hU : IsOpen U) : DifferentiableOn ℂ f U ↔ AnalyticOnNhd ℂ f U := + ⟨fun hf => hf.analyticOnNhd_of_finiteDimensional hU, fun hf => hf.differentiableOn⟩ + +/-- An everywhere complex-differentiable map on a finite-dimensional space is entire. -/ +theorem Differentiable.analyticOnNhd_of_finiteDimensional {f : E → F} + (hf : Differentiable ℂ f) : AnalyticOnNhd ℂ f Set.univ := + hf.differentiableOn.analyticOnNhd_of_finiteDimensional isOpen_univ + +end FiniteDimensional + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/BallAutomorphisms.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/BallAutomorphisms.lean new file mode 100644 index 0000000000..a5688fe619 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/BallAutomorphisms.lean @@ -0,0 +1,385 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Schwarz +public import Mathlib.Analysis.InnerProductSpace.PiL2 +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.BiholomorphicRigidity + +import Mathlib.Tactic.Module + +/-! +# Automorphisms of the Euclidean ball and the ball–polydisc distinction + +The explicit involution exchanges an interior point with zero. Holomorphy, a nonvanishing +denominator, the metric identity, preservation of the ball, and involutivity are proved. +Packaging as a biholomorphism and transitivity are proved consequences, independent of Cartan +uniqueness and circular-domain rigidity. The ball–polydisc inequivalence follows independently +from Schwarz bounds on derivatives and the parallelogram identity in dimension at least two. The +source uses the supremum norm and the target uses `EuclideanSpace`, explicitly. References: +[Scheidemann][Scheidemann2005] (2005), Theorem 3.2.1 and Exercise 3.3.4. + +## Main definitions + +* `ballParallelComponent`: Projection onto the complex line through `a`, with value zero when `a = + 0`. +* `ballMobius`: The standard ball involution. +* `ballMobiusOpenPartialHomeomorph`: The standard involution as an equivalence of open unit balls, + with an explicit formula. + +## Main results + +* `ballMobius_norm_identity`: The metric identity for the standard ball map, expressed without + division. +* `mapsTo_ballMobius`: The standard ball map preserves the unit ball, by its metric identity. +* `ballMobius_ballMobius`: The ball automorphism is an involution of the unit ball, using the + parallel and perpendicular components. +* `isBiholomorphic_ballMobius`: Both directions of the explicit ball equivalence are holomorphic. +* `exists_ball_automorphism`: The unit ball is homogeneous under biholomorphic automorphisms: any + interior point can be sent to any other, by composing two explicit ball involutions. +* `not_exists_isBiholomorphic_polydisc_ball`: The Euclidean unit ball and the unit polydisc are not + biholomorphic in dimension at least two. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Metric +open scoped InnerProductSpace + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℂ E] + +/-- Projection onto the complex line through `a`, with value zero when `a = 0`. -/ +@[expose] def ballParallelComponent (a z : E) : E := + (⟪a, z⟫_ℂ / (‖a‖ : ℂ) ^ 2) • a + +/-- The standard ball involution. Mathlib's inner product is linear in its second argument; the +scalar in the perpendicular component is `sqrt (1 - ‖a‖²)`. -/ +@[expose] def ballMobius (a z : E) : E := + (1 - ⟪a, z⟫_ℂ)⁻¹ • + (a - ballParallelComponent a z - + (Real.sqrt (1 - ‖a‖ ^ 2) : ℂ) • (z - ballParallelComponent a z)) + +/-- At the origin, the standard involution is negation, including dimension zero. -/ +theorem ballMobius_zero (z : E) : ballMobius 0 z = -z := by + simp [ballMobius, ballParallelComponent] + +/-- The ball involution exchanges zero with its parameter. -/ +theorem ballMobius_apply_zero (a : E) : ballMobius a 0 = a := by + simp [ballMobius, ballParallelComponent] + +/-- The ball involution sends its parameter to zero. -/ +theorem ballMobius_apply_self (a : E) : ballMobius a a = 0 := by + by_cases ha : a = 0 + · simp [ha, ballMobius_zero] + · have hn : (‖a‖ : ℂ) ^ 2 ≠ 0 := pow_ne_zero 2 (by exact_mod_cast (norm_ne_zero_iff.mpr ha)) + simp [ballMobius, ballParallelComponent, inner_self_eq_norm_sq_to_K, div_self hn] + +/-- The denominator in the ball involution is nonzero on the unit ball. -/ +theorem ballMobius_denominator_ne_zero {a z : E} (ha : a ∈ ball 0 1) (hz : z ∈ ball 0 1) : + 1 - ⟪a, z⟫_ℂ ≠ 0 := by + have ha' : ‖a‖ < 1 := by simpa only [mem_ball, dist_zero_right] using ha + have hz' : ‖z‖ < 1 := by simpa only [mem_ball, dist_zero_right] using hz + have hi : ‖⟪a, z⟫_ℂ‖ < 1 := calc + ‖⟪a, z⟫_ℂ‖ ≤ ‖a‖ * ‖z‖ := norm_inner_le_norm _ _ + _ ≤ 1 * ‖z‖ := mul_le_mul_of_nonneg_right ha'.le (norm_nonneg _) + _ < 1 := by simpa using hz' + intro h + have he := (sub_eq_zero.mp h).symm + simp [he] at hi + +/-- The projection formula is complex differentiable even for the zero parameter. -/ +theorem differentiable_ballParallelComponent (a : E) : Differentiable ℂ (ballParallelComponent a) + := by + unfold ballParallelComponent + simpa only [innerSL_apply_apply, div_eq_mul_inv] using + ((innerSL ℂ a).differentiable.mul_const (((‖a‖ : ℂ) ^ 2)⁻¹)).smul_const a + +/-- The explicit ball involution is holomorphic on the unit ball. -/ +theorem differentiableOn_ballMobius {a : E} (ha : a ∈ ball 0 1) : + DifferentiableOn ℂ (ballMobius a) (ball 0 1) := by + intro z hz + have hi : DifferentiableAt ℂ (fun w => ⟪a, w⟫_ℂ) z := (innerSL ℂ a).differentiableAt + have hp := differentiable_ballParallelComponent a z + exact ((((differentiableAt_const (1 : ℂ)).sub hi).inv + (ballMobius_denominator_ne_zero ha hz)).smul + (((differentiableAt_const a).sub hp).sub + ((differentiableAt_const (Real.sqrt (1 - ‖a‖ ^ 2) : ℂ)).smul + (differentiableAt_id.sub hp)))).differentiableWithinAt + +/-- Orthogonal projection onto the parameter line preserves its inner product with the parameter. -/ +theorem inner_ballParallelComponent (a z : E) : + ⟪a, ballParallelComponent a z⟫_ℂ = ⟪a, z⟫_ℂ := by + by_cases ha : a = 0 + · simp [ha] + · have hn : (‖a‖ : ℂ) ^ 2 ≠ 0 := by exact_mod_cast pow_ne_zero 2 (norm_ne_zero_iff.mpr ha) + simp [ballParallelComponent, inner_smul_right, inner_self_eq_norm_sq_to_K, hn] + +/-- The squared norm of the parallel component, in a form valid also for a zero parameter. -/ +theorem norm_ballParallelComponent_sq_mul (a z : E) : + ‖ballParallelComponent a z‖ ^ 2 * ‖a‖ ^ 2 = ‖⟪a, z⟫_ℂ‖ ^ 2 := by + by_cases ha : a = 0 + · simp [ha] + · have hn := norm_ne_zero_iff.mpr ha + simp only [ballParallelComponent, norm_smul, norm_div, norm_pow, + Complex.norm_real, Real.norm_eq_abs, abs_norm] + field_simp + +/-- The metric identity for the standard ball map, expressed without division. -/ +theorem ballMobius_norm_identity {a z : E} (ha : a ∈ ball 0 1) (hz : z ∈ ball 0 1) : + (1 - ‖ballMobius a z‖ ^ 2) * ‖1 - ⟪a, z⟫_ℂ‖ ^ 2 = + (1 - ‖a‖ ^ 2) * (1 - ‖z‖ ^ 2) := by + let p := ballParallelComponent a z + let q := z - p + let s := Real.sqrt (1 - ‖a‖ ^ 2) + have ha' : ‖a‖ < 1 := by simpa using ha + have hs : s ^ 2 = 1 - ‖a‖ ^ 2 := Real.sq_sqrt (by nlinarith [norm_nonneg a]) + have haq : ⟪a, q⟫_ℂ = 0 := by + simp [q, p, inner_sub_right, inner_ballParallelComponent] + have hpq : ⟪p, q⟫_ℂ = 0 := by + simp only [p, ballParallelComponent, inner_smul_left, haq, mul_zero] + have horth : ⟪a - p, (s : ℂ) • q⟫_ℂ = 0 := by + simp only [inner_smul_right, inner_sub_left, haq, hpq, sub_self, mul_zero] + have hq : ‖z‖ ^ 2 = ‖p‖ ^ 2 + ‖q‖ ^ 2 := by + have h := norm_add_sq (𝕜 := ℂ) p q + simpa only [q, add_sub_cancel, hpq, map_zero, mul_zero, add_zero] using h + have hp : ‖a - p‖ ^ 2 = ‖a‖ ^ 2 - 2 * (⟪a, z⟫_ℂ).re + ‖p‖ ^ 2 := by + simpa only [p, inner_ballParallelComponent, RCLike.re_to_complex] using + (norm_sub_sq (𝕜 := ℂ) a p) + have hN : ‖a - p - (s : ℂ) • q‖ ^ 2 = + ‖a‖ ^ 2 - 2 * (⟪a, z⟫_ℂ).re + ‖⟪a, z⟫_ℂ‖ ^ 2 + + (1 - ‖a‖ ^ 2) * ‖z‖ ^ 2 := by + have h := norm_sub_sq (𝕜 := ℂ) (a - p) ((s : ℂ) • q) + simp only [horth, map_zero, mul_zero, sub_zero, norm_smul, Complex.norm_real, + Real.norm_eq_abs, mul_pow, sq_abs] at h + have hpp := norm_ballParallelComponent_sq_mul a z + change ‖p‖ ^ 2 * ‖a‖ ^ 2 = _ at hpp + rw [hs, hp] at h + nlinarith [hq] + have hd : ‖1 - ⟪a, z⟫_ℂ‖ ≠ 0 := norm_ne_zero_iff.mpr (ballMobius_denominator_ne_zero ha hz) + have hscale : ‖ballMobius a z‖ ^ 2 * ‖1 - ⟪a, z⟫_ℂ‖ ^ 2 = + ‖a - p - (s : ℂ) • q‖ ^ 2 := by + simp only [ballMobius, norm_smul, norm_inv, mul_pow, p, q, s] + field_simp + have hden : ‖1 - ⟪a, z⟫_ℂ‖ ^ 2 = 1 - 2 * (⟪a, z⟫_ℂ).re + ‖⟪a, z⟫_ℂ‖ ^ 2 := by + simp only [Complex.sq_norm, Complex.normSq_apply, Complex.sub_re, Complex.one_re, + Complex.sub_im, Complex.one_im] + ring + rw [hN] at hscale + nlinarith + +/-- The standard ball map preserves the unit ball, by its metric identity. -/ +theorem mapsTo_ballMobius {a : E} (ha : a ∈ ball 0 1) : + MapsTo (ballMobius a) (ball 0 1) (ball 0 1) := by + intro z hz + have ha' : ‖a‖ < 1 := by simpa using ha + have hz' : ‖z‖ < 1 := by simpa using hz + have hpos : 0 < (1 - ‖a‖ ^ 2) * (1 - ‖z‖ ^ 2) := + mul_pos (by nlinarith [norm_nonneg a]) (by nlinarith [norm_nonneg z]) + rw [← ballMobius_norm_identity ha hz] at hpos + have hn : 0 < 1 - ‖ballMobius a z‖ ^ 2 := + pos_of_mul_pos_left hpos (sq_nonneg _) + simpa only [mem_ball, dist_zero_right] using + (show ‖ballMobius a z‖ < 1 by nlinarith [norm_nonneg (ballMobius a z)]) + +/-- The ball automorphism is an involution of the unit ball, using the parallel and perpendicular +components. -/ +theorem ballMobius_ballMobius {a : E} (ha : a ∈ ball 0 1) : + ∀ z ∈ ball 0 1, ballMobius a (ballMobius a z) = z := by + intro z hz + let s : ℂ := (Real.sqrt (1 - ‖a‖ ^ 2) : ℂ) + let A : ℂ := (‖a‖ : ℂ) ^ 2 + let P : E →ₗ[ℂ] E := A⁻¹ • (innerSL ℂ a).toLinearMap.smulRight a + let T : E →ₗ[ℂ] E := P + s • (LinearMap.id - P) + have hP (w : E) : P w = ballParallelComponent a w := by + simp only [P, A, LinearMap.smul_apply, LinearMap.smulRight_apply, + ContinuousLinearMap.coe_coe, innerSL_apply_apply, ballParallelComponent, div_eq_mul_inv] + module + have hT (w : E) : T w = P w + s • (w - P w) := rfl + have hiP (w : E) : ⟪a, P w⟫_ℂ = ⟪a, w⟫_ℂ := by + rw [hP, inner_ballParallelComponent] + have hiT (w : E) : ⟪a, T w⟫_ℂ = ⟪a, w⟫_ℂ := by + simp only [hT, inner_add_right, inner_smul_right, inner_sub_right, hiP, + sub_self, mul_zero, add_zero] + have hPa : P a = a := by + by_cases h : a = 0 + · simp [h] + · have hn : A ≠ 0 := by dsimp [A]; exact_mod_cast pow_ne_zero 2 (norm_ne_zero_iff.mpr h) + simp [hP, ballParallelComponent, inner_self_eq_norm_sq_to_K, A, hn] + have hTa : T a = a := by rw [hT, hPa]; simp + have hAP (w : E) : A • P w = ⟪a, w⟫_ℂ • a := by + by_cases h : a = 0 + · simp [A, h] + · have hn : A ≠ 0 := by dsimp [A]; exact_mod_cast pow_ne_zero 2 (norm_ne_zero_iff.mpr h) + simp [P, smul_smul, hn] + have hs : s ^ 2 = 1 - A := by + have ha' : ‖a‖ < 1 := by simpa using ha + have h := Real.sq_sqrt (show 0 ≤ 1 - ‖a‖ ^ 2 by nlinarith [norm_nonneg a]) + dsimp [s, A] + exact_mod_cast h + have hPT (w : E) : P (T w) = P w := by + simp only [hP, ballParallelComponent, hiT] + have hTT (w : E) : T (T w) = (1 - A) • w + ⟪a, w⟫_ℂ • a := by + calc + T (T w) = P w + s ^ 2 • (w - P w) := by rw [hT, hPT, hT]; module + _ = (1 - A) • w + A • P w := by rw [hs]; module + _ = _ := by rw [hAP] + have hmob (w : E) : ballMobius a w = (1 - ⟪a, w⟫_ℂ)⁻¹ • (a - T w) := by + rw [ballMobius, hT, hP] + dsimp [s] + module + let c := ⟪a, z⟫_ℂ + let d := 1 - c + have hd : d ≠ 0 := ballMobius_denominator_ne_zero ha hz + have hd' : 1 - ⟪a, ballMobius a z⟫_ℂ ≠ 0 := + ballMobius_denominator_ne_zero ha (mapsTo_ballMobius ha hz) + have hden : d * (1 - ⟪a, ballMobius a z⟫_ℂ) = 1 - A := by + rw [hmob] + simp only [inner_smul_right, inner_sub_right, inner_self_eq_norm_sq_to_K, hiT] + change d * (1 - d⁻¹ * (A - c)) = 1 - A + field_simp + dsimp [d] + ring + rw [hmob, inv_smul_eq_iff₀ hd'] + apply smul_right_injective E hd + change d • (a - T (ballMobius a z)) = d • ((1 - ⟪a, ballMobius a z⟫_ℂ) • z) + rw [smul_sub] + conv_lhs => rw [hmob, map_smul, map_sub, hTa, hTT] + change d • a - d • (d⁻¹ • (a - ((1 - A) • z + c • a))) = + d • ((1 - ⟪a, ballMobius a z⟫_ℂ) • z) + rw [smul_inv_smul₀ hd, smul_smul, hden] + dsimp [d] + module + +/-- The standard involution as an equivalence of open unit balls, with an explicit formula. -/ +@[expose] def ballMobiusOpenPartialHomeomorph (a : E) (ha : a ∈ ball 0 1) : + OpenPartialHomeomorph E E where + toFun := ballMobius a + invFun := ballMobius a + source := ball 0 1 + target := ball 0 1 + map_source' := mapsTo_ballMobius ha + map_target' := mapsTo_ballMobius ha + left_inv' := ballMobius_ballMobius ha + right_inv' := ballMobius_ballMobius ha + continuousOn_toFun := (differentiableOn_ballMobius ha).continuousOn + continuousOn_invFun := (differentiableOn_ballMobius ha).continuousOn + open_source := isOpen_ball + open_target := isOpen_ball + +/-- Both directions of the explicit ball equivalence are holomorphic. -/ +theorem isBiholomorphic_ballMobius (a : E) (ha : a ∈ ball 0 1) : + IsBiholomorphic (ballMobiusOpenPartialHomeomorph a ha) := + ⟨differentiableOn_ballMobius ha, differentiableOn_ballMobius ha⟩ + +/-- The unit ball is homogeneous under biholomorphic automorphisms: any interior point can be sent +to any other, by composing two explicit ball involutions. -/ +theorem exists_ball_automorphism {a b : E} + (ha : a ∈ ball 0 1) (hb : b ∈ ball 0 1) : + ∃ e : OpenPartialHomeomorph E E, IsBiholomorphic e ∧ + e.source = ball 0 1 ∧ e.target = ball 0 1 ∧ e a = b := by + let A := ballMobiusOpenPartialHomeomorph a ha + let B := ballMobiusOpenPartialHomeomorph b hb + refine ⟨A.trans B, (isBiholomorphic_ballMobius a ha).trans (isBiholomorphic_ballMobius b hb), + ?_, ?_, ?_⟩ + · rw [OpenPartialHomeomorph.trans_source] + exact inter_eq_left.mpr (mapsTo_ballMobius ha) + · rw [OpenPartialHomeomorph.trans_target] + exact inter_eq_left.mpr (mapsTo_ballMobius hb) + · change ballMobius b (ballMobius a a) = b + rw [ballMobius_apply_self a, ballMobius_apply_zero] + +/-- The derivative at zero of an origin-preserving biholomorphism between unit balls preserves +norms. Schwarz bounds for the map and its inverse prove both inequalities, without Cartan +uniqueness or finite-dimensional assumptions. -/ +theorem IsBiholomorphic.norm_fderiv_apply_eq_of_unit_ball + {A B : Type*} [NormedAddCommGroup A] [NormedSpace ℂ A] + [NormedAddCommGroup B] [NormedSpace ℂ B] + {e : OpenPartialHomeomorph A B} (he : IsBiholomorphic e) + (hs : e.source = ball 0 1) (ht : e.target = ball 0 1) (hfix : e 0 = 0) + (x : A) : ‖fderiv ℂ e 0 x‖ = ‖x‖ := by + have hzero : (0 : A) ∈ e.source := by rw [hs]; exact mem_ball_self zero_lt_one + have hinv : e.symm 0 = 0 := by simpa [hfix] using e.left_inv hzero + have hd : ‖fderiv ℂ e 0‖ ≤ 1 := + Complex.norm_fderiv_le_one_of_mapsTo_ball (hs ▸ he.1) + (fun z hz => by + rw [hfix] + exact ball_subset_closedBall (ht ▸ e.map_source (hs ▸ hz))) zero_lt_one + have hi : ‖fderiv ℂ e.symm 0‖ ≤ 1 := + Complex.norm_fderiv_le_one_of_mapsTo_ball (ht ▸ he.2) + (fun z hz => by + rw [hinv] + exact ball_subset_closedBall (hs ▸ e.map_target (ht ▸ hz))) zero_lt_one + have hleft : fderiv ℂ e.symm 0 (fderiv ℂ e 0 x) = x := by + simpa [hfix] using DFunLike.congr_fun (he.fderiv_symm_comp hzero) x + apply le_antisymm + · simpa using (fderiv ℂ e 0).le_of_opNorm_le_of_le hd (le_refl ‖x‖) + · calc + ‖x‖ = ‖fderiv ℂ e.symm 0 (fderiv ℂ e 0 x)‖ := congrArg norm hleft.symm + _ ≤ ‖fderiv ℂ e 0 x‖ := by + simpa using (fderiv ℂ e.symm 0).le_of_opNorm_le_of_le hi + (le_refl ‖fderiv ℂ e 0 x‖) + +/-- The Euclidean unit ball and the unit polydisc are not biholomorphic in dimension at least two. +Normalize at zero using a ball automorphism; Schwarz's lemma makes the derivative +norm-preserving, contradicting the parallelogram identity. This proof is independent of Cartan +uniqueness. The dimension hypothesis excludes the singleton and one-variable cases. -/ +theorem not_exists_isBiholomorphic_polydisc_ball {ι : Type*} [Fintype ι] + (hdim : 2 ≤ Fintype.card ι) : + ¬ ∃ e : OpenPartialHomeomorph (ι → ℂ) (EuclideanSpace ℂ ι), + IsBiholomorphic e ∧ e.source = ball 0 1 ∧ e.target = ball 0 1 := by + classical + rintro ⟨e, he, hs, ht⟩ + have hzero : (0 : ι → ℂ) ∈ e.source := by rw [hs]; exact mem_ball_self zero_lt_one + have ha : e 0 ∈ ball 0 1 := ht ▸ e.map_source hzero + let M := ballMobiusOpenPartialHomeomorph (e 0) ha + let g := e.trans M + have hg : IsBiholomorphic g := he.trans (isBiholomorphic_ballMobius (e 0) ha) + have hgs : g.source = ball 0 1 := by + rw [OpenPartialHomeomorph.trans_source] + change e.source ∩ e ⁻¹' ball 0 1 = ball 0 1 + rw [← ht] + exact (inter_eq_left.mpr (fun z hz => e.map_source hz)).trans hs + have hgt : g.target = ball 0 1 := by + rw [OpenPartialHomeomorph.trans_target] + change ball 0 1 ∩ (ballMobius (e 0)) ⁻¹' e.target = ball 0 1 + rw [ht] + exact inter_eq_left.mpr (mapsTo_ballMobius ha) + have hg0 : g 0 = 0 := ballMobius_apply_self (e 0) + let L := fderiv ℂ g 0 + have hL (x : ι → ℂ) : ‖L x‖ = ‖x‖ := + hg.norm_fderiv_apply_eq_of_unit_ball hgs hgt hg0 x + obtain ⟨i, j, hij⟩ := Fintype.one_lt_card_iff.mp (by omega : 1 < Fintype.card ι) + let u : ι → ℂ := Pi.single i 1 + let v : ι → ℂ := Pi.single j 1 + have hu : ‖u‖ = 1 := by simp [u, Pi.norm_single] + have hv : ‖v‖ = 1 := by simp [v, Pi.norm_single] + have hnorm (c : ℂ) (hc : ‖c‖ = 1) : ‖u + c • v‖ = 1 := by + apply le_antisymm + · apply (pi_norm_le_iff_of_nonneg zero_le_one).mpr + intro k + by_cases hki : k = i + · subst k + simp [u, v, hij] + · by_cases hkj : k = j + · subst k + simp [u, v, hij.symm, hc] + · simp [u, v, hki, hkj] + · simpa [u, v, Pi.single_apply, hij] using norm_le_pi_norm (u + c • v) i + have hadd : ‖u + v‖ = 1 := by simpa using hnorm 1 (by simp) + have hsub : ‖u - v‖ = 1 := by simpa [sub_eq_add_neg] using hnorm (-1) (by simp) + have hp := parallelogram_law_with_norm ℂ (L u) (L v) + rw [← map_add, ← map_sub, hL, hL, hL, hL, hu, hv, hadd, hsub] at hp + norm_num at hp + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Biholomorphic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Biholomorphic.lean new file mode 100644 index 0000000000..6abcf9d9b9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Biholomorphic.lean @@ -0,0 +1,297 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.InverseFunctionTheorem.ContDiff +public import Mathlib.Topology.OpenPartialHomeomorph.Composition +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives + +/-! +# Biholomorphic maps between open sets + +`IsBiholomorphic` adds holomorphy of both maps to Mathlib's `OpenPartialHomeomorph`. The source +and target are already open; connectedness and nonemptiness are not required. The derivative +identities work in complex normed spaces. Equality of dimensions requires a nonempty source. +Local inverse results use finite-dimensional spaces and the existing holomorphic–analytic +equivalence and Mathlib's inverse function theorem. + +Reference: [Range][Range1986] (1986), I §2.4, Theorem 2.5 and Corollary 2.6. The chain rule and +coordinate Jacobian are in `Derivatives`. + +## Main definitions + +* `IsBiholomorphic`: An equivalence between open sets is biholomorphic when both maps are + holomorphic on their respective open domains. +* `affineOpenPartialHomeomorph`: An invertible complex linear map followed by a translation, as an + equivalence of the whole spaces. +* `shearOpenPartialHomeomorph`: A continuous shear has an explicit inverse obtained by subtracting + the same function. + +## Main results + +* `exists_biholomorphic_of_isInvertible_fderiv`: **Holomorphic inverse mapping theorem.** An + invertible complex derivative gives a biholomorphic restriction to an open neighborhood inside the + given open set. +* `exists_open_injOn_of_injective_fderiv`: **[Range][Range1986] I, Corollary 2.6.** An injective + complex derivative gives local injectivity, also when the target has larger dimension. + +## References + +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology ContDiff + +namespace SeveralComplexVariables + +variable {E F G : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [NormedAddCommGroup G] [NormedSpace ℂ G] + +/-- An equivalence between open sets is biholomorphic when both maps are holomorphic on their +respective open domains. No connectedness or nonemptiness is imposed. -/ +@[expose] def IsBiholomorphic (e : OpenPartialHomeomorph E F) : Prop := + DifferentiableOn ℂ e e.source ∧ DifferentiableOn ℂ e.symm e.target + +/-- The inverse of a biholomorphic map is biholomorphic. -/ +theorem IsBiholomorphic.symm {e : OpenPartialHomeomorph E F} (he : IsBiholomorphic e) : + IsBiholomorphic e.symm := ⟨he.2, he.1⟩ + +/-- The identity map of the whole space is biholomorphic. -/ +theorem isBiholomorphic_refl : IsBiholomorphic (OpenPartialHomeomorph.refl E) := + ⟨differentiable_id.differentiableOn, differentiable_id.differentiableOn⟩ + +/-- Compositions of biholomorphic maps are biholomorphic on their natural open source. -/ +theorem IsBiholomorphic.trans {e : OpenPartialHomeomorph E F} + {e' : OpenPartialHomeomorph F G} (he : IsBiholomorphic e) (he' : IsBiholomorphic e') : + IsBiholomorphic (e.trans e') := by + constructor + · exact he'.1.comp (he.1.mono inter_subset_left) (fun _ hx => hx.2) + · exact he.2.comp (he'.2.mono inter_subset_left) (fun _ hx => hx.2) + +/-- Restriction to the intersection of the source with the interior of any set preserves +biholomorphy. For an open set this is ordinary restriction. -/ +theorem IsBiholomorphic.restr {e : OpenPartialHomeomorph E F} (he : IsBiholomorphic e) + (s : Set E) : IsBiholomorphic (e.restr s) := + ⟨he.1.mono inter_subset_left, he.2.mono inter_subset_left⟩ + +/-- A biholomorphic map is complex differentiable at every point of its source. -/ +theorem IsBiholomorphic.differentiableAt {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) {a : E} (ha : a ∈ e.source) : DifferentiableAt ℂ e a := + (he.1 a ha).differentiableAt (e.open_source.mem_nhds ha) + +/-- The derivative of the inverse composed with the forward derivative is the identity. -/ +theorem IsBiholomorphic.fderiv_symm_comp {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) {a : E} (ha : a ∈ e.source) : + (fderiv ℂ e.symm (e a)).comp (fderiv ℂ e a) = ContinuousLinearMap.id ℂ E := by + rw [← fderiv_comp a (he.symm.differentiableAt (e.map_source ha)) (he.differentiableAt ha)] + have h : (e.symm ∘ e) =ᶠ[𝓝 a] id := e.eventually_left_inverse ha + exact h.fderiv_eq.trans fderiv_id + +/-- The forward derivative composed with the derivative of the inverse is the identity. -/ +theorem IsBiholomorphic.fderiv_comp_symm {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) {a : E} (ha : a ∈ e.source) : + (fderiv ℂ e a).comp (fderiv ℂ e.symm (e a)) = ContinuousLinearMap.id ℂ F := by + simpa only [OpenPartialHomeomorph.symm_symm, e.left_inv ha] using + he.symm.fderiv_symm_comp (e.map_source ha) + +/-- The derivative of a biholomorphic map is an invertible continuous complex linear map. -/ +theorem IsBiholomorphic.isInvertible_fderiv {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) {a : E} (ha : a ∈ e.source) : + (fderiv ℂ e a).IsInvertible := + .of_inverse (he.fderiv_comp_symm ha) (he.fderiv_symm_comp ha) + +/-- The derivative of the inverse is the inverse of the derivative. -/ +theorem IsBiholomorphic.fderiv_symm {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) {a : E} (ha : a ∈ e.source) : + fderiv ℂ e.symm (e a) = (fderiv ℂ e a).inverse := + (ContinuousLinearMap.inverse_eq (he.fderiv_comp_symm ha) (he.fderiv_symm_comp ha)).symm + +/-- Nonempty biholomorphically equivalent open sets have equal ambient complex dimensions. +Nonemptiness is essential: empty sets in different dimensions are equivalent. -/ +theorem IsBiholomorphic.finrank_eq {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) (hne : e.source.Nonempty) : + Module.finrank ℂ E = Module.finrank ℂ F := by + obtain ⟨a, ha⟩ := hne + obtain ⟨L, hL⟩ := he.isInvertible_fderiv ha + exact L.toLinearEquiv.finrank_eq + +/-- Holomorphy of a function on the target is equivalent to holomorphy after a biholomorphic change +of coordinates on the source. -/ +theorem IsBiholomorphic.differentiableOn_comp_iff {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) {g : F → G} : + DifferentiableOn ℂ (g ∘ e) e.source ↔ DifferentiableOn ℂ g e.target := by + constructor + · intro h + have hc := h.comp he.2 e.symm.mapsTo + exact hc.congr (fun y hy => congrArg g (e.right_inv hy).symm) + · exact fun h => h.comp he.1 e.mapsTo + +section Inverse + +variable [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] + +/-- **Holomorphic inverse mapping theorem.** An invertible complex derivative gives +a biholomorphic restriction to an open neighborhood inside the given open set. +The forward representative agrees with the original map everywhere. -/ +theorem exists_biholomorphic_of_isInvertible_fderiv {U : Set E} (hU : IsOpen U) + {f : E → F} (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) + (hinv : (fderiv ℂ f a).IsInvertible) : + ∃ e : OpenPartialHomeomorph E F, IsBiholomorphic e ∧ a ∈ e.source ∧ + e.source ⊆ U ∧ (e : E → F) = f := by + let := FiniteDimensional.complete ℂ E + let := FiniteDimensional.complete ℂ F + obtain ⟨L, hL⟩ := hinv + have hfa := hf.analyticOnNhd_of_finiteDimensional hU a ha + have hc : ContDiffAt ℂ ω f a := hfa.contDiffAt + have hd : HasFDerivAt f (L : E →L[ℂ] F) a := by + rw [hL] + exact hfa.differentiableAt.hasFDerivAt + let e := hc.toOpenPartialHomeomorph f hd (by simp) + have hae : a ∈ e.source := hc.mem_toOpenPartialHomeomorph_source hd (by simp) + have hga : AnalyticAt ℂ e.symm (f a) := (hc.to_localInverse hd (by simp)).analyticAt + have hn : U ∩ e ⁻¹' {y | AnalyticAt ℂ e.symm y} ∈ 𝓝 a := + inter_mem (hU.mem_nhds ha) (hfa.continuousAt.preimage_mem_nhds hga.eventually_analyticAt) + obtain ⟨V, hVS, hV, haV⟩ := mem_nhds_iff.mp hn + refine ⟨e.restr V, ?_, ?_, ?_, rfl⟩ + · constructor + · exact hf.mono (fun x hx => (hVS (interior_subset hx.2)).1) + · intro y hy + have h := (hVS (interior_subset hy.2)).2 + change AnalyticAt ℂ e.symm (e (e.symm y)) at h + have hg : AnalyticAt ℂ e.symm y := by simpa only [e.right_inv hy.1] using h + exact hg.differentiableAt.differentiableWithinAt + · exact ⟨hae, hV.interior_eq.symm ▸ haV⟩ + · exact fun x hx => (hVS (interior_subset hx.2)).1 + +/-- A holomorphic map is locally biholomorphic exactly when its derivative is invertible. -/ +theorem isInvertible_fderiv_iff_exists_biholomorphic {U : Set E} (hU : IsOpen U) + {f : E → F} (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) : + (fderiv ℂ f a).IsInvertible ↔ + ∃ e : OpenPartialHomeomorph E F, IsBiholomorphic e ∧ a ∈ e.source ∧ + e.source ⊆ U ∧ (e : E → F) = f := by + refine ⟨exists_biholomorphic_of_isInvertible_fderiv hU hf ha, ?_⟩ + rintro ⟨e, he, hae, _, rfl⟩ + exact he.isInvertible_fderiv hae + +/-- **[Range][Range1986] I, Corollary 2.6.** An injective complex derivative gives local +injectivity, +also when the target has larger dimension. No surjectivity assumption is needed. -/ +theorem exists_open_injOn_of_injective_fderiv {U : Set E} (hU : IsOpen U) + {f : E → F} (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) + (hi : Function.Injective (fderiv ℂ f a)) : + ∃ V, IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ InjOn f V := by + let A := (fderiv ℂ f a).toLinearMap + obtain ⟨B, hB⟩ := A.exists_leftInverse_of_injective (LinearMap.ker_eq_bot.mpr hi) + let L : F →L[ℂ] E := B.toContinuousLinearMap + have hd : fderiv ℂ (L ∘ f) a = ContinuousLinearMap.id ℂ E := by + rw [fderiv_comp a L.differentiableAt ((hf a ha).differentiableAt (hU.mem_nhds ha)), + L.fderiv] + ext x + exact DFunLike.congr_fun hB x + have hcomp : DifferentiableOn ℂ (L ∘ f) U := L.differentiable.comp_differentiableOn hf + obtain ⟨e, he, hae, hsub, heq⟩ := exists_biholomorphic_of_isInvertible_fderiv hU hcomp ha + (by rw [hd]; exact ⟨ContinuousLinearEquiv.refl ℂ E, rfl⟩) + refine ⟨e.source, e.open_source, hae, hsub, ?_⟩ + intro x hx y hy hxy + apply e.injOn hx hy + rw [heq] + exact congrArg L hxy + +end Inverse + +section Examples + +/-- An invertible complex linear map followed by a translation, as an equivalence of the whole +spaces. -/ +@[expose] def affineOpenPartialHomeomorph (L : E ≃L[ℂ] F) (b : F) : OpenPartialHomeomorph E F := + (L.toHomeomorph.trans (Homeomorph.addRight b)).toOpenPartialHomeomorph + +/-- The forward affine map applies the linear map and then adds the translation. -/ +@[simp] theorem affineOpenPartialHomeomorph_apply (L : E ≃L[ℂ] F) (b : F) (x : E) : + affineOpenPartialHomeomorph L b x = L x + b := rfl + +/-- The inverse affine map first subtracts the translation. -/ +@[simp] theorem affineOpenPartialHomeomorph_symm_apply (L : E ≃L[ℂ] F) (b : F) (y : F) : + (affineOpenPartialHomeomorph L b).symm y = L.symm (y - b) := by + change L.symm (y + -b) = L.symm (y - b) + rw [sub_eq_add_neg] + +/-- Invertible complex affine maps are biholomorphic. -/ +theorem isBiholomorphic_affine (L : E ≃L[ℂ] F) (b : F) : + IsBiholomorphic (affineOpenPartialHomeomorph L b) := by + constructor + · exact (L.differentiable.add_const b).differentiableOn + · exact (L.symm.differentiable.comp (differentiable_id.add_const (-b))).differentiableOn + +/-- A continuous shear has an explicit inverse obtained by subtracting the same function. -/ +@[expose] def shearOpenPartialHomeomorph (h : F → E) (hh : Continuous h) : + OpenPartialHomeomorph (E × F) (E × F) := + ({ toFun := fun p => (p.1 + h p.2, p.2) + invFun := fun p => (p.1 - h p.2, p.2) + left_inv := by intro p; simp + right_inv := by intro p; simp + continuous_toFun := (continuous_fst.add (hh.comp continuous_snd)).prodMk continuous_snd + continuous_invFun := (continuous_fst.sub (hh.comp continuous_snd)).prodMk continuous_snd } : + (E × F) ≃ₜ (E × F)).toOpenPartialHomeomorph + +omit [NormedSpace ℂ E] [NormedSpace ℂ F] in +/-- The forward shear adds a function of the second coordinate to the first. -/ +@[simp] theorem shearOpenPartialHomeomorph_apply (h : F → E) (hh : Continuous h) (p : E × F) : + shearOpenPartialHomeomorph h hh p = (p.1 + h p.2, p.2) := rfl + +omit [NormedSpace ℂ E] [NormedSpace ℂ F] in +/-- The inverse shear subtracts the same function. -/ +@[simp] theorem shearOpenPartialHomeomorph_symm_apply (h : F → E) (hh : Continuous h) + (p : E × F) : (shearOpenPartialHomeomorph h hh).symm p = (p.1 - h p.2, p.2) := rfl + +/-- An entire holomorphic function gives a biholomorphic shear, including nonlinear examples. -/ +theorem isBiholomorphic_shear {h : F → E} (hh : Differentiable ℂ h) : + IsBiholomorphic (shearOpenPartialHomeomorph h hh.continuous) := by + constructor + · exact ((differentiable_fst.add (hh.comp differentiable_snd)).prodMk + differentiable_snd).differentiableOn + · exact ((differentiable_fst.sub (hh.comp differentiable_snd)).prodMk + differentiable_snd).differentiableOn + +end Examples + +section Coordinates + +variable {ι : Type*} [Fintype ι] [DecidableEq ι] + +omit [DecidableEq ι] in +/-- Nonempty biholomorphically equivalent coordinate domains have the same number of complex +coordinates, including the possibility of zero coordinates. -/ +theorem IsBiholomorphic.card_eq {κ : Type*} [Fintype κ] + {e : OpenPartialHomeomorph (ι → ℂ) (κ → ℂ)} (he : IsBiholomorphic e) + (hne : e.source.Nonempty) : Fintype.card ι = Fintype.card κ := by + simpa using he.finrank_eq hne + +/-- The coordinate determinant criterion in [Range][Range1986]'s local inverse theorem. -/ +theorem exists_biholomorphic_of_det_complexJacobian_ne_zero {U : Set (ι → ℂ)} + (hU : IsOpen U) {f : (ι → ℂ) → (ι → ℂ)} (hf : DifferentiableOn ℂ f U) + {a : ι → ℂ} (ha : a ∈ U) (hd : (complexJacobian f a).det ≠ 0) : + ∃ e : OpenPartialHomeomorph (ι → ℂ) (ι → ℂ), IsBiholomorphic e ∧ a ∈ e.source ∧ + e.source ⊆ U ∧ (e : (ι → ℂ) → (ι → ℂ)) = f := + exists_biholomorphic_of_isInvertible_fderiv hU hf ha + ((det_complexJacobian_ne_zero_iff ((hf a ha).differentiableAt (hU.mem_nhds ha))).mp hd) + +/-- A biholomorphic map has nonvanishing complex Jacobian determinant throughout its source. -/ +theorem IsBiholomorphic.det_complexJacobian_ne_zero + {e : OpenPartialHomeomorph (ι → ℂ) (ι → ℂ)} (he : IsBiholomorphic e) + {a : ι → ℂ} (ha : a ∈ e.source) : (complexJacobian e a).det ≠ 0 := + (det_complexJacobian_ne_zero_iff (he.differentiableAt ha)).mpr (he.isInvertible_fderiv ha) + +end Coordinates + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/BiholomorphicRigidity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/BiholomorphicRigidity.lean new file mode 100644 index 0000000000..6c800f66ff --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/BiholomorphicRigidity.lean @@ -0,0 +1,177 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanUniqueness +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Circular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple + +/-! +# Rigidity of biholomorphic maps + +Equality of first jets and circular-domain linearity follow from Cartan's uniqueness theorem. +The independent analytic step uses Cauchy's derivative formula to show that a +rotation-equivariant holomorphic map is linear. Equality is asserted on the source, not for +arbitrary ambient representatives outside it. Reference: [Scheidemann][Scheidemann2005] (2005), +Section 3.3. + +## Main results + +`IsBiholomorphic.eqOn_of_value_fderiv_eq` is rigidity from equality of 1-jets. +`IsBiholomorphic.exists_linearEquiv_of_circular` is linearity of a biholomorphism of circular +domains fixing the origin. `eqOn_fderiv_of_circle_equivariant` is the analytic step that a +rotation-equivariant holomorphic map is linear. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] + +omit [FiniteDimensional ℂ F] in +/-- Two biholomorphisms with the same source and target are determined by their value and derivative +at one point of a bounded connected source. Depends on Cartan uniqueness; boundedness of the +target is unnecessary. -/ +theorem IsBiholomorphic.eqOn_of_value_fderiv_eq + {e e' : OpenPartialHomeomorph E F} (he : IsBiholomorphic e) (he' : IsBiholomorphic e') + (hs : e'.source = e.source) (ht : e'.target = e.target) + (hc : IsPreconnected e.source) (hb : Bornology.IsBounded e.source) + {a : E} (ha : a ∈ e.source) (hv : e' a = e a) + (hd : fderiv ℂ e' a = fderiv ℂ e a) : EqOn e' e e.source := by + let := FiniteDimensional.complete ℂ E + have hmem : MapsTo e' e.source e.target := by + intro x hx + rw [← ht] + exact e'.map_source (hs ▸ hx) + have hd' : DifferentiableOn ℂ e' e.source := hs ▸ he'.1 + have hcomp : DifferentiableOn ℂ (e.symm ∘ e') e.source := he.2.comp hd' hmem + have hder : fderiv ℂ (e.symm ∘ e') a = ContinuousLinearMap.id ℂ E := by + rw [fderiv_comp a (he.symm.differentiableAt (hmem ha)) + ((hd' a ha).differentiableAt (e.open_source.mem_nhds ha)), hv, hd] + exact he.fderiv_symm_comp ha + have hid := eqOn_id_of_mapsTo_of_fderiv_eq_id e.open_source hc hb + (hcomp.analyticOnNhd_of_finiteDimensional e.open_source) + (fun x hx => e.symm.map_source (hmem hx)) ha + (by simp [hv, e.left_inv ha]) hder + intro x hx + have h := congrArg e (hid hx) + simpa only [Function.comp_apply, e.right_inv (hmem hx), id_eq] using h + +omit [FiniteDimensional ℂ F] in +/-- A holomorphic map commuting with complex rotations agrees with its derivative at zero on a +preconnected neighborhood of zero. Cauchy's derivative formula on scalar slices proves local +equality, and the identity theorem propagates it. -/ +theorem eqOn_fderiv_of_circle_equivariant [CompleteSpace F] {U : Set E} (ho : IsOpen U) + (hc : IsPreconnected U) (hzero : (0 : E) ∈ U) {f : E → F} + (hf : DifferentiableOn ℂ f U) + (hrot : ∀ z ∈ U, ∀ c : ℂ, ‖c‖ = 1 → f (c • z) = c • f z) : + EqOn f (fderiv ℂ f 0) U := by + obtain ⟨r, hr, hsub⟩ := Metric.mem_nhds_iff.mp (ho.mem_nhds hzero) + apply hf.eqOn_of_preconnected_of_eqOn ho hc (fderiv ℂ f 0).differentiable.differentiableOn + isOpen_ball ⟨0, mem_ball_self hr⟩ hsub + intro z hz + have hcz (c : ℂ) (hc : c ∈ closedBall 0 1) : c • z ∈ U := by + apply hsub + rw [mem_ball, dist_zero_right] at hz ⊢ + rw [mem_closedBall, dist_zero_right] at hc + exact (norm_smul c z).le.trans_lt + ((mul_le_mul_of_nonneg_right hc (norm_nonneg z)).trans_lt (by simpa using hz)) + have hd : DifferentiableOn ℂ (fun c : ℂ => f (c • z)) (closedBall 0 1) := by + intro c hc + exact ((hf (c • z) (hcz c hc)).differentiableAt + (ho.mem_nhds (hcz c hc))).comp c (differentiableAt_id.smul_const z) + |>.differentiableWithinAt + have hd' : DifferentiableOn ℂ (fun c : ℂ => c • f z) (closedBall 0 1) := + (differentiable_id.smul_const (f z)).differentiableOn + have heq := circleIntegral.integral_congr (c := 0) (show (0 : ℝ) ≤ 1 by norm_num) + (f := fun c : ℂ => (1 / (c - 0) ^ 2) • f (c • z)) + (g := fun c : ℂ => (1 / (c - 0) ^ 2) • (c • f z)) + (fun c hc => by dsimp only; rw [hrot z (hsub hz) c (by simpa using hc)]) + rw [hd.deriv_eq_smul_circleIntegral (by norm_num), + hd'.deriv_eq_smul_circleIntegral (by norm_num)] at heq + have hdf : HasDerivAt (fun c : ℂ => f (c • z)) (fderiv ℂ f 0 z) 0 := by + have hpre : HasFDerivAt f (fderiv ℂ f 0) ((0 : ℂ) • z) := by + simpa using ((hf 0 hzero).differentiableAt (ho.mem_nhds hzero)).hasFDerivAt + simpa [Function.comp_def] using hpre.comp_hasDerivAt 0 ((hasDerivAt_id (0 : ℂ)).smul_const z) + have hlin : HasDerivAt (fun c : ℂ => c • f z) (f z) 0 := by + simpa using (hasDerivAt_id (0 : ℂ)).smul_const (f z) + rw [hdf.deriv, hlin.deriv] at heq + exact (smul_right_injective F Complex.two_pi_I_ne_zero heq).symm + +omit [FiniteDimensional ℂ F] in +/-- Origin-preserving biholomorphisms of circular domains commute with rotations. This follows from +Cartan uniqueness on the bounded source; boundedness of the target is unnecessary. -/ +theorem IsBiholomorphic.map_smul_of_circular + {e : OpenPartialHomeomorph E F} (he : IsBiholomorphic e) + (hc : IsPreconnected e.source) (hb : Bornology.IsBounded e.source) + (hrot : IsCircular e.source) (hrot' : IsCircular e.target) + (hzero : (0 : E) ∈ e.source) (hfix : e 0 = 0) + {z : E} (hz : z ∈ e.source) {c : ℂ} (hc1 : ‖c‖ = 1) : + e (c • z) = c • e z := by + let := FiniteDimensional.complete ℂ E + have hcn : c ≠ 0 := norm_ne_zero_iff.mp (by rw [hc1]; norm_num) + have hci : ‖c⁻¹‖ = 1 := by simp [hc1] + have hi0 : e.symm 0 = 0 := by simpa [hfix] using e.left_inv hzero + let g : E → E := fun x => e.symm (c⁻¹ • e (c • x)) + have hmem : MapsTo (fun x => c⁻¹ • e (c • x)) e.source e.target := + fun x hx => hrot'.smul_mem (e.map_source (hrot.smul_mem hx hc1)) hci + have hdiff : DifferentiableOn ℂ g e.source := + he.2.comp ((he.1.comp (differentiable_id.const_smul c).differentiableOn + (fun x hx => hrot.smul_mem hx hc1)).const_smul c⁻¹) hmem + have hinner : HasFDerivAt (fun x => c⁻¹ • e (c • x)) (fderiv ℂ e 0) 0 := by + have hd : HasFDerivAt e (fderiv ℂ e 0) (c • (0 : E)) := by + simpa using (he.differentiableAt hzero).hasFDerivAt + convert (hd.comp 0 ((hasFDerivAt_id (𝕜 := ℂ) (0 : E)).const_smul c)).const_smul c⁻¹ using 1 + · simp only [Function.comp_def, Pi.smul_def] + · ext x + simp [hcn] + have hd : HasFDerivAt g (ContinuousLinearMap.id ℂ E) 0 := by + have hinv : HasFDerivAt e.symm (fderiv ℂ e.symm (e 0)) (c⁻¹ • e (c • (0 : E))) := by + simpa [hfix] using (he.symm.differentiableAt (e.map_source hzero)).hasFDerivAt + simpa [g, Function.comp_def, he.fderiv_symm_comp hzero] using hinv.comp 0 hinner + have hid := eqOn_id_of_mapsTo_of_fderiv_eq_id e.open_source hc hb + (hdiff.analyticOnNhd_of_finiteDimensional e.open_source) + (fun x hx => e.symm.map_source (hmem hx)) hzero + (by simp [g, hfix, hi0]) hd.fderiv + have heq : c⁻¹ • e (c • z) = e z := by + simpa only [g, e.right_inv (hmem hz), id_eq] using congrArg e (hid hz) + simpa [hcn] using congrArg (fun y : F => c • y) heq + +/-- An origin-preserving biholomorphism between circular domains with bounded source agrees with an +invertible complex-linear map. Cartan uniqueness gives rotation equivariance, and Cauchy's +derivative formula eliminates the nonlinear terms. Zero-dimensional spaces are included; +membership of zero supplies nonemptiness. -/ +theorem IsBiholomorphic.exists_linearEquiv_of_circular + {e : OpenPartialHomeomorph E F} (he : IsBiholomorphic e) + (hc : IsPreconnected e.source) (hb : Bornology.IsBounded e.source) + (hrot : IsCircular e.source) + (hrot' : IsCircular e.target) (hzero : (0 : E) ∈ e.source) (hfix : e 0 = 0) : + ∃ L : E ≃L[ℂ] F, EqOn e L e.source := by + let := FiniteDimensional.complete ℂ F + obtain ⟨L, hL⟩ := he.isInvertible_fderiv hzero + refine ⟨L, ?_⟩ + have h := eqOn_fderiv_of_circle_equivariant e.open_source hc hzero he.1 + (fun z hz c hc1 => he.map_smul_of_circular hc hb hrot hrot' hzero hfix hz hc1) + intro x hx + change e x = L.toContinuousLinearMap x + rw [hL] + exact h hx + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CartanThullen.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CartanThullen.lean new file mode 100644 index 0000000000..e2ea867aa1 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CartanThullen.lean @@ -0,0 +1,289 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Connected.LocallyConnected +public import Mathlib.Topology.Sequences +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Exhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen + +/-! +# The Cartan–Thullen characterizations + +The core equivalences relate holomorphic convexity, obstruction to common local continuation, a +single function's domain of existence, and hull boundary distance. The function-theoretic +equivalences apply to open subsets of arbitrary finite-dimensional complex normed spaces; the +numerical hull-radius forms use coordinate sup norms. Connectedness is not required. They +include the empty set, the whole space, and dimension zero. + +Thullen's Taylor continuation lemma gives the forward implication. For the converse, a countable +basis of balls and overlap components supplies escaping sequences that detect every local +continuation patch. Baire's theorem gives one holomorphic function unbounded on all these +sequences. This proves the full equivalences, including for disconnected open sets. + +References: [Range][Range1986] II §3.6; [Fritzsche–Grauert][FritzscheGrauert2002] II §§5–6; +[Scheidemann][Scheidemann2005] §7.3; [Jakóbczak–Jarnicki][JakobczakJarnicki2021] §2.7; +[Hörmander][Hormander1973] §2.5. + +## Main results + +`isDomainOfHolomorphy_iff_isHolomorphicallyConvex` is the Cartan–Thullen equivalence. +`isDomainOfHolomorphy_iff_exists_domainOfExistence` produces a single completely nonextendable +function. `isDomainOfHolomorphy_iff_hasHolomorphicHullDistanceProperty` and +`isDomainOfHolomorphy_iff_hasHolomorphicHullRadiusProperty` are the hull-radius forms. +`isHolomorphicallyConvex_of_convex` is the convex example. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +section General +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U : Set E} + +/-- Finite-dimensional source spaces are proper. -/ +local instance : ProperSpace E := FiniteDimensional.proper ℂ E + +/-- Finite-dimensional source spaces have countable bases. -/ +local instance : SecondCountableTopology E := + (Module.finBasis ℂ E).equivFunL.toHomeomorph.secondCountableTopology + +omit [FiniteDimensional ℂ E] in +/-- A component of the overlap with a connected larger open set approaches the boundary of the +original set inside the larger set. -/ +private theorem exists_boundary_point_of_component (ho : IsOpen U) + {V : Set E} (hV : IsOpen V) (hc : IsPreconnected V) + {x : E} (hx : x ∈ U ∩ V) (hn : ¬ V ⊆ U) : + ∃ a ∈ V, a ∉ U ∧ a ∈ closure (connectedComponentIn (U ∩ V) x) := by + let C := connectedComponentIn (U ∩ V) x + have hC : IsOpen C := (ho.inter hV).connectedComponentIn + have hxC : x ∈ C := mem_connectedComponentIn hx + have hCF : C ⊆ U ∩ V := connectedComponentIn_subset _ _ + have hrel {a : E} (ha : a ∈ closure C) (haF : a ∈ U ∩ V) : a ∈ C := by + have hconn : IsPreconnected (insert a C) := + isPreconnected_connectedComponentIn.subset_closure (subset_insert _ _) + (insert_subset ha subset_closure) + exact (hconn.subset_connectedComponentIn (mem_insert_of_mem _ hxC) + (insert_subset haF hCF)) (mem_insert _ _) + by_contra! h + apply hn + apply subset_trans (hc.subset_of_closure_inter_subset hC ⟨x, hx.2, hxC⟩ ?_) + (hCF.trans inter_subset_left) + rintro a ⟨haC, haV⟩ + exact hrel haC ⟨by by_contra haU; exact h a haV haU haC, haV⟩ + +/-- There is a countable basis of nonempty open balls in a finite coordinate space. -/ +private theorem exists_countable_ball_basis (E : Type*) [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] : + ∃ b : Set (Set E), b.Countable ∧ TopologicalSpace.IsTopologicalBasis b ∧ + ∀ B ∈ b, ∃ c r, 0 < r ∧ B = ball c r := by + let T : Set (Set E) := {B | ∃ c r, 0 < r ∧ B = ball c r} + have hT : TopologicalSpace.IsTopologicalBasis T := by + apply TopologicalSpace.isTopologicalBasis_of_isOpen_of_nhds + · rintro _ ⟨c, r, hr, rfl⟩; exact isOpen_ball + · intro x N hx hN + obtain ⟨r, hr, hsub⟩ := Metric.mem_nhds_iff.mp (hN.mem_nhds hx) + exact ⟨ball x r, ⟨x, r, hr, rfl⟩, mem_ball_self hr, hsub⟩ + obtain ⟨b, hbT, hbc, hb⟩ := hT.exists_countable + exact ⟨b, hbc, hb, hbT⟩ + +/-- One holomorphic function is unbounded on every member of a countable family of escaping +sequences. Baire's theorem combines the individual obstructions. -/ +private theorem exists_unbounded_on_sequences {I : Type*} [Countable I] + (hU : IsHolomorphicallyConvex U) (ho : IsOpen U) + (p : I → ℕ → E) (hp : ∀ i j, p i j ∈ U) + (he : ∀ i, EscapesCompactSubsets U (p i)) : + ∃ f : E → ℂ, AnalyticOnNhd ℂ f U ∧ + ∀ i, ¬ BddAbove (range (fun j => ‖f (p i j)‖)) := by + classical + let V : TopologicalSpace.Opens E := ⟨U, ho⟩ + let : LocallyCompactSpace V := ho.locallyCompactSpace + have : (uniformity C(V, ℂ)).IsCountablyGenerated := inferInstance + have : (uniformity (HolomorphicMap V ℂ)).IsCountablyGenerated := + Filter.comap.isCountablyGenerated _ _ + have : TopologicalSpace.IsCompletelyPseudoMetrizableSpace (HolomorphicMap V ℂ) := + .of_completeSpace_pseudometrizable + let : BaireSpace (HolomorphicMap V ℂ) := BaireSpace.of_completelyPseudoMetrizable + let A (q : I × ℕ) : Set (HolomorphicMap V ℂ) := + {f | ∀ j, ‖f.val ⟨p q.1 j, hp q.1 j⟩‖ ≤ q.2} + have hclosed (q : I × ℕ) : IsClosed (A q) := by + simp only [A, ofPred_forall] + exact isClosed_iInter fun j => isClosed_le + (continuous_holomorphicMap_eval V ⟨p q.1 j, hp q.1 j⟩).norm continuous_const + have hempty (q : I × ℕ) : interior (A q) = ∅ := by + apply eq_empty_iff_forall_notMem.mpr + intro g hg + have hgA := interior_subset hg + obtain ⟨h, hh, hno⟩ := + (isHolomorphicallyConvex_iff_unbounded_on_escaping_sequences ho).mp hU + (p q.1) (hp q.1) (he q.1) + let H : HolomorphicMap V ℂ := ⟨⟨fun z => h z, hh.continuousOn.domRestrict⟩, + hh.congr ho (fun z hz => by rw [openExtension_apply V _ hz]; rfl)⟩ + let c (k : ℕ) : ℂ := 1 / ((k : ℂ) + 1) + have hlim : Tendsto (fun k => g + c k • H) atTop (𝓝 g) := by + simpa [c] using (tendsto_const_nhds (x := g)).add + ((tendsto_one_div_add_atTop_nhds_zero_nat (𝕜 := ℂ)).smul_const H) + obtain ⟨k, hk⟩ := (hlim.eventually (mem_interior_iff_mem_nhds.mp hg)).exists + have hc : 0 < ‖c k‖ := by + apply norm_pos_iff.mpr + apply one_div_ne_zero + exact_mod_cast Nat.succ_ne_zero k + apply hno + refine ⟨2 * (q.2 : ℝ) / ‖c k‖, ?_⟩ + rintro _ ⟨j, rfl⟩ + apply (le_div_iff₀ hc).mpr + have hnorm := norm_sub_le ((g + c k • H).val ⟨p q.1 j, hp q.1 j⟩) + (g.val ⟨p q.1 j, hp q.1 j⟩) + change ‖g.val ⟨p q.1 j, hp q.1 j⟩ + c k * h (p q.1 j) - + g.val ⟨p q.1 j, hp q.1 j⟩‖ ≤ _ at hnorm + rw [add_sub_cancel_left, norm_mul] at hnorm + nlinarith [hk j, hgA j] + have hdense := dense_iInter_of_isOpen (fun q => (hclosed q).isOpen_compl) + (fun q => interior_eq_empty_iff_dense_compl.mp (hempty q)) + obtain ⟨f, hf⟩ := hdense.nonempty + refine ⟨openExtension V f.val, f.property, ?_⟩ + intro i hbound + obtain ⟨M, hM⟩ := hbound + obtain ⟨N, hN⟩ := exists_nat_ge M + apply (mem_iInter.mp hf (i, N)) + intro j + have h := (hM (mem_range_self j)).trans hN + simpa only [openExtension_apply V _ (hp i j)] using h + +/-- **Existence of a completely nonextendable function.** Baire's theorem gives one +function unbounded on a countable family of escaping sequences that detects every +local continuation patch. Disconnected open sets are allowed. -/ +theorem IsHolomorphicallyConvex.exists_domainOfExistence + (hU : IsHolomorphicallyConvex U) (ho : IsOpen U) : + ∃ f : E → ℂ, IsDomainOfExistence U f := by + classical + obtain ⟨b, hbc, hb, hballs⟩ := exists_countable_ball_basis E + have : Countable b := hbc.to_subtype + have hne (B : b) : B.val.Nonempty := by + obtain ⟨c, r, hr, hB⟩ := hballs B.val B.property + exact ⟨c, hB ▸ mem_ball_self hr⟩ + let I := {q : b × b // q.2.val ⊆ U ∩ q.1.val ∧ ¬ q.1.val ⊆ U} + let x (q : I) := (hne q.val.2).some + let C (q : I) := connectedComponentIn (U ∩ q.val.1.val) (x q) + have hx (q : I) : x q ∈ U ∩ q.val.1.val := q.property.1 (hne q.val.2).some_mem + have hseq (q : I) : ∃ p : ℕ → E, + (∀ j, p j ∈ C q) ∧ EscapesCompactSubsets U p := by + obtain ⟨c, r, hr, hB⟩ := hballs q.val.1.val q.val.1.property + have hc : IsPreconnected q.val.1.val := hB ▸ (convex_ball c r).isPreconnected + obtain ⟨a, _, haU, haC⟩ := exists_boundary_point_of_component ho + (hb.isOpen q.val.1.property) hc (hx q) q.property.2 + obtain ⟨p, hp, ht⟩ := mem_closure_iff_seq_limit.mp haC + refine ⟨p, hp, ?_⟩ + intro K hK hKU + exact ht.eventually (hK.isClosed.isOpen_compl.mem_nhds (fun haK => haU (hKU haK))) + choose p hp he using hseq + have hpU (q : I) (j : ℕ) : p q j ∈ U := + (connectedComponentIn_subset _ _ (hp q j)).1 + obtain ⟨f, hf, hno⟩ := exists_unbounded_on_sequences hU ho p hpU he + refine ⟨f, hf, ?_⟩ + intro V W hV hc hW hWne hWU hWV hext + by_contra hnot + obtain ⟨g, hg, hgf⟩ := hext + obtain ⟨w, hw⟩ := hWne + let D := connectedComponentIn (U ∩ V) w + have hDo : IsOpen D := (ho.inter hV).connectedComponentIn + have hwD : w ∈ D := mem_connectedComponentIn ⟨hWU hw, hWV hw⟩ + have hDsub : D ⊆ U ∩ V := connectedComponentIn_subset _ _ + have heqD : EqOn g f D := + (hg.mono (hDsub.trans inter_subset_right)).eqOn_of_preconnected_of_eventuallyEq + (hf.mono (hDsub.trans inter_subset_left)) isPreconnected_connectedComponentIn hwD + (Filter.mem_of_superset (hW.mem_nhds hw) hgf) + obtain ⟨a, haV, haU, haD⟩ := exists_boundary_point_of_component ho hV hc.isPreconnected + ⟨hWU hw, hWV hw⟩ hnot + obtain ⟨r, hr, hrV⟩ := Metric.nhds_basis_closedBall.mem_iff.mp (hV.mem_nhds haV) + obtain ⟨B, hBb, haB, hBr⟩ := hb.exists_subset_of_mem_open (mem_ball_self hr) isOpen_ball + have hBcl : closure B ⊆ closedBall a r := + (closure_mono hBr).trans closure_ball_subset_closedBall + have hBV : closure B ⊆ V := hBcl.trans hrV + have hBK : IsCompact (closure B) := + (isCompact_closedBall a r).of_isClosed_subset isClosed_closure hBcl + obtain ⟨z, hzB, hzD⟩ := _root_.mem_closure_iff.mp haD B (hb.isOpen hBb) haB + obtain ⟨A, hAb, hzA, hAsub⟩ := hb.exists_subset_of_mem_open + (show z ∈ B ∩ D from ⟨hzB, hzD⟩) ((hb.isOpen hBb).inter hDo) + let q : I := ⟨(⟨B, hBb⟩, ⟨A, hAb⟩), + fun z hz => ⟨(hDsub (hAsub hz).2).1, (hAsub hz).1⟩, + fun h => haU (h haB)⟩ + have hxD : x q ∈ D := (hAsub (hne q.val.2).some_mem).2 + have hCsub : C q ⊆ U ∩ B := connectedComponentIn_subset _ _ + have hCV : C q ⊆ V := hCsub.trans (inter_subset_right.trans (subset_closure.trans hBV)) + have heqC : EqOn g f (C q) := + (hg.mono hCV).eqOn_of_preconnected_of_eventuallyEq + (hf.mono (hCsub.trans inter_subset_left)) isPreconnected_connectedComponentIn + (mem_connectedComponentIn (hx q)) + (Filter.mem_of_superset (hDo.mem_nhds hxD) heqD) + obtain ⟨M, hM⟩ := hBK.bddAbove_image (hg.continuousOn.mono hBV).norm + apply hno q + refine ⟨M, ?_⟩ + rintro _ ⟨j, rfl⟩ + change ‖f (p q j)‖ ≤ M + rw [← heqC (hp q j)] + exact hM ⟨p q j, subset_closure (hCsub (hp q j)).2, rfl⟩ + +/-- **Cartan–Thullen, reverse implication.** A single completely nonextendable +function obstructs common local continuation beyond the open set. -/ +theorem IsHolomorphicallyConvex.isDomainOfHolomorphy + (hU : IsHolomorphicallyConvex U) (ho : IsOpen U) : IsDomainOfHolomorphy U := by + obtain ⟨f, hf⟩ := hU.exists_domainOfExistence ho + exact hf.isDomainOfHolomorphy + +/-- **Cartan–Thullen.** Holomorphic convexity is equivalent to the domain-of-holomorphy +property. The reverse implication uses a completely nonextendable function. -/ +theorem isDomainOfHolomorphy_iff_isHolomorphicallyConvex (ho : IsOpen U) : + IsDomainOfHolomorphy U ↔ IsHolomorphicallyConvex U := + ⟨fun h => h.isHolomorphicallyConvex ho, fun h => h.isDomainOfHolomorphy ho⟩ + +/-- A domain of holomorphy is the domain of existence of a single scalar function. The converse +follows from the obstruction to common local continuation. -/ +theorem isDomainOfHolomorphy_iff_exists_domainOfExistence (ho : IsOpen U) : + IsDomainOfHolomorphy U ↔ ∃ f : E → ℂ, IsDomainOfExistence U f := + ⟨fun h => (h.isHolomorphicallyConvex ho).exists_domainOfExistence ho, + fun ⟨_, hf⟩ => hf.isDomainOfHolomorphy⟩ + +/-- Convex open subsets of finite-dimensional complex normed spaces are holomorphically convex. +This deduction uses the separating-hyperplane example and Thullen's lemma. -/ +theorem isHolomorphicallyConvex_of_convex (hU : Convex ℝ U) (ho : IsOpen U) : + IsHolomorphicallyConvex U := (isDomainOfHolomorphy_of_convex hU ho).isHolomorphicallyConvex ho + +end General + +variable {n : ℕ} {U : Set (Fin n → ℂ)} + +/-- Exact preservation of compact hull boundary distance characterizes domains of holomorphy, by the +equivalence with holomorphic convexity. -/ +theorem isDomainOfHolomorphy_iff_hasHolomorphicHullDistanceProperty (ho : IsOpen U) : + IsDomainOfHolomorphy U ↔ HasHolomorphicHullDistanceProperty U := + ⟨fun h => h.hasHolomorphicHullDistanceProperty ho, + fun h => (h.isHolomorphicallyConvex ho).isDomainOfHolomorphy ho⟩ + +/-- The uniform polydisc-radius formulation is another Cartan–Thullen characterization. -/ +theorem isDomainOfHolomorphy_iff_hasHolomorphicHullRadiusProperty (ho : IsOpen U) : + IsDomainOfHolomorphy U ↔ HasHolomorphicHullRadiusProperty U := + ⟨fun h => h.hasHolomorphicHullRadiusProperty ho, + fun h => (h.isHolomorphicallyConvex ho).isDomainOfHolomorphy ho⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CartanUniqueness.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CartanUniqueness.lean new file mode 100644 index 0000000000..6ee5218ce6 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CartanUniqueness.lean @@ -0,0 +1,126 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Group.Bounded +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Montel + +/-! +# Cartan uniqueness on bounded domains + +The theorem in this file concerns holomorphic self-maps of bounded finite-dimensional domains. +It is Cartan's uniqueness theorem from [Scheidemann][Scheidemann2005] (2005), Theorem 3.3.1, +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Theorem 2.3.2, and [Lebl][Lebl2026] (2026), +Section 1.5. It is independent of sheaves and of Cartan's theorems A and B. + +The proof averages the bounded iterates and uses Montel's theorem to extract a locally uniform +limit. Derivative convergence gives identity derivative at the fixed point. Telescoping gives +invariance of the limit under the original map, so local injectivity and the identity principle +force the original map to be the identity. + +## Main results + +`eqOn_id_of_mapsTo_of_fderiv_eq_id` is Cartan's uniqueness theorem: a holomorphic self-map of a +bounded domain which fixes a point and has identity derivative there is the identity on the +connected component of that point. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [J. Lebl, *Tasty Bits of Several Complex Variables: A Whirlwind Tour of the Subject*][Lebl2026] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +/-- **Cartan's uniqueness theorem.** A holomorphic self-map of a bounded connected open set +that fixes an interior point and has identity derivative there is the identity on the set. +Boundedness is essential; no injectivity or surjectivity of the map is assumed. +The formulation includes zero-dimensional domains. -/ +theorem eqOn_id_of_mapsTo_of_fderiv_eq_id + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) (hb : Bornology.IsBounded U) + {f : E → E} (hf : AnalyticOnNhd ℂ f U) (hmaps : MapsTo f U U) + {a : E} (ha : a ∈ U) (hfix : f a = a) + (hderiv : fderiv ℂ f a = ContinuousLinearMap.id ℂ E) : EqOn f id U := by + classical + let : CompleteSpace E := FiniteDimensional.complete ℂ E + obtain ⟨M, hM0, hM⟩ := hb.exists_pos_norm_le + let A (n : ℕ) (z : E) : E := ((n + 1 : ℕ) : ℂ)⁻¹ • + ∑ k ∈ Finset.range (n + 1), f^[k] z + have hA (n : ℕ) : AnalyticOnNhd ℂ (A n) U := + ((DifferentiableOn.fun_sum (fun k _ => hf.differentiableOn.iterate hmaps k)).const_smul + ((n + 1 : ℕ) : ℂ)⁻¹).analyticOnNhd_of_finiteDimensional hU + have hAb (n : ℕ) (z : E) (hz : z ∈ U) : ‖A n z‖ ≤ M := by + have hn : (0 : ℝ) < n + 1 := by positivity + calc + ‖A n z‖ = ((n : ℝ) + 1)⁻¹ * ‖∑ k ∈ Finset.range (n + 1), f^[k] z‖ := by + dsimp only [A] + rw [norm_smul, norm_inv, norm_natCast, Nat.cast_add, Nat.cast_one] + _ ≤ ((n : ℝ) + 1)⁻¹ * (((n : ℝ) + 1) * M) := by + apply mul_le_mul_of_nonneg_left _ (inv_nonneg.mpr hn.le) + calc + _ ≤ ∑ k ∈ Finset.range (n + 1), ‖f^[k] z‖ := norm_sum_le _ _ + _ ≤ ∑ _k ∈ Finset.range (n + 1), M := + Finset.sum_le_sum fun k _ => hM _ (hmaps.iterate k hz) + _ = _ := by simp + _ = M := by field_simp + have hfd : HasFDerivAt f (ContinuousLinearMap.id ℂ E) a := by + rw [← hderiv] + exact (hf a ha).differentiableAt.hasFDerivAt + have hAd (n : ℕ) : fderiv ℂ (A n) a = ContinuousLinearMap.id ℂ E := by + have hk (k : ℕ) : HasFDerivAt f^[k] (ContinuousLinearMap.id ℂ E) a := by + simpa only [← ContinuousLinearMap.one_def, one_pow] using hfd.iterate hfix k + have H := (HasFDerivAt.fun_sum (u := Finset.range (n + 1)) (fun k _ => hk k)).const_smul + ((n + 1 : ℕ) : ℂ)⁻¹ + have hn : ((n + 1 : ℕ) : ℂ) ≠ 0 := by exact_mod_cast Nat.succ_ne_zero n + simpa only [A, Finset.sum_const, Finset.card_range, ← Nat.cast_smul_eq_nsmul ℂ, + smul_smul, inv_mul_cancel₀ hn, one_smul, Pi.smul_def] using H.fderiv + obtain ⟨g, φ, hφ, hg, hlim⟩ := + exists_subseq_tendstoLocallyUniformlyOn_of_uniform_bound hU hA hAb + have hgd : fderiv ℂ g a = ContinuousLinearMap.id ℂ E := by + have H := (hlim.fderiv_of_finiteDimensional (.of_forall fun n => hA (φ n)) hU).tendsto_at ha + simp only [hAd] at H + exact tendsto_nhds_unique H tendsto_const_nhds + have htel (n : ℕ) (z : E) : A n (f z) - A n z = + ((n + 1 : ℕ) : ℂ)⁻¹ • (f^[n + 1] z - z) := by + dsimp only [A] + rw [← smul_sub, ← Finset.sum_sub_distrib] + congr 1 + simpa only [Function.iterate_succ_apply, Function.iterate_zero_apply] using + (Finset.sum_range_sub (fun k => f^[k] z) (n + 1)) + have hzero (z : E) (hz : z ∈ U) : + Tendsto (fun n => A n (f z) - A n z) atTop (𝓝 0) := by + apply squeeze_zero_norm (fun n => ?_) + (show Tendsto (fun n : ℕ => ((n : ℝ) + 1)⁻¹ * (2 * M)) atTop (𝓝 0) by + simpa only [one_div, zero_mul] using + (tendsto_one_div_add_atTop_nhds_zero_nat (𝕜 := ℝ)).mul_const (2 * M)) + rw [htel, norm_smul, norm_inv, norm_natCast, Nat.cast_add, Nat.cast_one] + apply mul_le_mul_of_nonneg_left _ (by positivity) + exact (norm_sub_le _ _).trans (by linarith [hM _ (hmaps.iterate (n + 1) hz), hM z hz]) + have hgf (z : E) (hz : z ∈ U) : g (f z) = g z := by + have H := (hlim.tendsto_at (hmaps hz)).sub (hlim.tendsto_at hz) + exact sub_eq_zero.mp (tendsto_nhds_unique H ((hzero z hz).comp hφ.tendsto_atTop)) + obtain ⟨V, hV, haV, _, hinj⟩ := exists_open_injOn_of_injective_fderiv hU hg.differentiableOn ha + (by rw [hgd]; exact Function.injective_id) + have heq : f =ᶠ[𝓝 a] id := by + have hpre : f ⁻¹' V ∈ 𝓝 a := (hf a ha).continuousAt.preimage_mem_nhds + (hV.mem_nhds (by simpa only [hfix] using haV)) + filter_upwards [hU.mem_nhds ha, hV.mem_nhds haV, hpre] with z hz hzV hfzV + exact hinj hfzV hzV (hgf z hz) + exact hf.eqOn_of_preconnected_of_eventuallyEq analyticOnNhd_id hconn ha heq + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyCoefficients.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyCoefficients.lean new file mode 100644 index 0000000000..b7edfa7eb9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyCoefficients.lean @@ -0,0 +1,327 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchySeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ParametricIntegral + +/-! +# Mixed Cauchy coefficients + +Higher Cauchy kernels on polydiscs with separate radii. Differentiating the evaluation point +raises the corresponding kernel exponent; the integration contour remains fixed. This identifies +every mixed derivative with the multi-index factorial times its Cauchy coefficient, proves +independence from the contour radii, and yields the sharp mixed-derivative Cauchy estimate. +`PolydiscTaylor` uses these coefficients for convergent Taylor expansions. + +## Main definitions + +* `cauchyKernel`: The higher Cauchy kernel of multi-index `m`. +* `polydiscCauchyTransform`: The higher Cauchy transform with a fixed contour and variable + evaluation point. +* `polydiscCauchyCoeffWithRadii`: Multi-index Cauchy coefficients for a polydisc with separate + radii. + +## Main results + +* `multiIndexDeriv_eq_factorial_smul_cauchyCoeff`: Mixed derivatives at the center are multi-index + factorials times the Cauchy coefficients. +* `polydiscCauchyCoeffWithRadii_eq_of_radii`: Changing the positive contour radii does not change + the Cauchy coefficients. +* `norm_multiIndexDeriv_le`: Cauchy's estimate for every mixed derivative, with the usual + multi-index factorial and a separate radius in each coordinate. +-/ + +public noncomputable section + +open Complex Filter Function MeasureTheory Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {d : ℕ} {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- The higher Cauchy kernel of multi-index `m`. -/ +@[expose] def cauchyKernel (m : Fin d → ℕ) (w z : Fin d → ℂ) : ℂ := + ∏ i, (z i - w i)⁻¹ ^ (m i + 1) + +/-- The higher Cauchy transform with a fixed contour and variable + evaluation point. -/ +@[expose] def polydiscCauchyTransform (f : (Fin d → ℂ) → E) (c : Fin d → ℂ) (R : Fin d → ℝ) + (m : Fin d → ℕ) (w : Fin d → ℂ) : E := + ((2 * π * I : ℂ) ^ d)⁻¹ • torusIntegral (fun z => cauchyKernel m w z • f z) c R + +/-- Multi-index Cauchy coefficients for a polydisc with separate radii. -/ +@[expose] def polydiscCauchyCoeffWithRadii (f : (Fin d → ℂ) → E) (c : Fin d → ℂ) + (R : Fin d → ℝ) (m : Fin d → ℕ) : E := polydiscCauchyTransform f c R m c + +/-- Separate-radius coefficients recover the original equal-radius coefficients. -/ +theorem polydiscCauchyCoeffWithRadii_const (f : (Fin d → ℂ) → E) (c : Fin d → ℂ) + (R : ℝ) (m : Fin d → ℕ) : + polydiscCauchyCoeffWithRadii f c (fun _ => R) m = polydiscCauchyCoeff f c R m := rfl + +/-- Updating the pole in coordinate `i` isolates that factor of the Cauchy kernel. -/ +theorem cauchyKernel_update (m : Fin d → ℕ) (w z : Fin d → ℂ) (i : Fin d) (v : ℂ) : + cauchyKernel m (update w i v) z = + (∏ j ∈ Finset.univ.erase i, (z j - w j)⁻¹ ^ (m j + 1)) * + (z i - v)⁻¹ ^ (m i + 1) := by + rw [cauchyKernel, ← Finset.prod_erase_mul _ _ (Finset.mem_univ i)] + congr 1 + · apply Finset.prod_congr rfl + intro j hj + rw [update_of_ne (Finset.ne_of_mem_erase hj)] + · simp + +/-- Differentiating in coordinate `i` raises that kernel exponent by one. -/ +theorem hasDerivAt_cauchyKernel_update (m : Fin d → ℕ) (w z : Fin d → ℂ) + (i : Fin d) (v : ℂ) (hz : z i - v ≠ 0) : + HasDerivAt (fun a => cauchyKernel m (update w i a) z) + ((m i + 1 : ℂ) * cauchyKernel (update m i (m i + 1)) (update w i v) z) v := by + have hprod : (∏ j ∈ Finset.univ.erase i, (z j - w j)⁻¹ ^ (update m i (m i + 1) j + 1)) = + ∏ j ∈ Finset.univ.erase i, (z j - w j)⁻¹ ^ (m j + 1) := by + apply Finset.prod_congr rfl + intro j hj + rw [update_of_ne (Finset.ne_of_mem_erase hj)] + simp_rw [cauchyKernel_update] + convert! ((((hasDerivAt_id v).const_sub (z i)).inv hz).pow (m i + 1)).const_mul + (∏ j ∈ Finset.univ.erase i, (z j - w j)⁻¹ ^ (m j + 1)) using 1 + rw [hprod] + simp [pow_succ, div_eq_mul_inv] + ring + +/-- Cauchy's multi-index coefficient estimate with one radius for each coordinate. -/ +theorem norm_polydiscCauchyCoeffWithRadii_le {f : (Fin d → ℂ) → E} + {c : Fin d → ℂ} {R : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) (m : Fin d → ℕ) : + ‖polydiscCauchyCoeffWithRadii f c R m‖ ≤ M * ∏ i, (R i)⁻¹ ^ m i := by + have hker (θ : Fin d → ℝ) : ‖cauchyKernel m c (torusMap c R θ)‖ = + ∏ i, (R i)⁻¹ ^ (m i + 1) := by + simp only [cauchyKernel, norm_prod, norm_pow, norm_inv, + norm_torusMap_sub (fun i => (hR i).le)] + rw [polydiscCauchyCoeffWithRadii, polydiscCauchyTransform, norm_smul] + refine (mul_le_mul_of_nonneg_left (norm_torusIntegral_le_of_norm_le_const + (C := M * ∏ i, (R i)⁻¹ ^ (m i + 1)) ?_) (norm_nonneg _)).trans_eq ?_ + · intro θ + rw [norm_smul, hker] + exact (mul_le_mul_of_nonneg_left + (hM _ (torusMap_mem_closedPolydisc (fun i => (hR i).le) θ)) + (Finset.prod_nonneg fun i _ => pow_nonneg (inv_nonneg.mpr (hR i).le) _)).trans_eq + (mul_comm _ _) + · simp only [norm_inv, norm_pow, norm_mul, norm_ofNat, norm_real, norm_I, mul_one, + Real.norm_eq_abs, abs_of_pos Real.pi_pos, abs_of_pos (hR _)] + have hp : (∏ i, R i) * (∏ i, (R i)⁻¹ ^ (m i + 1)) = ∏ i, (R i)⁻¹ ^ m i := by + rw [← Finset.prod_mul_distrib] + apply Finset.prod_congr rfl + intro i hi + rw [pow_succ] + field_simp [(hR i).ne'] + calc + ((2 * π) ^ d)⁻¹ * (((2 * π) ^ d * ∏ i, R i) * (M * ∏ i, (R i)⁻¹ ^ (m i + 1))) = + M * ((∏ i, R i) * ∏ i, (R i)⁻¹ ^ (m i + 1)) := by + field_simp + _ = _ := by rw [hp] + +variable [CompleteSpace E] + +/-- Higher Cauchy kernels are jointly continuous in the interior evaluation point and the contour +parameter. -/ +theorem continuousOn_cauchyKernel_torus {c : Fin d → ℂ} {R : Fin d → ℝ} + (hR : ∀ i, 0 < R i) (m : Fin d → ℕ) : + ContinuousOn (fun p : (Fin d → ℂ) × (Fin d → ℝ) => + cauchyKernel m p.1 (torusMap c R p.2)) (polydisc c R ×ˢ univ) := by + apply continuousOn_finsetProd + intro i hi + apply ContinuousOn.pow + apply ContinuousOn.inv₀ + · exact ((((continuous_apply i).comp (continuous_torusMap c R)).comp + continuous_snd).sub ((continuous_apply i).comp continuous_fst)).continuousOn + · intro p hp + exact sub_ne_zero.mpr (torusMap_apply_ne_of_norm_sub_lt hR + (by simpa [dist_eq_norm] using mem_polydisc.mp hp.1 i)) + +omit [CompleteSpace E] in +/-- Coordinate differentiation under the fixed-contour higher Cauchy integral. -/ +theorem hasDerivAt_polydiscCauchyTransform_update {f : (Fin d → ℂ) → E} + {c w : Fin d → ℂ} {R : Fin d → ℝ} (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hw : w ∈ polydisc c R) (m : Fin d → ℕ) (i : Fin d) : + HasDerivAt (fun a => polydiscCauchyTransform f c R m (update w i a)) + ((m i + 1 : ℂ) • polydiscCauchyTransform f c R (update m i (m i + 1)) w) (w i) := by + let V : Set ℂ := (update w i) ⁻¹' polydisc c R + let K : Set (Fin d → ℝ) := Icc 0 (fun _ => 2 * π) + let J (θ : Fin d → ℝ) : ℂ := ∏ j, R j * exp (θ j * I) * I + let G (a : ℂ) (θ : Fin d → ℝ) := + J θ • cauchyKernel m (update w i a) (torusMap c R θ) • f (torusMap c R θ) + let G' (a : ℂ) (θ : Fin d → ℝ) := + (m i + 1 : ℂ) • J θ • cauchyKernel (update m i (m i + 1)) + (update w i a) (torusMap c R θ) • f (torusMap c R θ) + have hV : IsOpen V := (isOpen_polydisc c R).preimage + (continuous_const.update i continuous_id) + have hwi : w i ∈ V := by simpa [V] using hw + have hu : Continuous (fun p : ℂ × (Fin d → ℝ) => update w i p.1) := + (show Continuous (fun _ : ℂ × (Fin d → ℝ) => w) from continuous_const).update i continuous_fst + have hker (k : Fin d → ℕ) : ContinuousOn + (fun p : ℂ × (Fin d → ℝ) => cauchyKernel k (update w i p.1) (torusMap c R p.2)) + (V ×ˢ K) := by + apply continuousOn_finsetProd + intro j hj + apply ContinuousOn.pow + apply ContinuousOn.inv₀ + · exact ((((continuous_apply j).comp (continuous_torusMap c R)).comp continuous_snd).sub + ((continuous_apply j).comp hu)).continuousOn + · intro p hp + exact sub_ne_zero.mpr (torusMap_apply_ne_of_norm_sub_lt hR + (by simpa [dist_eq_norm] using mem_polydisc.mp hp.1 j)) + have hfun : ContinuousOn (fun p : ℂ × (Fin d → ℝ) => f (torusMap c R p.2)) (V ×ˢ K) := + hfc.comp ((continuous_torusMap c R).comp continuous_snd).continuousOn + (fun p _ => torusMap_mem_closedPolydisc (fun j => (hR j).le) p.2) + have hJ : Continuous (fun p : ℂ × (Fin d → ℝ) => J p.2) := by dsimp [J]; fun_prop + have hG : ContinuousOn (fun p : ℂ × (Fin d → ℝ) => G p.1 p.2) (V ×ˢ K) := + hJ.continuousOn.smul ((hker m).smul hfun) + have hG' : ContinuousOn (fun p : ℂ × (Fin d → ℝ) => G' p.1 p.2) (V ×ˢ K) := + continuousOn_const.smul (hJ.continuousOn.smul ((hker _).smul hfun)) + have hd : ∀ a ∈ V, ∀ θ ∈ K, HasDerivAt (fun b => G b θ) (G' a θ) a := by + intro a ha θ hθ + have hp : torusMap c R θ i - a ≠ 0 := by + have H := sub_ne_zero.mpr (torusMap_apply_ne_of_norm_sub_lt + (c := c) (θ := θ) (i := i) (w := update w i a) hR + (by simpa [dist_eq_norm] using mem_polydisc.mp ha i)) + simpa using H + simpa only [G, G', Pi.smul_def, smul_smul, mul_assoc, mul_left_comm] using! + ((hasDerivAt_cauchyKernel_update m w (torusMap c R θ) i a hp).smul_const + (f (torusMap c R θ))).const_smul (J θ) + have H := (hasDerivAt_integral_of_continuousOn_compact (μ := volume) + (show IsCompact K from isCompact_Icc) hV hwi hG hG' hd).const_smul + (((2 * π * I : ℂ) ^ d)⁻¹) + have hval : (∫ θ in K, G' (w i) θ) = (m i + 1 : ℂ) • + torusIntegral (fun z => cauchyKernel (update m i (m i + 1)) w z • f z) c R := by + simp only [G', update_eq_self] + rw [integral_smul] + rfl + rw [hval, smul_comm (((2 * π * I : ℂ) ^ d)⁻¹) (m i + 1 : ℂ)] at H + simpa only [polydiscCauchyTransform, torusIntegral, G, K, J, Pi.smul_def] using! H + +/-- The zeroth Cauchy transform equals the original function in the open polydisc. -/ +theorem polydiscCauchyTransform_zero_eq {f : (Fin d → ℂ) → E} {c w : Fin d → ℂ} {R : Fin d → ℝ} + (hR : ∀ i, 0 < R i) (hw : w ∈ polydisc c R) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) : + polydiscCauchyTransform f c R 0 w = f w := by + simpa [polydiscCauchyTransform, cauchyKernel] using + two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul + hR + (fun i => by simpa [dist_eq_norm] using mem_polydisc.mp hw i) hfc hfa + +/-- Prepending an index to a list increments its count there and fixes the other counts. -/ +private theorem count_cons_eq_update (is : List (Fin d)) (i : Fin d) : + (fun j => (i :: is).count j) = update (fun j => is.count j) i (is.count i + 1) := by + funext j + by_cases hji : j = i + · subst j; simp + · simp [hji, Ne.symm hji] + +/-- The product of factorials of the counts after prepending an index. -/ +private theorem prod_factorial_count_cons (is : List (Fin d)) (i : Fin d) : + (∏ j, (((i :: is).count j).factorial : ℂ)) = + (∏ j, ((is.count j).factorial : ℂ)) * (is.count i + 1 : ℂ) := by + calc + (∏ j, (((i :: is).count j).factorial : ℂ)) = + ∏ j, (if j = i then (is.count i + 1 : ℂ) else 1) * ((is.count j).factorial : ℂ) := by + apply Finset.prod_congr rfl + intro j hj + by_cases hji : j = i + · subst j; simp [Nat.factorial_succ] + · simp [hji, Ne.symm hji] + _ = _ := by rw [Finset.prod_mul_distrib]; simp [mul_comm] + +omit [CompleteSpace E] in +/-- Repeated coordinate differentiation of the zeroth Cauchy transform yields factorials times the +corresponding higher Cauchy transform. -/ +theorem iteratedPartialDeriv_polydiscCauchyTransform_zero {f : (Fin d → ℂ) → E} + {c w : Fin d → ℂ} {R : Fin d → ℝ} (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hw : w ∈ polydisc c R) (is : List (Fin d)) : + iteratedPartialDeriv is (polydiscCauchyTransform f c R 0) w = + (∏ j, ((is.count j).factorial : ℂ)) • + polydiscCauchyTransform f c R (fun j => is.count j) w := by + induction is generalizing w with + | nil => simp [iteratedPartialDeriv, Pi.zero_def] + | cons i is ih => + change partialDeriv i (iteratedPartialDeriv is (polydiscCauchyTransform f c R 0)) w = _ + have heq : partialDeriv i (iteratedPartialDeriv is (polydiscCauchyTransform f c R 0)) w = + partialDeriv i (fun v => (∏ j, ((is.count j).factorial : ℂ)) • + polydiscCauchyTransform f c R (fun j => is.count j) v) w := by + apply partialDeriv_congr + filter_upwards [(isOpen_polydisc c R).eventually_mem hw] with v hv + exact ih hv + rw [heq, partialDeriv] + have H := + (hasDerivAt_polydiscCauchyTransform_update hR hfc hw (fun j => is.count j) i).const_smul + (∏ j, ((is.count j).factorial : ℂ)) + have HD := H.deriv + simp only [Pi.smul_def, smul_smul] at HD + rw [prod_factorial_count_cons, count_cons_eq_update] + convert! HD using 1 + +/-- Mixed derivatives at the center are multi-index factorials times the Cauchy coefficients. -/ +theorem multiIndexDeriv_eq_factorial_smul_cauchyCoeff {f : (Fin d → ℂ) → E} + {c : Fin d → ℂ} {R : Fin d → ℝ} (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) (m : Fin d → ℕ) : + multiIndexDeriv m f c = (∏ i, (m i).factorial : ℂ) • polydiscCauchyCoeffWithRadii f c R m := by + have hc : c ∈ polydisc c R := mem_polydisc.mpr (by simpa using hR) + have hcongr := iteratedPartialDeriv_congrOn (isOpen_polydisc c R) + (fun z hz => (polydiscCauchyTransform_zero_eq hR hz hfc hfa).symm) (multiIndexList m) hc + rw [multiIndexDeriv, hcongr, iteratedPartialDeriv_polydiscCauchyTransform_zero hR hfc hc] + simp only [count_multiIndexList, polydiscCauchyCoeffWithRadii] + +/-- Cauchy coefficients are the mixed Taylor coefficients, independent of a contour choice. -/ +theorem polydiscCauchyCoeffWithRadii_eq_multiIndexDeriv {f : (Fin d → ℂ) → E} + {c : Fin d → ℂ} {R : Fin d → ℝ} (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) (m : Fin d → ℕ) : + polydiscCauchyCoeffWithRadii f c R m = + (∏ i, (m i).factorial : ℂ)⁻¹ • multiIndexDeriv m f c := by + rw [multiIndexDeriv_eq_factorial_smul_cauchyCoeff hR hfc hfa m, smul_smul, + inv_mul_cancel₀ (Finset.prod_ne_zero_iff.mpr (fun i _ => + Nat.cast_ne_zero.mpr (m i).factorial_ne_zero)), one_smul] + +/-- Changing the positive contour radii does not change the Cauchy coefficients. -/ +theorem polydiscCauchyCoeffWithRadii_eq_of_radii {f : (Fin d → ℂ) → E} + {c : Fin d → ℂ} {R S : Fin d → ℝ} (hR : ∀ i, 0 < R i) (hS : ∀ i, 0 < S i) + (hfcR : ContinuousOn f (closedPolydisc c R)) + (hfaR : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hfcS : ContinuousOn f (closedPolydisc c S)) + (hfaS : ∀ z ∈ closedPolydisc c S, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) (m : Fin d → ℕ) : + polydiscCauchyCoeffWithRadii f c R m = polydiscCauchyCoeffWithRadii f c S m := by + rw [polydiscCauchyCoeffWithRadii_eq_multiIndexDeriv hR hfcR hfaR, + polydiscCauchyCoeffWithRadii_eq_multiIndexDeriv hS hfcS hfaS] + +/-- Cauchy's estimate for every mixed derivative, with the usual multi-index factorial and a +separate radius in each coordinate. -/ +theorem norm_multiIndexDeriv_le {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} + {R : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) (m : Fin d → ℕ) : + ‖multiIndexDeriv m f c‖ ≤ (∏ i, ((m i).factorial : ℝ)) * (M * ∏ i, (R i)⁻¹ ^ m i) := by + rw [multiIndexDeriv_eq_factorial_smul_cauchyCoeff hR hfc hfa, norm_smul] + simpa only [norm_prod, norm_natCast] using + mul_le_mul_of_nonneg_left (norm_polydiscCauchyCoeffWithRadii_le hR hM m) + (norm_nonneg (∏ i, ((m i).factorial : ℂ))) + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyDerivatives.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyDerivatives.lean new file mode 100644 index 0000000000..111c9f0226 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyDerivatives.lean @@ -0,0 +1,138 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.Deriv.ZPow +public import Mathlib.Analysis.Complex.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ParametricIntegral + +/-! +# Cauchy's derivative formula at an arbitrary point of a disk + +Mathlib's higher-derivative circle formula is stated at the center. Here the evaluation point +may be anywhere in the open disk. Differentiating the contour kernel with respect to that point +preserves the hypothesis of continuity on the boundary: no boundary derivatives of the function +are required. + +These Banach-valued, one-variable results also support iterated Cauchy formulas in several +variables. The circle center and evaluation point are independent, and the derivative order is +arbitrary. The statements use Mathlib's `HasDerivAt`, `iteratedDeriv`, `DiffContOnCl`, and +circle-integral interfaces rather than introducing a separate contour or derivative theory. +Their intended Mathlib home is `Analysis.Complex.CauchyIntegral`. + +## Main results + +* `hasDerivAt_circleIntegral_sub_zpow_smul`: Differentiation in the evaluation point raises the + order of the circle Cauchy kernel. +* `DiffContOnCl.iteratedDeriv_eq_circleIntegral_sub_zpow_smul`: Cauchy's formula for every + derivative at any point inside the circle. +* `hasDerivAt_circleIntegral_sub_zpow_mul`: Differentiation in the evaluation point raises the order + of the circle Cauchy kernel. +* `DiffContOnCl.iteratedDeriv_eq_circleIntegral_sub_zpow_mul`: Cauchy's formula for every derivative + at any point inside the circle. +-/ + +open Complex MeasureTheory Metric Filter Set +open scoped Topology + +public noncomputable section + +section Banach +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Differentiation in the evaluation point raises the order of the circle Cauchy kernel. -/ +theorem hasDerivAt_circleIntegral_sub_zpow_smul + {c w : ℂ} {R : ℝ} (hR : 0 ≤ R) (hw : w ∈ ball c R) + {f : ℂ → E} (hf : ContinuousOn f (sphere c R)) (n : ℕ) : + HasDerivAt (fun w => ∮ s in C(c, R), (s - w) ^ (-(n + 1 : ℤ)) • f s) + (((n : ℂ) + 1) • ∮ s in C(c, R), (s - w) ^ (-((n + 1 : ℕ) + 1 : ℤ)) • f s) w := by + have hkernel (k : ℕ) : ContinuousOn (fun p : ℂ × ℝ => + (circleMap c R p.2 - p.1) ^ (-(k + 1 : ℤ))) + (ball c R ×ˢ Icc 0 (2 * Real.pi)) := by + exact (((continuous_circleMap c R).comp continuous_snd).sub continuous_fst).continuousOn.zpow₀ _ + (fun p hp => Or.inl (sub_ne_zero.mpr (circleMap_ne_mem_ball hp.1 p.2))) + have hcircle : ContinuousOn (fun p : ℂ × ℝ => deriv (circleMap c R) p.2) + (ball c R ×ˢ Icc 0 (2 * Real.pi)) := by + simp only [deriv_circleMap] + fun_prop + have hfun : ContinuousOn (fun p : ℂ × ℝ => f (circleMap c R p.2)) + (ball c R ×ˢ Icc 0 (2 * Real.pi)) := + hf.comp ((continuous_circleMap c R).comp continuous_snd).continuousOn + (fun p _ => circleMap_mem_sphere c hR p.2) + have h := hasDerivAt_integral_of_continuousOn_compact + (μ := volume) (K := Icc 0 (2 * Real.pi)) + (F := fun w θ => deriv (circleMap c R) θ • + ((circleMap c R θ - w) ^ (-(n + 1 : ℤ)) • f (circleMap c R θ))) + (F' := fun w θ => ((n : ℂ) + 1) • (deriv (circleMap c R) θ • + ((circleMap c R θ - w) ^ (-((n + 1 : ℕ) + 1 : ℤ)) • f (circleMap c R θ)))) + isCompact_Icc isOpen_ball hw + (hcircle.smul ((hkernel n).smul hfun)) + (continuousOn_const.smul (hcircle.smul ((hkernel (n + 1)).smul hfun))) ?_ + · simpa only [circleIntegral_def_Icc, integral_smul] using h + intro x hx θ _ + have hd := (hasDerivAt_zpow (-(n + 1 : ℤ)) (circleMap c R θ - x) + (Or.inl (sub_ne_zero.mpr (circleMap_ne_mem_ball hx θ)))).comp x + ((hasDerivAt_id x).const_sub (circleMap c R θ)) + have hexp : -(n + 1 : ℤ) - 1 = -((n + 1 : ℕ) + 1 : ℤ) := by omega + have hd' : HasDerivAt (fun w => (circleMap c R θ - w) ^ (-(n + 1 : ℤ))) + (((n : ℂ) + 1) * (circleMap c R θ - x) ^ (-((n + 1 : ℕ) + 1 : ℤ))) x := by + simpa only [Function.comp_def, id_eq, hexp, Int.cast_neg, Int.cast_add, + Int.cast_natCast, Int.cast_one, mul_neg_one, neg_mul, neg_neg] using hd + convert (hd'.smul_const (f (circleMap c R θ))).const_smul (deriv (circleMap c R) θ) using 1 + simp only [smul_smul] + congr 1 + ring + +variable [CompleteSpace E] + +/-- Cauchy's formula for every derivative at any point inside the circle. The function need only be +holomorphic in the open disk and continuous on its closure. -/ +theorem DiffContOnCl.iteratedDeriv_eq_circleIntegral_sub_zpow_smul + {c : ℂ} {R : ℝ} {f : ℂ → E} (hf : DiffContOnCl ℂ f (ball c R)) + (hR : 0 < R) (n : ℕ) {w : ℂ} (hw : w ∈ ball c R) : + iteratedDeriv n f w = ((n.factorial : ℂ) * (2 * (Real.pi : ℂ) * I)⁻¹) • + ∮ s in C(c, R), (s - w) ^ (-(n + 1 : ℤ)) • f s := by + induction n generalizing w with + | zero => + simpa using + (hf.two_pi_i_inv_smul_circleIntegral_sub_inv_smul hw).symm + | succ n ih => + have heq : (iteratedDeriv n f) =ᶠ[nhds w] + (fun w => ((n.factorial : ℂ) * (2 * (Real.pi : ℂ) * I)⁻¹) • + ∮ s in C(c, R), (s - w) ^ (-(n + 1 : ℤ)) • f s) := by + filter_upwards [isOpen_ball.mem_nhds hw] with v hv + exact ih hv + rw [iteratedDeriv_succ, heq.deriv_eq] + have hd := ((hasDerivAt_circleIntegral_sub_zpow_smul hR.le hw + (hf.continuousOn_ball.mono sphere_subset_closedBall) n).const_smul + ((n.factorial : ℂ) * (2 * (Real.pi : ℂ) * I)⁻¹)).deriv + apply hd.trans + simp only [Nat.factorial_succ, Nat.cast_mul, Nat.cast_add, Nat.cast_one, smul_smul] + congr 1 + ring + +end Banach + +/-- Differentiation in the evaluation point raises the order of the circle Cauchy kernel. -/ +theorem hasDerivAt_circleIntegral_sub_zpow_mul + {c w : ℂ} {R : ℝ} (hR : 0 ≤ R) (hw : w ∈ ball c R) + {f : ℂ → ℂ} (hf : ContinuousOn f (sphere c R)) (n : ℕ) : + HasDerivAt (fun w => ∮ s in C(c, R), (s - w) ^ (-(n + 1 : ℤ)) * f s) + (((n : ℂ) + 1) * ∮ s in C(c, R), (s - w) ^ (-((n + 1 : ℕ) + 1 : ℤ)) * f s) w := by + simpa only [smul_eq_mul] using hasDerivAt_circleIntegral_sub_zpow_smul hR hw hf n + +/-- Cauchy's formula for every derivative at any point inside the circle. The function need only be +holomorphic in the open disk and continuous on its closure. -/ +theorem DiffContOnCl.iteratedDeriv_eq_circleIntegral_sub_zpow_mul + {c : ℂ} {R : ℝ} {f : ℂ → ℂ} (hf : DiffContOnCl ℂ f (ball c R)) + (hR : 0 < R) (n : ℕ) {w : ℂ} (hw : w ∈ ball c R) : + iteratedDeriv n f w = (n.factorial : ℂ) * (2 * (Real.pi : ℂ) * I)⁻¹ * + ∮ s in C(c, R), (s - w) ^ (-(n + 1 : ℤ)) * f s := by + simpa only [smul_eq_mul] using hf.iteratedDeriv_eq_circleIntegral_sub_zpow_smul hR n hw + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyEstimates.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyEstimates.lean new file mode 100644 index 0000000000..e4787fee99 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyEstimates.lean @@ -0,0 +1,90 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Liouville +public import Mathlib.Topology.MetricSpace.Thickening +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives + +/-! +# Cauchy estimates and local derivative bounds + +These estimates reuse the one-variable Cauchy estimate on coordinate slices. The source has the +supremum norm, so a coordinate disc fits in the ball of the same radius. Derivatives are also +uniformly bounded on small closed thickenings of compact subsets of a one-variable holomorphic +domain. + +## Main results + +`norm_partialDeriv_le` is the Cauchy estimate for a coordinate derivative on a polydisc. +`norm_partialDeriv_le_of_slice` is the one-variable slice form. +`AnalyticOnNhd.exists_cthickening_deriv_bound` bounds derivatives uniformly on a closed +thickening of a compact subset of a one-variable domain. +-/ + +public section + +open Complex Function Metric Set + +/-- The derivative of a holomorphic function is uniformly bounded on a sufficiently small closed +thickening of any compact subset of its open domain. -/ +theorem AnalyticOnNhd.exists_cthickening_deriv_bound + {Ω K : Set ℂ} {f : ℂ → ℂ} (hf : AnalyticOnNhd ℂ f Ω) + (hΩopen : IsOpen Ω) (hK : IsCompact K) (hKΩ : K ⊆ Ω) : + ∃ δ : ℝ, 0 < δ ∧ Metric.cthickening δ K ⊆ Ω ∧ + ∃ C : ℝ, 0 ≤ C ∧ ∀ w ∈ Metric.cthickening δ K, ‖deriv f w‖ ≤ C := by + obtain ⟨δ₁, hδ₁, hδ₁compact⟩ := hK.exists_isCompact_cthickening + obtain ⟨δ₂, hδ₂, hδ₂Ω⟩ := hK.exists_cthickening_subset_open hΩopen hKΩ + let δ := min δ₁ δ₂ + have hcompact : IsCompact (Metric.cthickening δ K) := + hδ₁compact.of_isClosed_subset Metric.isClosed_cthickening + (Metric.cthickening_mono (min_le_left _ _) K) + have hsub : Metric.cthickening δ K ⊆ Ω := + (Metric.cthickening_mono (min_le_right _ _) K).trans hδ₂Ω + obtain ⟨C, hC⟩ := hcompact.bddAbove_image (hf.deriv.continuousOn.mono hsub).norm + exact ⟨δ, lt_min hδ₁ hδ₂, hsub, max C 0, le_max_right _ _, + fun w hw => (hC (Set.mem_image_of_mem _ hw)).trans (le_max_left _ _)⟩ + +namespace SeveralComplexVariables + +variable {ι F : Type*} [Fintype ι] [DecidableEq ι] [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- Updating one coordinate within its closed disc stays in the corresponding sup-norm ball. -/ +theorem update_mem_closedBall {z : ι → ℂ} {i : ι} {w : ℂ} {r : ℝ} + (hr : 0 ≤ r) (hw : w ∈ closedBall (z i) r) : update z i w ∈ closedBall z r := by + rw [mem_closedBall, dist_pi_le_iff hr] + intro j + by_cases hji : j = i + · simpa [hji] using hw + · simpa [Function.update_of_ne hji] using hr + +omit [Fintype ι] in +/-- Cauchy's first derivative bound only needs holomorphy along the chosen coordinate disc. -/ +theorem norm_partialDeriv_le_of_slice {f : (ι → ℂ) → F} {z : ι → ℂ} + (i : ι) {r M : ℝ} (hr : 0 < r) + (hf : DifferentiableOn ℂ (fun w => f (update z i w)) (closedBall (z i) r)) + (hM : ∀ w ∈ sphere (z i) r, ‖f (update z i w)‖ ≤ M) : + ‖partialDeriv i f z‖ ≤ M / r := + Complex.norm_deriv_le_of_forall_mem_sphere_norm_le hr + (hf.diffContOnCl_ball Subset.rfl) hM + +/-- A bound on a closed sup-norm ball controls every coordinate derivative at its center. -/ +theorem norm_partialDeriv_le {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) {z : ι → ℂ} (i : ι) {r M : ℝ} (hr : 0 < r) + (hball : closedBall z r ⊆ U) (hM : ∀ w ∈ closedBall z r, ‖f w‖ ≤ M) : + ‖partialDeriv i f z‖ ≤ M / r := by + apply norm_partialDeriv_le_of_slice i hr + · intro w hw + exact ((hf _ (hball (update_mem_closedBall hr.le hw))).differentiableAt.comp w + (hasDerivAt_update z i w).differentiableAt).differentiableWithinAt + · intro w hw + exact hM _ (update_mem_closedBall hr.le (sphere_subset_closedBall hw)) + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyIntegral.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyIntegral.lean new file mode 100644 index 0000000000..37b7bcb084 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyIntegral.lean @@ -0,0 +1,204 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc + +/-! +# Cauchy's integral formula on a polydisc + +The vector-valued iterated Cauchy formula assumes continuity and coordinatewise analyticity on +the closed polydisc. It does not depend on the several-variable Osgood theorem. The +distinguished boundary is the coordinate torus of the closed polydisc `closedPolydisc`. + +## Main results + +`two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul` is the iterated formula with a separate +radius in each coordinate; `two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul_const` is the +equal-radius specialization. `torusIntegrable_cauchyKernelWithRadii` records integrability of the +Cauchy kernel on that torus whenever the evaluation point lies in the open polydisc. +-/ + +public section + +open Complex Filter Function MeasureTheory Metric Set +open scoped ENNReal NNReal Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-! +### Cauchy's formula on a polydisc +-/ + +omit [CompleteSpace E] in +/-- The vector-valued Cauchy kernel of a continuous function is integrable on a torus whenever the +evaluation point lies in the interior polydisc. -/ +theorem torusIntegrable_cauchyKernelWithRadii {n : ℕ} {f : (Fin n → ℂ) → E} {c w : Fin n → ℂ} {R : + Fin n → ℝ} + (hR : ∀ i, 0 < R i) (hw : ∀ i, ‖w i - c i‖ < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) : + TorusIntegrable (fun z => (∏ i, (z i - w i)⁻¹) • f z) c R := by + have hmaps : MapsTo (torusMap c R) + (Icc (0 : Fin n → ℝ) fun _ => 2 * π) (closedPolydisc c R) := + fun θ _ => torusMap_mem_closedPolydisc (fun i => (hR i).le) θ + have hfθ : ContinuousOn (fun θ => f (torusMap c R θ)) + (Icc (0 : Fin n → ℝ) fun _ => 2 * π) := + hfc.comp (continuous_torusMap c R).continuousOn hmaps + have hker : ContinuousOn + (fun θ : Fin n → ℝ => (∏ i, (torusMap c R θ i - w i)⁻¹)) + (Icc (0 : Fin n → ℝ) fun _ => 2 * π) := by + refine continuousOn_finsetProd _ fun i _ => ?_ + refine ((((continuous_apply i).comp (continuous_torusMap c R)).continuousOn).sub + continuousOn_const).inv₀ ?_ + intro θ _ + exact sub_ne_zero.2 (torusMap_apply_ne_of_norm_sub_lt hR (hw i)) + exact (hker.smul hfθ).integrableOn_compact isCompact_Icc + +/-- Splitting off the first coordinate factors the finite-product Cauchy kernel. -/ +theorem cauchyKernel_cons {n : ℕ} (x : ℂ) (y : Fin n → ℂ) (w : Fin (n + 1) → ℂ) : + (∏ i, ((Fin.cons x y : Fin (n + 1) → ℂ) i - w i)⁻¹) = + (x - w 0)⁻¹ * ∏ i, (y i - w i.succ)⁻¹ := by + simp [Fin.prod_univ_succ, mul_comm] + +/-- The one-variable Cauchy formula along the first-coordinate slice of a closed polydisc. All other +coordinates are fixed at the evaluation point. -/ +private theorem circleIntegral_cauchyKernel_cons {n : ℕ} + {f : (Fin (n + 1) → ℂ) → E} {c w : Fin (n + 1) → ℂ} {R : Fin (n + 1) → ℝ} + (hw : ∀ i, ‖w i - c i‖ < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) : + (2 * π * I : ℂ)⁻¹ • + (∮ x in C(c 0, R 0), (x - w 0)⁻¹ • f (Fin.cons x (w ∘ Fin.succ))) = + f (Fin.cons (w 0) (w ∘ Fin.succ)) := by + have hcons : Continuous (fun x : ℂ => (Fin.cons x (w ∘ Fin.succ) : Fin (n + 1) → ℂ)) := + Continuous.finCons (A := fun _ : Fin (n + 1) => ℂ) continuous_id continuous_const + have hψcont : ContinuousOn (fun x => f (Fin.cons x (w ∘ Fin.succ))) + (closedBall (c 0) (R 0)) := + hfc.comp hcons.continuousOn fun x hx => + cons_mem_closedPolydisc hx (fun i _ => + mem_closedBall.2 (le_of_lt (by simpa [dist_eq_norm] using hw i.succ))) + have hψdiff : ∀ x ∈ ball (c 0) (R 0), + DifferentiableAt ℂ (fun t => f (Fin.cons t (w ∘ Fin.succ))) x := by + intro x hx + have hz : Fin.cons x (w ∘ Fin.succ) ∈ closedPolydisc c R := + cons_mem_closedPolydisc (ball_subset_closedBall hx) fun i _ => + mem_closedBall.2 (le_of_lt (by simpa [dist_eq_norm] using hw i.succ)) + simpa [Fin.update_cons_zero] using (hfa _ hz 0).differentiableAt + have hcircle : + ((2 * π * I : ℂ)⁻¹ • + ∮ x in C(c 0, R 0), (x - w 0)⁻¹ • f (Fin.cons x (w ∘ Fin.succ))) = + f (Fin.cons (w 0) (w ∘ Fin.succ)) := by + have hw0 : w 0 ∈ ball (c 0) (R 0) := by simpa [dist_eq_norm] using hw 0 + simpa using + two_pi_I_inv_smul_circleIntegral_sub_inv_smul_of_differentiable_on_off_countable + (s := (∅ : Set ℂ)) countable_empty hw0 hψcont fun x hx => hψdiff x hx.1 + exact hcircle + +/-- Iterated Cauchy integral formula on a closed polydisc. -/ +theorem two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul {n : ℕ} {f : (Fin n → ℂ) → E} + {c w : Fin n → ℂ} {R : Fin n → ℝ} + (hR : ∀ i, 0 < R i) (hw : ∀ i, ‖w i - c i‖ < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) : + ((2 * π * I : ℂ) ^ n)⁻¹ • + torusIntegral (fun z => (∏ i, (z i - w i)⁻¹) • f z) c R = f w := by + induction n with + | zero => + have : w = c := Subsingleton.elim _ _ + subst this + simp [torusIntegral_dim0] + | succ n ih => + set F : (Fin (n + 1) → ℂ) → E := + fun z => (∏ i, (z i - w i)⁻¹) • f z + have hFint : TorusIntegrable F c R := + torusIntegrable_cauchyKernelWithRadii hR hw hfc + have hinter : ∀ x ∈ sphere (c 0) (R 0), + torusIntegral (fun y => F (Fin.cons x y)) (c ∘ Fin.succ) (R ∘ Fin.succ) = + (x - w 0)⁻¹ • ((2 * π * I : ℂ) ^ n • + f (Fin.cons x (w ∘ Fin.succ))) := by + intro x hx + have hxcl := sphere_subset_closedBall hx + have hgcont : ContinuousOn (fun y => f (Fin.cons x y)) + (closedPolydisc (c ∘ Fin.succ) (R ∘ Fin.succ)) := + hfc.comp (continuousOn_const.finCons continuousOn_id) + (fun y hy => cons_mem_closedPolydisc hxcl hy) + have hga : ∀ y ∈ closedPolydisc (c ∘ Fin.succ) (R ∘ Fin.succ), ∀ j, + AnalyticAt ℂ (fun t => f (Fin.cons x (update y j t))) (y j) := by + intro y hy j + have hz := cons_mem_closedPolydisc hxcl hy + simpa [Fin.cons_update] using hfa (Fin.cons x y) hz j.succ + have hw' : ∀ i : Fin n, ‖w i.succ - c i.succ‖ < R i.succ := fun i => hw i.succ + have ih' := + ih (f := fun y => f (Fin.cons x y)) (c := c ∘ Fin.succ) (w := w ∘ Fin.succ) + (fun i => hR i.succ) hw' hgcont hga + have ih_int : + torusIntegral (fun y => (∏ i, (y i - w i.succ)⁻¹) • f (Fin.cons x y)) + (c ∘ Fin.succ) (R ∘ Fin.succ) = + (2 * π * I : ℂ) ^ n • f (Fin.cons x (w ∘ Fin.succ)) := + ((eq_inv_smul_iff₀ (two_pi_I_pow_ne_zero n)).mp ih'.symm).symm + have hsmul := torusIntegral_smul (x - w 0)⁻¹ + (fun y => (∏ i, (y i - w i.succ)⁻¹) • f (Fin.cons x y)) + (c ∘ Fin.succ) (R ∘ Fin.succ) + calc + torusIntegral (fun y => F (Fin.cons x y)) (c ∘ Fin.succ) (R ∘ Fin.succ) + = torusIntegral (fun y => (x - w 0)⁻¹ • + (∏ i, (y i - w i.succ)⁻¹) • f (Fin.cons x y)) + (c ∘ Fin.succ) (R ∘ Fin.succ) := by + congr 1 + funext y + simp only [F] + rw [cauchyKernel_cons x y w, mul_smul] + _ = (x - w 0)⁻¹ • torusIntegral + (fun y => (∏ i, (y i - w i.succ)⁻¹) • f (Fin.cons x y)) + (c ∘ Fin.succ) (R ∘ Fin.succ) := hsmul + _ = (x - w 0)⁻¹ • ((2 * π * I : ℂ) ^ n • + f (Fin.cons x (w ∘ Fin.succ))) := by rw [ih_int] + have hcircle := circleIntegral_cauchyKernel_cons hw hfc hfa + have houter : + torusIntegral F c R = + (2 * π * I : ℂ) ^ n • + ∮ x in C(c 0, R 0), (x - w 0)⁻¹ • f (Fin.cons x (w ∘ Fin.succ)) := by + rw [torusIntegral_succ hFint] + refine (circleIntegral.integral_congr (hR 0).le fun x hx => hinter x hx).trans ?_ + rw [show (fun x => (x - w 0)⁻¹ • ((2 * π * I : ℂ) ^ n • + f (Fin.cons x (w ∘ Fin.succ)))) = + fun x => ((2 * π * I : ℂ) ^ n) • ((x - w 0)⁻¹ • + f (Fin.cons x (w ∘ Fin.succ))) by + funext x; simp [smul_smul, mul_comm]] + rw [circleIntegral.integral_smul] + have hw_eq : Fin.cons (w 0) (w ∘ Fin.succ) = w := Fin.cons_self_tail w + rw [← hw_eq, houter, smul_smul] + convert hcircle using 2 + simp [pow_succ, two_pi_I_pow_ne_zero n] + +omit [CompleteSpace E] in +/-- Equal-radius compatibility form of Cauchy-kernel integrability. -/ +theorem torusIntegrable_cauchyKernel {n : ℕ} {f : (Fin n → ℂ) → E} + {c w : Fin n → ℂ} {R : ℝ} (hR : 0 < R) (hw : ∀ i, ‖w i - c i‖ < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) : + TorusIntegrable (fun z => (∏ i, (z i - w i)⁻¹) • f z) c (fun _ => R) := + torusIntegrable_cauchyKernelWithRadii (fun _ => hR) hw hfc + +/-- Equal-radius compatibility form of the polydisc Cauchy formula. -/ +theorem two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul_const {n : ℕ} {f : (Fin n → ℂ) → E} + {c w : Fin n → ℂ} {R : ℝ} + (hR : 0 < R) (hw : ∀ i, ‖w i - c i‖ < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) + (hfa : ∀ z ∈ closedPolydisc c (fun _ => R), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) : + ((2 * π * I : ℂ) ^ n)⁻¹ • + torusIntegral (fun z => (∏ i, (z i - w i)⁻¹) • f z) c (fun _ => R) = f w := + two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul (fun _ => hR) hw hfc hfa + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyPompeiu.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyPompeiu.lean new file mode 100644 index 0000000000..c3e835d038 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyPompeiu.lean @@ -0,0 +1,382 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.ContDiff.Basic +public import Mathlib.Analysis.Calculus.FDeriv.Const +public import Mathlib.Analysis.Complex.RealDeriv +public import Mathlib.Analysis.SpecialFunctions.Complex.Circle +public import Mathlib.Analysis.SpecialFunctions.PolarCoord +public import Mathlib.MeasureTheory.Integral.IntegralEqImproper + +/-! +# The Cauchy–Pompeiu identity + +For a real-linear map `L` and a direction `v`, the antiholomorphic part of `L` along `v` is `(L +v + I • L (I • v)) / 2`; for the real derivative of a function of one complex variable and `v = +1` this is the Wirtinger derivative `∂f/∂\bar z`. A real-linear map is complex-linear exactly +when all its antiholomorphic parts vanish. + +The Cauchy–Pompeiu identity states that for a compactly supported `C¹` function `φ : ℂ → F`, `∫ +(∂φ/∂\bar z)(w) / w = -π φ(0)`. The proof passes to polar coordinates: in the direction of the +ray the integrand is the radial derivative, whose integral over each ray is `-φ(0)`, and in the +angular direction it is the angular derivative divided by the radius, whose integral over each +circle vanishes by periodicity. No Green or Stokes theorem is used. + +References: [Hörmander][Hormander1973] (1973), Theorem 1.2.1; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Lemma 4.2.4. + +## Main definitions + +* `dbarAlong`: The antiholomorphic part of a real-linear map along a direction: `(L v + I • L (I • + v)) / 2`. +* `complexLinearOfDbar`: A real-linear map whose antiholomorphic parts all vanish, as a + complex-linear map. +* `polarRadialDeriv`: The radial derivative of `φ` at the point with polar coordinates `p`. +* `polarAngularDeriv`: The angular derivative of `φ` at the point with polar coordinates `p`, + divided by the radius. + +## Main results + +* `integral_inv_smul_dbarAlong_fderiv`: **The Cauchy–Pompeiu identity.** For a compactly supported + `C¹` function `φ : ℂ → F`, `∫ w⁻¹ • ∂φ/∂\bar z (w) = -π • φ 0`. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Complex MeasureTheory Set Filter +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +section Dbar + +/-- The antiholomorphic part of a real-linear map along a direction: `(L v + I • L (I • v)) / 2`. +For the real derivative of a function of one complex variable at `v = 1` this is `∂/∂\bar z`. -/ +@[expose] def dbarAlong (L : E →L[ℝ] F) (v : E) : F := (2 : ℂ)⁻¹ • (L v + I • L (I • v)) + +/-- The antiholomorphic part along `v` vanishes exactly when `L` commutes with `I` on `v`. -/ +theorem dbarAlong_eq_zero_iff (L : E →L[ℝ] F) (v : E) : + dbarAlong L v = 0 ↔ L (I • v) = I • L v := by + unfold dbarAlong + rw [smul_eq_zero, or_iff_right (inv_ne_zero two_ne_zero)] + constructor + · intro h + have h1 : L v = -(I • L (I • v)) := eq_neg_of_add_eq_zero_left h + calc L (I • v) = -(I • I • L (I • v)) := by + rw [smul_smul, I_mul_I, neg_one_smul, neg_neg] + _ = I • L v := by rw [h1, smul_neg] + · intro h + rw [h, smul_smul, I_mul_I, neg_one_smul, add_neg_cancel] + +/-- The antiholomorphic part of the zero map vanishes. -/ +theorem dbarAlong_zero (v : E) : dbarAlong (0 : E →L[ℝ] F) v = 0 := by + simp [dbarAlong] + +/-- The antiholomorphic part is additive in the map. -/ +theorem dbarAlong_add (L M : E →L[ℝ] F) (v : E) : + dbarAlong (L + M) v = dbarAlong L v + dbarAlong M v := by + simp only [dbarAlong, FunLike.coe_add, Pi.add_apply, smul_add] + module + +/-- The antiholomorphic part respects differences of maps. -/ +theorem dbarAlong_sub (L M : E →L[ℝ] F) (v : E) : + dbarAlong (L - M) v = dbarAlong L v - dbarAlong M v := by + simp only [dbarAlong, FunLike.coe_sub, Pi.sub_apply, smul_sub] + module + +/-- The antiholomorphic part of a complex-linear map vanishes. -/ +theorem dbarAlong_restrictScalars (L : E →L[ℂ] F) (v : E) : + dbarAlong (L.restrictScalars ℝ) v = 0 := by + rw [dbarAlong_eq_zero_iff] + simp + +/-- The antiholomorphic part of the composition of a real-linear map with a continuous linear map `T +: E →L[ℝ] F` and a complex-linear evaluation. -/ +theorem dbarAlong_comp_clm {G : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] + (T : F →L[ℂ] G) (L : E →L[ℝ] F) (v : E) : + dbarAlong ((T.restrictScalars ℝ).comp L) v = T (dbarAlong L v) := by + simp [dbarAlong, map_add, map_smul] + +/-- A real-linear map whose antiholomorphic parts all vanish, as a complex-linear map. -/ +@[expose] def complexLinearOfDbar (L : E →L[ℝ] F) (h : ∀ v, dbarAlong L v = 0) : E →L[ℂ] F where + toFun := L + map_add' := map_add L + map_smul' := fun c v => by + have hI : ∀ v, L (I • v) = I • L v := fun v => (dbarAlong_eq_zero_iff L v).mp (h v) + simp only [RingHom.id_apply] + calc L (c • v) = L ((c.re : ℝ) • v + (c.im : ℝ) • (I • v)) := by + congr 1 + rw [← Complex.coe_smul, ← Complex.coe_smul, smul_smul, ← add_smul, Complex.re_add_im] + _ = c • L v := by + rw [map_add, map_smul, map_smul, hI, ← Complex.coe_smul, ← Complex.coe_smul, smul_smul, + ← add_smul, Complex.re_add_im] + cont := L.cont + +/-- The complex-linear map built from vanishing antiholomorphic parts has the same underlying +function. -/ +@[simp] theorem coe_complexLinearOfDbar (L : E →L[ℝ] F) (h : ∀ v, dbarAlong L v = 0) : + ⇑(complexLinearOfDbar L h) = ⇑L := rfl + +/-- Restricting scalars of `complexLinearOfDbar L h` recovers `L`. -/ +theorem restrictScalars_complexLinearOfDbar (L : E →L[ℝ] F) (h : ∀ v, dbarAlong L v = 0) : + (complexLinearOfDbar L h).restrictScalars ℝ = L := by + ext v + rfl + +end Dbar + +section Polar + +/-- The radial derivative of `φ` at the point with polar coordinates `p`. -/ +@[expose] def polarRadialDeriv (φ : ℂ → F) (p : ℝ × ℝ) : F := + fderiv ℝ φ (p.1 * exp (p.2 * I)) (exp (p.2 * I)) + +/-- The angular derivative of `φ` at the point with polar coordinates `p`, divided by the radius. -/ +@[expose] def polarAngularDeriv (φ : ℂ → F) (p : ℝ × ℝ) : F := + fderiv ℝ φ (p.1 * exp (p.2 * I)) (I * exp (p.2 * I)) + +/-- Rotation identity for a real-linear map on `ℂ`. -/ +theorem apply_exp_add_I_smul_apply_I_mul_exp (L : ℂ →L[ℝ] F) (θ : ℝ) : + L (exp (θ * I)) + I • L (I * exp (θ * I)) = exp (-(θ * I)) • (L 1 + I • L I) := by + have h1 : exp (θ * I) = (Real.cos θ) • (1 : ℂ) + (Real.sin θ) • I := by + rw [exp_mul_I] + simp [Complex.real_smul] + have h2 : I * exp (θ * I) = (-Real.sin θ) • (1 : ℂ) + (Real.cos θ) • I := by + rw [exp_mul_I] + simp only [Complex.real_smul, ofReal_neg] + ring_nf + simp [I_sq] + ring + have h3 : exp (-(θ * I)) = (cos (θ : ℂ) - sin (θ : ℂ) * I) := by + rw [← neg_mul, ← ofReal_neg, exp_mul_I] + simp [Complex.ofReal_neg] + ring + rw [h2, h1, map_add, map_add, map_smul, map_smul, map_smul, map_smul, h3] + simp only [← Complex.coe_smul, ofReal_neg, ofReal_cos, ofReal_sin] + match_scalars <;> first + | ring1 + | linear_combination (Complex.sin θ) * I_sq + +/-- The polar-coordinate form of the Cauchy–Pompeiu integrand. -/ +theorem smul_inv_smul_dbarAlong_polar (φ : ℂ → F) {r θ : ℝ} (hr : 0 < r) : + r • ((Complex.polarCoord.symm (r, θ))⁻¹ • dbarAlong (fderiv ℝ φ (Complex.polarCoord.symm (r, + θ))) 1) = + (2 : ℂ)⁻¹ • (polarRadialDeriv φ (r, θ) + I • polarAngularDeriv φ (r, θ)) := by + have hw : Complex.polarCoord.symm (r, θ) = r * exp (θ * I) := by + rw [Complex.polarCoord_symm_apply, exp_mul_I] + push_cast + ring + rw [hw] + have hinv : ((r : ℂ) * exp (θ * I))⁻¹ = (r : ℂ)⁻¹ * exp (-(θ * I)) := by + rw [mul_inv, ← exp_neg] + rw [hinv, polarRadialDeriv, polarAngularDeriv] + simp only + rw [apply_exp_add_I_smul_apply_I_mul_exp, dbarAlong] + simp only [smul_eq_mul, mul_one] + rw [← Complex.coe_smul, smul_smul, smul_smul, smul_smul] + congr 1 + have : (r : ℂ) ≠ 0 := by exact_mod_cast hr.ne' + field_simp + +/-- The radial derivative of a `C¹` function is continuous in polar coordinates. -/ +theorem continuous_polarRadialDeriv {φ : ℂ → F} (hφ : ContDiff ℝ 1 φ) : + Continuous (polarRadialDeriv φ) := by + unfold polarRadialDeriv + exact ((hφ.continuous_fderiv one_ne_zero).comp (by fun_prop)).clm_apply (by fun_prop) + +/-- The angular derivative of a `C¹` function is continuous in polar coordinates. -/ +theorem continuous_polarAngularDeriv {φ : ℂ → F} (hφ : ContDiff ℝ 1 φ) : + Continuous (polarAngularDeriv φ) := by + unfold polarAngularDeriv + exact ((hφ.continuous_fderiv one_ne_zero).comp (by fun_prop)).clm_apply (by fun_prop) + +/-- The real derivative vanishes at points whose modulus exceeds the support radius. -/ +theorem fderiv_eq_zero_of_norm_gt {φ : ℂ → F} {R : ℝ} (hR : tsupport φ ⊆ Metric.closedBall 0 R) + {w : ℂ} (hw : R < ‖w‖) : fderiv ℝ φ w = 0 := by + apply image_eq_zero_of_notMem_tsupport + intro h + have := hR (tsupport_fderiv_subset ℝ h) + rw [Metric.mem_closedBall, dist_zero_right] at this + exact absurd this (not_le.mpr hw) + +/-- A uniform bound on the derivative bounds the radial derivative. -/ +theorem norm_polarRadialDeriv_le {φ : ℂ → F} {C : ℝ} (hC : ∀ w, ‖fderiv ℝ φ w‖ ≤ C) (p : ℝ × ℝ) : + ‖polarRadialDeriv φ p‖ ≤ C := by + unfold polarRadialDeriv + calc ‖fderiv ℝ φ (p.1 * exp (p.2 * I)) (exp (p.2 * I))‖ + ≤ ‖fderiv ℝ φ (p.1 * exp (p.2 * I))‖ * ‖exp (p.2 * I)‖ := ContinuousLinearMap.le_opNorm _ _ + _ ≤ C := by rw [norm_exp_ofReal_mul_I, mul_one]; exact hC _ + +/-- A uniform bound on the derivative bounds the angular derivative. -/ +theorem norm_polarAngularDeriv_le {φ : ℂ → F} {C : ℝ} (hC : ∀ w, ‖fderiv ℝ φ w‖ ≤ C) (p : ℝ × ℝ) : + ‖polarAngularDeriv φ p‖ ≤ C := by + unfold polarAngularDeriv + calc ‖fderiv ℝ φ (p.1 * exp (p.2 * I)) (I * exp (p.2 * I))‖ + ≤ ‖fderiv ℝ φ (p.1 * exp (p.2 * I))‖ * ‖I * exp (p.2 * I)‖ := ContinuousLinearMap.le_opNorm + _ _ + _ ≤ C := by rw [norm_mul, norm_I, norm_exp_ofReal_mul_I, one_mul, mul_one]; exact hC _ + +/-- The modulus of `r e^{iθ}` is `|r|`. -/ +theorem norm_mul_exp_ofReal_mul_I (r θ : ℝ) : ‖(r : ℂ) * exp (θ * I)‖ = |r| := by + rw [norm_mul, norm_exp_ofReal_mul_I, mul_one, Complex.norm_real, Real.norm_eq_abs] + +/-- The radial derivative vanishes beyond the support radius. -/ +theorem polarRadialDeriv_eq_zero {φ : ℂ → F} {R : ℝ} (hR : tsupport φ ⊆ Metric.closedBall 0 R) + {p : ℝ × ℝ} (hp : R < |p.1|) : polarRadialDeriv φ p = 0 := by + unfold polarRadialDeriv + rw [fderiv_eq_zero_of_norm_gt hR (by rwa [norm_mul_exp_ofReal_mul_I])] + rfl + +/-- The angular derivative vanishes beyond the support radius. -/ +theorem polarAngularDeriv_eq_zero {φ : ℂ → F} {R : ℝ} (hR : tsupport φ ⊆ Metric.closedBall 0 R) + {p : ℝ × ℝ} (hp : R < |p.1|) : polarAngularDeriv φ p = 0 := by + unfold polarAngularDeriv + rw [fderiv_eq_zero_of_norm_gt hR (by rwa [norm_mul_exp_ofReal_mul_I])] + rfl + +omit [NormedSpace ℂ F] in +/-- A bounded continuous function on the polar-coordinate rectangle vanishing beyond a radius is +integrable on the polar target. -/ +theorem integrableOn_polarCoord_target_of_bound {A : ℝ × ℝ → F} (hA : Continuous A) {C R : ℝ} + (hC : ∀ p, ‖A p‖ ≤ C) (hzero : ∀ p : ℝ × ℝ, R < |p.1| → A p = 0) : + IntegrableOn A polarCoord.target := by + have hC0 : 0 ≤ C := (norm_nonneg _).trans (hC 0) + have hg : Integrable ((Icc (0 : ℝ) R ×ˢ Icc (-π) π).indicator fun _ => C) := + (integrableOn_const (isCompact_Icc.prod isCompact_Icc).measure_lt_top.ne).integrable_indicator + (measurableSet_Icc.prod measurableSet_Icc) + refine Integrable.mono' hg.integrableOn hA.aestronglyMeasurable ?_ + refine ae_restrict_of_forall_mem polarCoord.open_target.measurableSet fun p hp => ?_ + rw [polarCoord_target] at hp + by_cases h : p.1 ≤ R + · rw [indicator_of_mem (show p ∈ Icc (0 : ℝ) R ×ˢ Icc (-π) π from + ⟨⟨hp.1.le, h⟩, hp.2.1.le, hp.2.2.le⟩)] + exact hC p + · rw [hzero p (by rw [abs_of_pos hp.1]; exact not_le.mp h), norm_zero] + exact indicator_nonneg (fun _ _ => hC0) p + +omit [NormedSpace ℂ F] in +/-- A continuous function on the half-line vanishing beyond a radius is integrable there. -/ +theorem integrableOn_Ioi_of_continuous_of_eq_zero {g : ℝ → F} (hg : Continuous g) {R : ℝ} + (hz : ∀ r, R < r → g r = 0) : IntegrableOn g (Ioi 0) := by + have h1 : IntegrableOn g (Icc 0 R) := hg.continuousOn.integrableOn_Icc + have h2 : IntegrableOn g (Ioi R) := + ((integrable_zero _ _ _).integrableOn).congr_fun (fun r hr => (hz r hr).symm) measurableSet_Ioi + refine (h1.union h2).mono_set fun r hr => ?_ + rcases le_or_gt r R with h | h + · exact Or.inl ⟨le_of_lt hr, h⟩ + · exact Or.inr h + +variable [CompleteSpace F] + +/-- The radial integral of the radial derivative along a ray is `-φ 0`. -/ +theorem integral_Ioi_polarRadialDeriv {φ : ℂ → F} (hφ : ContDiff ℝ 1 φ) {R : ℝ} + (hR : tsupport φ ⊆ Metric.closedBall 0 R) (θ : ℝ) : + ∫ r in Ioi (0 : ℝ), polarRadialDeriv φ (r, θ) = -φ 0 := by + have hderiv : ∀ r ∈ Ici (0 : ℝ), + HasDerivAt (fun r : ℝ => φ (r * exp (θ * I))) (polarRadialDeriv φ (r, θ)) r := by + intro r _ + have h1 : HasDerivAt (fun r : ℝ => (r : ℂ) * exp (θ * I)) (exp (θ * I)) r := by + simpa using (hasDerivAt_id r).ofReal_comp.mul_const (exp (θ * I)) + exact (hφ.differentiable one_ne_zero _).hasFDerivAt.comp_hasDerivAt r h1 + have hint : IntegrableOn (fun r : ℝ => polarRadialDeriv φ (r, θ)) (Ioi 0) := by + refine integrableOn_Ioi_of_continuous_of_eq_zero (R := R) + ((continuous_polarRadialDeriv hφ).comp (by fun_prop)) fun r hr => ?_ + exact polarRadialDeriv_eq_zero hR (lt_of_lt_of_le hr (le_abs_self r)) + have hlim : Tendsto (fun r : ℝ => φ (r * exp (θ * I))) atTop (𝓝 0) := by + refine tendsto_const_nhds.congr' ((eventually_gt_atTop R).mono fun r hr => ?_) + symm + apply image_eq_zero_of_notMem_tsupport + intro h + have := hR h + rw [Metric.mem_closedBall, dist_zero_right, norm_mul_exp_ofReal_mul_I] at this + exact absurd (lt_of_lt_of_le hr (le_abs_self r)) (not_lt.mpr this) + have := integral_Ioi_of_hasDerivAt_of_tendsto' hderiv hint hlim + simpa using this + +/-- The angular integral of the angular derivative around a circle vanishes. -/ +theorem integral_Ioo_polarAngularDeriv {φ : ℂ → F} (hφ : ContDiff ℝ 1 φ) {r : ℝ} (hr : 0 < r) : + ∫ θ in Ioo (-π) π, polarAngularDeriv φ (r, θ) = 0 := by + have hderiv : ∀ θ ∈ uIcc (-π) π, + HasDerivAt (fun θ : ℝ => φ (r * exp (θ * I))) (r • polarAngularDeriv φ (r, θ)) θ := by + intro θ _ + have h1 : HasDerivAt (fun θ : ℝ => (r : ℂ) * exp (θ * I)) ((r : ℂ) * (exp (θ * I) * I)) θ := by + simpa using ((hasDerivAt_id θ).ofReal_comp.mul_const I).cexp.const_mul (r : ℂ) + refine ((hφ.differentiable one_ne_zero _).hasFDerivAt.comp_hasDerivAt θ h1).congr_deriv ?_ + unfold polarAngularDeriv + rw [show (r : ℂ) * (exp (θ * I) * I) = r • (I * exp (θ * I)) by + rw [Complex.real_smul]; ring, map_smul] + have hcont : IntervalIntegrable (fun θ : ℝ => r • polarAngularDeriv φ (r, θ)) volume (-π) π := + (((continuous_polarAngularDeriv hφ).comp (by fun_prop)).const_smul r).intervalIntegrable _ _ + have hftc := intervalIntegral.integral_eq_sub_of_hasDerivAt hderiv hcont + have hzero : φ (r * exp (π * I)) - φ (r * exp ((-π : ℝ) * I)) = 0 := by + rw [show ((-π : ℝ) : ℂ) * I = -(π * I) by push_cast; ring, exp_neg, exp_pi_mul_I] + simp + rw [hzero, intervalIntegral.integral_of_le (by linarith [Real.pi_pos]), + integral_Ioc_eq_integral_Ioo, integral_smul] at hftc + exact (smul_eq_zero.mp hftc).resolve_left hr.ne' + +/-- **The Cauchy–Pompeiu identity.** For a compactly supported `C¹` function `φ : ℂ → F`, +`∫ w⁻¹ • ∂φ/∂\bar z (w) = -π • φ 0`. -/ +theorem integral_inv_smul_dbarAlong_fderiv {φ : ℂ → F} (hφ : ContDiff ℝ 1 φ) + (hsupp : HasCompactSupport φ) : + ∫ w, w⁻¹ • dbarAlong (fderiv ℝ φ w) 1 = -((π : ℂ) • φ 0) := by + obtain ⟨R, hR⟩ := hsupp.isBounded.subset_closedBall 0 + obtain ⟨C, hC⟩ := (hsupp.fderiv ℝ).exists_bound_of_continuous (hφ.continuous_fderiv one_ne_zero) + have hAi : IntegrableOn (polarRadialDeriv φ) polarCoord.target := + integrableOn_polarCoord_target_of_bound (continuous_polarRadialDeriv hφ) + (norm_polarRadialDeriv_le hC) fun p hp => polarRadialDeriv_eq_zero hR hp + have hBi : IntegrableOn (polarAngularDeriv φ) polarCoord.target := + integrableOn_polarCoord_target_of_bound (continuous_polarAngularDeriv hφ) + (norm_polarAngularDeriv_le hC) fun p hp => polarAngularDeriv_eq_zero hR hp + rw [← Complex.integral_comp_polarCoord_symm] + have hpt : EqOn (fun p : ℝ × ℝ => p.1 • ((Complex.polarCoord.symm p)⁻¹ • + dbarAlong (fderiv ℝ φ (Complex.polarCoord.symm p)) 1)) + (fun p => (2 : ℂ)⁻¹ • (polarRadialDeriv φ p + I • polarAngularDeriv φ p)) + polarCoord.target := by + rintro ⟨r, θ⟩ hp + rw [polarCoord_target] at hp + exact smul_inv_smul_dbarAlong_polar φ hp.1 + have hBi2 : Integrable (fun p => I • polarAngularDeriv φ p) (volume.restrict polarCoord.target) := + hBi.smul I + rw [setIntegral_congr_fun polarCoord.open_target.measurableSet hpt, integral_smul, + integral_add hAi hBi2, integral_smul] + have hA_int : ∫ p in polarCoord.target, polarRadialDeriv φ p = -((2 * π : ℝ) • φ 0) := by + have hAi' : Integrable (polarRadialDeriv φ) + ((volume.restrict (Ioi (0 : ℝ))).prod (volume.restrict (Ioo (-π) π))) := by + rwa [Measure.prod_restrict, ← Measure.volume_eq_prod, ← polarCoord_target] + rw [polarCoord_target, Measure.volume_eq_prod, ← Measure.prod_restrict, + integral_prod_symm _ hAi'] + simp_rw [integral_Ioi_polarRadialDeriv hφ hR] + rw [setIntegral_const, measureReal_def, Real.volume_Ioo, + ENNReal.toReal_ofReal (by linarith [Real.pi_pos]), smul_neg] + congr 2 + ring + have hB_int : ∫ p in polarCoord.target, polarAngularDeriv φ p = 0 := by + have hBi' : Integrable (polarAngularDeriv φ) + ((volume.restrict (Ioi (0 : ℝ))).prod (volume.restrict (Ioo (-π) π))) := by + rwa [Measure.prod_restrict, ← Measure.volume_eq_prod, ← polarCoord_target] + rw [polarCoord_target, Measure.volume_eq_prod, ← Measure.prod_restrict, integral_prod _ hBi'] + exact setIntegral_eq_zero_of_forall_eq_zero fun r hr => integral_Ioo_polarAngularDeriv hφ hr + rw [hA_int, hB_int, smul_zero, add_zero, ← Complex.coe_smul, smul_neg, smul_smul] + congr 2 + push_cast + field_simp + +end Polar + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyRiemann.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyRiemann.lean new file mode 100644 index 0000000000..869d5f460a --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyRiemann.lean @@ -0,0 +1,133 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Conformal +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives + +/-! +# Coordinate Cauchy–Riemann equations + +Real differentiability and the coordinate Cauchy–Riemann equations characterize holomorphy on an +open finite-dimensional domain. The proof uses Mathlib's one-variable conversion theorem and +Osgood, rather than constructing a second complex derivative theory. + +The domain `ι → ℂ` is intentional: each Wirtinger derivative and each displayed Cauchy–Riemann +equation singles out a coordinate. The codomain may be a complex normed space, with completeness +assumed for the analyticity results. Coordinate-free holomorphy is expressed by the usual +complex Fréchet derivative; these results describe it in coordinates and relate the real +derivative to the existing `partialDeriv` interface. + +## Main definitions + +* `wirtingerDeriv`: The holomorphic Wirtinger derivative, defined from the real Fréchet derivative. +* `conjWirtingerDeriv`: The antiholomorphic Wirtinger derivative, defined from the real Fréchet + derivative. + +## Main results + +* `hasFDerivAt_update_real`: The real derivative of a coordinate slice is the restriction of the + real derivative to that coordinate's complex plane. +* `analyticOnNhd_iff_differentiableAt_real_cauchyRiemann`: On an open set, holomorphy is equivalent + to real differentiability together with the coordinate Cauchy–Riemann equations. +* `AnalyticOnNhd.conjWirtingerDeriv_eq_zero`: The antiholomorphic Wirtinger derivative vanishes for + a holomorphic function. +* `AnalyticOnNhd.wirtingerDeriv_eq_partialDeriv`: For holomorphic functions the holomorphic + Wirtinger derivative agrees with the complex coordinate derivative `partialDeriv`. +-/ + +public noncomputable section + +open Complex Filter Function Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {ι F : Type*} [Fintype ι] [DecidableEq ι] [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- The holomorphic Wirtinger derivative, defined from the real Fréchet derivative. -/ +@[expose] def wirtingerDeriv (i : ι) (f : (ι → ℂ) → F) (z : ι → ℂ) : F := + (1 / 2 : ℂ) • (fderiv ℝ f z (Pi.single i 1) - I • fderiv ℝ f z (Pi.single i I)) + +/-- The antiholomorphic Wirtinger derivative, defined from the real Fréchet derivative. -/ +@[expose] def conjWirtingerDeriv (i : ι) (f : (ι → ℂ) → F) (z : ι → ℂ) : F := + (1 / 2 : ℂ) • (fderiv ℝ f z (Pi.single i 1) + I • fderiv ℝ f z (Pi.single i I)) + +omit [Fintype ι] in +/-- The real derivative of a coordinate slice is the restriction of the real derivative to that +coordinate's complex plane. -/ +theorem hasFDerivAt_update_real [Finite ι] {f : (ι → ℂ) → F} (z : ι → ℂ) (i : ι) (w : ℂ) + (hf : DifferentiableAt ℝ f (update z i w)) : + HasFDerivAt (fun v => f (update z i v)) + ((fderiv ℝ f (update z i w)).comp + ((ContinuousLinearMap.single ℂ (fun _ : ι => ℂ) i).restrictScalars ℝ)) w := by + classical + let := Fintype.ofFinite ι + have hs : HasFDerivAt (update z i) + ((ContinuousLinearMap.single ℂ (fun _ : ι => ℂ) i).restrictScalars ℝ) w := by + convert! (hasDerivAt_update z i w).hasFDerivAt.restrictScalars ℝ using 1 + ext v j + simp [Pi.single_apply, smul_eq_mul] + exact hf.hasFDerivAt.comp w hs + +variable [CompleteSpace F] + +/-- On an open set, holomorphy is equivalent to real differentiability together with the coordinate +Cauchy–Riemann equations. Continuous real differentiability is not needed. -/ +theorem analyticOnNhd_iff_differentiableAt_real_cauchyRiemann + {U : Set (ι → ℂ)} (hU : IsOpen U) {f : (ι → ℂ) → F} : + AnalyticOnNhd ℂ f U ↔ + (∀ z ∈ U, DifferentiableAt ℝ f z) ∧ + ∀ z ∈ U, ∀ i, fderiv ℝ f z (Pi.single i I) = I • fderiv ℝ f z (Pi.single i 1) := by + constructor + · intro hf + refine ⟨fun z hz => (hf z hz).differentiableAt.restrictScalars ℝ, ?_⟩ + intro z hz i + rw [(hf z hz).differentiableAt.fderiv_restrictScalars ℝ] + change fderiv ℂ f z (Pi.single i I) = I • fderiv ℂ f z (Pi.single i 1) + rw [show Pi.single i I = I • (Pi.single i (1 : ℂ)) by + ext j; by_cases hji : j = i <;> simp [hji]] + exact map_smul _ _ _ + · rintro ⟨hreal, hCR⟩ + apply analyticOnNhd_pi_of_analyticOnNhd_update hU + (fun z hz => (hreal z hz).continuousAt.continuousWithinAt) + intro z hz i + rw [analyticAt_iff_eventually_differentiableAt] + have hmem : ∀ᶠ w in 𝓝 (z i), update z i w ∈ U := by + exact ((hasDerivAt_update z i (z i)).continuousAt.preimage_mem_nhds + (by simpa using hU.mem_nhds hz)) + filter_upwards [hmem] with w hw + have H := hasFDerivAt_update_real z i w (hreal _ hw) + apply differentiableAt_complex_iff_differentiableAt_real.mpr + refine ⟨H.differentiableAt, ?_⟩ + rw [H.fderiv] + simpa using hCR (update z i w) hw i + +/-- The antiholomorphic Wirtinger derivative vanishes for a holomorphic function. -/ +theorem _root_.AnalyticOnNhd.conjWirtingerDeriv_eq_zero {U : Set (ι → ℂ)} + {f : (ι → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) + {z : ι → ℂ} (hz : z ∈ U) (i : ι) : conjWirtingerDeriv i f z = 0 := by + have hCR := (analyticOnNhd_iff_differentiableAt_real_cauchyRiemann hU).mp hf |>.2 z hz i + simp [conjWirtingerDeriv, hCR, smul_smul] + +/-- For holomorphic functions the holomorphic Wirtinger derivative agrees with the complex +coordinate derivative `partialDeriv`. -/ +theorem _root_.AnalyticOnNhd.wirtingerDeriv_eq_partialDeriv {U : Set (ι → ℂ)} + {f : (ι → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) + {z : ι → ℂ} (hz : z ∈ U) (i : ι) : wirtingerDeriv i f z = partialDeriv i f z := by + have hCR := (analyticOnNhd_iff_differentiableAt_real_cauchyRiemann hU).mp hf |>.2 z hz i + rw [wirtingerDeriv, hCR, smul_smul, I_mul_I, neg_one_smul, sub_neg_eq_add, + ← two_smul ℂ, smul_smul] + norm_num + rw [partialDeriv_eq_fderiv (hf z hz).differentiableAt, + (hf z hz).differentiableAt.fderiv_restrictScalars ℝ] + rfl + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchySeries.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchySeries.lean new file mode 100644 index 0000000000..90cc526e8c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchySeries.lean @@ -0,0 +1,679 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Constructions +public import Mathlib.Analysis.Calculus.FDeriv.Analytic +public import Mathlib.Data.Fin.Tuple.NatAntidiagonal +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyIntegral + +/-! +# Multivariable Cauchy coefficients and series + +Cauchy coefficients, their estimates, and their packaging as a `FormalMultilinearSeries`. +`hasFPowerSeriesOnBall_polydiscCauchy_full` represents the function on the entire open +equal-radius polydisc. The original half-radius theorem remains as a compatibility wrapper. +Diagonal coefficients are identified with iterated Fréchet derivatives. + +Apply Mathlib's `HasFPowerSeriesOnBall.tendstoLocallyUniformlyOn` and +`HasFPowerSeriesOnBall.uniform_geometric_approx` to obtain locally uniform partial-sum +convergence and geometric remainder bounds on smaller polydiscs. Individual mixed coefficients +and radius independence are developed in `CauchyCoefficients`; the separate-radius multi-index +expansion, its uniform convergence and remainder estimates are in `PolydiscTaylor`. + +## Main definitions + +* `multiIndexMonomial`: The continuous multilinear monomial associated to a multi-index of total + degree `n`. +* `polydiscCauchyCoeff`: The multi-index Cauchy coefficient of a vector-valued function on a + polydisc. +* `polydiscCauchySeries`: The formal multilinear series obtained by grouping the polydisc Cauchy + coefficients by total degree. + +## Main results + +* `hasSum_polydiscCauchySeries`: The Cauchy series converges to the function at every point of the + open polydisc. +* `hasFPowerSeriesOnBall_polydiscCauchy_full`: The Cauchy series represents the function on the full + open supremum-norm ball, not just the half-radius ball needed by the original Osgood proof. +* `hasFPowerSeriesOnBall_polydiscCauchy`: A continuous, separately analytic function on a closed + polydisc is represented on the concentric polydisc of half the radius by its multivariable Cauchy + series. +* `polydiscCauchySeries_diag_eq_iteratedFDeriv`: On the diagonal, the Cauchy series is the usual + Taylor series of iterated Fréchet derivatives. +-/ + +public section + +open Complex Filter Function MeasureTheory Metric Set +open scoped ENNReal NNReal Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-! +### Multi-index Cauchy series +-/ + +/-- The continuous multilinear monomial associated to a multi-index of total degree `n`. -/ +noncomputable def multiIndexMonomial {d n : ℕ} (m : Fin d → ℕ) + (hm : ∑ i, m i = n) : + ContinuousMultilinearMap ℂ (fun _ : Fin n => (Fin d → ℂ)) ℂ := by + let e : (Σ i, Fin (m i)) ≃ Fin n := Fintype.equivFinOfCardEq (by simpa using hm) + exact ((ContinuousMultilinearMap.mkPiAlgebra ℂ (Σ i, Fin (m i)) ℂ).compContinuousLinearMap + (fun q => ContinuousLinearMap.proj q.1)).domDomCongr e + +/-- On the diagonal, `multiIndexMonomial` evaluates to the usual multi-index monomial. -/ +theorem multiIndexMonomial_apply {d n : ℕ} (m : Fin d → ℕ) + (hm : ∑ i, m i = n) (w : Fin d → ℂ) : + multiIndexMonomial m hm (fun _ => w) = ∏ i, w i ^ m i := by + simp [multiIndexMonomial, Fintype.prod_sigma] + +/-- The operator norm of `multiIndexMonomial` is at most one for the sup norm. -/ +theorem norm_multiIndexMonomial_le {d n : ℕ} (m : Fin d → ℕ) + (hm : ∑ i, m i = n) : ‖multiIndexMonomial m hm‖ ≤ 1 := by + rw [multiIndexMonomial, ContinuousMultilinearMap.norm_domDomCongr] + refine (ContinuousMultilinearMap.norm_compContinuousLinearMap_le _ _).trans ?_ + rw [ContinuousMultilinearMap.norm_mkPiAlgebra] + simp only [one_mul] + refine Finset.prod_le_one₀ (fun _ _ => norm_nonneg _) fun q _ => ?_ + refine ContinuousLinearMap.opNorm_le_bound _ zero_le_one fun w => ?_ + simpa using norm_le_pi_norm w q.1 + +/-- Absolute summability of a finite product of geometric series. -/ +theorem summable_norm_pi_geometric {K : Type*} [NormedCommRing K] + {d : ℕ} (x : Fin d → K) (hx : ∀ i, ‖x i‖ < 1) : + Summable fun m : Fin d → ℕ => ‖∏ i, x i ^ m i‖ := by + induction d with + | zero => + exact (hasSum_single (0 : Fin 0 → ℕ) fun m hm => + (hm (Subsingleton.elim _ _)).elim).summable + | succ d ih => + let e := Fin.consEquiv (fun _ : Fin (d + 1) => ℕ) + have hhead : Summable (fun n : ℕ => ‖x 0 ^ n‖) := + summable_norm_geometric_of_norm_lt_one (hx 0) + have htail := ih (fun i => x i.succ) (fun i => hx i.succ) + have hprod := hhead.mul_of_nonneg htail (fun _ => norm_nonneg _) (fun _ => norm_nonneg _) + rw [← e.summable_iff] + refine Summable.of_nonneg_of_le (fun _ => norm_nonneg _) ?_ hprod + intro p + simpa only [Function.comp_apply, e, Fin.consEquiv_apply, Fin.prod_univ_succ, + Fin.cons_zero, Fin.cons_succ] using + norm_mul_le (x 0 ^ p.1) (∏ i, x i.succ ^ p.2 i) + +/-- The multivariable geometric series sums to the product of its one-variable sums. -/ +theorem hasSum_pi_geometric {K : Type*} [NormedField K] [CompleteSpace K] + {d : ℕ} (x : Fin d → K) (hx : ∀ i, ‖x i‖ < 1) : + HasSum (fun m : Fin d → ℕ => ∏ i, x i ^ m i) (∏ i, (1 - x i)⁻¹) := by + induction d with + | zero => + simp + | succ d ih => + let e := Fin.consEquiv (fun _ : Fin (d + 1) => ℕ) + have hhead : HasSum (fun n : ℕ => x 0 ^ n) (1 - x 0)⁻¹ := + hasSum_geometric_of_norm_lt_one (hx 0) + have htail : HasSum (fun m : Fin d → ℕ => ∏ i, x i.succ ^ m i) + (∏ i : Fin d, (1 - x i.succ)⁻¹) := + ih (fun i => x i.succ) (fun i => hx i.succ) + have hnormHead : Summable (fun n : ℕ => ‖x 0 ^ n‖) := + summable_norm_geometric_of_norm_lt_one (hx 0) + have hnormTail : Summable (fun m : Fin d → ℕ => ‖∏ i, x i.succ ^ m i‖) := + summable_norm_pi_geometric _ (fun i => hx i.succ) + have hsummul : Summable + (fun p : ℕ × (Fin d → ℕ) => x 0 ^ p.1 * ∏ i, x i.succ ^ p.2 i) := + (hnormHead.mul_norm hnormTail).of_norm + have hprod : HasSum + (fun p : ℕ × (Fin d → ℕ) => x 0 ^ p.1 * ∏ i, x i.succ ^ p.2 i) + ((1 - x 0)⁻¹ * ∏ i : Fin d, (1 - x i.succ)⁻¹) := by + rw [← hhead.tsum_eq, ← htail.tsum_eq, + tsum_mul_tsum_of_summable_norm hnormHead hnormTail] + exact hsummul.hasSum + rw [← e.hasSum_iff] + convert hprod using 1 + · ext p + simp [e, Fin.prod_univ_succ] + · simp [Fin.prod_univ_succ, mul_comm] + +/-- A multivariable geometric series, summed by total degree. -/ +private theorem hasSum_antidiagonalTuple_geometric {K : Type*} [NormedField K] [CompleteSpace K] + {d : ℕ} (x : Fin d → K) + (hx : ∀ i, ‖x i‖ < 1) : + HasSum (fun n : ℕ => ∑ m ∈ Finset.Nat.antidiagonalTuple d n, ∏ i, x i ^ m i) + (∏ i, (1 - x i)⁻¹) := by + have h := hasSum_pi_geometric x hx + let e := Finset.Nat.sigmaAntidiagonalTupleEquivTuple d + have he0 : HasSum + ((fun m : Fin d → ℕ => ∏ i, x i ^ m i) ∘ e) + (∏ i, (1 - x i)⁻¹) := e.hasSum_iff.mpr h + have he : HasSum + (fun p : Σ n, Finset.Nat.antidiagonalTuple d n => + ∏ i, x i ^ (p.2 : Fin d → ℕ) i) + (∏ i, (1 - x i)⁻¹) := by + convert he0 using 1 + · ext p + rfl + have hfin : ∀ n, HasSum + (fun m : Finset.Nat.antidiagonalTuple d n => ∏ i, x i ^ (m : Fin d → ℕ) i) + (∑ m ∈ Finset.Nat.antidiagonalTuple d n, ∏ i, x i ^ m i) := by + intro n + rw [← Finset.sum_finset_coe] + exact hasSum_fintype (f := fun m : Finset.Nat.antidiagonalTuple d n => + ∏ i, x i ^ (m : Fin d → ℕ) i) + exact he.sigma hfin + +/-- The multi-index Cauchy coefficient of a vector-valued function on a polydisc. -/ +@[expose] noncomputable def polydiscCauchyCoeff {d : ℕ} (f : (Fin d → ℂ) → E) + (c : Fin d → ℂ) (R : ℝ) (m : Fin d → ℕ) : E := + ((2 * π * I : ℂ) ^ d)⁻¹ • torusIntegral + (fun z => (∏ i, (z i - c i)⁻¹ ^ (m i + 1)) • f z) c (fun _ => R) + +/-- The formal multilinear series obtained by grouping the polydisc Cauchy coefficients by total +degree. -/ +noncomputable def polydiscCauchySeries {d : ℕ} (f : (Fin d → ℂ) → E) + (c : Fin d → ℂ) (R : ℝ) : FormalMultilinearSeries ℂ (Fin d → ℂ) E := fun n => + ∑ m : Finset.Nat.antidiagonalTuple d n, + (multiIndexMonomial (m : Fin d → ℕ) + (Finset.Nat.mem_antidiagonalTuple.mp m.property)).smulRight + (polydiscCauchyCoeff f c R m) + +omit [CompleteSpace E] in +/-- Evaluation of the homogeneous terms of `polydiscCauchySeries` on the diagonal. -/ +theorem polydiscCauchySeries_apply {d n : ℕ} (f : (Fin d → ℂ) → E) + (c h : Fin d → ℂ) (R : ℝ) : + polydiscCauchySeries f c R n (fun _ => h) = + ∑ m : Finset.Nat.antidiagonalTuple d n, + (∏ i, h i ^ (m : Fin d → ℕ) i) • polydiscCauchyCoeff f c R m := by + simp [polydiscCauchySeries, multiIndexMonomial_apply] + +omit [CompleteSpace E] in +/-- Cauchy's coefficient estimate for the multi-index coefficients of a bounded function on a closed +polydisc. -/ +theorem norm_polydiscCauchyCoeff_le {d : ℕ} {f : (Fin d → ℂ) → E} + {c : Fin d → ℂ} {R M : ℝ} (hR : 0 < R) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) (m : Fin d → ℕ) : + ‖polydiscCauchyCoeff f c R m‖ ≤ M * R⁻¹ ^ (∑ i, m i) := by + have hM0 : 0 ≤ M := (norm_nonneg (f c)).trans (hM c (by + intro i _ + simp [mem_closedBall, dist_self, hR.le])) + rw [polydiscCauchyCoeff, norm_smul] + refine (mul_le_mul_of_nonneg_left (norm_torusIntegral_le_of_norm_le_const + (C := M * R⁻¹ ^ (∑ i, (m i + 1))) ?_) + (norm_nonneg _)).trans_eq ?_ + · intro θ + rw [norm_smul] + calc + ‖∏ i, (torusMap c (fun _ => R) θ i - c i)⁻¹ ^ (m i + 1)‖ * + ‖f (torusMap c (fun _ => R) θ)‖ + ≤ ‖∏ i, (torusMap c (fun _ => R) θ i - c i)⁻¹ ^ (m i + 1)‖ * M := + mul_le_mul_of_nonneg_left (hM _ (torusMap_mem_closedPolydisc (fun _ => hR.le) θ)) + (norm_nonneg _) + _ = M * R⁻¹ ^ (∑ i, (m i + 1)) := by + simp only [norm_prod, norm_pow, norm_inv, norm_torusMap_sub (fun _ => hR.le)] + rw [Finset.prod_pow_eq_pow_sum] + ring + · simp only [norm_inv, norm_pow, norm_mul, norm_ofNat, norm_real, norm_I, mul_one, + Real.norm_eq_abs, abs_of_pos hR, abs_of_pos Real.pi_pos, Fin.prod_const] + simp only [Finset.sum_add_distrib, Finset.sum_const, Finset.card_univ, Fintype.card_fin, + nsmul_eq_mul, mul_one] + field_simp + simp only [one_div, pow_add] + calc + R ^ d * M * (R⁻¹ ^ (∑ x, m x) * R⁻¹ ^ d) = + M * R⁻¹ ^ (∑ x, m x) * (R ^ d * R⁻¹ ^ d) := by ring + _ = M * R⁻¹ ^ ∑ x, m x := by + rw [← mul_pow, mul_inv_cancel₀ hR.ne', one_pow, mul_one] + +omit [CompleteSpace E] in +/-- Cauchy estimate for the homogeneous terms of the polydisc Cauchy series. -/ +private theorem norm_polydiscCauchySeries_mul_pow_le {d : ℕ} {f : (Fin d → ℂ) → E} + {c : Fin d → ℂ} {R M r : ℝ} (hR : 0 < R) (hr : 0 ≤ r) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) (n : ℕ) : + ‖polydiscCauchySeries f c R n‖ * r ^ n ≤ + M * ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (r * R⁻¹) ^ (m : Fin d → ℕ) i := by + have hM0 : 0 ≤ M := (norm_nonneg (f c)).trans (hM c (by + intro i _ + simp [mem_closedBall, dist_self, hR.le])) + rw [polydiscCauchySeries] + calc + ‖∑ m : Finset.Nat.antidiagonalTuple d n, + (multiIndexMonomial (m : Fin d → ℕ) + (Finset.Nat.mem_antidiagonalTuple.mp m.property)).smulRight + (polydiscCauchyCoeff f c R m)‖ * r ^ n + ≤ (∑ m : Finset.Nat.antidiagonalTuple d n, + ‖(multiIndexMonomial (m : Fin d → ℕ) + (Finset.Nat.mem_antidiagonalTuple.mp m.property)).smulRight + (polydiscCauchyCoeff f c R m)‖) * r ^ n := by + gcongr + exact norm_sum_le _ _ + _ ≤ (∑ _m : Finset.Nat.antidiagonalTuple d n, M * R⁻¹ ^ n) * r ^ n := by + gcongr with m + rw [ContinuousMultilinearMap.norm_smulRight] + calc + ‖multiIndexMonomial (m : Fin d → ℕ) + (Finset.Nat.mem_antidiagonalTuple.mp m.property)‖ * + ‖polydiscCauchyCoeff f c R m‖ + ≤ 1 * (M * R⁻¹ ^ (∑ i, (m : Fin d → ℕ) i)) := by + gcongr + · exact norm_multiIndexMonomial_le _ _ + · exact norm_polydiscCauchyCoeff_le hR hM _ + _ = M * R⁻¹ ^ n := by + rw [Finset.Nat.mem_antidiagonalTuple.mp m.property] + ring + _ = M * ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (r * R⁻¹) ^ (m : Fin d → ℕ) i := by + rw [Finset.sum_mul, Finset.mul_sum] + apply Finset.sum_congr rfl + intro m _ + simp_rw [mul_pow] + rw [Finset.prod_mul_distrib, Finset.prod_pow_eq_pow_sum, + Finset.prod_pow_eq_pow_sum, + Finset.Nat.mem_antidiagonalTuple.mp m.property] + ring + +omit [CompleteSpace E] in +/-- Below the radius, the Cauchy estimates give a summable geometric majorant. -/ +private theorem summable_norm_polydiscCauchySeries_mul_pow {d : ℕ} + {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} {R M r : ℝ} (hR : 0 < R) + (hr : 0 ≤ r) (hrR : r < R) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) : + Summable fun n => ‖polydiscCauchySeries f c R n‖ * r ^ n := by + have hq0 : 0 ≤ r * R⁻¹ := mul_nonneg hr (inv_nonneg.mpr hR.le) + have hq1 : r * R⁻¹ < 1 := by + rw [← div_eq_mul_inv, div_lt_one hR] + exact hrR + have hq1norm : ∀ _i : Fin d, ‖(r * R⁻¹ : ℝ)‖ < 1 := fun _ => by + rw [Real.norm_eq_abs, abs_of_nonneg hq0] + exact hq1 + have hseries : HasSum (fun n : ℕ => + ∑ m ∈ Finset.Nat.antidiagonalTuple d n, + ∏ i, (r * R⁻¹) ^ (m : Fin d → ℕ) i) + (∏ _i : Fin d, (1 - r * R⁻¹)⁻¹) := + hasSum_antidiagonalTuple_geometric (K := ℝ) (fun _ => r * R⁻¹) hq1norm + have hgeom : Summable fun n : ℕ => + ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (r * R⁻¹) ^ (m : Fin d → ℕ) i := by + exact hseries.summable.congr fun n => + (Finset.sum_finset_coe + (fun m : Fin d → ℕ => ∏ i, (r * R⁻¹) ^ m i) + (Finset.Nat.antidiagonalTuple d n)).symm + have hmajor : Summable fun n => M * + ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (r * R⁻¹) ^ (m : Fin d → ℕ) i := hgeom.mul_left M + refine Summable.of_nonneg_of_le (fun _ => mul_nonneg (norm_nonneg _) (pow_nonneg hr _)) + (norm_polydiscCauchySeries_mul_pow_le hR hr hM) ?_ + exact hmajor + +/-- Expansion of the polydisc Cauchy kernel by total degree. -/ +private theorem hasSum_polydiscCauchyKernel {d : ℕ} {z c h : Fin d → ℂ} + (hz : ∀ i, z i ≠ c i) (hh : ∀ i, ‖h i‖ < ‖z i - c i‖) : + HasSum (fun n : ℕ => ∑ m : Finset.Nat.antidiagonalTuple d n, + (∏ i, h i ^ (m : Fin d → ℕ) i) * + ∏ i, (z i - c i)⁻¹ ^ ((m : Fin d → ℕ) i + 1)) + (∏ i, (z i - (c + h) i)⁻¹) := by + have hx : ∀ i, ‖h i / (z i - c i)‖ < 1 := by + intro i + rw [norm_div, div_lt_one (norm_pos_iff.mpr (sub_ne_zero.mpr (hz i)))] + exact hh i + have hs := (hasSum_antidiagonalTuple_geometric + (fun i => h i / (z i - c i)) hx).mul_right (∏ i, (z i - c i)⁻¹) + have hterm : (fun n : ℕ => ∑ m : Finset.Nat.antidiagonalTuple d n, + (∏ i, h i ^ (m : Fin d → ℕ) i) * + ∏ i, (z i - c i)⁻¹ ^ ((m : Fin d → ℕ) i + 1)) = + fun n => (∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (h i / (z i - c i)) ^ (m : Fin d → ℕ) i) * + ∏ i, (z i - c i)⁻¹ := by + funext n + rw [Finset.sum_mul] + apply Finset.sum_congr rfl + intro m _ + rw [← Finset.prod_mul_distrib, ← Finset.prod_mul_distrib] + apply Finset.prod_congr rfl + intro i _ + rw [pow_succ, div_pow, inv_pow] + field_simp [sub_ne_zero.mpr (hz i)] + have hconst : (∏ i, (z i - (c + h) i)⁻¹) = + (∏ i, (1 - h i / (z i - c i))⁻¹) * ∏ i, (z i - c i)⁻¹ := by + rw [← Finset.prod_mul_distrib] + apply Finset.prod_congr rfl + intro i _ + have hzi : z i - c i ≠ 0 := sub_ne_zero.mpr (hz i) + have hzih : z i - (c + h) i ≠ 0 := by + intro heq + have : z i - c i = h i := by + calc + z i - c i = (c + h) i - c i := by rw [sub_eq_zero.mp heq] + _ = h i := by simp [Pi.add_apply] + have hi := hh i + rw [this] at hi + exact (lt_irrefl _ hi) + simp only [Pi.add_apply] + field_simp [hzi, hzih] + ring + have hsource : (fun n => (∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (h i / (z i - c i)) ^ (m : Fin d → ℕ) i) * + ∏ i, (z i - c i)⁻¹) = + fun n => (∑ m ∈ Finset.Nat.antidiagonalTuple d n, + ∏ i, (h i / (z i - c i)) ^ m i) * ∏ i, (z i - c i)⁻¹ := by + funext n + exact congrArg (fun v => v * ∏ i, (z i - c i)⁻¹) + (Finset.sum_finset_coe + (fun m : Fin d → ℕ => ∏ i, (h i / (z i - c i)) ^ m i) + (Finset.Nat.antidiagonalTuple d n)) + rw [hterm, hsource, hconst] + exact hs + +omit [CompleteSpace E] in +/-- A uniformly absolutely summable series may be integrated termwise on a torus. -/ +theorem hasSum_torusIntegral_of_uniform {d : ℕ} {κ : Type*} [Countable κ] + {F : κ → (Fin d → ℂ) → E} + {g : (Fin d → ℂ) → E} {c : Fin d → ℂ} {R : Fin d → ℝ} {a : κ → ℝ} + (ha : Summable a) + (hFint : ∀ n, TorusIntegrable (F n) c R) + (hbound : ∀ n θ, ‖F n (torusMap c R θ)‖ ≤ a n) + (hsum : ∀ θ, HasSum (fun n => F n (torusMap c R θ)) (g (torusMap c R θ))) : + HasSum (fun n => torusIntegral (F n) c R) (torusIntegral g c R) := by + let J : (Fin d → ℝ) → ℂ := fun θ => ∏ i, R i * exp (θ i * I) * I + have h := MeasureTheory.hasSum_integral_of_dominated_convergence + (μ := volume.restrict (Icc (0 : Fin d → ℝ) fun _ => 2 * π)) + (F := fun n θ => J θ • F n (torusMap c R θ)) + (f := fun θ => J θ • g (torusMap c R θ)) + (fun n _ => (∏ i, |R i|) * a n) + (fun n => (hFint n).function_integrable.1) + (fun n => ae_of_all _ fun θ => by + rw [norm_smul] + have hJ : ‖J θ‖ = ∏ i, |R i| := by simp [J] + rw [hJ] + exact mul_le_mul_of_nonneg_left (hbound n θ) (by positivity)) + (ae_of_all _ fun _ => (ha.mul_left (∏ i, |R i|))) + (by + simp only [tsum_mul_left] + exact integrableOn_const (hs := measure_Icc_lt_top.ne)) + (ae_of_all _ fun θ => (hsum θ).const_smul (J θ)) + simpa [torusIntegral, J] using h + +/-- The homogeneous term of total degree `n` in the Cauchy kernel expansion. -/ +private noncomputable def polydiscCauchyTerm {d : ℕ} (f : (Fin d → ℂ) → E) + (c h : Fin d → ℂ) (n : ℕ) (z : Fin d → ℂ) : E := + (∑ m : Finset.Nat.antidiagonalTuple d n, + (∏ i, h i ^ (m : Fin d → ℕ) i) * + ∏ i, (z i - c i)⁻¹ ^ ((m : Fin d → ℕ) i + 1)) • f z + +omit [CompleteSpace E] in +/-- Torus integrals commute with finite sums. -/ +private theorem torusIntegral_fintype_sum {d : ℕ} {α : Type*} [Fintype α] + {F : α → (Fin d → ℂ) → E} {c : Fin d → ℂ} {R : Fin d → ℝ} + (hF : ∀ a, TorusIntegrable (F a) c R) : + torusIntegral (fun z => ∑ a, F a z) c R = ∑ a, torusIntegral (F a) c R := by + simp only [torusIntegral, Finset.smul_sum] + exact integral_finsetSum _ fun a _ => (hF a).function_integrable + +omit [CompleteSpace E] in +/-- Each monomial summand of the Cauchy kernel expansion is torus integrable. -/ +private theorem torusIntegrable_polydiscCauchySummand {d : ℕ} + {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} {R : ℝ} (hR : 0 < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) (m : Fin d → ℕ) : + TorusIntegrable (fun z => ((∏ i, h i ^ m i) * + ∏ i, (z i - c i)⁻¹ ^ (m i + 1)) • f z) c (fun _ => R) := by + have hfθ : ContinuousOn (fun θ => f (torusMap c (fun _ => R) θ)) + (Icc (0 : Fin d → ℝ) fun _ => 2 * π) := + hfc.comp (continuous_torusMap_const c R).continuousOn + (fun θ _ => torusMap_mem_closedPolydisc (fun _ => hR.le) θ) + have hscalar : ContinuousOn (fun θ : Fin d → ℝ => + (∏ i, h i ^ m i) * + ∏ i, (torusMap c (fun _ => R) θ i - c i)⁻¹ ^ (m i + 1)) + (Icc (0 : Fin d → ℝ) fun _ => 2 * π) := by + refine continuousOn_const.mul (continuousOn_finsetProd _ fun i _ => ?_) + refine (((((continuous_apply i).comp (continuous_torusMap_const c R)).continuousOn).sub + continuousOn_const).inv₀ ?_).pow _ + intro θ _ + apply sub_ne_zero.mpr + intro heq + have := norm_torusMap_sub (c := c) (fun _ => hR.le) θ i + have heq' : torusMap c (fun _ => R) θ i = c i := by + simpa only [Function.comp_apply] using heq + rw [heq', sub_self, norm_zero] at this + exact hR.ne' this.symm + exact (hscalar.smul hfθ).integrableOn_compact isCompact_Icc + +omit [CompleteSpace E] in +/-- Each homogeneous term of the Cauchy kernel expansion is torus integrable. -/ +private theorem torusIntegrable_polydiscCauchyTerm {d n : ℕ} + {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} {R : ℝ} (hR : 0 < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) : + TorusIntegrable (polydiscCauchyTerm f c h n) c (fun _ => R) := by + have hfθ : ContinuousOn (fun θ => f (torusMap c (fun _ => R) θ)) + (Icc (0 : Fin d → ℝ) fun _ => 2 * π) := + hfc.comp (continuous_torusMap_const c R).continuousOn + (fun θ _ => torusMap_mem_closedPolydisc (fun _ => hR.le) θ) + have hscalar : ContinuousOn (fun θ : Fin d → ℝ => + ∑ m : Finset.Nat.antidiagonalTuple d n, + (∏ i, h i ^ (m : Fin d → ℕ) i) * + ∏ i, (torusMap c (fun _ => R) θ i - c i)⁻¹ ^ + ((m : Fin d → ℕ) i + 1)) + (Icc (0 : Fin d → ℝ) fun _ => 2 * π) := by + refine continuousOn_finsetSum _ fun m _ => + continuousOn_const.mul (continuousOn_finsetProd _ fun i _ => ?_) + refine (((((continuous_apply i).comp (continuous_torusMap_const c R)).continuousOn).sub + continuousOn_const).inv₀ ?_).pow _ + intro θ _ + apply sub_ne_zero.mpr + intro heq + have := norm_torusMap_sub (c := c) (fun _ => hR.le) θ i + have heq' : torusMap c (fun _ => R) θ i = c i := by + simpa only [Function.comp_apply] using heq + rw [heq', sub_self, norm_zero] at this + exact hR.ne' this.symm + exact (hscalar.smul hfθ).integrableOn_compact isCompact_Icc + +omit [CompleteSpace E] in +/-- Bound for the homogeneous Cauchy terms on the distinguished boundary. -/ +private theorem norm_polydiscCauchyTerm_le {d n : ℕ} {f : (Fin d → ℂ) → E} + {c h : Fin d → ℂ} {R M : ℝ} (hR : 0 < R) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) (θ : Fin d → ℝ) : + ‖polydiscCauchyTerm f c h n (torusMap c (fun _ => R) θ)‖ ≤ + (M * R⁻¹ ^ d) * ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (‖h i‖ * R⁻¹) ^ (m : Fin d → ℕ) i := by + have hM0 : 0 ≤ M := (norm_nonneg (f c)).trans (hM c (by + intro i _ + simp [mem_closedBall, dist_self, hR.le])) + rw [polydiscCauchyTerm, norm_smul] + calc + ‖∑ m : Finset.Nat.antidiagonalTuple d n, + (∏ i, h i ^ (m : Fin d → ℕ) i) * + ∏ i, (torusMap c (fun _ => R) θ i - c i)⁻¹ ^ + ((m : Fin d → ℕ) i + 1)‖ * + ‖f (torusMap c (fun _ => R) θ)‖ + ≤ (∑ m : Finset.Nat.antidiagonalTuple d n, + ‖(∏ i, h i ^ (m : Fin d → ℕ) i) * + ∏ i, (torusMap c (fun _ => R) θ i - c i)⁻¹ ^ + ((m : Fin d → ℕ) i + 1)‖) * M := by + gcongr + · exact norm_sum_le _ _ + · exact hM _ (torusMap_mem_closedPolydisc (fun _ => hR.le) θ) + _ = (M * R⁻¹ ^ d) * ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, (‖h i‖ * R⁻¹) ^ (m : Fin d → ℕ) i := by + rw [Finset.mul_sum, Finset.sum_mul] + apply Finset.sum_congr rfl + intro m _ + simp only [norm_mul, norm_prod, norm_pow, norm_inv, + norm_torusMap_sub (fun _ => hR.le)] + simp_rw [pow_succ, mul_pow] + simp only [Finset.prod_mul_distrib, Finset.prod_const, Finset.card_univ, + Fintype.card_fin] + ring + +omit [CompleteSpace E] in +/-- A term of the Cauchy series, evaluated on a diagonal, is a torus integral. -/ +private theorem polydiscCauchySeries_apply_eq_torusIntegral {d n : ℕ} + {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} {R : ℝ} (hR : 0 < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) : + polydiscCauchySeries f c R n (fun _ => h) = + ((2 * π * I : ℂ) ^ d)⁻¹ • + torusIntegral (polydiscCauchyTerm f c h n) c (fun _ => R) := by + let A : ℂ := ((2 * π * I : ℂ) ^ d)⁻¹ + let a : Finset.Nat.antidiagonalTuple d n → ℂ := + fun m => ∏ i, h i ^ (m : Fin d → ℕ) i + let K : Finset.Nat.antidiagonalTuple d n → (Fin d → ℂ) → E := + fun m z => (∏ i, (z i - c i)⁻¹ ^ ((m : Fin d → ℕ) i + 1)) • f z + rw [polydiscCauchySeries_apply] + simp only [polydiscCauchyCoeff] + change (∑ m, a m • (A • torusIntegral (K m) c (fun _ => R))) = + A • torusIntegral (polydiscCauchyTerm f c h n) c (fun _ => R) + have hInt : ∀ m, TorusIntegrable (fun z => a m • K m z) c (fun _ => R) := by + intro m + simpa only [a, K, smul_smul] using + (torusIntegrable_polydiscCauchySummand (f := f) (c := c) (h := h) hR hfc + (m : Fin d → ℕ)) + calc + (∑ m, a m • (A • torusIntegral (K m) c (fun _ => R))) = + A • ∑ m, a m • torusIntegral (K m) c (fun _ => R) := by + rw [Finset.smul_sum] + apply Finset.sum_congr rfl + intro m _ + simp only [smul_smul] + rw [mul_comm] + _ = A • ∑ m, torusIntegral (fun z => a m • K m z) c (fun _ => R) := by + congr 1 + apply Finset.sum_congr rfl + intro m _ + exact (torusIntegral_smul (a m) (K m) c (fun _ => R)).symm + _ = A • torusIntegral (fun z => ∑ m, a m • K m z) c (fun _ => R) := by + rw [torusIntegral_fintype_sum hInt] + _ = A • torusIntegral (polydiscCauchyTerm f c h n) c (fun _ => R) := by + congr 2 + funext z + rw [polydiscCauchyTerm, Finset.sum_smul] + apply Finset.sum_congr rfl + intro m _ + simp only [a, K, smul_smul] + +omit [CompleteSpace E] in +/-- The polydisc Cauchy series sums to the Cauchy integral. -/ +private theorem hasSum_polydiscCauchySeries_integral {d : ℕ} + {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} {R M : ℝ} (hR : 0 < R) + (hh : ∀ i, ‖h i‖ < R) (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) : + HasSum (fun n => polydiscCauchySeries f c R n (fun _ => h)) + (((2 * π * I : ℂ) ^ d)⁻¹ • torusIntegral + (fun z => (∏ i, (z i - (c + h) i)⁻¹) • f z) c (fun _ => R)) := by + let q : Fin d → ℝ := fun i => ‖h i‖ * R⁻¹ + let a : ℕ → ℝ := fun n => (M * R⁻¹ ^ d) * + ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, q i ^ (m : Fin d → ℕ) i + have hq0 : ∀ i, 0 ≤ q i := fun i => mul_nonneg (norm_nonneg _) (inv_nonneg.mpr hR.le) + have hq1 : ∀ i, ‖q i‖ < 1 := by + intro i + rw [Real.norm_eq_abs, abs_of_nonneg (hq0 i)] + simp only [q] + rw [← div_eq_mul_inv, div_lt_one hR] + exact hh i + have hgeom : Summable fun n => + ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, q i ^ (m : Fin d → ℕ) i := by + exact (hasSum_antidiagonalTuple_geometric q hq1).summable.congr fun n => + (Finset.sum_finset_coe + (fun m : Fin d → ℕ => ∏ i, q i ^ m i) + (Finset.Nat.antidiagonalTuple d n)).symm + have ha : Summable a := by + change Summable fun n => (M * R⁻¹ ^ d) * + ∑ m : Finset.Nat.antidiagonalTuple d n, + ∏ i, q i ^ (m : Fin d → ℕ) i + exact hgeom.mul_left (M * R⁻¹ ^ d) + have ht := hasSum_torusIntegral_of_uniform (E := E) + (g := fun z => (∏ i, (z i - (c + h) i)⁻¹) • f z) ha + (fun n => torusIntegrable_polydiscCauchyTerm hR hfc) + (fun n θ => by + simpa [a, q] using norm_polydiscCauchyTerm_le hR hM θ) + (fun θ => by + have hz : ∀ i, torusMap c (fun _ => R) θ i ≠ c i := by + intro i heq + have := norm_torusMap_sub (c := c) (fun _ => hR.le) θ i + rw [heq, sub_self, norm_zero] at this + exact hR.ne' this.symm + have hk := hasSum_polydiscCauchyKernel + (z := torusMap c (fun _ => R) θ) (c := c) (h := h) hz (fun i => by + rw [norm_torusMap_sub (c := c) (fun _ => hR.le) θ i] + exact hh i) + simpa [polydiscCauchyTerm] using + hk.smul_const (f (torusMap c (fun _ => R) θ))) + have hs := ht.const_smul (((2 * π * I : ℂ) ^ d)⁻¹) + simpa only [polydiscCauchySeries_apply_eq_torusIntegral hR hfc] using hs + +/-- The Cauchy series converges to the function at every point of the open polydisc. -/ +theorem hasSum_polydiscCauchySeries {d : ℕ} + {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} {R M : ℝ} (hR : 0 < R) + (hh : ∀ i, ‖h i‖ < R) (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) + (hfa : ∀ z ∈ closedPolydisc c (fun _ => R), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) : + HasSum (fun n => polydiscCauchySeries f c R n (fun _ => h)) (f (c + h)) := by + have H := hasSum_polydiscCauchySeries_integral hR hh hfc hM + rwa [two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul_const hR + (fun i => by simpa using hh i) hfc hfa] at H + +/-- The Cauchy series represents the function on the full open supremum-norm ball, not just the +half-radius ball needed by the original Osgood proof. -/ +theorem hasFPowerSeriesOnBall_polydiscCauchy_full {d : ℕ} + {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} {R M : ℝ} (hR : 0 < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) + (hfa : ∀ z ∈ closedPolydisc c (fun _ => R), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) : + HasFPowerSeriesOnBall f (polydiscCauchySeries f c R) c (ENNReal.ofReal R) := by + refine ⟨?_, ENNReal.ofReal_pos.mpr hR, ?_⟩ + · apply le_of_forall_lt_imp_le_of_dense + intro q hq + have hqtop : q ≠ ⊤ := ne_top_of_lt hq + have hqR : (q.toNNReal : ℝ) < R := by + have H := (ENNReal.toReal_lt_toReal hqtop ENNReal.ofReal_ne_top).mpr hq + simpa [ENNReal.toReal_ofReal hR.le, ENNReal.coe_toNNReal_eq_toReal] using H + simpa [ENNReal.coe_toNNReal hqtop] using + (polydiscCauchySeries f c R).le_radius_of_summable_norm + (summable_norm_polydiscCauchySeries_mul_pow hR q.toNNReal.coe_nonneg hqR hM) + · intro h hh + let r : ℝ≥0 := ⟨R, hR.le⟩ + have hr : (r : ℝ≥0∞) = ENNReal.ofReal R := by + rw [ENNReal.coe_nnreal_eq] + rfl + rw [← hr, Metric.mem_eball, edist_eq_enorm_sub, sub_zero, enorm_lt_coe] at hh + exact hasSum_polydiscCauchySeries hR + (fun i => (norm_le_pi_norm h i).trans_lt hh) hfc hfa hM + +/-- A continuous, separately analytic function on a closed polydisc is represented on the concentric +polydisc of half the radius by its multivariable Cauchy series. -/ +theorem hasFPowerSeriesOnBall_polydiscCauchy {d : ℕ} + {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} {R M : ℝ} (hR : 0 < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) + (hfa : ∀ z ∈ closedPolydisc c (fun _ => R), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) : + HasFPowerSeriesOnBall f (polydiscCauchySeries f c R) c + (ENNReal.ofReal (R / 2)) := by + exact (hasFPowerSeriesOnBall_polydiscCauchy_full hR hfc hfa hM).mono + (ENNReal.ofReal_pos.mpr (by positivity)) + (ENNReal.ofReal_le_ofReal (by linarith)) + +/-- On the diagonal, the Cauchy series is the usual Taylor series of iterated Fréchet derivatives. +This uses Mathlib's general coefficient theorem, not a new derivative theory. -/ +theorem polydiscCauchySeries_diag_eq_iteratedFDeriv {d : ℕ} + {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} {R M : ℝ} (hR : 0 < R) + (hfc : ContinuousOn f (closedPolydisc c (fun _ => R))) + (hfa : ∀ z ∈ closedPolydisc c (fun _ => R), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) + (hM : ∀ z ∈ closedPolydisc c (fun _ => R), ‖f z‖ ≤ M) (n : ℕ) (v : Fin d → ℂ) : + polydiscCauchySeries f c R n (fun _ => v) = + (n.factorial : ℂ)⁻¹ • iteratedFDeriv ℂ n f c (fun _ => v) := by + have h := hasFPowerSeriesOnBall_polydiscCauchy_full hR hfc hfa hM + rw [← h.factorial_smul v n, ← Nat.cast_smul_eq_nsmul ℂ, smul_smul, + inv_mul_cancel₀ (Nat.cast_ne_zero.mpr n.factorial_ne_zero), one_smul] + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyTransform.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyTransform.lean new file mode 100644 index 0000000000..d0ef717f7d --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CauchyTransform.lean @@ -0,0 +1,277 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.ParametricIntegral +public import Mathlib.Analysis.SpecialFunctions.Pow.Integral +public import Mathlib.LinearAlgebra.Complex.FiniteDimensional +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyPompeiu + +/-! +# The Cauchy transform in one variable with parameters + +For a compactly supported `C¹` function `g` on `ℂ × G`, the Cauchy transform in the first +variable is `u(z, y) = π⁻¹ ∫ w⁻¹ • g (z - w, y)`. The kernel `w⁻¹` is locally integrable in the +plane, so `u` is real-differentiable with derivative obtained by differentiating under the +integral; the translation structure places the derivative on `g`. The Cauchy–Pompeiu identity +then gives `∂u/∂\bar z = g`, and along the parameter directions the antiholomorphic part of the +derivative of `u` is the Cauchy transform of the corresponding antiholomorphic part of the +derivative of `g`. The transform vanishes on every slice on which `g` vanishes. + +References: [Hörmander][Hormander1973] (1973), Theorem 1.2.2 and Theorem 2.3.1; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Proposition 4.2.2. + +## Main definitions + +* `cauchyTransformFst`: The Cauchy transform in the first variable of a function on `ℂ × G`. + +## Main results + +* `hasFDerivAt_cauchyTransformFst`: **Differentiation of the Cauchy transform.** The derivative is + the Cauchy transform of the derivative. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Complex MeasureTheory Set Filter Metric +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {G F : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- The Cauchy transform in the first variable of a function on `ℂ × G`. -/ +@[expose] def cauchyTransformFst (g : ℂ × G → F) (x : ℂ × G) : F := + (π : ℂ)⁻¹ • ∫ w : ℂ, w⁻¹ • g (x - (w, 0)) + +section Kernel + +omit [NormedSpace ℂ F] [CompleteSpace F] in +/-- The Cauchy kernel is locally integrable in the plane. -/ +theorem integrable_indicator_closedBall_mul_inv_norm (C R : ℝ) : + Integrable ((closedBall (0 : ℂ) R).indicator fun w => C * ‖w‖⁻¹) := by + have hmeas : AEStronglyMeasurable (fun w : ℂ => C * ‖w‖⁻¹) volume := + (measurable_const.mul measurable_norm.inv).aestronglyMeasurable + have h : IntegrableOn (fun w : ℂ => C * ‖w‖⁻¹) (ball 0 (R + 1)) := by + refine integrableOn_ball_of_norm_le_rpow (E := ℂ) (μ := volume) (C := |C|) (α := 1) ?_ ?_ + (ae_of_all _ fun w => ?_) hmeas + · rw [Complex.finrank_real_complex]; norm_num + · rw [Complex.finrank_real_complex]; norm_num + · rw [Real.rpow_neg_one, norm_mul, Real.norm_eq_abs, norm_inv, norm_norm] + exact (h.mono_set (closedBall_subset_ball (lt_add_one R))).integrable_indicator + measurableSet_closedBall + +omit [CompleteSpace F] in +/-- A kernel-type bound: a function of the form `w⁻¹ • h w` with `h` bounded and vanishing outside a +closed ball is integrable. -/ +theorem integrable_inv_smul_of_bound {h : ℂ → F} (hmeas : AEStronglyMeasurable h volume) {C R : ℝ} + (hC : ∀ w, ‖h w‖ ≤ C) (hz : ∀ w, R < ‖w‖ → h w = 0) : + Integrable fun w : ℂ => w⁻¹ • h w := by + refine Integrable.mono' (integrable_indicator_closedBall_mul_inv_norm C R) + (measurable_inv.aestronglyMeasurable.smul hmeas) (ae_of_all _ fun w => ?_) + by_cases hw : w ∈ closedBall (0 : ℂ) R + · rw [indicator_of_mem hw, norm_smul, norm_inv, mul_comm] + exact mul_le_mul_of_nonneg_right (hC w) (inv_nonneg.mpr (norm_nonneg _)) + · rw [mem_closedBall, dist_zero_right, not_le] at hw + rw [indicator_of_notMem (by rwa [mem_closedBall, dist_zero_right, not_le]), hz w hw, + smul_zero, norm_zero] + +end Kernel + +section Support + +variable {g : ℂ × G → F} + +omit [NormedSpace ℂ G] [NormedSpace ℂ F] [CompleteSpace F] in +/-- Points far in the first variable leave the support after translation. -/ +theorem sub_notMem_of_norm_gt {R' : ℝ} (hR : tsupport g ⊆ closedBall 0 R') {x₀ x : ℂ × G} + (hx : x ∈ ball x₀ 1) {w : ℂ} (hw : R' + ‖x₀‖ + 1 < ‖w‖) : x - (w, 0) ∉ tsupport g := by + intro hmem + have h1 := hR hmem + rw [mem_closedBall, dist_zero_right] at h1 + have hx' : ‖x‖ < ‖x₀‖ + 1 := by + have := mem_ball.mp hx + rw [dist_eq_norm] at this + calc ‖x‖ = ‖(x - x₀) + x₀‖ := by rw [sub_add_cancel] + _ ≤ ‖x - x₀‖ + ‖x₀‖ := norm_add_le _ _ + _ < ‖x₀‖ + 1 := by linarith + have h2 : ‖w‖ - ‖x‖ ≤ ‖x - (w, 0)‖ := by + have : ‖((w, 0) : ℂ × G)‖ = ‖w‖ := by rw [Prod.norm_mk, norm_zero, max_eq_left (norm_nonneg _)] + rw [← this, norm_sub_rev] + exact norm_sub_norm_le _ _ + linarith + +omit [NormedSpace ℂ G] [NormedSpace ℂ F] [CompleteSpace F] in +/-- The translated function vanishes for large `w`. -/ +theorem eq_zero_of_norm_gt {R' : ℝ} (hR : tsupport g ⊆ closedBall 0 R') {x₀ x : ℂ × G} + (hx : x ∈ ball x₀ 1) {w : ℂ} (hw : R' + ‖x₀‖ + 1 < ‖w‖) : g (x - (w, 0)) = 0 := + image_eq_zero_of_notMem_tsupport (sub_notMem_of_norm_gt hR hx hw) + +omit [CompleteSpace F] in +/-- The derivative of the translated function vanishes for large `w`. -/ +theorem fderiv_eq_zero_of_norm_gt' {R' : ℝ} (hR : tsupport g ⊆ closedBall 0 R') {x₀ x : ℂ × G} + (hx : x ∈ ball x₀ 1) {w : ℂ} (hw : R' + ‖x₀‖ + 1 < ‖w‖) : fderiv ℝ g (x - (w, 0)) = 0 := + image_eq_zero_of_notMem_tsupport fun h => + sub_notMem_of_norm_gt hR hx hw (tsupport_fderiv_subset ℝ h) + +end Support + +section Derivative + +variable {g : ℂ × G → F} + +omit [CompleteSpace F] in +/-- Integrability of the derivative kernel. -/ +theorem integrable_inv_smul_fderiv_sub (hg : ContDiff ℝ 1 g) (hs : HasCompactSupport g) + (x₀ : ℂ × G) : Integrable fun w : ℂ => w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) := by + obtain ⟨R', hR⟩ := hs.isBounded.subset_closedBall 0 + obtain ⟨C, hC⟩ := (hs.fderiv ℝ).exists_bound_of_continuous (hg.continuous_fderiv one_ne_zero) + refine integrable_inv_smul_of_bound (R := R' + ‖x₀‖ + 1) + (((hg.continuous_fderiv one_ne_zero).comp (by fun_prop)).aestronglyMeasurable) + (fun w => hC _) fun w hw => fderiv_eq_zero_of_norm_gt' hR (mem_ball_self one_pos) hw + +omit [CompleteSpace F] in +/-- Integrability of the Cauchy transform integrand. -/ +theorem integrable_inv_smul_sub (hg : ContDiff ℝ 1 g) (hs : HasCompactSupport g) (x₀ : ℂ × G) : + Integrable fun w : ℂ => w⁻¹ • g (x₀ - (w, 0)) := by + obtain ⟨R', hR⟩ := hs.isBounded.subset_closedBall 0 + obtain ⟨C, hC⟩ := hs.exists_bound_of_continuous hg.continuous + refine integrable_inv_smul_of_bound (R := R' + ‖x₀‖ + 1) + ((hg.continuous.comp (by fun_prop)).aestronglyMeasurable) + (fun w => hC _) fun w hw => eq_zero_of_norm_gt hR (mem_ball_self one_pos) hw + +omit [CompleteSpace F] in +/-- **Differentiation of the Cauchy transform.** The derivative is the Cauchy transform of the +derivative. -/ +theorem hasFDerivAt_cauchyTransformFst (hg : ContDiff ℝ 1 g) (hs : HasCompactSupport g) + (x₀ : ℂ × G) : + HasFDerivAt (cauchyTransformFst g) + ((π : ℂ)⁻¹ • ∫ w : ℂ, w⁻¹ • fderiv ℝ g (x₀ - (w, 0))) x₀ := by + obtain ⟨R', hR⟩ := hs.isBounded.subset_closedBall 0 + obtain ⟨C, hC⟩ := (hs.fderiv ℝ).exists_bound_of_continuous (hg.continuous_fderiv one_ne_zero) + have hmain : HasFDerivAt (fun x : ℂ × G => ∫ w : ℂ, w⁻¹ • g (x - (w, 0))) + (∫ w : ℂ, w⁻¹ • fderiv ℝ g (x₀ - (w, 0))) x₀ := by + refine hasFDerivAt_integral_of_dominated_of_fderiv_le (𝕜 := ℝ) + (F' := fun x w => w⁻¹ • fderiv ℝ g (x - (w, 0))) + (bound := (closedBall (0 : ℂ) (R' + ‖x₀‖ + 1)).indicator fun w => C * ‖w‖⁻¹) + (ball_mem_nhds x₀ one_pos) ?_ (integrable_inv_smul_sub hg hs x₀) ?_ ?_ + (integrable_indicator_closedBall_mul_inv_norm _ _) ?_ + · exact Eventually.of_forall fun x => + measurable_inv.aestronglyMeasurable.smul + ((hg.continuous.comp (by fun_prop)).aestronglyMeasurable) + · exact measurable_inv.aestronglyMeasurable.smul + (((hg.continuous_fderiv one_ne_zero).comp (by fun_prop)).aestronglyMeasurable) + · refine ae_of_all _ fun w x hx => ?_ + by_cases hw : w ∈ closedBall (0 : ℂ) (R' + ‖x₀‖ + 1) + · rw [indicator_of_mem hw, norm_smul, norm_inv, mul_comm] + exact mul_le_mul_of_nonneg_right (hC _) (inv_nonneg.mpr (norm_nonneg _)) + · rw [mem_closedBall, dist_zero_right, not_le] at hw + rw [indicator_of_notMem (by rwa [mem_closedBall, dist_zero_right, not_le]), + fderiv_eq_zero_of_norm_gt' hR hx hw, smul_zero, norm_zero] + · refine ae_of_all _ fun w x _ => ?_ + have h1 : HasFDerivAt (fun x : ℂ × G => x - (w, 0)) (ContinuousLinearMap.id ℝ (ℂ × G)) x := + (hasFDerivAt_id x).sub_const _ + have h2 := ((hg.differentiable one_ne_zero) _).hasFDerivAt.comp x h1 + rw [ContinuousLinearMap.comp_id] at h2 + exact h2.const_smul w⁻¹ + exact hmain.const_smul _ + +omit [CompleteSpace F] in +/-- The derivative of the Cauchy transform applied to a direction. -/ +theorem fderiv_cauchyTransformFst_apply (hg : ContDiff ℝ 1 g) (hs : HasCompactSupport g) + (x₀ v : ℂ × G) : + fderiv ℝ (cauchyTransformFst g) x₀ v = (π : ℂ)⁻¹ • ∫ w : ℂ, w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) v + := by + rw [(hasFDerivAt_cauchyTransformFst hg hs x₀).fderiv, smul_apply, + ContinuousLinearMap.integral_apply (integrable_inv_smul_fderiv_sub hg hs x₀)] + congr 1 + +omit [CompleteSpace F] in +/-- The antiholomorphic part of the derivative of the Cauchy transform along a direction is the +Cauchy transform of the antiholomorphic part of the derivative. -/ +theorem dbarAlong_fderiv_cauchyTransformFst (hg : ContDiff ℝ 1 g) (hs : HasCompactSupport g) + (x₀ v : ℂ × G) : + dbarAlong (fderiv ℝ (cauchyTransformFst g) x₀) v = + (π : ℂ)⁻¹ • ∫ w : ℂ, w⁻¹ • dbarAlong (fderiv ℝ g (x₀ - (w, 0))) v := by + have hint := integrable_inv_smul_fderiv_sub hg hs x₀ + have h1 : Integrable fun w : ℂ => w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) v := by + simpa only [FunLike.coe_smul, Pi.smul_apply] using hint.apply_continuousLinearMap v + have h2 : Integrable fun w : ℂ => w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) (I • v) := by + simpa only [FunLike.coe_smul, Pi.smul_apply] using hint.apply_continuousLinearMap (I • v) + have h1' : Integrable fun w : ℂ => (2 : ℂ)⁻¹ • (w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) v) := h1.smul _ + have h2' : Integrable fun w : ℂ => + ((2 : ℂ)⁻¹ * I) • (w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) (I • v)) := h2.smul _ + have hpt : ∀ w : ℂ, w⁻¹ • ((2 : ℂ)⁻¹ • (fderiv ℝ g (x₀ - (w, 0)) v + + I • fderiv ℝ g (x₀ - (w, 0)) (I • v))) = + (2 : ℂ)⁻¹ • (w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) v) + + ((2 : ℂ)⁻¹ * I) • (w⁻¹ • fderiv ℝ g (x₀ - (w, 0)) (I • v)) := by + intro w + module + unfold dbarAlong + rw [fderiv_cauchyTransformFst_apply hg hs, fderiv_cauchyTransformFst_apply hg hs] + simp_rw [hpt] + rw [integral_add h1' h2', integral_smul, integral_smul] + module + +omit [NormedSpace ℂ G] [CompleteSpace F] in +/-- The Cauchy transform vanishes on a slice where `g` vanishes. -/ +theorem cauchyTransformFst_eq_zero {y : G} (hy : ∀ z : ℂ, g (z, y) = 0) (z : ℂ) : + cauchyTransformFst g (z, y) = 0 := by + unfold cauchyTransformFst + have : ∀ w : ℂ, w⁻¹ • g (z - w, y) = 0 := fun w => by rw [hy, smul_zero] + simp only [Prod.mk_sub_mk, sub_zero, this, integral_zero, smul_zero] + +end Derivative + +section Pompeiu + +variable {h : ℂ × G → F} + +/-- The Cauchy–Pompeiu identity in the first variable with parameters: the Cauchy transform of +`∂h/∂\bar z₁` recovers `h`. -/ +theorem integral_inv_smul_dbarAlong_fderiv_sub (hh : ContDiff ℝ 1 h) (hs : HasCompactSupport h) + (x₀ : ℂ × G) : + ∫ w : ℂ, w⁻¹ • dbarAlong (fderiv ℝ h (x₀ - (w, 0))) ((1 : ℂ), (0 : G)) = (π : ℂ) • h x₀ := by + set ψ : ℂ → F := fun w => h (x₀ - (w, 0)) with hψ + have hiso : Isometry fun w : ℂ => x₀ - (w, 0) := by + refine Isometry.of_dist_eq fun w w' => ?_ + rw [dist_eq_norm, dist_eq_norm, sub_sub_sub_cancel_left, Prod.mk_sub_mk, sub_zero, Prod.norm_mk, + norm_zero, max_eq_left (norm_nonneg _), norm_sub_rev] + have hψs : HasCompactSupport ψ := hs.comp_isClosedEmbedding hiso.isClosedEmbedding + have hψc : ContDiff ℝ 1 ψ := + hh.comp (contDiff_const.sub (ContinuousLinearMap.inl ℝ ℂ G).contDiff) + have hder : ∀ w : ℂ, fderiv ℝ ψ w = + (fderiv ℝ h (x₀ - (w, 0))).comp (-(ContinuousLinearMap.inl ℝ ℂ G)) := by + intro w + have h1 : HasFDerivAt (fun w : ℂ => x₀ - (w, 0)) (-(ContinuousLinearMap.inl ℝ ℂ G)) w := + (ContinuousLinearMap.inl ℝ ℂ G).hasFDerivAt.const_sub x₀ + exact (((hh.differentiable one_ne_zero) _).hasFDerivAt.comp w h1).fderiv + have hdbar : ∀ w : ℂ, dbarAlong (fderiv ℝ ψ w) 1 = + -dbarAlong (fderiv ℝ h (x₀ - (w, 0))) ((1 : ℂ), (0 : G)) := by + intro w + rw [hder] + simp only [dbarAlong, ContinuousLinearMap.comp_apply, neg_apply, + ContinuousLinearMap.inl_apply, map_neg, smul_eq_mul, mul_one, Prod.smul_mk, smul_zero, + smul_neg] + module + have := integral_inv_smul_dbarAlong_fderiv hψc hψs + simp_rw [hdbar, smul_neg, integral_neg] at this + rw [neg_eq_iff_eq_neg.mp this, neg_neg, hψ] + simp only + rw [show ((0 : ℂ), (0 : G)) = 0 from rfl, sub_zero] + +end Pompeiu + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Circular.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Circular.lean new file mode 100644 index 0000000000..292f9d7ce3 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Circular.lean @@ -0,0 +1,123 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.LocallyConvex.BalancedCoreHull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt + +/-! +# Circular sets and balanced geometry + +Circular symmetry rotates all coordinates by the same scalar. This is weaker than Reinhardt +symmetry. Openness, connectedness and nonemptiness remain separate properties. Balanced sets and +their hulls use Mathlib's `Balanced` and `balancedHull`. Reference: +[Scheidemann][Scheidemann2005] (2005), Section 2.1 and Corollary 3.3.3. + +## Main definitions + +* `IsCircular`: Invariance under one common complex rotation, about the origin. + +## Main results + +* `isCircular_of_balanced`: Balanced sets are circular, including the empty set. +* `isCircular_balancedHull`: Mathlib's balanced hull is circular. +* `isPathConnected_balancedHull`: A nonempty balanced hull is path connected, independently of the + original set's connectedness. +* `IsReinhardt.isCircular`: Independent coordinate rotations include common rotations. +* `IsCompleteReinhardt.balanced`: Complete Reinhardt sets are balanced for complex scalar + multiplication. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Set Metric + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] {U V : Set E} + +/-- Invariance under one common complex rotation, about the origin. -/ +@[expose] def IsCircular (U : Set E) : Prop := + ∀ ⦃z⦄, z ∈ U → ∀ ⦃c : ℂ⦄, ‖c‖ = 1 → c • z ∈ U + +/-- Multiplication by a complex scalar of norm one preserves a circular set. -/ +theorem IsCircular.smul_mem (hU : IsCircular U) {z : E} (hz : z ∈ U) + {c : ℂ} (hc : ‖c‖ = 1) : c • z ∈ U := hU hz hc + +/-- The empty set is circular. -/ +theorem isCircular_empty : IsCircular (∅ : Set E) := fun _ h => h.elim + +/-- The whole space is circular. -/ +theorem isCircular_univ : IsCircular (univ : Set E) := fun _ _ _ _ => mem_univ _ + +/-- Intersections preserve circular symmetry. -/ +theorem IsCircular.inter (hU : IsCircular U) (hV : IsCircular V) : IsCircular (U ∩ V) := + fun _ hz _ hc => ⟨hU hz.1 hc, hV hz.2 hc⟩ + +/-- Unions preserve circular symmetry. -/ +theorem IsCircular.union (hU : IsCircular U) (hV : IsCircular V) : IsCircular (U ∪ V) := + fun _ hz _ hc => hz.elim (fun h => Or.inl (hU h hc)) (fun h => Or.inr (hV h hc)) + +/-- Balanced sets are circular, including the empty set. -/ +theorem isCircular_of_balanced (hU : Balanced ℂ U) : IsCircular U := + fun _ hz _ hc => (balanced_iff_smul_mem.mp hU) hc.le hz + +/-- Mathlib's balanced hull is circular. -/ +theorem isCircular_balancedHull (U : Set E) : IsCircular (balancedHull ℂ U) := + isCircular_of_balanced (balancedHull.balanced U) + +/-- A nonempty balanced hull is path connected, independently of the original set's connectedness. +This follows by contraction along the real radial segments. -/ +theorem isPathConnected_balancedHull (hne : U.Nonempty) : IsPathConnected (balancedHull ℂ U) := by + let : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ ℂ E + have hB := balancedHull.balanced (𝕜 := ℂ) U + have hs : StarConvex ℝ (0 : E) (balancedHull ℂ U) := by + intro z hz a b ha hb hab + simp only [smul_zero, zero_add] + rw [RCLike.real_smul_eq_coe_smul (K := ℂ)] + apply (balanced_iff_smul_mem.mp hB) _ hz + simpa [abs_of_nonneg hb] using (show b ≤ 1 by linarith) + exact hs.isPathConnected (hB.zero_mem (hne.mono (subset_balancedHull ℂ))) + +/-- Linear inverse images preserve circular symmetry. -/ +theorem IsCircular.preimage (L : E →L[ℂ] F) {V : Set F} (hV : IsCircular V) : + IsCircular (L ⁻¹' V) := by + intro z hz c hc + change L (c • z) ∈ V + rw [map_smul] + exact hV hz hc + +/-- Balls about zero are circular for any complex norm, without a coordinate assumption. -/ +theorem isCircular_ball (r : ℝ) : IsCircular (ball (0 : E) r) := by + intro z hz c hc + simpa only [mem_ball, dist_zero_right, norm_smul, hc, one_mul] using hz + +/-- Independent coordinate rotations include common rotations. -/ +theorem IsReinhardt.isCircular {ι : Type*} [Fintype ι] {U : Set (ι → ℂ)} + (hU : IsReinhardt U) : IsCircular U := by + intro z hz c hc + exact hU hz (fun i => by simp [hc]) + +/-- Complete Reinhardt sets are balanced for complex scalar multiplication. -/ +theorem IsCompleteReinhardt.balanced {ι : Type*} [Finite ι] {U : Set (ι → ℂ)} + (hU : IsCompleteReinhardt U) : Balanced ℂ U := by + classical + let := Fintype.ofFinite ι + rw [balanced_iff_smul_mem] + intro c hc z hz + apply hU hz + intro i + simpa only [Pi.smul_apply, norm_smul, one_mul] using + mul_le_mul_of_nonneg_right hc (norm_nonneg (z i)) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CircularContinuation.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CircularContinuation.lean new file mode 100644 index 0000000000..8f85e3893c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CircularContinuation.lean @@ -0,0 +1,238 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.CPolynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Circular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy + +/-! +# Homogeneous expansion and continuation on circular domains + +The terms are diagonals of Mathlib continuous multilinear Taylor coefficients, hence homogeneous +polynomials. Convergence is grouped by total degree, not by individual coordinate monomials. +Cauchy projections identify the terms on circular domains, and geometric majorants give locally +uniform convergence on the balanced hull. Reference: [Scheidemann][Scheidemann2005] (2005), +Theorem 2.1.8. Banach-valued targets are allowed. + +## Main results + +`homogeneousTerm` is the degree-`k` diagonal of a multilinear Taylor series. +`IsCircular.hasSumLocallyUniformlyOn_homogeneousTerm_balancedHull` is locally uniform convergence of +the homogeneous expansion on the balanced hull. `exists_extension_balancedHull` is continuation from +a circular domain to its balanced hull. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Metric Complex +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- The homogeneous term of degree `k` of a multilinear power series centered at zero. -/ +@[expose] def homogeneousTerm (p : FormalMultilinearSeries ℂ E F) (k : ℕ) (z : E) : F := + p k (fun _ => z) + +omit [FiniteDimensional ℂ E] [CompleteSpace F] in +/-- A homogeneous term is the corresponding multilinear map on the constant tuple. -/ +theorem homogeneousTerm_apply (p : FormalMultilinearSeries ℂ E F) (k : ℕ) (z : E) : + homogeneousTerm p k z = p k (fun _ => z) := rfl + +omit [FiniteDimensional ℂ E] [CompleteSpace F] in +/-- The degree is expressed by the usual scalar homogeneity identity. -/ +theorem homogeneousTerm_smul (p : FormalMultilinearSeries ℂ E F) (k : ℕ) (c : ℂ) (z : E) : + homogeneousTerm p k (c • z) = c ^ k • homogeneousTerm p k z := by + simpa [homogeneousTerm] using (p k).map_smul_univ (fun _ => c) (fun _ => z) + +omit [FiniteDimensional ℂ E] [CompleteSpace F] in +/-- A homogeneous Taylor term is analytic on the whole ambient space. -/ +theorem analyticOnNhd_homogeneousTerm (p : FormalMultilinearSeries ℂ E F) (k : ℕ) + (S : Set E) : AnalyticOnNhd ℂ (homogeneousTerm p k) S := by + intro z _ + exact (p k).analyticAt.comp (analyticAt_pi_iff.mpr fun _ => analyticAt_id) + +/-- On a circular domain, the homogeneous Taylor terms are the Cauchy projections under simultaneous +rotation of all coordinates. -/ +theorem homogeneousTerm_eq_circleIntegral {U : Set E} (ho : IsOpen U) + (hc : IsPreconnected U) (hrot : IsCircular U) (hzero : (0 : E) ∈ U) + {f : E → F} (hf : AnalyticOnNhd ℂ f U) {p : FormalMultilinearSeries ℂ E F} + (hp : HasFPowerSeriesAt f p 0) (k : ℕ) : + EqOn (homogeneousTerm p k) + (fun z => (2 * Real.pi * I : ℂ)⁻¹ • + ∮ w in C(0, 1), w⁻¹ ^ k • w⁻¹ • f (w • z)) U := by + let H : E × ℂ → F := fun q => q.2⁻¹ ^ k • q.2⁻¹ • f (q.2 • q.1) + have hH : AnalyticOnNhd ℂ H {q | q.2 ≠ 0 ∧ q.2 • q.1 ∈ U} := by + intro q hq + exact ((analyticAt_snd.inv hq.1).pow k).smul + ((analyticAt_snd.inv hq.1).smul + ((hf _ hq.2).comp_of_eq (analyticAt_snd.smul analyticAt_fst) rfl)) + have hproj := (analyticOnNhd_circleIntegral_kernel (c := 0) ho hH + (by norm_num : (0 : ℝ) ≤ 1) + (fun z hz w hw => by + have hw' : ‖w‖ = 1 := by simpa using hw + exact ⟨norm_ne_zero_iff.mp (by rw [hw']; norm_num), + hrot.smul_mem hz hw'⟩)).const_smul + (c := (2 * Real.pi * I : ℂ)⁻¹) + apply DifferentiableOn.eqOn_of_preconnected_of_eventuallyEq ho hc + (analyticOnNhd_homogeneousTerm p k U).differentiableOn hproj.differentiableOn hzero + obtain ⟨r, hr, hball⟩ := Metric.isOpen_iff.mp ho 0 hzero + filter_upwards [ball_mem_nhds (0 : E) hr] with z hz + let L : ℂ →L[ℂ] E := (ContinuousLinearMap.id ℂ ℂ).smulRight z + have hline : HasFPowerSeriesAt (fun w : ℂ => f (w • z)) + (p.compContinuousLinearMap L) 0 := by + have hp' : HasFPowerSeriesAt f p (L 0) := by simpa [L] using hp + exact hp'.compContinuousLinearMap + have hd : DifferentiableOn ℂ (fun w : ℂ => f (w • z)) (closedBall 0 1) := by + intro w hw + apply ((hf _ (hball ?_)).differentiableAt.comp w L.differentiableAt).differentiableWithinAt + change w • z ∈ ball 0 r + rw [mem_ball_zero_iff, norm_smul] + exact (mul_le_of_le_one_left (norm_nonneg z) (mem_closedBall_zero_iff.mp hw)).trans_lt + (mem_ball_zero_iff.mp hz) + have he := hline.eq_formalMultilinearSeries + (hd.hasFPowerSeriesOnBall (R := 1) (by norm_num)).hasFPowerSeriesAt + have he' := congrArg (fun q : FormalMultilinearSeries ℂ ℂ F => q k (fun _ => 1)) he + simpa only [FormalMultilinearSeries.compContinuousLinearMap_apply, L, + Function.comp_def, Pi.smul_apply, NNReal.coe_one, + ContinuousLinearMap.smulRight_apply, ContinuousLinearMap.id_apply, one_smul, + homogeneousTerm, cauchyPowerSeries_apply, sub_zero, one_div, H] using he' + +omit [FiniteDimensional ℂ E] in +/-- Openness lets every point of a balanced hull be represented by a strict, nonzero contraction of +a point of the original set. -/ +private theorem exists_strict_contraction {U : Set E} (ho : IsOpen U) + (hzero : (0 : E) ∈ U) {x : E} (hx : x ∈ balancedHull ℂ U) : + ∃ (c : ℂ) (z : E), c ≠ 0 ∧ ‖c‖ < 1 ∧ z ∈ U ∧ c • z = x := by + obtain ⟨d, hd, y, hy, rfl⟩ := mem_balancedHull_iff.mp hx + by_cases hd0 : d = 0 + · exact ⟨1 / 2, 0, by norm_num, by norm_num, hzero, by simp [hd0]⟩ + have hn : {t : ℝ | (t : ℂ) • y ∈ U} ∈ 𝓝 1 := by + exact (continuous_ofReal.smul continuous_const).continuousAt.preimage_mem_nhds + (ho.mem_nhds (by simpa using hy)) + obtain ⟨ε, hε, hsub⟩ := Metric.mem_nhds_iff.mp hn + let t : ℝ := 1 + ε / 2 + have ht : 1 < t := by dsimp [t]; linarith + have ht0 : 0 < t := zero_lt_one.trans ht + have hty : (t : ℂ) • y ∈ U := hsub (by + simp only [mem_ball, Real.dist_eq, t, add_sub_cancel_left, abs_of_pos (half_pos hε)] + exact half_lt_self hε) + refine ⟨d / t, (t : ℂ) • y, div_ne_zero hd0 (ofReal_ne_zero.mpr ht0.ne'), ?_, hty, ?_⟩ + · rw [norm_div, Complex.norm_of_nonneg ht0.le] + exact (div_lt_one ht0).mpr (hd.trans_lt ht) + · rw [smul_smul, div_mul_cancel₀ _ (ofReal_ne_zero.mpr ht0.ne')] + +/-- Cauchy projections give a locally summable geometric majorant throughout the balanced hull of a +circular domain. -/ +private theorem hasSumLocallyUniformlyOn_homogeneousTerm {U : Set E} (ho : IsOpen U) + (hc : IsPreconnected U) (hrot : IsCircular U) (hzero : (0 : E) ∈ U) + {f : E → F} (hf : AnalyticOnNhd ℂ f U) {p : FormalMultilinearSeries ℂ E F} + (hp : HasFPowerSeriesAt f p 0) : + HasSumLocallyUniformlyOn (homogeneousTerm p) (fun z => ∑' k, homogeneousTerm p k z) + (balancedHull ℂ U) := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + apply hasSumLocallyUniformlyOn_of_of_forall_exists_nhds + intro x hx + obtain ⟨c, z, hc0, hc1, hz, rfl⟩ := exists_strict_contraction ho hzero hx + have hn : ∀ᶠ y in 𝓝 z, ∀ w ∈ sphere (0 : ℂ) 1, w • y ∈ U := by + apply (isCompact_sphere (0 : ℂ) 1).eventually_forall_of_forall_eventually + intro w hw + apply (continuous_snd.smul continuous_fst).continuousAt.preimage_mem_nhds + exact ho.mem_nhds (hrot.smul_mem hz (by simpa using hw)) + obtain ⟨δ, hδ, hball⟩ := nhds_basis_closedBall.mem_iff.mp hn + let K := (fun q : E × ℂ => q.2 • q.1) '' (closedBall z δ ×ˢ sphere 0 1) + have hK : IsCompact K := ((isCompact_closedBall z δ).prod (isCompact_sphere 0 1)).image + (continuous_snd.smul continuous_fst) + have hKU : K ⊆ U := by + rintro _ ⟨⟨y, w⟩, ⟨hy, hw⟩, rfl⟩ + exact hball hy w hw + obtain ⟨M, hM⟩ := hK.bddAbove_image (hf.continuousOn.mono hKU).norm + let C := max M 0 + have hbound (y : E) (hy : y ∈ closedBall z δ) (k : ℕ) : ‖homogeneousTerm p k y‖ ≤ C := by + have hyU : y ∈ U := by simpa using hball hy 1 (by simp) + rw [homogeneousTerm_eq_circleIntegral ho hc hrot hzero hf hp k hyU] + apply (circleIntegral.norm_two_pi_i_inv_smul_integral_le_of_norm_le_const + (by norm_num : (0 : ℝ) ≤ 1) ?_).trans_eq (one_mul C) + intro w hw + have hw' : ‖w‖ = 1 := by simpa using hw + simp only [norm_smul, norm_pow, norm_inv, hw', inv_one, one_pow, one_mul] + exact (hM ⟨w • y, ⟨(y, w), ⟨hy, hw⟩, rfl⟩, rfl⟩).trans (le_max_left _ _) + let N := {y : E | c⁻¹ • y ∈ ball z δ} + have hN : N ∈ 𝓝 (c • z) := by + apply (continuous_const.smul continuous_id).continuousAt.preimage_mem_nhds + simpa [hc0] using ball_mem_nhds z hδ + have hterm (k : ℕ) (y : E) (hy : y ∈ N) : + ‖homogeneousTerm p k y‖ ≤ C * ‖c‖ ^ k := by + have he : y = c • (c⁻¹ • y) := by simp [hc0] + calc + ‖homogeneousTerm p k y‖ = ‖c‖ ^ k * ‖homogeneousTerm p k (c⁻¹ • y)‖ := by + conv_lhs => rw [he, homogeneousTerm_smul] + rw [norm_smul, norm_pow] + _ ≤ ‖c‖ ^ k * C := mul_le_mul_of_nonneg_left + (hbound _ (ball_subset_closedBall hy) k) (by positivity) + _ = C * ‖c‖ ^ k := mul_comm _ _ + refine ⟨N, mem_nhdsWithin_of_mem_nhds hN, ?_⟩ + exact hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + (tendstoUniformlyOn_tsum ((summable_geometric_of_lt_one (norm_nonneg c) hc1).mul_left C) + hterm) + +/-- Homogeneous Taylor expansion on a circular domain extends to its balanced hull. Cauchy +projections under common rotations and compact majorants on radial contractions give +convergence; analytic uniqueness identifies the sum with the original function. The chosen +Taylor series is supplied explicitly. -/ +theorem IsCircular.hasSumLocallyUniformlyOn_homogeneousTerm_balancedHull {U : Set E} (ho : IsOpen U) + (hc : IsPreconnected U) (hrot : IsCircular U) (hzero : (0 : E) ∈ U) + {f : E → F} (hf : AnalyticOnNhd ℂ f U) {p : FormalMultilinearSeries ℂ E F} + (hp : HasFPowerSeriesAt f p 0) : + HasSumLocallyUniformlyOn (homogeneousTerm p) f U ∧ + HasSumLocallyUniformlyOn (homogeneousTerm p) (fun z => ∑' k, homogeneousTerm p k z) + (balancedHull ℂ U) ∧ + AnalyticOnNhd ℂ (fun z => ∑' k, homogeneousTerm p k z) (balancedHull ℂ U) := by + have hs := hasSumLocallyUniformlyOn_homogeneousTerm ho hc hrot hzero hf hp + have ha : AnalyticOnNhd ℂ (fun z => ∑' k, homogeneousTerm p k z) (balancedHull ℂ U) := by + apply hs.analyticOnNhd_of_finiteDimensional _ (ho.balancedHull hzero) + filter_upwards with s + exact Finset.analyticOnNhd_fun_sum s fun k _ => + analyticOnNhd_homogeneousTerm p k _ + have he : EqOn (fun z => ∑' k, homogeneousTerm p k z) f U := by + apply DifferentiableOn.eqOn_of_preconnected_of_eventuallyEq ho hc + (ha.mono (subset_balancedHull ℂ)).differentiableOn hf.differentiableOn hzero + filter_upwards [hp.eventually_hasSum] with z hz + simpa only [homogeneousTerm, zero_add] using hz.tsum_eq + exact ⟨(hs.mono (subset_balancedHull ℂ)).congr_right (fun z hz => he hz), hs, ha⟩ + +/-- A holomorphic function on a circular domain containing zero extends to its balanced hull. +Depends on homogeneous expansion. -/ +theorem exists_extension_balancedHull {U : Set E} (ho : IsOpen U) + (hc : IsPreconnected U) (hrot : IsCircular U) (hzero : (0 : E) ∈ U) + {f : E → F} (hf : AnalyticOnNhd ℂ f U) : + ∃ g, AnalyticOnNhd ℂ g (balancedHull ℂ U) ∧ EqOn g f U := by + obtain ⟨p, hp⟩ := hf 0 hzero + obtain ⟨hs, _, ha⟩ + := IsCircular.hasSumLocallyUniformlyOn_homogeneousTerm_balancedHull ho hc hrot hzero hf hp + exact ⟨_, ha, fun z hz => (hs.hasSum hz).tsum_eq⟩ + +/-- Extensions to the balanced hull are unique by the identity theorem and geometry. -/ +theorem eqOn_balancedHull_of_eqOn {U : Set E} (ho : IsOpen U) (hzero : (0 : E) ∈ U) + {f g : E → F} (hf : AnalyticOnNhd ℂ f (balancedHull ℂ U)) + (hg : AnalyticOnNhd ℂ g (balancedHull ℂ U)) (he : EqOn f g U) : + EqOn f g (balancedHull ℂ U) := + DifferentiableOn.eqOn_of_preconnected_of_eqOn (ho.balancedHull hzero) + (isPathConnected_balancedHull ⟨0, hzero⟩).isConnected.isPreconnected + hf.differentiableOn hg.differentiableOn ho ⟨0, hzero⟩ (subset_balancedHull ℂ) he + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CommonExtension.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CommonExtension.lean new file mode 100644 index 0000000000..64fb8568c0 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CommonExtension.lean @@ -0,0 +1,139 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Uniqueness +public import Mathlib.Analysis.LocallyConvex.Separation +public import Mathlib.Analysis.RCLike.Extend +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity + +/-! +# Common extension domains inside a complex vector space + +`IsCommonAnalyticExtension U V` says that `U ⊆ V` and every scalar analytic function on `U` +extends to `V`. It does not impose openness, connectedness, or maximality, and does not define +an abstract envelope. Simultaneous extension cannot introduce new scalar values, by extending +the reciprocal of a nowhere-zero function. + +Convex separation also bounds common extension domains by the real convex hull. References: +[Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), Proposition 2.9.2 and Corollary 2.9.3, +specialized to domains in a complex normed space. + +## Main definitions + +* `IsCommonAnalyticExtension`: Every scalar analytic function on `U` extends to the larger set `V`. + +## Main results + +* `IsCommonAnalyticExtension.trans`: Common extension composes. +* `IsCommonAnalyticExtension.image_eq`: A scalar analytic function on a connected common extension + domain has exactly its original range. +* `IsCommonAnalyticExtension.subset_convexHull`: A common extension domain lies in the real convex + hull of the original domain. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public section + +open Filter Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Every scalar analytic function on `U` extends to the larger set `V`. Topological hypotheses and +maximality are separate; no extension outside the ambient space is intended. -/ +@[expose] def IsCommonAnalyticExtension (U V : Set E) : Prop := + U ⊆ V ∧ ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → + ∃ g, AnalyticOnNhd ℂ g V ∧ EqOn g f U + +/-- Construct a common extension property from containment and extension of each scalar analytic +function. -/ +theorem isCommonAnalyticExtension_of_forall {U V : Set E} (hUV : U ⊆ V) + (he : ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → + ∃ g, AnalyticOnNhd ℂ g V ∧ EqOn g f U) : IsCommonAnalyticExtension U V := + ⟨hUV, he⟩ + +/-- A common extension pair includes the original set in the extension set. -/ +theorem IsCommonAnalyticExtension.subset {U V : Set E} (h : IsCommonAnalyticExtension U V) : + U ⊆ V := h.1 + +/-- Apply a common extension property to a scalar analytic function. -/ +theorem IsCommonAnalyticExtension.exists_extension {U V : Set E} + (h : IsCommonAnalyticExtension U V) {f : E → ℂ} (hf : AnalyticOnNhd ℂ f U) : + ∃ g, AnalyticOnNhd ℂ g V ∧ EqOn g f U := h.2 f hf + +/-- Every set is a common extension domain for itself. -/ +theorem isCommonAnalyticExtension_refl (U : Set E) : IsCommonAnalyticExtension U U := + ⟨Subset.rfl, fun f hf => ⟨f, hf, fun _ _ => rfl⟩⟩ + +/-- Common extension composes. -/ +theorem IsCommonAnalyticExtension.trans {U V W : Set E} + (hUV : IsCommonAnalyticExtension U V) (hVW : IsCommonAnalyticExtension V W) : + IsCommonAnalyticExtension U W := by + refine ⟨hUV.1.trans hVW.1, fun f hf => ?_⟩ + obtain ⟨g, hg, he⟩ := hUV.2 f hf + obtain ⟨k, hk, he'⟩ := hVW.2 g hg + exact ⟨k, hk, (he'.mono hUV.1).trans he⟩ + +/-- An omitted scalar value remains omitted on a connected common extension domain. -/ +theorem IsCommonAnalyticExtension.ne_on {U V : Set E} (h : IsCommonAnalyticExtension U V) + (ho : IsOpen U) (hne : U.Nonempty) (hc : IsPreconnected V) + {f : E → ℂ} (hf : AnalyticOnNhd ℂ f V) {c : ℂ} (hno : ∀ z ∈ U, f z ≠ c) : + ∀ z ∈ V, f z ≠ c := by + have hi : AnalyticOnNhd ℂ (fun z => (f z - c)⁻¹) U := + fun z hz => ((hf z (h.1 hz)).sub analyticAt_const).inv (sub_ne_zero.mpr (hno z hz)) + obtain ⟨g, hg, he⟩ := h.2 _ hi + have hp : AnalyticOnNhd ℂ (fun z => (f z - c) * g z) V := + (hf.sub analyticOnNhd_const).mul hg + obtain ⟨a, ha⟩ := hne + have he₁ : (fun z => (f z - c) * g z) =ᶠ[𝓝 a] (fun _ => (1 : ℂ)) := by + filter_upwards [ho.mem_nhds ha] with z hz + rw [he hz] + exact mul_inv_cancel₀ (sub_ne_zero.mpr (hno z hz)) + have hp₁ := hp.eqOn_of_preconnected_of_eventuallyEq analyticOnNhd_const hc (h.1 ha) he₁ + intro z hz heq + have := hp₁ hz + simp [heq] at this + +/-- A scalar analytic function on a connected common extension domain has exactly its original +range. This is the Euclidean version of Proposition 2.9.2. -/ +theorem IsCommonAnalyticExtension.image_eq {U V : Set E} (h : IsCommonAnalyticExtension U V) + (ho : IsOpen U) (hne : U.Nonempty) (hc : IsPreconnected V) + {f : E → ℂ} (hf : AnalyticOnNhd ℂ f V) : f '' V = f '' U := by + classical + apply Subset.antisymm _ (image_mono h.1) + rintro c ⟨z, hz, rfl⟩ + by_contra hn + have hno : ∀ w ∈ U, f w ≠ f z := fun w hw he => hn ⟨w, hw, he⟩ + exact h.ne_on ho hne hc hf hno z hz rfl + +/-- A common extension domain lies in the real convex hull of the original domain. The proof uses +real convex separation, complexification of the separating functional, and preservation of +omitted values. This assertion involves no abstract envelopes. -/ +theorem IsCommonAnalyticExtension.subset_convexHull + {U V : Set E} (h : IsCommonAnalyticExtension U V) (ho : IsOpen U) + (hne : U.Nonempty) (hc : IsPreconnected V) : V ⊆ convexHull ℝ U := by + intro z hz + by_contra hn + obtain ⟨l, hl⟩ := geometric_hahn_banach_open_point (convex_convexHull ℝ U) + (ho.convexHull (𝕜 := ℝ)) hn + let L : E →L[ℂ] ℂ := l.extendRCLike + have hno : ∀ w ∈ U, L w ≠ L z := by + intro w hw he + have he' : l w = l z := by + simpa only [L, StrongDual.re_extendRCLike_apply] using + congrArg (RCLike.re : ℂ → ℝ) he + exact (ne_of_lt (hl w (_root_.subset_convexHull ℝ U hw))) he' + exact h.ne_on ho hne hc (fun w _ => L.analyticAt w) hno z hz rfl + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CompactHole.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CompactHole.lean new file mode 100644 index 0000000000..a3dbcd1689 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/CompactHole.lean @@ -0,0 +1,374 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.FDeriv.Symmetric +public import Mathlib.Geometry.Manifold.PartitionOfUnity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyTransform + +/-! +# Hartogs' compact-hole extension theorem in a product space + +Ehrenpreis' proof of Hartogs' extension theorem. Let `D ⊆ ℂ × G` be open with `G` a nontrivial +finite-dimensional complex normed space, `K ⊆ D` compact with `D \ K` connected, and `f` +holomorphic on `D \ K`. A smooth cutoff `φ` equal to one near `K` with compact support in `D` +gives the smooth function `F₀ = (1 - φ) f`, extended by zero across `K`. Its antiholomorphic +derivatives `∂F₀/∂\bar z` along every direction are compactly supported, and their symmetry, +from the symmetry of the second derivative of `F₀`, shows that the Cauchy transform `u` in the +first variable of `∂F₀/∂\bar z₁` has the same antiholomorphic derivatives as `F₀`. Hence `F₀ - +u` is holomorphic on `D`. On the open set of points of `D` whose second coordinate lies outside +the projection of the support of `φ`, both `F₀ = f` and `u = 0`; this set is nonempty because +the projection of `D` cannot be compact, and the identity principle on `D \ K` finishes the +proof. + +References: [Hörmander][Hormander1973] (1973), Theorem 2.3.2; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Theorem 4.2.5; [Boas][Boas2013] (2013), Section +2.4. + +## Main results + +* `exists_analyticOnNhd_extension_of_isCompact_prod`: **Hartogs' compact-hole extension theorem in a + product space.** For an open set `D ⊆ ℂ × G` with `G` a nontrivial finite-dimensional complex + normed space, a compact `K ⊆ D` with `D \ K` connected, and `f` holomorphic on `D \ K`, there is a + holomorphic function on `D` agreeing with `f` on `D \ K`. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Complex MeasureTheory Set Filter Metric Function +open scoped Topology + +namespace SeveralComplexVariables + +section Symmetry + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- The antiholomorphic derivatives of a `C²` function commute: the antiholomorphic part along `v'` +of the derivative of `∂F₀/∂\bar z_v` equals the antiholomorphic part along `v` of the derivative +of `∂F₀/∂\bar z_{v'}`. -/ +theorem dbarAlong_fderiv_dbarAlong_fderiv_symm {F₀ : E → F} {x : E} (hF : ContDiffAt ℝ 2 F₀ x) + (v v' : E) : + dbarAlong (fderiv ℝ (fun y => dbarAlong (fderiv ℝ F₀ y) v) x) v' = + dbarAlong (fderiv ℝ (fun y => dbarAlong (fderiv ℝ F₀ y) v') x) v := by + have hsymm : IsSymmSndFDerivAt ℝ F₀ x := hF.isSymmSndFDerivAt (by simp) + have hd : HasFDerivAt (fderiv ℝ F₀) (fderiv ℝ (fderiv ℝ F₀) x) x := + ((hF.fderiv_right (m := 1) le_rfl).differentiableAt one_ne_zero).hasFDerivAt + set D2 := fderiv ℝ (fderiv ℝ F₀) x with hD2 + have key : ∀ u : E, HasFDerivAt (fun y => dbarAlong (fderiv ℝ F₀ y) u) + ((2 : ℂ)⁻¹ • (D2.flip u + I • D2.flip (I • u))) x := by + intro u + have h1 : HasFDerivAt (fun y => fderiv ℝ F₀ y u) (D2.flip u) x := by + have := hd.clm_apply (hasFDerivAt_const u x) + simpa using this + have h2 : HasFDerivAt (fun y => fderiv ℝ F₀ y (I • u)) (D2.flip (I • u)) x := by + have := hd.clm_apply (hasFDerivAt_const (I • u) x) + simpa using this + exact (h1.add (h2.const_smul I)).const_smul (2 : ℂ)⁻¹ + rw [(key v).fderiv, (key v').fderiv] + simp only [dbarAlong, FunLike.coe_smul, FunLike.coe_add, Pi.smul_apply, Pi.add_apply, + ContinuousLinearMap.flip_apply] + rw [hsymm v' v, hsymm v' (I • v), hsymm (I • v') v, hsymm (I • v') (I • v)] + module + +end Symmetry + +section Cutoff + +variable {G F : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] [FiniteDimensional ℂ G] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +open scoped ContDiff + +/-- Cutoff data for a compact hole `K` in an open set `D`: a smooth function equal to one on an open +neighborhood of `K`, with open support `s` whose closure is compact in `D`. -/ +private structure HoleCutoffData (D K : Set (ℂ × G)) where + /-- The cutoff function. -/ + φ : ℂ × G → ℝ + /-- An open neighborhood of `K` on which the cutoff equals one. -/ + neighborhood : Set (ℂ × G) + /-- The support of the cutoff. -/ + s : Set (ℂ × G) + /-- The cutoff is smooth. -/ + contDiff : ContDiff ℝ ∞ φ + /-- The neighborhood on which the cutoff equals one is open. -/ + isOpen_neighborhood : IsOpen neighborhood + /-- The neighborhood contains the hole. -/ + subset_neighborhood : K ⊆ neighborhood + /-- The cutoff equals one on the neighborhood of the hole. -/ + eq_one : ∀ x ∈ neighborhood, φ x = 1 + /-- The support is open. -/ + isOpen_s : IsOpen s + /-- The specified support is the nonzero locus of the cutoff. -/ + support_eq : support φ = s + /-- The support has compact closure. -/ + isCompact_closure : IsCompact (closure s) + /-- The closure of the support lies in the original domain. -/ + closure_subset : closure s ⊆ D + +omit [NormedSpace ℂ F] [CompleteSpace F] in +/-- Existence of cutoff data, from a smooth Urysohn function on thickenings of `K`. -/ +private theorem nonempty_holeCutoffData {D K : Set (ℂ × G)} (hD : IsOpen D) (hK : IsCompact K) + (hKD : K ⊆ D) : Nonempty (HoleCutoffData D K) := by + obtain ⟨δ, hδ, hδD⟩ := hK.exists_cthickening_subset_open hD hKD + obtain ⟨φ, hφ, -, hsupp, hone⟩ := exists_contDiff_support_eq_eq_one_iff (n := ⊤) (E := ℂ × G) + (isOpen_thickening (δ := δ / 2) (E := K)) (isClosed_cthickening (δ := δ / 4) (E := K)) + (cthickening_subset_thickening' (by positivity) (by linarith) K) + refine ⟨⟨φ, thickening (δ / 4) K, thickening (δ / 2) K, hφ, isOpen_thickening, + self_subset_thickening (by positivity) K, + fun x hx => (hone x).mp (thickening_subset_cthickening _ _ hx), isOpen_thickening, hsupp, + ?_, ?_⟩⟩ + · exact (hK.cthickening (r := δ / 2)).of_isClosed_subset isClosed_closure + (closure_thickening_subset_cthickening _ _) + · exact (closure_thickening_subset_cthickening _ _).trans + ((cthickening_mono (by linarith) K).trans hδD) + +omit [FiniteDimensional ℂ G] [NormedSpace ℂ F] [CompleteSpace F] in +/-- The hole lies in the support of the cutoff. -/ +private theorem HoleCutoffData.subset_s {D K : Set (ℂ × G)} (h : HoleCutoffData D K) : K ⊆ h.s := + fun x hx => by + rw [← h.support_eq, mem_support, h.eq_one x (h.subset_neighborhood hx)] + exact one_ne_zero + +omit [FiniteDimensional ℂ G] [NormedSpace ℂ F] [CompleteSpace F] in +/-- The cutoff vanishes outside its support. -/ +private theorem HoleCutoffData.eq_zero_of_notMem {D K : Set (ℂ × G)} (h : HoleCutoffData D K) + {x : ℂ × G} (hx : x ∉ h.s) : h.φ x = 0 := by + rw [← h.support_eq] at hx + exact notMem_support.mp hx + +omit [FiniteDimensional ℂ G] [NormedSpace ℂ F] [CompleteSpace F] in +/-- Points outside the closure of the support are outside the hole. -/ +private theorem HoleCutoffData.notMem_hole_of_notMem_closure {D K : Set (ℂ × G)} + (h : HoleCutoffData D K) + {x : ℂ × G} (hx : x ∉ closure h.s) : x ∉ K := + fun hxK => hx (subset_closure (h.subset_s hxK)) + +open scoped Classical in +/-- The modification `(1 - φ) • f`, set to zero on the hole. -/ +private def holeCutoff (K : Set (ℂ × G)) (φ : ℂ × G → ℝ) (f : ℂ × G → F) (x : ℂ × G) : F := + if x ∈ K then 0 else (1 - φ x) • f x + +omit [NormedAddCommGroup G] [NormedSpace ℂ G] [FiniteDimensional ℂ G] [CompleteSpace F] in +/-- The modified function vanishes where the cutoff equals one. -/ +private theorem holeCutoff_eq_zero_of_one {K : Set (ℂ × G)} {φ : ℂ × G → ℝ} {f : ℂ × G → F} + {x : ℂ × G} + (hx : φ x = 1) : holeCutoff K φ f x = 0 := by + unfold holeCutoff + split_ifs <;> simp [hx] + +omit [NormedAddCommGroup G] [NormedSpace ℂ G] [FiniteDimensional ℂ G] [CompleteSpace F] in +/-- Off the hole and off the support of the cutoff, the modified function is `f`. -/ +private theorem holeCutoff_eq_of_zero {K : Set (ℂ × G)} {φ : ℂ × G → ℝ} {f : ℂ × G → F} {x : ℂ × G} + (hxK : x ∉ K) (hx : φ x = 0) : holeCutoff K φ f x = f x := by + simp [holeCutoff, hxK, hx] + +variable {D K : Set (ℂ × G)} {f : ℂ × G → F} + +omit [FiniteDimensional ℂ G] in +/-- The modified function is `C²` on `D`. -/ +private theorem contDiffAt_holeCutoff (h : HoleCutoffData D K) (hD : IsOpen D) (hKc : IsClosed K) + (hf : AnalyticOnNhd ℂ f (D \ K)) {x : ℂ × G} (hx : x ∈ D) : + ContDiffAt ℝ 2 (holeCutoff K h.φ f) x := by + by_cases hxU : x ∈ h.neighborhood + · have heq : holeCutoff K h.φ f =ᶠ[𝓝 x] fun _ => (0 : F) := + eventuallyEq_of_mem (h.isOpen_neighborhood.mem_nhds hxU) fun y hy => + holeCutoff_eq_zero_of_one (h.eq_one y hy) + exact contDiffAt_const.congr_of_eventuallyEq heq + · have hxK : x ∉ K := fun hxK => hxU (h.subset_neighborhood hxK) + have hmem : x ∈ D \ K := ⟨hx, hxK⟩ + have heq : holeCutoff K h.φ f =ᶠ[𝓝 x] fun y => (1 - h.φ y) • f y := + eventuallyEq_of_mem ((hD.sdiff hKc).mem_nhds hmem) fun y hy => by + simp [holeCutoff, hy.2] + have hfc : ContDiffAt ℝ 2 f x := (hf x hmem).contDiffAt.restrict_scalars ℝ + have hφc : ContDiffAt ℝ 2 h.φ x := h.contDiff.contDiffAt.of_le (by simp) + exact ((contDiffAt_const.sub hφc).smul hfc).congr_of_eventuallyEq heq + +omit [FiniteDimensional ℂ G] [CompleteSpace F] in +/-- Away from the closure of the support of the cutoff, the modified function is `f`. -/ +private theorem holeCutoff_eventuallyEq (h : HoleCutoffData D K) (x : ℂ × G) (hx : x ∉ closure h.s) + : + holeCutoff K h.φ f =ᶠ[𝓝 x] f := + eventuallyEq_of_mem (isClosed_closure.isOpen_compl.mem_nhds hx) fun _ hy => + holeCutoff_eq_of_zero (h.notMem_hole_of_notMem_closure hy) + (h.eq_zero_of_notMem fun hs => hy (subset_closure hs)) + +open scoped Classical in +/-- The antiholomorphic derivative of a function on `D` along a direction, extended by zero. -/ +private def dbarExt (D : Set (ℂ × G)) (F₀ : ℂ × G → F) (v : ℂ × G) (x : ℂ × G) : F := + if x ∈ D then dbarAlong (fderiv ℝ F₀ x) v else 0 + +omit [FiniteDimensional ℂ G] [CompleteSpace F] in +/-- On `D`, the extended derivative is the antiholomorphic derivative. -/ +private theorem dbarExt_eventuallyEq (hD : IsOpen D) {F₀ : ℂ × G → F} {v x : ℂ × G} (hx : x ∈ D) : + dbarExt D F₀ v =ᶠ[𝓝 x] fun y => dbarAlong (fderiv ℝ F₀ y) v := + eventuallyEq_of_mem (hD.mem_nhds hx) fun y hy => by simp [dbarExt, hy] + +omit [FiniteDimensional ℂ G] [CompleteSpace F] in +/-- The value of the extended derivative at a point of `D`. -/ +private theorem dbarExt_of_mem {F₀ : ℂ × G → F} {v x : ℂ × G} (hx : x ∈ D) : + dbarExt D F₀ v x = dbarAlong (fderiv ℝ F₀ x) v := by simp [dbarExt, hx] + +omit [FiniteDimensional ℂ G] [CompleteSpace F] in +/-- The extended antiholomorphic derivatives vanish outside the closure of the support. -/ +private theorem dbarExt_holeCutoff_eq_zero (h : HoleCutoffData D K) + (hf : AnalyticOnNhd ℂ f (D \ K)) (v : ℂ × G) {x : ℂ × G} + (hx : x ∉ closure h.s) : dbarExt D (holeCutoff K h.φ f) v x = 0 := by + by_cases hxD : x ∈ D + · rw [dbarExt_of_mem hxD, (holeCutoff_eventuallyEq h (f := f) x hx).fderiv_eq, + (hf x ⟨hxD, h.notMem_hole_of_notMem_closure hx⟩).differentiableAt.fderiv_restrictScalars ℝ, + dbarAlong_restrictScalars] + · simp [dbarExt, hxD] + +omit [FiniteDimensional ℂ G] in +/-- The extended antiholomorphic derivatives of the modified function are `C¹`. -/ +private theorem contDiff_dbarExt_holeCutoff (h : HoleCutoffData D K) (hD : IsOpen D) + (hKc : IsClosed K) + (hf : AnalyticOnNhd ℂ f (D \ K)) (v : ℂ × G) : + ContDiff ℝ 1 (dbarExt D (holeCutoff K h.φ f) v) := by + rw [contDiff_iff_contDiffAt] + intro x + by_cases hx : x ∈ D + · have hfd : ContDiffAt ℝ 1 (fderiv ℝ (holeCutoff K h.φ f)) x := + (contDiffAt_holeCutoff h hD hKc hf hx).fderiv_right (m := 1) le_rfl + have : ContDiffAt ℝ 1 (fun y => dbarAlong (fderiv ℝ (holeCutoff K h.φ f) y) v) x := by + unfold dbarAlong + exact contDiffAt_const.smul ((hfd.clm_apply contDiffAt_const).add + (contDiffAt_const.smul (hfd.clm_apply contDiffAt_const))) + exact this.congr_of_eventuallyEq (dbarExt_eventuallyEq hD hx) + · have hxs : x ∉ closure h.s := fun hc => hx (h.closure_subset hc) + have heq : dbarExt D (holeCutoff K h.φ f) v =ᶠ[𝓝 x] fun _ => (0 : F) := + eventuallyEq_of_mem (isClosed_closure.isOpen_compl.mem_nhds hxs) fun y hy => + dbarExt_holeCutoff_eq_zero h hf v hy + exact contDiffAt_const.congr_of_eventuallyEq heq + +omit [FiniteDimensional ℂ G] [CompleteSpace F] in +/-- The extended antiholomorphic derivatives of the modified function have compact support. -/ +private theorem hasCompactSupport_dbarExt_holeCutoff (h : HoleCutoffData D K) + (hf : AnalyticOnNhd ℂ f (D \ K)) (v : ℂ × G) : + HasCompactSupport (dbarExt D (holeCutoff K h.φ f) v) := + HasCompactSupport.intro h.isCompact_closure fun _ hx => dbarExt_holeCutoff_eq_zero h hf v hx + +omit [FiniteDimensional ℂ G] in +/-- Symmetry of the extended antiholomorphic derivatives. -/ +private theorem dbarAlong_fderiv_dbarExt_holeCutoff_symm (h : HoleCutoffData D K) (hD : IsOpen D) + (hKc : IsClosed K) + (hf : AnalyticOnNhd ℂ f (D \ K)) (y v v' : ℂ × G) : + dbarAlong (fderiv ℝ (dbarExt D (holeCutoff K h.φ f) v) y) v' = + dbarAlong (fderiv ℝ (dbarExt D (holeCutoff K h.φ f) v') y) v := by + by_cases hy : y ∈ D + · rw [(dbarExt_eventuallyEq hD hy).fderiv_eq, (dbarExt_eventuallyEq hD hy).fderiv_eq] + exact dbarAlong_fderiv_dbarAlong_fderiv_symm (contDiffAt_holeCutoff h hD hKc hf hy) v v' + · have hys : y ∉ closure h.s := fun hc => hy (h.closure_subset hc) + have hz : ∀ u : ℂ × G, fderiv ℝ (dbarExt D (holeCutoff K h.φ f) u) y = 0 := by + intro u + have heq : dbarExt D (holeCutoff K h.φ f) u =ᶠ[𝓝 y] fun _ => (0 : F) := + eventuallyEq_of_mem (isClosed_closure.isOpen_compl.mem_nhds hys) fun z hz => + dbarExt_holeCutoff_eq_zero h hf u hz + rw [heq.fderiv_eq, fderiv_const_apply] + rw [hz, hz, dbarAlong_zero, dbarAlong_zero] + +end Cutoff + +section Main + +variable {G F : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] [FiniteDimensional ℂ G] + [Nontrivial G] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- **Hartogs' compact-hole extension theorem in a product space.** For an open set +`D ⊆ ℂ × G` with `G` a nontrivial finite-dimensional complex normed space, a compact `K ⊆ D` +with `D \ K` connected, and `f` holomorphic on `D \ K`, there is a holomorphic function on `D` +agreeing with `f` on `D \ K`. -/ +theorem exists_analyticOnNhd_extension_of_isCompact_prod {D K : Set (ℂ × G)} (hD : IsOpen D) + (hK : IsCompact K) (hKD : K ⊆ D) (hconn : IsPreconnected (D \ K)) {f : ℂ × G → F} + (hf : AnalyticOnNhd ℂ f (D \ K)) : + ∃ g : ℂ × G → F, AnalyticOnNhd ℂ g D ∧ EqOn g f (D \ K) := by + rcases K.eq_empty_or_nonempty with hKe | hKne + · subst hKe + exact ⟨f, by simpa using hf, fun x _ => rfl⟩ + obtain ⟨h⟩ := nonempty_holeCutoffData hD hK hKD + have hKc : IsClosed K := hK.isClosed + set F₀ := holeCutoff K h.φ f with hF₀ + set e₁ : ℂ × G := ((1 : ℂ), (0 : G)) with he₁ + have hg1 : ∀ v, ContDiff ℝ 1 (dbarExt D F₀ v) := contDiff_dbarExt_holeCutoff h hD hKc hf + have hgs : ∀ v, HasCompactSupport (dbarExt D F₀ v) := hasCompactSupport_dbarExt_holeCutoff h hf + set u := cauchyTransformFst (dbarExt D F₀ e₁) with hu + set g : ℂ × G → F := fun x => F₀ x - u x with hg + have hdiff : DifferentiableOn ℂ g D := by + intro x hx + have hF₀d : HasFDerivAt F₀ (fderiv ℝ F₀ x) x := + ((contDiffAt_holeCutoff h hD hKc hf hx).differentiableAt (by norm_num)).hasFDerivAt + have hud : HasFDerivAt u (fderiv ℝ u x) x := + (hasFDerivAt_cauchyTransformFst (hg1 e₁) (hgs e₁) x).differentiableAt.hasFDerivAt + have hL : HasFDerivAt g (fderiv ℝ F₀ x - fderiv ℝ u x) x := hF₀d.sub hud + have hdbar : ∀ v, dbarAlong (fderiv ℝ F₀ x - fderiv ℝ u x) v = 0 := by + intro v + rw [dbarAlong_sub, dbarAlong_fderiv_cauchyTransformFst (hg1 e₁) (hgs e₁) x v] + have hsym : ∀ w : ℂ, dbarAlong (fderiv ℝ (dbarExt D F₀ e₁) (x - (w, 0))) v = + dbarAlong (fderiv ℝ (dbarExt D F₀ v) (x - (w, 0))) e₁ := fun w => + dbarAlong_fderiv_dbarExt_holeCutoff_symm h hD hKc hf _ e₁ v + simp_rw [hsym] + rw [integral_inv_smul_dbarAlong_fderiv_sub (hg1 v) (hgs v) x, smul_smul, + inv_mul_cancel₀ (by exact_mod_cast Real.pi_ne_zero), one_smul, dbarExt_of_mem hx, + sub_self] + exact (hasFDerivAt_of_restrictScalars ℝ hL + (restrictScalars_complexLinearOfDbar _ hdbar)).differentiableAt.differentiableWithinAt + have hga : AnalyticOnNhd ℂ g D := hdiff.analyticOnNhd_of_finiteDimensional hD + set T := Prod.snd '' closure h.s with hT + have hTc : IsCompact T := h.isCompact_closure.image continuous_snd + set V := D ∩ Prod.snd ⁻¹' Tᶜ with hV + have hVo : IsOpen V := hD.inter (hTc.isClosed.isOpen_compl.preimage continuous_snd) + have hVsub : V ⊆ D \ K := fun x hx => + ⟨hx.1, fun hxK => hx.2 (mem_image_of_mem _ (subset_closure (h.subset_s hxK)))⟩ + have hVne : V.Nonempty := by + by_contra hemp + rw [not_nonempty_iff_eq_empty] at hemp + have h1 : Prod.snd '' D ⊆ T := by + rintro _ ⟨x, hx, rfl⟩ + by_contra hxT + exact (eq_empty_iff_forall_notMem.mp hemp) x ⟨hx, hxT⟩ + have h2 : T ⊆ Prod.snd '' D := image_mono h.closure_subset + have heq : Prod.snd '' D = T := Subset.antisymm h1 h2 + have hopen : IsOpen (Prod.snd '' D) := isOpenMap_snd D hD + have hne : (Prod.snd '' D).Nonempty := (hKne.mono hKD).image _ + have hclopen : IsClopen (Prod.snd '' D) := ⟨by rw [heq]; exact hTc.isClosed, hopen⟩ + have huniv := hclopen.eq_univ hne + have hcpt : IsCompact (univ : Set G) := by + rw [← huniv, heq] + exact hTc + exact NoncompactSpace.noncompact_univ hcpt + obtain ⟨x₀, hx₀⟩ := hVne + have hgf : EqOn g f V := by + intro x hx + have hxs : x ∉ closure h.s := fun hc => hx.2 (mem_image_of_mem _ hc) + have hF : F₀ x = f x := + holeCutoff_eq_of_zero (h.notMem_hole_of_notMem_closure hxs) + (h.eq_zero_of_notMem fun hs => hxs (subset_closure hs)) + have hu0 : u x = 0 := by + have hz : ∀ z : ℂ, dbarExt D F₀ e₁ (z, x.2) = 0 := fun z => + dbarExt_holeCutoff_eq_zero h hf e₁ fun hc => hx.2 ⟨(z, x.2), hc, rfl⟩ + have := cauchyTransformFst_eq_zero hz x.1 + simpa using this + change F₀ x - u x = f x + rw [hF, hu0, sub_zero] + refine ⟨g, hga, ?_⟩ + exact (hga.mono sdiff_subset).eqOn_of_preconnected_of_eventuallyEq hf hconn (hVsub hx₀) + (eventuallyEq_of_mem (hVo.mem_nhds hx₀) hgf) + +end Main + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ContourIntegral.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ContourIntegral.lean new file mode 100644 index 0000000000..dceb49d974 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ContourIntegral.lean @@ -0,0 +1,123 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Integral.CircleIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ParametricIntegral + +/-! +# Holomorphic parameters in compact contour integrals + +A jointly holomorphic kernel can be integrated over a fixed compact parameter set, after a +continuous parametrization and multiplication by a fixed integrable weight. The weight need not +be holomorphic. In the circle specialization it includes the contour derivative and a continuous +boundary function. + +This is simplex-independent infrastructure for continued Cauchy representations. It does not +assert a Jordan-curve theorem or homotopy invariance of contours. + +## Main results + +`analyticOnNhd_integral_smul_compact_kernel` gives analytic dependence for Banach-valued kernels; +`analyticOnNhd_integral_mul_compact_kernel` is its scalar specialization. Compactness supplies +derivative bounds and separable images, with no second-countability assumption on the parameter +space. `analyticOnNhd_circleIntegral_kernel_mul` is the scalar circle specialization. +-/ + +open Complex MeasureTheory Filter Metric Set +open scoped Topology +public section +variable {E α : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [MeasurableSpace α] [TopologicalSpace α] + [BorelSpace α] [T2Space α] + +/-- A compact integral of a jointly analytic Banach-valued kernel, with a fixed integrable scalar +weight, is analytic in its parameters. -/ +theorem analyticOnNhd_integral_smul_compact_kernel + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {μ : Measure α} {K : Set α} (hK : IsCompact K) + {g : α → ℂ} (hg : IntegrableOn g K μ) + {γ : α → ℂ} (hγ : ContinuousOn γ K) + {U : Set E} (hU : IsOpen U) {W : Set (E × ℂ)} + {H : E × ℂ → F} (hH : AnalyticOnNhd ℂ H W) + (hW : ∀ x ∈ U, ∀ t ∈ K, (x, γ t) ∈ W) : + AnalyticOnNhd ℂ (fun x => ∫ t in K, g t • H (x, γ t) ∂μ) U := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + let D := fun (x : E) (t : α) => + (fderiv ℂ H (x, γ t)).comp (ContinuousLinearMap.inl ℂ E ℂ) + have hc : ContinuousOn (fun p : E × α => H (p.1, γ p.2)) (U ×ˢ K) := + hH.continuousOn.comp + (continuousOn_fst.prodMk (hγ.comp continuousOn_snd (fun _ hp => hp.2))) + (fun p hp => hW p.1 hp.1 p.2 hp.2) + have hD : ContinuousOn (fun p : E × α => D p.1 p.2) (U ×ˢ K) := + (hH.fderiv.continuousOn.comp + (continuousOn_fst.prodMk (hγ.comp continuousOn_snd (fun _ hp => hp.2))) + (fun p hp => hW p.1 hp.1 p.2 hp.2)).clm_comp continuousOn_const + have hslice {x : E} (hx : x ∈ U) : ContinuousOn (fun t => H (x, γ t)) K := + hc.comp (continuous_const.prodMk continuous_id).continuousOn (fun t ht => ⟨hx, ht⟩) + apply DifferentiableOn.analyticOnNhd_of_finiteDimensional _ hU + intro x hx + obtain ⟨r, hr, hball⟩ := nhds_basis_closedBall.mem_iff.mp (hU.mem_nhds hx) + obtain ⟨M, hM⟩ := ((isCompact_closedBall x r).prod hK).bddAbove_image + (hD.mono (Set.prod_mono hball Subset.rfl)).norm + apply (hasFDerivAt_integral_of_dominated_of_fderiv_le + (μ := μ.restrict K) (F := fun x t => g t • H (x, γ t)) + (F' := fun x t => g t • D x t) (bound := fun t => ‖g t‖ * M) + (closedBall_mem_nhds x hr) ?_ (hg.smul_continuousOn_of_isCompact (hslice hx) hK) ?_ ?_ + (hg.norm.mul_const M) ?_).differentiableAt.differentiableWithinAt + · filter_upwards [hU.mem_nhds hx] with y hy + exact (hg.smul_continuousOn_of_isCompact (hslice hy) hK).aestronglyMeasurable + · exact hg.aestronglyMeasurable.smul + ((hD.comp (continuous_const.prodMk continuous_id).continuousOn + (fun t ht => ⟨hx, ht⟩)).aestronglyMeasurable_of_isCompact hK hK.measurableSet) + · filter_upwards [ae_restrict_mem hK.measurableSet] with t ht + intro y hy + rw [norm_smul] + exact mul_le_mul_of_nonneg_left (hM ⟨(y, t), ⟨hy, ht⟩, rfl⟩) (norm_nonneg _) + · filter_upwards [ae_restrict_mem hK.measurableSet] with t ht + intro y hy + exact (((hH _ (hW y (hball hy) t ht)).differentiableAt.hasFDerivAt).comp y + (hasFDerivAt_prodMk_left (𝕜 := ℂ) y (γ t))).const_smul (g t) + +/-- Holomorphic dependence of a compact weighted integral of a jointly holomorphic kernel. Only the +parametrization, not the weight, must be continuous. -/ +theorem analyticOnNhd_integral_mul_compact_kernel + {μ : Measure α} {K : Set α} (hK : IsCompact K) + {g : α → ℂ} (hg : IntegrableOn g K μ) + {γ : α → ℂ} (hγ : ContinuousOn γ K) + {U : Set E} (hU : IsOpen U) {W : Set (E × ℂ)} + {H : E × ℂ → ℂ} (hH : AnalyticOnNhd ℂ H W) + (hW : ∀ x ∈ U, ∀ t ∈ K, (x, γ t) ∈ W) : + AnalyticOnNhd ℂ (fun x => ∫ t in K, g t * H (x, γ t) ∂μ) U := by + simpa only [smul_eq_mul] using + analyticOnNhd_integral_smul_compact_kernel hK hg hγ hU hH hW + +omit [MeasurableSpace α] [TopologicalSpace α] [BorelSpace α] [T2Space α] in +/-- Integrating a holomorphic parameter-dependent kernel against a continuous boundary function on a +fixed circle preserves holomorphy in all parameters. -/ +theorem analyticOnNhd_circleIntegral_kernel_mul + {U : Set E} (hU : IsOpen U) {W : Set (E × ℂ)} + {H : E × ℂ → ℂ} (hH : AnalyticOnNhd ℂ H W) + {c : ℂ} {R : ℝ} (hR : 0 ≤ R) {f : ℂ → ℂ} + (hf : ContinuousOn f (sphere c R)) + (hW : ∀ x ∈ U, ∀ s ∈ sphere c R, (x, s) ∈ W) : + AnalyticOnNhd ℂ (fun x => ∮ s in C(c, R), H (x, s) * f s) U := by + have hg : ContinuousOn (fun t : ℝ => deriv (circleMap c R) t * f (circleMap c R t)) + (Icc 0 (2 * Real.pi)) := by + apply ContinuousOn.mul + · change ContinuousOn (fun t : ℝ => deriv (circleMap c R) t) _ + simp only [deriv_circleMap] + fun_prop + · exact hf.comp (continuous_circleMap c R).continuousOn + (fun t _ => circleMap_mem_sphere c hR t) + have h := analyticOnNhd_integral_mul_compact_kernel (μ := volume) isCompact_Icc + (hg.integrableOn_compact isCompact_Icc) (continuous_circleMap c R).continuousOn hU hH + (fun x hx t _ => hW x hx _ (circleMap_mem_sphere c hR t)) + simpa only [circleIntegral_def_Icc, smul_eq_mul, mul_assoc, mul_left_comm, mul_comm] using h + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Derivatives.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Derivatives.lean new file mode 100644 index 0000000000..f9d8199d59 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Derivatives.lean @@ -0,0 +1,471 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.Deriv.Pi +public import Mathlib.Analysis.Calculus.FDeriv.Analytic +public import Mathlib.Analysis.Calculus.FDeriv.Symmetric +public import Mathlib.LinearAlgebra.Matrix.ToLin +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity + +/-! +# Coordinate derivatives of holomorphic functions + +Coordinate differentiation is defined using one-variable slices, and identified with evaluation +of the Fréchet derivative on a coordinate vector. Holomorphy of derivatives is inherited from +Mathlib's general Fréchet derivative theorem. Mixed derivatives can be indexed by coordinate +lists or multi-indices; permutation invariance identifies these forms. + +## Main results + +`partialDeriv` is the coordinate derivative of a map on `ι → 𝕜`, for any nontrivially normed field. + `partialDeriv_eq_fderiv` identifies +it with the Fréchet derivative on a coordinate vector. `iteratedPartialDeriv` and `multiIndexDeriv` +are mixed derivatives, identified by `iteratedPartialDeriv_eq_multiIndexDeriv`. +`iteratedPartialDeriv_perm` is permutation invariance. `complexJacobian` is the Jacobian matrix of +coordinate derivatives. +-/ + +public noncomputable section + +open Complex Filter Function Set +open scoped Topology + +namespace SeveralComplexVariables + +section General + +variable {𝕜 ι F : Type*} [NontriviallyNormedField 𝕜] [Fintype ι] [DecidableEq ι] + [NormedAddCommGroup F] [NormedSpace 𝕜 F] + +/-- Differentiate in coordinate `i`, holding all other coordinates fixed. The scalar field is any +nontrivially normed field; the several-complex-variables theory uses `𝕜 = ℂ`. -/ +@[expose] def partialDeriv (i : ι) (f : (ι → 𝕜) → F) (z : ι → 𝕜) : F := + deriv (fun w => f (update z i w)) (z i) + +omit [Fintype ι] in +/-- The derivative of a coordinate slice is the corresponding Fréchet derivative value. -/ +theorem hasDerivAt_update_of_differentiableAt [Finite ι] {f : (ι → 𝕜) → F} {z : ι → 𝕜} + (hf : DifferentiableAt 𝕜 f z) (i : ι) : + HasDerivAt (fun w => f (update z i w)) (fderiv 𝕜 f z (Pi.single i 1)) (z i) := by + classical + let := Fintype.ofFinite ι + have hf' : HasFDerivAt f (fderiv 𝕜 f z) (update z i (z i)) := by simpa using hf.hasFDerivAt + exact hf'.comp_hasDerivAt (z i) (hasDerivAt_update z i (z i)) + +omit [Fintype ι] in +/-- Coordinate derivatives are Fréchet derivatives evaluated on coordinate vectors. -/ +theorem partialDeriv_eq_fderiv [Finite ι] {f : (ι → 𝕜) → F} {z : ι → 𝕜} + (hf : DifferentiableAt 𝕜 f z) (i : ι) : + partialDeriv i f z = fderiv 𝕜 f z (Pi.single i 1) := by + classical + let := Fintype.ofFinite ι + exact + (hasDerivAt_update_of_differentiableAt hf i).deriv + +omit [Fintype ι] in +/-- A coordinate derivative only depends on the germ of the function. -/ +theorem partialDeriv_congr [Finite ι] {f g : (ι → 𝕜) → F} {z : ι → 𝕜} + (hfg : f =ᶠ[𝓝 z] g) (i : ι) : partialDeriv i f z = partialDeriv i g z := by + classical + let := Fintype.ofFinite ι + apply Filter.EventuallyEq.deriv_eq + have ht : Tendsto (update z i) (𝓝 (z i)) (𝓝 z) := by + simpa using (hasDerivAt_update z i (z i)).continuousAt.tendsto + exact hfg.comp_tendsto ht + +/-- The Fréchet derivative is recovered from the coordinate derivatives. -/ +theorem fderiv_eq_sum_partialDeriv {f : (ι → 𝕜) → F} {z : ι → 𝕜} + (hf : DifferentiableAt 𝕜 f z) (v : ι → 𝕜) : + fderiv 𝕜 f z v = ∑ i, v i • partialDeriv i f z := by + simp_rw [partialDeriv_eq_fderiv hf, ← map_smul, ← map_sum] + congr 1 + ext j + simp [Pi.single_apply] + +omit [Fintype ι] in +/-- Coordinate differentiation respects subtraction at differentiability points. -/ +theorem partialDeriv_sub [Finite ι] {f g : (ι → 𝕜) → F} {z : ι → 𝕜} + (hf : DifferentiableAt 𝕜 f z) (hg : DifferentiableAt 𝕜 g z) (i : ι) : + partialDeriv i (f - g) z = partialDeriv i f z - partialDeriv i g z := by + classical + let := Fintype.ofFinite ι + exact deriv_sub (hasDerivAt_update_of_differentiableAt hf i).differentiableAt + (hasDerivAt_update_of_differentiableAt hg i).differentiableAt + +omit [Fintype ι] in +/-- Coordinate differentiation of a product of scalar functions follows the ordinary product rule, +holding the other coordinates fixed. -/ +theorem partialDeriv_mul [Finite ι] {f g : (ι → 𝕜) → 𝕜} {z : ι → 𝕜} + (hf : DifferentiableAt 𝕜 f z) (hg : DifferentiableAt 𝕜 g z) (i : ι) : + partialDeriv i (f * g) z = partialDeriv i f z * g z + f z * partialDeriv i g z := by + classical + let := Fintype.ofFinite ι + have hf' := hasDerivAt_update_of_differentiableAt hf i + have hg' := hasDerivAt_update_of_differentiableAt hg i + have h := deriv_fun_mul hf'.differentiableAt hg'.differentiableAt + simpa [partialDeriv, update_eq_self] using h + +omit [Fintype ι] in +/-- Coordinate differentiation commutes with a finite sum of differentiable functions. -/ +theorem partialDeriv_finset_sum [Finite ι] {α : Type*} {f : α → (ι → 𝕜) → F} + (t : Finset α) {z : ι → 𝕜} (hf : ∀ a ∈ t, DifferentiableAt 𝕜 (f a) z) (i : ι) : + partialDeriv i (fun w => ∑ a ∈ t, f a w) z = ∑ a ∈ t, partialDeriv i (f a) z := by + classical + let := Fintype.ofFinite ι + exact deriv_fun_sum fun a ha => (hasDerivAt_update_of_differentiableAt (hf a ha) + i).differentiableAt + +end General + +variable {ι F : Type*} [Fintype ι] [DecidableEq ι] [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- Holomorphy restricts to each coordinate slice. -/ +theorem _root_.AnalyticOnNhd.analyticAt_update {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) {z : ι → ℂ} (hz : z ∈ U) (i : ι) : + AnalyticAt ℂ (fun w => f (update z i w)) (z i) := by + have hu : AnalyticAt ℂ (update z i) (z i) := + analyticAt_iff_eventually_differentiableAt.mpr + (Eventually.of_forall fun w => (hasDerivAt_update z i w).differentiableAt) + exact (hf z hz).comp_of_eq hu (update_eq_self i z) + +variable [CompleteSpace F] + +/-- Every coordinate derivative of an analytic function is analytic. -/ +theorem _root_.AnalyticOnNhd.partialDeriv {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) (i : ι) : + AnalyticOnNhd ℂ (partialDeriv i f) U := by + intro z hz + have ha : AnalyticAt ℂ (fun w => fderiv ℂ f w (Pi.single i 1)) z := by + simpa only [Function.comp_def, ContinuousLinearMap.apply_apply] using! + ((ContinuousLinearMap.apply ℂ F (Pi.single i (1 : ℂ))).analyticAt + (fderiv ℂ f z)).comp_of_eq (hf z hz).fderiv rfl + apply ha.congr + filter_upwards [hU.eventually_mem hz] with w hw + exact (partialDeriv_eq_fderiv (hf w hw).differentiableAt i).symm + +/-- Repeated coordinate differentiation, with the leftmost coordinate acting last. -/ +@[expose] def iteratedPartialDeriv {𝕜 ι F : Type*} [NontriviallyNormedField 𝕜] [DecidableEq ι] + [NormedAddCommGroup F] [NormedSpace 𝕜 F] : List ι → ((ι → 𝕜) → F) → (ι → 𝕜) → F + | [], f => f + | i :: is, f => partialDeriv i (iteratedPartialDeriv is f) + +/-- Differentiate a coordinate derivative by composing the second Fréchet derivative with evaluation +on its coordinate vector. -/ +theorem hasFDerivAt_partialDeriv {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) {z : ι → ℂ} (hz : z ∈ U) (i : ι) : + HasFDerivAt (partialDeriv i f) + ((ContinuousLinearMap.apply ℂ F (Pi.single i 1)).comp + (fderiv ℂ (fderiv ℂ f) z)) z := by + have H := (ContinuousLinearMap.apply ℂ F (Pi.single i (1 : ℂ))).hasFDerivAt.comp z + (hf z hz).fderiv.differentiableAt.hasFDerivAt + apply H.congr_of_eventuallyEq + filter_upwards [hU.eventually_mem hz] with w hw + exact partialDeriv_eq_fderiv (hf w hw).differentiableAt i + +/-- Mixed coordinate derivatives commute for a holomorphic function. -/ +theorem partialDeriv_partialDeriv_comm {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) {z : ι → ℂ} (hz : z ∈ U) (i j : ι) : + partialDeriv i (partialDeriv j f) z = partialDeriv j (partialDeriv i f) z := by + rw [partialDeriv_eq_fderiv (hasFDerivAt_partialDeriv hf hU hz j).differentiableAt, + partialDeriv_eq_fderiv (hasFDerivAt_partialDeriv hf hU hz i).differentiableAt, + (hasFDerivAt_partialDeriv hf hU hz j).fderiv, + (hasFDerivAt_partialDeriv hf hU hz i).fderiv] + exact (hf z hz).contDiffAt.isSymmSndFDerivAt_of_omega (Pi.single i 1) (Pi.single j 1) + +/-- All iterated coordinate derivatives are holomorphic on the original open domain. -/ +theorem _root_.AnalyticOnNhd.iteratedPartialDeriv {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) (is : List ι) : + AnalyticOnNhd ℂ (iteratedPartialDeriv is f) U := by + induction is with + | nil => exact hf + | cons i is ih => exact ih.partialDeriv hU i + +/-- Iterated coordinate derivatives depend only on the multiplicity of each coordinate, not on their +order in the differentiation list. -/ +theorem iteratedPartialDeriv_perm {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) {is js : List ι} (h : is.Perm js) : + EqOn (iteratedPartialDeriv is f) (iteratedPartialDeriv js f) U := by + induction h with + | nil => intro z hz; rfl + | cons i h ih => + intro z hz + apply partialDeriv_congr + filter_upwards [hU.eventually_mem hz] with w hw + exact ih hw + | swap i j is => + intro z hz + exact partialDeriv_partialDeriv_comm (hf.iteratedPartialDeriv hU is) hU hz j i + | trans h₁ h₂ ih₁ ih₂ => exact ih₁.trans ih₂ + +omit [CompleteSpace F] in +omit [Fintype ι] in +/-- Iterated coordinate derivatives agree on an open set where the original functions agree. -/ +theorem iteratedPartialDeriv_congrOn [Finite ι] {U : Set (ι → ℂ)} {f g : (ι → ℂ) → F} + (hU : IsOpen U) (hfg : EqOn f g U) (is : List ι) : + EqOn (iteratedPartialDeriv is f) (iteratedPartialDeriv is g) U := by + classical + let := Fintype.ofFinite ι + induction is with + | nil => exact hfg + | cons i is ih => + intro z hz + apply partialDeriv_congr + filter_upwards [hU.eventually_mem hz] with w hw + exact ih hw + +/-- Mixed coordinate differentiation commutes with finite sums of holomorphic functions. -/ +theorem iteratedPartialDeriv_finset_sum {α : Type*} {U : Set (ι → ℂ)} + {f : α → (ι → ℂ) → F} (t : Finset α) (hf : ∀ a ∈ t, AnalyticOnNhd ℂ (f a) U) + (hU : IsOpen U) (is : List ι) : + EqOn (iteratedPartialDeriv is (fun z => ∑ a ∈ t, f a z)) + (fun z => ∑ a ∈ t, iteratedPartialDeriv is (f a) z) U := by + induction is with + | nil => intro z hz; rfl + | cons i is ih => + intro z hz + change partialDeriv i (iteratedPartialDeriv is (fun w => ∑ a ∈ t, f a w)) z = _ + have heq : iteratedPartialDeriv is (fun w => ∑ a ∈ t, f a w) =ᶠ[𝓝 z] + (fun w => ∑ a ∈ t, iteratedPartialDeriv is (f a) w) := + (hU.eventually_mem hz).mono (fun w hw => ih hw) + rw [partialDeriv_congr heq i] + exact partialDeriv_finset_sum t + (fun a ha => ((hf a ha).iteratedPartialDeriv hU is z hz).differentiableAt) i + +/-- Pascal's rule reindexes a sum of consecutive terms into the next row of binomial coefficients: +the combinatorial core of the Leibniz rule for iterated derivatives. -/ +private theorem sum_choose_shift (k : ℕ) (X : ℕ → ℂ) : + (∑ j ∈ Finset.range (k + 1), (k.choose j : ℂ) * (X (j + 1) + X j)) = + ∑ j ∈ Finset.range (k + 2), ((k + 1).choose j : ℂ) * X j := by + have hzero : (k.choose (k + 1) : ℂ) * X (k + 1) = 0 := by simp + have hstep1 : ∑ j ∈ Finset.range (k + 1), (k.choose j : ℂ) * X j = + X 0 + ∑ j ∈ Finset.range (k + 1), (k.choose (j + 1) : ℂ) * X (j + 1) := by + rw [Finset.sum_range_succ' (fun j => (k.choose j : ℂ) * X j) k] + simp only [Nat.choose_zero_right, Nat.cast_one, one_mul] + rw [Finset.sum_range_succ (fun j => (k.choose (j + 1) : ℂ) * X (j + 1)) k, hzero, add_zero] + ring + have hpeel : ∑ j ∈ Finset.range (k + 2), ((k + 1).choose j : ℂ) * X j = + X 0 + ∑ j ∈ Finset.range (k + 1), ((k + 1).choose (j + 1) : ℂ) * X (j + 1) := by + rw [Finset.sum_range_succ' (fun j => ((k + 1).choose j : ℂ) * X j) (k + 1)] + simp only [Nat.choose_zero_right, Nat.cast_one, one_mul] + ring + rw [hpeel] + have hpascal : ∀ j ∈ Finset.range (k + 1), + ((k + 1).choose (j + 1) : ℂ) * X (j + 1) = + (k.choose j : ℂ) * X (j + 1) + (k.choose (j + 1) : ℂ) * X (j + 1) := by + intro j _ + rw [Nat.choose_succ_succ', Nat.cast_add, add_mul] + rw [Finset.sum_congr rfl hpascal, Finset.sum_add_distrib] + have hexpand : ∀ j ∈ Finset.range (k + 1), (k.choose j : ℂ) * (X (j + 1) + X j) = + (k.choose j : ℂ) * X (j + 1) + (k.choose j : ℂ) * X j := fun j _ => by ring + rw [Finset.sum_congr rfl hexpand, Finset.sum_add_distrib, hstep1] + ring + +omit [Fintype ι] in +/-- Coordinate differentiation of a scalar multiple follows the ordinary constant-multiple rule, +holding the other coordinates fixed. -/ +theorem partialDeriv_const_mul [Finite ι] {f : (ι → ℂ) → ℂ} {z : ι → ℂ} (c : ℂ) + (hf : DifferentiableAt ℂ f z) (i : ι) : + partialDeriv i (fun w => c * f w) z = c * partialDeriv i f z := by + classical + let := Fintype.ofFinite ι + exact + deriv_const_mul c (hasDerivAt_update_of_differentiableAt hf i).differentiableAt + +/-- Repeated differentiation of a product of scalar functions in a single coordinate follows the +ordinary Leibniz binomial rule, since each step is the ordinary product rule. -/ +theorem iteratedPartialDeriv_replicate_mul {U : Set (ι → ℂ)} {f g : (ι → ℂ) → ℂ} + (hf : AnalyticOnNhd ℂ f U) (hg : AnalyticOnNhd ℂ g U) (hU : IsOpen U) (i : ι) (k : ℕ) : + EqOn (iteratedPartialDeriv (List.replicate k i) (f * g)) + (fun z => ∑ j ∈ Finset.range (k + 1), (k.choose j : ℂ) * + (iteratedPartialDeriv (List.replicate j i) f z * + iteratedPartialDeriv (List.replicate (k - j) i) g z)) U := by + induction k with + | zero => intro z hz; simp [iteratedPartialDeriv] + | succ k ih => + intro z hz + have hstep : iteratedPartialDeriv (List.replicate (k + 1) i) (f * g) z = + partialDeriv i (iteratedPartialDeriv (List.replicate k i) (f * g)) z := rfl + rw [hstep] + have heq : iteratedPartialDeriv (List.replicate k i) (f * g) =ᶠ[𝓝 z] + (fun z => ∑ j ∈ Finset.range (k + 1), (k.choose j : ℂ) * + (iteratedPartialDeriv (List.replicate j i) f z * + iteratedPartialDeriv (List.replicate (k - j) i) g z)) := + (hU.eventually_mem hz).mono (fun w hw => ih hw) + rw [partialDeriv_congr heq i] + have hAdiff : ∀ j, DifferentiableAt ℂ (iteratedPartialDeriv (List.replicate j i) f) z := + fun j => (hf.iteratedPartialDeriv hU (List.replicate j i) z hz).differentiableAt + have hBdiff : ∀ j, DifferentiableAt ℂ (iteratedPartialDeriv (List.replicate j i) g) z := + fun j => (hg.iteratedPartialDeriv hU (List.replicate j i) z hz).differentiableAt + have hsum := partialDeriv_finset_sum (F := ℂ) + (f := fun j (w : ι → ℂ) => (k.choose j : ℂ) * + (iteratedPartialDeriv (List.replicate j i) f w * + iteratedPartialDeriv (List.replicate (k - j) i) g w)) + (Finset.range (k + 1)) (fun j _ => ((hAdiff j).mul (hBdiff (k - j))).const_mul _) i + rw [hsum] + have hterm : ∀ j ∈ Finset.range (k + 1), + partialDeriv i (fun z => (k.choose j : ℂ) * (iteratedPartialDeriv + (List.replicate j i) f z * iteratedPartialDeriv (List.replicate (k - j) i) g z)) z = + (k.choose j : ℂ) * (iteratedPartialDeriv (List.replicate (j + 1) i) f z * + iteratedPartialDeriv (List.replicate (k - j) i) g z + + iteratedPartialDeriv (List.replicate j i) f z * + iteratedPartialDeriv (List.replicate (k - j + 1) i) g z) := by + intro j _ + have hcm := partialDeriv_const_mul + (f := fun w => iteratedPartialDeriv (List.replicate j i) f w * + iteratedPartialDeriv (List.replicate (k - j) i) g w) + (k.choose j : ℂ) ((hAdiff j).mul (hBdiff (k - j))) i + rw [hcm] + have hpm : partialDeriv i (fun w => iteratedPartialDeriv (List.replicate j i) f w * + iteratedPartialDeriv (List.replicate (k - j) i) g w) z = + partialDeriv i (iteratedPartialDeriv (List.replicate j i) f) z * + iteratedPartialDeriv (List.replicate (k - j) i) g z + + iteratedPartialDeriv (List.replicate j i) f z * + partialDeriv i (iteratedPartialDeriv (List.replicate (k - j) i) g) z := + partialDeriv_mul (hAdiff j) (hBdiff (k - j)) i + rw [hpm] + congr 2 + rw [Finset.sum_congr rfl hterm] + set X : ℕ → ℂ := fun m => iteratedPartialDeriv (List.replicate m i) f z * + iteratedPartialDeriv (List.replicate (k + 1 - m) i) g z with hXdef + have hgoal : ∑ j ∈ Finset.range (k + 1), (k.choose j : ℂ) * + (iteratedPartialDeriv (List.replicate (j + 1) i) f z * + iteratedPartialDeriv (List.replicate (k - j) i) g z + + iteratedPartialDeriv (List.replicate j i) f z * + iteratedPartialDeriv (List.replicate (k - j + 1) i) g z) = + ∑ j ∈ Finset.range (k + 1), (k.choose j : ℂ) * (X (j + 1) + X j) := by + apply Finset.sum_congr rfl + intro j hj + simp only [Finset.mem_range] at hj + have e1 : k - j = k + 1 - (j + 1) := by omega + have e3 : k + 1 - (j + 1) + 1 = k + 1 - j := by omega + simp only [hXdef, e1, e3] + rw [hgoal, sum_choose_shift] + +section MultiIndex + +variable {d : ℕ} {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- A canonical list containing coordinate `i` exactly `m i` times. -/ +@[expose] def multiIndexList (m : Fin d → ℕ) : List (Fin d) := + (List.ofFn (fun i => List.replicate (m i) i)).flatten + +/-- The canonical coordinate list has the prescribed multiplicities. -/ +@[simp] theorem count_multiIndexList (m : Fin d → ℕ) (i : Fin d) : + (multiIndexList m).count i = m i := by + simp [multiIndexList, List.count_flatten, List.map_ofFn, List.count_replicate, + List.sum_ofFn] + +/-- The mixed coordinate derivative of multi-index `m`, in canonical coordinate order. For +holomorphic maps, permutation invariance makes the choice of order immaterial. -/ +@[expose] def multiIndexDeriv (m : Fin d → ℕ) (f : (Fin d → ℂ) → E) : (Fin d → ℂ) → E := + iteratedPartialDeriv (multiIndexList m) f + +variable [CompleteSpace E] + +/-- The mixed derivative can be computed in any order with the prescribed multiplicities. -/ +theorem iteratedPartialDeriv_eq_multiIndexDeriv {U : Set (Fin d → ℂ)} + {f : (Fin d → ℂ) → E} (hf : AnalyticOnNhd ℂ f U) (hU : IsOpen U) + {z : Fin d → ℂ} (hz : z ∈ U) {is : List (Fin d)} {m : Fin d → ℕ} + (hm : ∀ i, is.count i = m i) : iteratedPartialDeriv is f z = multiIndexDeriv m f z := by + apply iteratedPartialDeriv_perm hf hU _ hz + apply List.perm_iff_count.mpr + simpa using hm + +end MultiIndex + +/-- The complex Jacobian in the standard coordinate bases. -/ +@[expose] def complexJacobian {κ : Type*} (f : (ι → ℂ) → (κ → ℂ)) (z : ι → ℂ) : Matrix κ ι ℂ := + fun j i => partialDeriv i (fun w => f w j) z + +omit [Fintype ι] in +/-- Entries of the complex Jacobian are the coordinate entries of the Fréchet derivative. -/ +theorem complexJacobian_apply [Finite ι] {κ : Type*} [Finite κ] + {f : (ι → ℂ) → (κ → ℂ)} {z : ι → ℂ} (hf : DifferentiableAt ℂ f z) + (j : κ) (i : ι) : complexJacobian f z j i = fderiv ℂ f z (Pi.single i 1) j := by + classical + let := Fintype.ofFinite ι + let := Fintype.ofFinite κ + rw [complexJacobian, partialDeriv_eq_fderiv (differentiableAt_pi.mp hf j), fderiv_apply hf j] + rfl + +omit [CompleteSpace F] in +omit [Fintype ι] in +/-- The coordinate chain rule, with an arbitrary complex normed outer target. -/ +theorem partialDeriv_comp [Finite ι] {κ : Type*} [Fintype κ] [DecidableEq κ] + {f : (ι → ℂ) → (κ → ℂ)} {g : (κ → ℂ) → F} {z : ι → ℂ} + (hg : DifferentiableAt ℂ g (f z)) (hf : DifferentiableAt ℂ f z) (i : ι) : + partialDeriv i (g ∘ f) z = ∑ j, complexJacobian f z j i • partialDeriv j g (f z) := by + classical + let := Fintype.ofFinite ι + rw [partialDeriv_eq_fderiv (hg.comp z hf), fderiv_comp z hg hf] + simp only [ContinuousLinearMap.comp_apply] + rw [fderiv_eq_sum_partialDeriv hg] + simp_rw [complexJacobian_apply hf] + +omit [Fintype ι] in +/-- Jacobians compose by matrix multiplication. -/ +theorem complexJacobian_comp [Finite ι] {κ ν : Type*} [Fintype κ] [DecidableEq κ] [Finite ν] + {f : (ι → ℂ) → (κ → ℂ)} {g : (κ → ℂ) → (ν → ℂ)} {z : ι → ℂ} + (hg : DifferentiableAt ℂ g (f z)) (hf : DifferentiableAt ℂ f z) : + complexJacobian (g ∘ f) z = complexJacobian g (f z) * complexJacobian f z := by + classical + let := Fintype.ofFinite ι + let := Fintype.ofFinite ν + ext j i + change partialDeriv i ((fun w => g w j) ∘ f) z = _ + rw [partialDeriv_comp (differentiableAt_pi.mp hg j) hf] + simp [Matrix.mul_apply, complexJacobian, smul_eq_mul, mul_comm] + +/-- The complex Jacobian is Mathlib's matrix of the complex Fréchet derivative in the standard +coordinate bases. -/ +theorem complexJacobian_eq_toMatrix {κ : Type*} [Finite κ] + {f : (ι → ℂ) → (κ → ℂ)} {z : ι → ℂ} (hf : DifferentiableAt ℂ f z) : + complexJacobian f z = LinearMap.toMatrix' (fderiv ℂ f z).toLinearMap := by + classical + let := Fintype.ofFinite κ + ext j i + exact complexJacobian_apply hf j i + +omit [Fintype ι] in +/-- The Jacobian of the identity map is the identity matrix, including with no coordinates. -/ +theorem complexJacobian_id [Finite ι] (z : ι → ℂ) : complexJacobian id z = 1 := by + classical + let := Fintype.ofFinite ι + rw [complexJacobian_eq_toMatrix differentiableAt_id] + simp + +/-- The determinant form of the chain rule for maps between equal coordinate spaces. -/ +theorem det_complexJacobian_comp {f g : (ι → ℂ) → (ι → ℂ)} {z : ι → ℂ} + (hg : DifferentiableAt ℂ g (f z)) (hf : DifferentiableAt ℂ f z) : + (complexJacobian (g ∘ f) z).det = + (complexJacobian g (f z)).det * (complexJacobian f z).det := by + rw [complexJacobian_comp hg hf, Matrix.det_mul] + +/-- A square complex Jacobian has nonzero determinant exactly when the Fréchet derivative is +invertible. Differentiability is explicit because the derivative is otherwise totalized. -/ +theorem det_complexJacobian_ne_zero_iff {f : (ι → ℂ) → (ι → ℂ)} {z : ι → ℂ} + (hf : DifferentiableAt ℂ f z) : + (complexJacobian f z).det ≠ 0 ↔ (fderiv ℂ f z).IsInvertible := by + have hm : (complexJacobian f z).mulVec = fderiv ℂ f z := by + funext v + rw [complexJacobian_eq_toMatrix hf] + exact LinearMap.toMatrix'_mulVec _ v + have hi : Function.Injective (fderiv ℂ f z) ↔ (complexJacobian f z).det ≠ 0 := by + rw [← hm, Matrix.mulVec_injective_iff_isUnit, Matrix.isUnit_iff_isUnit_det, + isUnit_iff_ne_zero] + constructor + · intro h + have hinj := hi.mpr h + exact ⟨(LinearEquiv.ofBijective (fderiv ℂ f z).toLinearMap + ⟨hinj, LinearMap.surjective_of_injective hinj⟩).toContinuousLinearEquiv, rfl⟩ + · exact fun h => hi.mp h.injective + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/DomainOfHolomorphy.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/DomainOfHolomorphy.lean new file mode 100644 index 0000000000..b235c44c89 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/DomainOfHolomorphy.lean @@ -0,0 +1,222 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CommonExtension + +/-! +# Local continuation and domains of holomorphy + +Common continuation from `U` to `V` requires agreement only on a specified overlap `W`. It does +not require `U ⊆ V`, or agreement on every component of `U ∩ V`. `IsDomainOfHolomorphy` excludes +such a common continuation outside `U`. `IsDomainOfExistence` excludes continuation of one +specified scalar function. Openness and connectedness of `U` are separate; the predicates also +apply to disconnected open sets. The whole space and the empty set are included. + +References: [Jakóbczak–Jarnicki][JakobczakJarnicki2021] §2.7; [Scheidemann][Scheidemann2005] +§7.2; [Boas][Boas2013] §4.2.3. These definitions do not construct Riemann domains or envelopes +of holomorphy. + +## Main definitions + +* `HasCommonAnalyticContinuation`: All scalar analytic functions on `U` continue to `V`, with + agreement on `W`. +* `IsDomainOfHolomorphy`: No common continuation through a nonempty open overlap reaches outside + `U`. +* `IsDomainOfExistence`: A scalar function is analytic on `U` and has no continuation beyond it from + any nonempty open overlap. + +## Main results + +* `IsDomainOfExistence.isDomainOfHolomorphy`: The domain of existence of one function is a domain of + holomorphy. +* `IsDomainOfHolomorphy.eq_of_commonExtension`: A domain of holomorphy admits no proper connected + common extension containing it. +* `isDomainOfHolomorphy_of_entire_separators`: Entire functions vanishing at each exterior point but + nowhere on `U` obstruct all common continuation outside `U`, by applying the identity theorem to + their reciprocals. +* `isDomainOfHolomorphy_complex`: Every subset of the complex plane satisfies the analytic + continuation obstruction; in particular every planar open set is a domain of holomorphy. +* `isDomainOfHolomorphy_pi`: Finite products of planar open sets are domains of holomorphy. +* `isDomainOfHolomorphy_of_convex`: Every real-convex open subset of a finite-dimensional complex + normed space is a domain of holomorphy. +* `IsDomainOfHolomorphy.image_equiv`: The domain-of-holomorphy property is invariant under + continuous linear equivalences. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- All scalar analytic functions on `U` continue to `V`, with agreement on `W`. Containment and +topological assumptions are supplied separately. -/ +@[expose] def HasCommonAnalyticContinuation (U V W : Set E) : Prop := + ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → + ∃ g : E → ℂ, AnalyticOnNhd ℂ g V ∧ EqOn g f W + +/-- No common continuation through a nonempty open overlap reaches outside `U`. For open `U`, this +is the domain-of-holomorphy property, without imposing connectedness. -/ +@[expose] def IsDomainOfHolomorphy (U : Set E) : Prop := + ∀ V W : Set E, IsOpen V → IsConnected V → IsOpen W → W.Nonempty → + W ⊆ U → W ⊆ V → HasCommonAnalyticContinuation U V W → V ⊆ U + +/-- A scalar function is analytic on `U` and has no continuation beyond it from any nonempty open +overlap. This is the strong, local meaning of domain of existence. -/ +@[expose] def IsDomainOfExistence (U : Set E) (f : E → ℂ) : Prop := + AnalyticOnNhd ℂ f U ∧ + ∀ V W : Set E, IsOpen V → IsConnected V → IsOpen W → W.Nonempty → + W ⊆ U → W ⊆ V → (∃ g, AnalyticOnNhd ℂ g V ∧ EqOn g f W) → V ⊆ U + +/-- The domain-of-holomorphy property is invariant under continuous linear equivalences. -/ +theorem IsDomainOfHolomorphy.image_equiv {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + {U : Set E} (h : IsDomainOfHolomorphy U) (L : E ≃L[ℂ] F) : + IsDomainOfHolomorphy (L '' U) := by + intro V W hV hVc hW hWne hWU hWV hcont + have himg : ∀ z : F, z ∈ L '' U ↔ L.symm z ∈ U := fun z => by + constructor + · rintro ⟨x, hx, rfl⟩ + simpa using hx + · intro hz + exact ⟨L.symm z, hz, L.apply_symm_apply z⟩ + have hV' : IsOpen (L ⁻¹' V) := hV.preimage L.continuous + have hVc' : IsConnected (L ⁻¹' V) := by + rw [← L.image_symm_eq_preimage] + exact hVc.image _ L.symm.continuous.continuousOn + have hW' : IsOpen (L ⁻¹' W) := hW.preimage L.continuous + have hWne' : (L ⁻¹' W).Nonempty := by + obtain ⟨w, hw⟩ := hWne + exact ⟨L.symm w, by simpa using hw⟩ + have hWU' : L ⁻¹' W ⊆ U := fun z hz => by + have := (himg (L z)).mp (hWU hz) + simpa using this + have hWV' : L ⁻¹' W ⊆ L ⁻¹' V := fun z hz => hWV hz + have hcont' : HasCommonAnalyticContinuation U (L ⁻¹' V) (L ⁻¹' W) := by + intro f hf + have hf' : AnalyticOnNhd ℂ (f ∘ L.symm) (L '' U) := + hf.comp (L.symm.toContinuousLinearMap.analyticOnNhd _) fun z hz => (himg z).mp hz + obtain ⟨g, hg, hgf⟩ := hcont _ hf' + refine ⟨g ∘ L, hg.comp (L.toContinuousLinearMap.analyticOnNhd _) fun z hz => hz, + fun z hz => ?_⟩ + have := hgf hz + simpa using this + have hsub : L ⁻¹' V ⊆ U := h _ _ hV' hVc' hW' hWne' hWU' hWV' hcont' + intro z hz + rw [himg] + exact hsub (by simpa using hz) + +/-- A common extension to a containing set is a common continuation on any smaller overlap. -/ +theorem IsCommonAnalyticExtension.hasCommonAnalyticContinuation {U V W : Set E} + (h : IsCommonAnalyticExtension U V) (hWU : W ⊆ U) : + HasCommonAnalyticContinuation U V W := by + intro f hf + obtain ⟨g, hg, he⟩ := h.exists_extension hf + exact ⟨g, hg, he.mono hWU⟩ + +/-- The domain of existence of one function is a domain of holomorphy. -/ +theorem IsDomainOfExistence.isDomainOfHolomorphy {U : Set E} {f : E → ℂ} + (h : IsDomainOfExistence U f) : IsDomainOfHolomorphy U := + fun V W hV hc hW hn hWU hWV he => h.2 V W hV hc hW hn hWU hWV (he f h.1) + +/-- The whole ambient space is a domain of holomorphy. -/ +theorem isDomainOfHolomorphy_univ : IsDomainOfHolomorphy (univ : Set E) := + fun _ _ _ _ _ _ _ _ _ => subset_univ _ + +/-- The empty open set satisfies the domain-of-holomorphy property vacuously. -/ +theorem isDomainOfHolomorphy_empty : IsDomainOfHolomorphy (∅ : Set E) := by + intro V W _ _ _ hn hWU _ _ + obtain ⟨w, hw⟩ := hn + exact (hWU hw).elim + +/-- A function analytic on the whole space has that space as its domain of existence. -/ +theorem isDomainOfExistence_univ {f : E → ℂ} (hf : AnalyticOnNhd ℂ f univ) : + IsDomainOfExistence univ f := ⟨hf, fun _ _ _ _ _ _ _ _ _ => subset_univ _⟩ + +/-- A domain of holomorphy admits no proper connected common extension containing it. -/ +theorem IsDomainOfHolomorphy.eq_of_commonExtension {U V : Set E} + (h : IsDomainOfHolomorphy U) (hU : IsOpen U) (hn : U.Nonempty) + (hV : IsOpen V) (hc : IsConnected V) (he : IsCommonAnalyticExtension U V) : V = U := + Subset.antisymm + (h V U hV hc hU hn Subset.rfl he.subset + (he.hasCommonAnalyticContinuation Subset.rfl)) he.subset + +/-- Entire functions vanishing at each exterior point but nowhere on `U` obstruct all common +continuation outside `U`, by applying the identity theorem to their reciprocals. -/ +theorem isDomainOfHolomorphy_of_entire_separators {U : Set E} + (hsep : ∀ a ∉ U, ∃ q : E → ℂ, AnalyticOnNhd ℂ q univ ∧ + q a = 0 ∧ ∀ z ∈ U, q z ≠ 0) : IsDomainOfHolomorphy U := by + intro V W _ hc hW hn hWU hWV he a ha + by_contra hna + obtain ⟨q, hq, hqa, hqU⟩ := hsep a hna + have hi : AnalyticOnNhd ℂ (fun z => (q z)⁻¹) U := + fun z hz => (hq z (mem_univ z)).inv (hqU z hz) + obtain ⟨g, hg, hge⟩ := he _ hi + have hp : AnalyticOnNhd ℂ (fun z => q z * g z) V := (hq.mono (subset_univ V)).mul hg + obtain ⟨w, hw⟩ := hn + have hlocal : (fun z => q z * g z) =ᶠ[𝓝 w] (fun _ => (1 : ℂ)) := by + filter_upwards [hW.mem_nhds hw] with z hz + rw [hge hz, mul_inv_cancel₀ (hqU z (hWU hz))] + have heq := hp.eqOn_of_preconnected_of_eventuallyEq analyticOnNhd_const + hc.isPreconnected (hWV hw) hlocal + have hbad := heq ha + simp [hqa] at hbad + +/-- Every subset of the complex plane satisfies the analytic continuation obstruction; in particular +every planar open set is a domain of holomorphy. -/ +theorem isDomainOfHolomorphy_complex (U : Set ℂ) : IsDomainOfHolomorphy U := by + apply isDomainOfHolomorphy_of_entire_separators + intro a ha + refine ⟨fun z => z - a, analyticOnNhd_id.sub analyticOnNhd_const, sub_self a, ?_⟩ + intro z hz he + exact ha (sub_eq_zero.mp he ▸ hz) + +/-- Finite products of planar open sets are domains of holomorphy. The continuation obstruction +itself holds for arbitrary planar factors and includes an empty index type. -/ +theorem isDomainOfHolomorphy_pi {ι : Type*} [Fintype ι] (S : ι → Set ℂ) : + IsDomainOfHolomorphy (Set.pi univ S) := by + apply isDomainOfHolomorphy_of_entire_separators + intro a ha + have hnot : ¬ ∀ i, a i ∈ S i := by + intro h + exact ha (fun i _ => h i) + obtain ⟨i, hi⟩ := not_forall.mp hnot + refine ⟨fun z => z i - a i, + ((ContinuousLinearMap.proj i : (ι → ℂ) →L[ℂ] ℂ).analyticOnNhd univ).sub + analyticOnNhd_const, sub_self _, ?_⟩ + intro z hz he + apply hi + rw [← sub_eq_zero.mp he] + exact hz i (mem_univ i) + +/-- Every real-convex open subset of a finite-dimensional complex normed space is a domain of +holomorphy. A separating real functional is complexified to give a pole. -/ +theorem isDomainOfHolomorphy_of_convex {U : Set E} + (hU : Convex ℝ U) (ho : IsOpen U) : IsDomainOfHolomorphy U := by + apply isDomainOfHolomorphy_of_entire_separators + intro a ha + obtain ⟨l, hl⟩ := geometric_hahn_banach_open_point hU ho ha + let L : E →L[ℂ] ℂ := l.extendRCLike + refine ⟨fun z => L z - L a, (L.analyticOnNhd univ).sub analyticOnNhd_const, sub_self _, ?_⟩ + intro z hz he + have he' : l z = l a := by + simpa only [L, StrongDual.re_extendRCLike_apply] using + congrArg (RCLike.re : ℂ → ℝ) (sub_eq_zero.mp he) + exact (ne_of_lt (hl z hz)) he' + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/DominatedIntegral.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/DominatedIntegral.lean new file mode 100644 index 0000000000..4d2507f38c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/DominatedIntegral.lean @@ -0,0 +1,86 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Schwarz +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ParametricIntegral + +/-! +# Locally dominated holomorphic integrals + +A locally uniform integrable bound on a holomorphic integrand also bounds its derivatives on +smaller balls, by the Schwarz estimate. This avoids explicit logarithmic estimates when the +parameters occur in complex powers. Measurability of the derivative is kept as a separate +hypothesis so that the integration space needs no topology. + +## Main results + +`analyticOnNhd_integral_of_locally_dominated` is holomorphy of a parameter-dependent integral +under a locally integrable dominant, without a logarithmic estimate on the parameter. +-/ + +open Complex MeasureTheory Filter Metric Set +open scoped Topology +public section +variable {α P E : Type*} [MeasurableSpace α] + [NormedAddCommGroup P] [NormedSpace ℂ P] [FiniteDimensional ℂ P] + [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-- A locally dominated holomorphic integrand has a holomorphic integral. The derivative +measurability assumption is often obtained from continuity on the integration domain. -/ +theorem analyticOnNhd_integral_of_locally_dominated + {μ : Measure α} {U : Set P} {F : P → α → E} + (hU : IsOpen U) + (hmeas : ∀ x ∈ U, AEStronglyMeasurable (F x) μ) + (hderivmeas : ∀ x ∈ U, + AEStronglyMeasurable (fun a => fderiv ℂ (F · a) x) μ) + (hhol : ∀ᵐ a ∂μ, AnalyticOnNhd ℂ (F · a) U) + (hdom : ∀ x ∈ U, ∃ (s : Set P) (bound : α → ℝ), + s ∈ nhds x ∧ Integrable bound μ ∧ + ∀ᵐ a ∂μ, ∀ y ∈ s, ‖F y a‖ ≤ bound a) : + AnalyticOnNhd ℂ (fun x => ∫ a, F x a ∂μ) U := by + apply analyticOnNhd_integral_of_dominated_of_fderiv_le hU + intro x hx + obtain ⟨s, bound, hs, hboundInt, hbound⟩ := hdom x hx + obtain ⟨ε, hε, hball⟩ := Metric.mem_nhds_iff.mp (inter_mem hs (hU.mem_nhds hx)) + have hsub : ball x ε ⊆ U := fun y hy => (hball hy).2 + have hbnd : ∀ᵐ a ∂μ, ∀ y ∈ ball x ε, ‖F y a‖ ≤ bound a := + hbound.mono fun a ha y hy => ha y (hball hy).1 + let r := ε / 2 + have hr : 0 < r := half_pos hε + have hsmall : ball x r ⊆ ball x ε := ball_subset_ball (half_le_self hε.le) + have hnear (y : P) (hy : y ∈ ball x r) : ball y r ⊆ ball x ε := by + intro w hw + rw [mem_ball] at * + calc + dist w x ≤ dist w y + dist y x := dist_triangle _ _ _ + _ < r + r := add_lt_add hw hy + _ = ε := by dsimp [r]; ring + refine ⟨ball x r, (fun a => (2 * bound a) / r), + (fun y a => fderiv ℂ (F · a) y), ball_mem_nhds x hr, ?_, ?_, + hderivmeas x hx, ?_, ?_, ?_⟩ + · filter_upwards [hU.mem_nhds hx] with y hy + exact hmeas y hy + · exact hboundInt.mono' (hmeas x hx) + (hbnd.mono fun a ha => ha x (mem_ball_self hε)) + · filter_upwards [hhol, hbnd] with a ha hba + intro y hy + apply norm_fderiv_le_div_of_mapsTo_ball + (ha.differentiableOn.mono ((hnear y hy).trans hsub)) ?_ hr + intro w hw + rw [mem_closedBall, dist_eq_norm] + calc + ‖F w a - F y a‖ ≤ ‖F w a‖ + ‖F y a‖ := norm_sub_le _ _ + _ ≤ bound a + bound a := add_le_add (hba w (hnear y hy hw)) (hba y (hsmall hy)) + _ = 2 * bound a := by ring + · exact (hboundInt.const_mul 2).div_const r + · filter_upwards [hhol] with a ha + intro y hy + exact (ha y (hsub (hsmall hy))).differentiableAt.hasFDerivAt + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/FunctionSpace.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/FunctionSpace.lean new file mode 100644 index 0000000000..9e29d906df --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/FunctionSpace.lean @@ -0,0 +1,210 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Algebra.UniformConvergence +public import Mathlib.Topology.ContinuousMap.Algebra +public import Mathlib.Topology.UniformSpace.CompactConvergence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform + +/-! +# Holomorphic maps with the compact-open topology + +Holomorphic maps on an open subset of a complex normed space form a complex submodule of +continuous maps. For finite-dimensional source spaces and Banach targets this submodule is +closed. The topology and uniformity are inherited from Mathlib's continuous-map space, not from +a global sup norm. In particular, the space is complete for Banach targets. + +The zero extension below is only a device for expressing `AnalyticOnNhd` on the ambient space. +No continuity or analyticity at the boundary of the domain is asserted. + +## Main definitions + +* `openExtension`: Extend a continuous map on an open domain by zero; used only for local analytic + predicates. +* `holomorphicSubmodule`: Holomorphic maps are a submodule of continuous maps on the open domain. +* `HolomorphicMap`: Holomorphic maps on an open domain, with the induced compact-open topology and + uniformity. +* `holomorphicRestrict`: Restriction to a smaller open domain preserves holomorphy. +* `holomorphicPartialDeriv`: Coordinate differentiation as an operator on holomorphic maps. + +## Main results + +* `isClosed_holomorphicSubmodule`: Weierstrass convergence makes the holomorphic submodule closed. +* `holomorphicMap_tendsto_iff`: The inherited topology on holomorphic maps is precisely locally + uniform convergence. +* `continuous_holomorphicRestrict`: Restriction is continuous for the compact-open topology. +* `continuous_holomorphicPartialDeriv`: Coordinate differentiation is continuous for the + compact-open topology. +-/ + +public noncomputable section + +open Filter Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [NormedAddCommGroup F] + [NormedSpace ℂ F] + +open scoped Classical in +/-- Extend a continuous map on an open domain by zero; used only for local analytic predicates. -/ +@[expose] def openExtension (U : TopologicalSpace.Opens E) (f : C(U, F)) (z : E) : F := + if hz : z ∈ U then f ⟨z, hz⟩ else 0 + +omit [NormedSpace ℂ E] [NormedSpace ℂ F] in +/-- The value of the extension by zero at a point of the open set. -/ +theorem openExtension_apply (U : TopologicalSpace.Opens E) + (f : C(U, F)) {z : E} (hz : z ∈ U) : openExtension U f z = f ⟨z, hz⟩ := + dite_eq_left hz + +omit [NormedSpace ℂ E] [NormedSpace ℂ F] in +/-- The extension by zero restricts to the original function. -/ +@[simp] theorem openExtension_coe (U : TopologicalSpace.Opens E) + (f : C(U, F)) (z : U) : openExtension U f z = f z := by + simp [openExtension, z.property] + +/-- Holomorphic maps are a submodule of continuous maps on the open domain. -/ +@[expose] def holomorphicSubmodule (U : TopologicalSpace.Opens E) : Submodule ℂ C(U, F) where + carrier := {f | AnalyticOnNhd ℂ (openExtension U f) U} + zero_mem' := by + change AnalyticOnNhd ℂ (openExtension U 0) U + have h : openExtension U (0 : C(U, F)) = fun _ => 0 := by + funext z + simp [openExtension] + rw [h] + exact analyticOnNhd_const + add_mem' := by + intro f g hf hg + change AnalyticOnNhd ℂ (openExtension U (f + g)) U + have h : openExtension U (f + g) = openExtension U f + openExtension U g := by + funext z + by_cases hz : z ∈ U <;> simp [openExtension, hz] + rw [h] + exact hf.add hg + smul_mem' := by + intro c f hf + change AnalyticOnNhd ℂ (openExtension U (c • f)) U + have h : openExtension U (c • f) = c • openExtension U f := by + funext z + by_cases hz : z ∈ U <;> simp [openExtension, hz] + rw [h] + exact hf.const_smul + +/-- Holomorphic maps on an open domain, with the induced compact-open topology and uniformity. -/ +abbrev HolomorphicMap (U : TopologicalSpace.Opens E) (F : Type*) + [NormedAddCommGroup F] [NormedSpace ℂ F] : Type _ := ↥(holomorphicSubmodule (F := F) U) + +/-- Subtraction is uniformly continuous for the compact-open uniformity on holomorphic maps. -/ +instance (U : TopologicalSpace.Opens E) : IsUniformAddGroup (HolomorphicMap U F) where + uniformContinuous_sub := by + apply isUniformEmbedding_subtype_val.uniformContinuous_iff.mpr + apply ContinuousMap.isUniformEmbedding_toUniformOnFunIsCompact.uniformContinuous_iff.mpr + have h : UniformContinuous (fun f : HolomorphicMap U F => + ContinuousMap.toUniformOnFunIsCompact f.val) := + ContinuousMap.isUniformEmbedding_toUniformOnFunIsCompact.uniformContinuous.comp + uniformContinuous_subtype_val + exact (h.comp uniformContinuous_fst).sub (h.comp uniformContinuous_snd) + +variable [CompleteSpace F] + +omit [NormedSpace ℂ E] [NormedSpace ℂ F] [CompleteSpace F] in +/-- Convergence in the continuous-map space is exactly locally uniform convergence of the ambient +extensions on the open domain. -/ +theorem tendsto_iff_openExtension [LocallyCompactSpace E] {U : TopologicalSpace.Opens E} + {κ : Type*} {l : Filter κ} {f : κ → C(U, F)} {g : C(U, F)} : + Tendsto f l (𝓝 g) ↔ + TendstoLocallyUniformlyOn (fun n => openExtension U (f n)) (openExtension U g) l U := by + let := U.isOpen.locallyCompactSpace + rw [ContinuousMap.tendsto_iff_tendstoLocallyUniformly, + tendstoLocallyUniformlyOn_iff_tendstoLocallyUniformly_comp_coe] + simp only [Function.comp_def, openExtension_coe] + rfl + +/-- Weierstrass convergence makes the holomorphic submodule closed. -/ +theorem isClosed_holomorphicSubmodule [FiniteDimensional ℂ E] (U : TopologicalSpace.Opens E) : + IsClosed (holomorphicSubmodule (F := F) U : Set C(U, F)) := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + rw [isClosed_iff_forall_filter] + intro f l hl hmem hlim + have hc : Tendsto (fun g : C(U, F) => g) l (𝓝 f) := hlim + exact (tendsto_iff_openExtension.mp hc).analyticOnNhd_of_finiteDimensional + (le_principal_iff.mp hmem) U.isOpen + +/-- The compact-open uniform space of holomorphic maps into a Banach space is complete. -/ +instance [FiniteDimensional ℂ E] (U : TopologicalSpace.Opens E) : CompleteSpace (HolomorphicMap U + F) := + (isClosed_holomorphicSubmodule (F := F) U).isComplete.completeSpace_coe + +omit [CompleteSpace F] in +/-- Evaluation at a point is continuous in the compact-open topology. -/ +theorem continuous_holomorphicMap_eval (U : TopologicalSpace.Opens E) (z : U) : + Continuous (fun f : HolomorphicMap U F => f.val z) := + (continuous_eval_const z).comp continuous_subtype_val + +omit [CompleteSpace F] in +/-- The inherited topology on holomorphic maps is precisely locally uniform convergence. -/ +theorem holomorphicMap_tendsto_iff [LocallyCompactSpace E] {U : TopologicalSpace.Opens E} + {κ : Type*} {l : Filter κ} {f : κ → HolomorphicMap U F} {g : HolomorphicMap U F} : + Tendsto f l (𝓝 g) ↔ TendstoLocallyUniformlyOn + (fun n => openExtension U (f n).val) (openExtension U g.val) l U := by + rw [tendsto_subtype_rng, tendsto_iff_openExtension] + +omit [CompleteSpace F] in +/-- Restriction to a smaller open domain preserves holomorphy. -/ +@[expose] def holomorphicRestrict {U V : TopologicalSpace.Opens E} (hVU : V ≤ U) + (f : HolomorphicMap U F) : HolomorphicMap V F := by + let inc : C(V, U) := ⟨fun z => ⟨z, hVU z.property⟩, + continuous_subtype_val.subtype_mk _⟩ + refine ⟨f.val.comp inc, ?_⟩ + apply AnalyticOnNhd.congr V.isOpen (f.property.mono hVU) + intro z hz + rw [openExtension_apply U _ (hVU hz), openExtension_apply V _ hz] + rfl + +omit [CompleteSpace F] in +/-- Restriction is continuous for the compact-open topology. -/ +theorem continuous_holomorphicRestrict {U V : TopologicalSpace.Opens E} + (hVU : V ≤ U) : Continuous (holomorphicRestrict (F := F) hVU) := by + apply Continuous.subtype_mk + exact (ContinuousMap.continuous_precomp + ⟨fun z : V => (⟨z, hVU z.property⟩ : U), continuous_subtype_val.subtype_mk _⟩).comp + continuous_subtype_val + +variable {ι : Type*} [Fintype ι] [DecidableEq ι] + +/-- Coordinate differentiation as an operator on holomorphic maps. -/ +def holomorphicPartialDeriv (U : TopologicalSpace.Opens (ι → ℂ)) (i : ι) + (f : HolomorphicMap U F) : HolomorphicMap U F := by + have ha := f.property.partialDeriv U.isOpen i + refine ⟨⟨fun z => partialDeriv i (openExtension U f.val) z, + ha.continuousOn.domRestrict⟩, ?_⟩ + apply AnalyticOnNhd.congr U.isOpen ha + intro z hz + rw [openExtension_apply U _ hz] + rfl + +/-- Coordinate differentiation is continuous for the compact-open topology. -/ +theorem continuous_holomorphicPartialDeriv (U : TopologicalSpace.Opens (ι → ℂ)) (i : ι) : + Continuous (holomorphicPartialDeriv (F := F) U i) := by + rw [continuous_iff_continuousAt] + intro f + change Tendsto _ (𝓝 f) _ + rw [holomorphicMap_tendsto_iff] + have hlim := (holomorphicMap_tendsto_iff (f := fun g : HolomorphicMap U F => g)).mp + (tendsto_id : Tendsto (fun g : HolomorphicMap U F => g) (𝓝 f) (𝓝 f)) + have hd := hlim.partialDeriv (Eventually.of_forall fun g => g.property) U.isOpen i + apply (hd.congr (fun g z hz => ?_)).congr_right (fun z hz => ?_) + all_goals + rw [openExtension_apply U _ hz] + rfl + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/FunctionSpace/Extension.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/FunctionSpace/Extension.lean new file mode 100644 index 0000000000..a73fd29903 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/FunctionSpace/Extension.lean @@ -0,0 +1,212 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.OpenMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CommonExtension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple + +/-! +# Restriction and continuous extension of holomorphic maps + +Restriction is a continuous linear map, injective from a connected larger domain when the +smaller domain is nonempty. When it is surjective, its inverse is continuous for the +compact-open topology, by the Fréchet open-mapping argument for complete metrizable topological +vector spaces. Reference: [Scheidemann][Scheidemann2005] (2005), Proposition 2.1.3 and Exercise +2.1.13. + +## Main results + +`holomorphicRestrictCLM` is restriction as a continuous linear map. +`exists_holomorphicRestrictionEquiv` is a compact-open isomorphism when restriction is +bijective. `HolomorphicAlgebra` is the scalar holomorphic algebra, with +`holomorphicRestrictAlgHom` and `holomorphicRestrictionAlgEquiv` as the algebraic restriction +maps. `exists_holomorphicAlgebraEquiv_of_commonExtension` is an algebra isomorphism from a +common extension domain. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [NormedAddCommGroup F] + [NormedSpace ℂ F] + {U V : TopologicalSpace.Opens E} + +/-- Restriction as a continuous complex-linear operator between compact-open spaces. -/ +@[expose] def holomorphicRestrictCLM (hVU : V ≤ U) : HolomorphicMap U F →L[ℂ] HolomorphicMap V F + where + toFun := holomorphicRestrict hVU + map_add' := by intro f g; rfl + map_smul' := by intro c f; rfl + cont := continuous_holomorphicRestrict hVU + +/-- An ambient extension theorem makes restriction surjective on the bundled spaces. -/ +theorem holomorphicRestrict_surjective (hVU : V ≤ U) + (hext : ∀ f : E → F, AnalyticOnNhd ℂ f V → + ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f V) : + Function.Surjective (holomorphicRestrict (F := F) hVU) := by + intro f + obtain ⟨g, hg, heq⟩ := hext (openExtension V f.val) f.property + let G : HolomorphicMap U F := ⟨⟨fun z => g z, hg.continuousOn.domRestrict⟩, + hg.congr U.isOpen (fun z hz => by rw [openExtension_apply U _ hz]; rfl)⟩ + refine ⟨G, ?_⟩ + apply Subtype.ext + apply ContinuousMap.ext + intro z + exact (heq z.property).trans (openExtension_coe V f.val z) + +/-- On a connected larger domain, restriction to a nonempty open subset is injective. -/ +theorem holomorphicRestrict_injective (hVU : V ≤ U) + (hc : IsPreconnected (U : Set E)) (hne : (V : Set E).Nonempty) : + Function.Injective (holomorphicRestrict (F := F) hVU) := by + intro f g he + have hEq : EqOn (openExtension U f.val) (openExtension U g.val) V := by + intro z hz + have h := congrArg (fun k : HolomorphicMap V F => k.val ⟨z, hz⟩) he + rw [openExtension_apply U _ (hVU hz), openExtension_apply U _ (hVU hz)] + exact h + obtain ⟨z, hz⟩ := hne + have hAll := f.property.eqOn_of_preconnected_of_eventuallyEq g.property hc (hVU hz) + (Filter.mem_of_superset (V.isOpen.mem_nhds hz) hEq) + apply Subtype.ext + apply ContinuousMap.ext + intro z + simpa only [openExtension_coe] using hAll z.property + +/-- Restriction to a dense open subset is injective, without connectedness or nonemptiness +assumptions on either domain. Continuity of the holomorphic representatives suffices. -/ +theorem holomorphicRestrict_injective_of_subset_closure (hVU : V ≤ U) + (hd : (U : Set E) ⊆ closure (V : Set E)) : + Function.Injective (holomorphicRestrict (F := F) hVU) := by + intro f g he + have hEq : EqOn (openExtension U f.val) (openExtension U g.val) V := by + intro z hz + have h := congrArg (fun k : HolomorphicMap V F => k.val ⟨z, hz⟩) he + rw [openExtension_apply U _ (hVU hz), openExtension_apply U _ (hVU hz)] + exact h + have hAll := hEq.of_subset_closure f.property.continuousOn g.property.continuousOn hVU hd + apply Subtype.ext + apply ContinuousMap.ext + intro z + simpa only [openExtension_coe] using hAll z.property + +/-- Surjective restriction is a continuous linear equivalence under the identity-theorem hypotheses, +by the open-mapping theorem for complete metrizable compact-open spaces. Banach-valued targets +need not be finite dimensional. -/ +theorem exists_holomorphicRestrictionEquiv [FiniteDimensional ℂ E] [CompleteSpace F] (hVU : V ≤ U) + (hc : IsPreconnected (U : Set E)) (hne : (V : Set E).Nonempty) + (hs : Function.Surjective (holomorphicRestrict (F := F) hVU)) : + ∃ e : HolomorphicMap U F ≃L[ℂ] HolomorphicMap V F, + (e : HolomorphicMap U F → HolomorphicMap V F) = holomorphicRestrict hVU := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + let : SecondCountableTopology E := (Module.finBasis ℂ + E).equivFunL.toHomeomorph.secondCountableTopology + let : LocallyCompactSpace U := U.isOpen.locallyCompactSpace + let : LocallyCompactSpace V := V.isOpen.locallyCompactSpace + have : (uniformity C(U, F)).IsCountablyGenerated := inferInstance + have : (uniformity C(V, F)).IsCountablyGenerated := inferInstance + have : (uniformity (HolomorphicMap U F)).IsCountablyGenerated := + Filter.comap.isCountablyGenerated _ _ + have : (uniformity (HolomorphicMap V F)).IsCountablyGenerated := + Filter.comap.isCountablyGenerated _ _ + let : PseudoMetricSpace (HolomorphicMap U F) := UniformSpace.pseudoMetricSpace _ + let : PseudoMetricSpace (HolomorphicMap V F) := UniformSpace.pseudoMetricSpace _ + let e := LinearEquiv.ofBijective (holomorphicRestrictCLM (F := F) hVU).toLinearMap + ⟨holomorphicRestrict_injective hVU hc hne, hs⟩ + have hopen := ContinuousLinearMap.isOpenMap_of_surjective_complete (holomorphicRestrictCLM (F := + F) hVU) hs + exact ⟨ContinuousLinearEquiv.ofIsHomeomorph e + ⟨continuous_holomorphicRestrict hVU, + hopen, e.bijective⟩, rfl⟩ + +/-- Scalar holomorphic functions form a subalgebra of continuous functions. -/ +@[expose, reducible] +def holomorphicSubalgebra (U : TopologicalSpace.Opens E) : Subalgebra ℂ C(U, ℂ) where + carrier := (holomorphicSubmodule (F := ℂ) U : Set C(U, ℂ)) + zero_mem' := (holomorphicSubmodule U).zero_mem + add_mem' := (holomorphicSubmodule U).add_mem + mul_mem' := by + intro f g hf hg + apply AnalyticOnNhd.congr U.isOpen (hf.mul hg) + intro z hz + simp [openExtension_apply U _ hz] + algebraMap_mem' := by + intro c + apply AnalyticOnNhd.congr U.isOpen (analyticOnNhd_const (v := c)) + intro z hz + simp [openExtension_apply U _ hz] + +/-- The scalar holomorphic algebra has the same underlying type as the holomorphic space. -/ +abbrev HolomorphicAlgebra (U : TopologicalSpace.Opens E) : Type _ := ↥(holomorphicSubalgebra U) + +/-- Restriction preserves multiplication and constants as well as linear operations. -/ +@[expose] def holomorphicRestrictAlgHom (hVU : V ≤ U) : HolomorphicAlgebra U →ₐ[ℂ] + HolomorphicAlgebra V where + toFun := holomorphicRestrict hVU + map_zero' := rfl + map_one' := rfl + map_add' := by intros; rfl + map_mul' := by intros; rfl + commutes' := by intros; rfl + +/-- The algebra homomorphism has the same underlying function as ordinary restriction. -/ +@[simp] theorem holomorphicRestrictAlgHom_coe (hVU : V ≤ U) : + (holomorphicRestrictAlgHom hVU : HolomorphicAlgebra U → HolomorphicAlgebra V) = + holomorphicRestrict hVU := rfl + +/-- The algebraic restriction equivalence associated to surjectivity. Its continuity in both +directions is supplied by `exists_holomorphicRestrictionEquiv`. -/ +@[expose] def holomorphicRestrictionAlgEquiv (hVU : V ≤ U) + (hc : IsPreconnected (U : Set E)) (hne : (V : Set E).Nonempty) + (hs : Function.Surjective (holomorphicRestrict (F := ℂ) hVU)) : + HolomorphicAlgebra U ≃ₐ[ℂ] HolomorphicAlgebra V := + AlgEquiv.ofBijective (holomorphicRestrictAlgHom hVU) + ⟨holomorphicRestrict_injective hVU hc hne, hs⟩ + +/-- The scalar algebra equivalence is continuous in both directions for the compact-open topology, +using the Fréchet open-mapping theorem for inverse continuity. -/ +theorem continuous_holomorphicRestrictionAlgEquiv [FiniteDimensional ℂ E] (hVU : V ≤ U) + (hc : IsPreconnected (U : Set E)) (hne : (V : Set E).Nonempty) + (hs : Function.Surjective (holomorphicRestrict (F := ℂ) hVU)) : + Continuous (holomorphicRestrictionAlgEquiv hVU hc hne hs) ∧ + Continuous (holomorphicRestrictionAlgEquiv hVU hc hne hs).symm := by + obtain ⟨e, he⟩ := exists_holomorphicRestrictionEquiv hVU hc hne hs + refine ⟨continuous_holomorphicRestrict hVU, ?_⟩ + have hsymm : (fun f : HolomorphicAlgebra V => + (holomorphicRestrictionAlgEquiv hVU hc hne hs).symm f) = + (fun f : HolomorphicAlgebra V => e.symm f) := by + funext f + apply e.injective + rw [ContinuousLinearEquiv.apply_symm_apply, he] + exact (holomorphicRestrictionAlgEquiv hVU hc hne hs).apply_symm_apply f + change Continuous (fun f : HolomorphicAlgebra V => + (holomorphicRestrictionAlgEquiv hVU hc hne hs).symm f) + rw [hsymm] + exact e.symm.continuous + +/-- A common scalar extension pair gives an isomorphism of topological holomorphic algebras. The +connected larger set and nonempty smaller set ensure uniqueness. -/ +theorem exists_holomorphicAlgebraEquiv_of_commonExtension [FiniteDimensional ℂ E] + (h : IsCommonAnalyticExtension (V : Set E) (U : Set E)) + (hc : IsPreconnected (U : Set E)) (hne : (V : Set E).Nonempty) : + ∃ e : HolomorphicAlgebra U ≃ₐ[ℂ] HolomorphicAlgebra V, + (e : HolomorphicAlgebra U → HolomorphicAlgebra V) = holomorphicRestrict (F := ℂ) h.subset ∧ + Continuous e ∧ Continuous e.symm := by + have hs := holomorphicRestrict_surjective h.subset (fun _ hf => h.exists_extension hf) + exact ⟨holomorphicRestrictionAlgEquiv h.subset hc hne hs, rfl, + continuous_holomorphicRestrictionAlgEquiv h.subset hc hne hs⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsContinuation.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsContinuation.lean new file mode 100644 index 0000000000..5bd2e30519 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsContinuation.lean @@ -0,0 +1,125 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy + +/-! +# Hartogs continuation over an arbitrary connected base + +An analytic function on an annular cylinder together with full disc fibers over a nonempty open +part of the base extends to the full cylinder. No local boundedness near the missing part is +assumed. The proof uses a fixed circle integral and the identity principle in the base. +Reference: [Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), Theorem 2.6.1. + +## Main results + +`hartogsCylinder` is an annular cylinder together with full disc fibers over part of the base. +`exists_extension_hartogsCylinder` is Hartogs continuation across that figure, without a local +boundedness hypothesis on the missing part. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- An annular cylinder supplemented by full disc fibers over part of the base. -/ +@[expose] def hartogsCylinder (D D₀ : Set E) (ρ R : ℝ) : Set (E × ℂ) := + (D ×ˢ (ball 0 R \ closedBall 0 ρ)) ∪ (D₀ ×ˢ ball 0 R) + +/-- **Hartogs' continuity theorem.** The smaller base need not be connected. Finite positive +outer radius is used; no positive-dimensional base assumption is required. -/ +theorem exists_extension_hartogsCylinder {D D₀ : Set E} + (hD : IsOpen D) (hc : IsPreconnected D) (hD₀ : IsOpen D₀) (hne : D₀.Nonempty) + (hsub : D₀ ⊆ D) {ρ R : ℝ} (hρ : 0 ≤ ρ) (hρR : ρ < R) + {f : E × ℂ → F} (hf : AnalyticOnNhd ℂ f (hartogsCylinder D D₀ ρ R)) : + ∃ g, AnalyticOnNhd ℂ g (D ×ˢ ball 0 R) ∧ EqOn g f (hartogsCylinder D D₀ ρ R) := by + classical + obtain ⟨r, hρr, hrR⟩ := exists_between hρR + have hr : 0 < r := hρ.trans_lt hρr + let W : Set ((E × ℂ) × ℂ) := {q | (q.1.1, q.2) ∈ hartogsCylinder D D₀ ρ R ∧ q.2 ≠ q.1.2} + let H : (E × ℂ) × ℂ → F := fun q => (q.2 - q.1.2)⁻¹ • f (q.1.1, q.2) + have hH : AnalyticOnNhd ℂ H W := by + intro q hq + have hmap : AnalyticAt ℂ (fun q : (E × ℂ) × ℂ => (q.1.1, q.2)) q := + (analyticAt_fst.comp analyticAt_fst).prod analyticAt_snd + exact ((analyticAt_snd.sub (analyticAt_snd.comp analyticAt_fst)).inv + (sub_ne_zero.mpr hq.2)).smul + ((hf _ hq.1).comp_of_eq hmap rfl) + let J : E × ℂ → F := fun p => (2 * Real.pi * I : ℂ)⁻¹ • ∮ t in C(0, r), H (p, t) + have hJ : AnalyticOnNhd ℂ J (D ×ˢ ball 0 r) := by + apply (analyticOnNhd_circleIntegral_kernel (hD.prod isOpen_ball) hH hr.le ?_).const_smul + intro p hp t ht + have htn : ‖t‖ = r := by simpa [mem_sphere, dist_zero_right] using ht + refine ⟨Or.inl ⟨hp.1, ?_, ?_⟩, ?_⟩ + · simpa [mem_ball, dist_zero_right, htn] using hrR + · simpa [mem_closedBall, dist_zero_right, htn] using not_le.mpr hρr + · change t ≠ p.2 + intro he + have hpw : ‖p.2‖ < r := by simpa [mem_ball, dist_zero_right] using hp.2 + rw [he] at htn + linarith + have hJ₀ : ∀ z ∈ D₀, ∀ w ∈ ball (0 : ℂ) r, J (z, w) = f (z, w) := by + intro z hz w hw + have hs : AnalyticOnNhd ℂ (fun t => f (z, t)) (ball 0 R) := by + intro t ht + exact (hf _ (Or.inr ⟨hz, ht⟩)).comp (analyticAt_const.prod analyticAt_id) + exact Complex.two_pi_I_inv_smul_circleIntegral_sub_inv_smul_of_differentiable_on_off_countable + (f := fun t => f (z, t)) countable_empty hw + (hs.continuousOn.mono (closedBall_subset_ball hrR)) + (fun t ht => (hs t (ball_subset_ball hrR.le ht.1)).differentiableAt) + have hJa : ∀ z ∈ D, ∀ w ∈ ball (0 : ℂ) r \ closedBall 0 ρ, J (z, w) = f (z, w) := by + intro z hz w hw + have hj : AnalyticOnNhd ℂ (fun z => J (z, w)) D := + fun z hz => (hJ _ ⟨hz, hw.1⟩).comp (analyticAt_id.prod analyticAt_const) + have hh : AnalyticOnNhd ℂ (fun z => f (z, w)) D := + fun z hz => (hf _ (Or.inl ⟨hz, ball_subset_ball hrR.le hw.1, hw.2⟩)).comp + (analyticAt_id.prod analyticAt_const) + obtain ⟨a, ha⟩ := hne + exact hj.eqOn_of_preconnected_of_eventuallyEq hh hc (hsub ha) + (Filter.mem_of_superset (hD₀.mem_nhds ha) (fun y hy => hJ₀ y hy w hw.1)) hz + let g : E × ℂ → F := fun p => if ‖p.2‖ < r then J p else f p + have hgf : EqOn g f (D ×ˢ (ball 0 R \ closedBall 0 ρ)) := by + intro p hp + dsimp [g] + split_ifs with hw + · exact hJa p.1 hp.1 p.2 ⟨by simpa [mem_ball, dist_zero_right] using hw, hp.2.2⟩ + · rfl + refine ⟨g, ?_, ?_⟩ + · intro p hp + by_cases hw : ‖p.2‖ < r + · have he : g =ᶠ[𝓝 p] J := by + filter_upwards [(isOpen_lt continuous_snd.norm continuous_const).mem_nhds hw] with q hq + simp [g, hq] + exact (analyticAt_congr he).mpr (hJ p ⟨hp.1, by simpa [mem_ball, dist_zero_right] using hw⟩) + · have hp' : p ∈ D ×ˢ (ball 0 R \ closedBall 0 ρ) := + ⟨hp.1, hp.2, by simpa [mem_closedBall, dist_zero_right] using (not_le.mpr + (hρr.trans_le (not_lt.mp hw)))⟩ + have he : g =ᶠ[𝓝 p] f := Filter.mem_of_superset + ((hD.prod (isOpen_ball.sdiff isClosed_closedBall)).mem_nhds hp') hgf + exact (analyticAt_congr he).mpr (hf p (Or.inl hp')) + · intro p hp + rcases hp with hp | hp + · exact hgf hp + · dsimp [g] + split_ifs with hw + · exact hJ₀ p.1 hp.1 p.2 (by simpa [mem_ball, dist_zero_right] using hw) + · rfl + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsDomain.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsDomain.lean new file mode 100644 index 0000000000..92b251a85f --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsDomain.lean @@ -0,0 +1,260 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt + +/-! +# Hartogs sets and their fibers + +The product `E × ℂ` specifies a base and a distinguished complex fiber coordinate. `IsHartogs` +is rotational invariance in that coordinate; `IsCompleteHartogs` also allows contraction toward +zero. Openness, nonemptiness and connectedness of the total set are separate assumptions. +`HasPreconnectedFibers` is a further, independent property: empty fibers are allowed, and every +nonempty fiber is then connected. + +Complete Hartogs sets have star-convex, hence preconnected, fibers. Their base is exactly their +zero section. No symmetry or contraction in the base is required. To change the fiber center to +`a`, apply the predicates to `{p | (p.1, a + p.2) ∈ U}`. + +References: [Shabat][Shabat1991] (1991), I §1.2, pp. 9–10; [Range][Range1986] (1986), Chapter I, +E.1.10 and E.5.5. Hartogs series are treated separately in `HartogsSeries`. + +## Main definitions + +* `hartogsFiber`: The complex fiber of a set over a specified base point. +* `hartogsBase`: The base consists of the points with nonempty fiber. +* `IsHartogs`: Hartogs symmetry is invariance under rotations of the fiber coordinate about zero. +* `IsCompleteHartogs`: Complete Hartogs sets also contain every smaller fiber modulus, including + zero. +* `HasPreconnectedFibers`: Each fiber is preconnected. + +## Main results + +* `IsCompleteHartogs.isHartogs`: Complete Hartogs sets have Hartogs symmetry. +* `IsCompleteHartogs.hasPreconnectedFibers`: Complete Hartogs sets have preconnected fibers; empty + fibers need no exception. +* `hasPreconnectedFibers_iff`: Preconnected fibers are equivalently connected fibers at every point + of the base. +* `IsReinhardt.isHartogs_option`: Selecting the `none` coordinate in a Reinhardt set gives Hartogs + symmetry. +* `IsCompleteReinhardt.isCompleteHartogs_option`: Selecting the `none` coordinate in a complete + Reinhardt set gives complete Hartogs. +* `isOpen_hartogsBase`: The base of an open set in a product is open. +* `isPreconnected_hartogsBase`: The base of a preconnected set is preconnected. + +## References + +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [B. V. Shabat, *Introduction to Complex Analysis, Part II: Functions of Several + Variables*][Shabat1991] +-/ + +public section + +open Set + +namespace SeveralComplexVariables + +variable {E E' : Type*} {U V : Set (E × ℂ)} + +/-- The complex fiber of a set over a specified base point. -/ +@[expose] def hartogsFiber (U : Set (E × ℂ)) (z : E) : Set ℂ := + {w | (z, w) ∈ U} + +/-- The base consists of the points with nonempty fiber. -/ +@[expose] def hartogsBase (U : Set (E × ℂ)) : Set E := Prod.fst '' U + +/-- Hartogs symmetry is invariance under rotations of the fiber coordinate about zero. -/ +@[expose] def IsHartogs (U : Set (E × ℂ)) : Prop := + ∀ ⦃z w⦄, (z, w) ∈ U → ∀ ⦃v⦄, ‖v‖ = ‖w‖ → (z, v) ∈ U + +/-- Complete Hartogs sets also contain every smaller fiber modulus, including zero. -/ +@[expose] def IsCompleteHartogs (U : Set (E × ℂ)) : Prop := + ∀ ⦃z w⦄, (z, w) ∈ U → ∀ ⦃v⦄, ‖v‖ ≤ ‖w‖ → (z, v) ∈ U + +/-- Each fiber is preconnected. Equivalently, every nonempty fiber is connected. This does not +require Hartogs symmetry, openness, or connectedness of the total set. -/ +@[expose] def HasPreconnectedFibers (U : Set (E × ℂ)) : Prop := + ∀ z, IsPreconnected (hartogsFiber U z) + +/-- Membership in the base is equivalent to nonemptiness of the fiber. -/ +theorem mem_hartogsBase_iff {z : E} : z ∈ hartogsBase U ↔ (hartogsFiber U z).Nonempty := by + constructor + · rintro ⟨⟨x, w⟩, hw, rfl⟩ + exact ⟨w, hw⟩ + · rintro ⟨w, hw⟩ + exact ⟨(z, w), hw, rfl⟩ + +/-- The empty set has Hartogs symmetry. -/ +@[simp] theorem isHartogs_empty : IsHartogs (∅ : Set (E × ℂ)) := + fun _ _ h => h.elim + +/-- The whole product has Hartogs symmetry. -/ +@[simp] theorem isHartogs_univ : IsHartogs (univ : Set (E × ℂ)) := + fun _ _ _ _ _ => mem_univ _ + +/-- The empty set is complete Hartogs. -/ +@[simp] theorem isCompleteHartogs_empty : IsCompleteHartogs (∅ : Set (E × ℂ)) := + fun _ _ h => h.elim + +/-- The whole product is complete Hartogs. -/ +@[simp] theorem isCompleteHartogs_univ : IsCompleteHartogs (univ : Set (E × ℂ)) := + fun _ _ _ _ _ => mem_univ _ + +/-- Complete Hartogs sets have Hartogs symmetry. -/ +theorem IsCompleteHartogs.isHartogs (hU : IsCompleteHartogs U) : IsHartogs U := + fun _ _ hw _ hv => hU hw hv.le + +/-- Intersections preserve Hartogs symmetry. -/ +theorem IsHartogs.inter (hU : IsHartogs U) (hV : IsHartogs V) : IsHartogs (U ∩ V) := + fun _ _ hw _ hv => ⟨hU hw.1 hv, hV hw.2 hv⟩ + +/-- Unions preserve Hartogs symmetry, without requiring connected fibers. -/ +theorem IsHartogs.union (hU : IsHartogs U) (hV : IsHartogs V) : IsHartogs (U ∪ V) := + fun _ _ hw _ hv => hw.elim (fun h => Or.inl (hU h hv)) (fun h => Or.inr (hV h hv)) + +/-- Intersections preserve the complete Hartogs property. -/ +theorem IsCompleteHartogs.inter (hU : IsCompleteHartogs U) (hV : IsCompleteHartogs V) : + IsCompleteHartogs (U ∩ V) := + fun _ _ hw _ hv => ⟨hU hw.1 hv, hV hw.2 hv⟩ + +/-- Unions preserve the complete Hartogs property. -/ +theorem IsCompleteHartogs.union (hU : IsCompleteHartogs U) (hV : IsCompleteHartogs V) : + IsCompleteHartogs (U ∪ V) := + fun _ _ hw _ hv => hw.elim (fun h => Or.inl (hU h hv)) (fun h => Or.inr (hV h hv)) + +/-- Any change of base preserves Hartogs symmetry. -/ +theorem IsHartogs.preimage_base (hU : IsHartogs U) (g : E' → E) : + IsHartogs {p : E' × ℂ | (g p.1, p.2) ∈ U} := + fun _ _ hw _ hv => hU hw hv + +/-- Any change of base preserves the complete Hartogs property. -/ +theorem IsCompleteHartogs.preimage_base (hU : IsCompleteHartogs U) (g : E' → E) : + IsCompleteHartogs {p : E' × ℂ | (g p.1, p.2) ∈ U} := + fun _ _ hw _ hv => hU hw hv + +/-- Multiplication of a fiber coordinate by a unit-modulus scalar preserves membership. -/ +theorem IsHartogs.mul_mem (hU : IsHartogs U) {z : E} {w a : ℂ} + (hw : (z, w) ∈ U) (ha : ‖a‖ = 1) : (z, a * w) ∈ U := + hU hw (by simp [ha]) + +/-- Multiplication of a fiber coordinate by a complex contraction preserves membership. -/ +theorem IsCompleteHartogs.mul_mem (hU : IsCompleteHartogs U) {z : E} {w a : ℂ} + (hw : (z, w) ∈ U) (ha : ‖a‖ ≤ 1) : (z, a * w) ∈ U := by + apply hU hw + rw [norm_mul] + exact mul_le_of_le_one_left (norm_nonneg _) ha + +/-- Every nonempty fiber of a complete Hartogs set contains zero. -/ +theorem IsCompleteHartogs.zero_mem_fiber (hU : IsCompleteHartogs U) {z : E} + (hz : z ∈ hartogsBase U) : (z, 0) ∈ U := by + obtain ⟨w, hw⟩ := mem_hartogsBase_iff.mp hz + exact hU hw (by simp) + +/-- The base of a complete Hartogs set equals its zero section. -/ +theorem IsCompleteHartogs.mem_base_iff (hU : IsCompleteHartogs U) {z : E} : + z ∈ hartogsBase U ↔ (z, 0) ∈ U := + ⟨hU.zero_mem_fiber, fun hz => mem_hartogsBase_iff.mpr ⟨0, hz⟩⟩ + +/-- Fibers of a complete Hartogs set are star-convex about zero, including empty fibers. -/ +theorem IsCompleteHartogs.starConvex_fiber (hU : IsCompleteHartogs U) (z : E) : + StarConvex ℝ 0 (hartogsFiber U z) := by + intro w hw a b ha hb hab + simp only [smul_zero, zero_add] + apply hU hw + rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg hb] + exact mul_le_of_le_one_left (norm_nonneg _) (by linarith) + +/-- Nonempty fibers of complete Hartogs sets are path connected. -/ +theorem IsCompleteHartogs.isPathConnected_fiber (hU : IsCompleteHartogs U) {z : E} + (hz : z ∈ hartogsBase U) : IsPathConnected (hartogsFiber U z) := + (hU.starConvex_fiber z).isPathConnected (hU.zero_mem_fiber hz) + +/-- Complete Hartogs sets have preconnected fibers; empty fibers need no exception. -/ +theorem IsCompleteHartogs.hasPreconnectedFibers (hU : IsCompleteHartogs U) : + HasPreconnectedFibers U := by + intro z + rcases (hartogsFiber U z).eq_empty_or_nonempty with h | h + · rw [h] + exact isPreconnected_empty + · exact (hU.isPathConnected_fiber (mem_hartogsBase_iff.mpr h)).isConnected.isPreconnected + +/-- Fiber preconnectedness gives connectedness at every point of the projected base. -/ +theorem HasPreconnectedFibers.isConnected_fiber (hU : HasPreconnectedFibers U) {z : E} + (hz : z ∈ hartogsBase U) : IsConnected (hartogsFiber U z) := + ⟨mem_hartogsBase_iff.mp hz, hU z⟩ + +/-- Preconnected fibers are equivalently connected fibers at every point of the base. -/ +theorem hasPreconnectedFibers_iff : HasPreconnectedFibers U ↔ + ∀ z ∈ hartogsBase U, IsConnected (hartogsFiber U z) := by + constructor + · exact fun h _ hz => h.isConnected_fiber hz + · intro h z + rcases (hartogsFiber U z).eq_empty_or_nonempty with hz | hz + · rw [hz] + exact isPreconnected_empty + · exact (h z (mem_hartogsBase_iff.mpr hz)).isPreconnected + +/-- Products with centered discs are complete Hartogs, with no condition on the base. -/ +theorem isCompleteHartogs_prod_ball (B : Set E) (r : ℝ) : + IsCompleteHartogs (B ×ˢ Metric.ball (0 : ℂ) r) := by + intro z w hw v hv + refine ⟨hw.1, ?_⟩ + simpa only [Metric.mem_ball, dist_zero_right] using + hv.trans_lt (by simpa only [Metric.mem_ball, dist_zero_right] using hw.2) + +/-- Products with centered annuli have Hartogs symmetry, including degenerate annuli. -/ +theorem isHartogs_prod_annulus (B : Set E) (r R : ℝ) : + IsHartogs (B ×ˢ {w : ℂ | r < ‖w‖ ∧ ‖w‖ < R}) := by + intro z w hw v hv + exact ⟨hw.1, by simpa only [mem_ofPred_eq, hv] using hw.2⟩ + +/-- Selecting the `none` coordinate in a Reinhardt set gives Hartogs symmetry. -/ +theorem IsReinhardt.isHartogs_option {ι : Type*} {S : Set (Option ι → ℂ)} + (hS : IsReinhardt S) : + IsHartogs {p : (ι → ℂ) × ℂ | (fun i => i.elim p.2 p.1) ∈ S} := by + intro z w hw v hv + apply hS hw + intro i + cases i with + | none => exact hv + | some i => rfl + +/-- Selecting the `none` coordinate in a complete Reinhardt set gives complete Hartogs. -/ +theorem IsCompleteReinhardt.isCompleteHartogs_option {ι : Type*} + {S : Set (Option ι → ℂ)} (hS : IsCompleteReinhardt S) : + IsCompleteHartogs {p : (ι → ℂ) × ℂ | (fun i => i.elim p.2 p.1) ∈ S} := by + intro z w hw v hv + apply hS hw + intro i + cases i with + | none => exact hv + | some i => exact le_rfl + +section Topology + +variable [TopologicalSpace E] + +/-- The base of an open set in a product is open. -/ +theorem isOpen_hartogsBase (hU : IsOpen U) : IsOpen (hartogsBase U) := + isOpenMap_fst U hU + +/-- Fibers of an open set in a product are open. -/ +theorem isOpen_hartogsFiber (hU : IsOpen U) (z : E) : IsOpen (hartogsFiber U z) := + hU.preimage (continuous_const.prodMk continuous_id) + +/-- The base of a preconnected set is preconnected. -/ +theorem isPreconnected_hartogsBase (hU : IsPreconnected U) : + IsPreconnected (hartogsBase U) := + hU.image _ continuous_fst.continuousOn + +end Topology + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsExtension.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsExtension.lean new file mode 100644 index 0000000000..6c1d5eebb1 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsExtension.lean @@ -0,0 +1,191 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Module.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CompactHole +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsDomain + +/-! +# Hartogs extension + +This file develops the geometry of a standard Hartogs figure and uniqueness of its analytic +extensions. Extension from the figure follows from Hartogs continuation over a connected base. +Extension across general compact holes is deduced from the product-space theorem of +`CompactHole`, proved by Ehrenpreis' method, by a choice of linear coordinates. Separate +analyticity is treated in `SeparateAnalytic`. + +References: [Boas][Boas2013] (2013), Section 2.4; [Scheidemann][Scheidemann2005] (2005), +Exercise 2.1.7 and Section 2.3; [Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Corollary +2.1.2. + +All extension targets are subsets of finite-dimensional complex normed spaces. Coordinate balls +use the supremum norm, so the figure is built from polydiscs. Extension means agreement on the +old domain; functions outside the new domain are unrestricted. + +## Main definitions + +* `hartogsFigure`: A standard Hartogs figure: a thin full cylinder together with an outer annular + cylinder in the last coordinate. + +## Main results + +* `exists_analyticOnNhd_extension_hartogsFigure`: **Extension from a Hartogs figure.** A + Banach-valued holomorphic function on the figure extends to its full unit polydisc, by Hartogs + continuation in the last coordinate. +* `exists_analyticOnNhd_extension_of_isCompact`: **Hartogs' compact-hole extension theorem.** In + complex dimension at least two, a holomorphic function extends across a compact subset if its + complement in the domain is connected. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Function Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +section Figure + +variable {ι : Type*} [Fintype ι] + +/-- A standard Hartogs figure: a thin full cylinder together with an outer annular cylinder in the +last coordinate. The intended parameters satisfy `0 < r < 1` and `0 < s < 1`. -/ +@[expose] def hartogsFigure (r s : ℝ) : Set ((ι → ℂ) × ℂ) := + (ball 0 r ×ˢ ball 0 1) ∪ (ball 0 1 ×ˢ (ball 0 1 \ closedBall 0 s)) + +/-- The standard Hartogs figure has rotational symmetry in its fiber coordinate, including for +degenerate parameters and an empty base coordinate type. -/ +theorem isHartogs_hartogsFigure (r s : ℝ) : IsHartogs (hartogsFigure (ι := ι) r s) := by + unfold hartogsFigure + apply (isCompleteHartogs_prod_ball _ _).isHartogs.union + intro z w hw v hv + refine ⟨hw.1, ?_⟩ + simpa only [mem_sdiff, mem_ball, mem_closedBall, dist_zero_right, hv] using hw.2 + +/-- The standard Hartogs figure is open, even for an empty coordinate index type. -/ +theorem isOpen_hartogsFigure (r s : ℝ) : IsOpen (hartogsFigure (ι := ι) r s) := + (isOpen_ball.prod isOpen_ball).union + (isOpen_ball.prod (isOpen_ball.sdiff isClosed_closedBall)) + +/-- The Hartogs figure lies in the full unit polydisc when its inner base radius is at most one. -/ +theorem hartogsFigure_subset {r : ℝ} (hr : r ≤ 1) (s : ℝ) : + hartogsFigure (ι := ι) r s ⊆ ball 0 1 ×ˢ ball 0 1 := by + rintro z (hz | hz) + · exact ⟨ball_subset_ball hr hz.1, hz.2⟩ + · exact ⟨hz.1, hz.2.1⟩ + +/-- A positive inner base radius makes the Hartogs figure contain the origin. -/ +theorem zero_mem_hartogsFigure {r : ℝ} (hr : 0 < r) (s : ℝ) : + (0 : (ι → ℂ) × ℂ) ∈ hartogsFigure r s := + Or.inl ⟨mem_ball_self hr, mem_ball_self zero_lt_one⟩ + +/-- With no base coordinates, a positive-radius Hartogs figure is already the full disk. Thus the +figure-extension statement needs no positive-dimensional base assumption. -/ +theorem hartogsFigure_eq_of_isEmpty [IsEmpty ι] {r : ℝ} (hr : 0 < r) (s : ℝ) : + hartogsFigure (ι := ι) r s = ball 0 1 ×ˢ ball 0 1 := by + ext z + simp only [hartogsFigure, mem_union, mem_prod, Subsingleton.elim z.1 (0 : ι → ℂ), + mem_ball, dist_self, hr, dist_zero_right, true_and, zero_lt_one, mem_sdiff, + mem_closedBall, not_le, or_iff_left_iff_imp, and_imp] + exact fun h _ => h + +omit [CompleteSpace F] in +/-- Two analytic extensions from a Hartogs figure agree throughout the full unit polydisc. This +uniqueness theorem is proved independently of the extension-existence theorem. -/ +theorem eqOn_of_eqOn_hartogsFigure {r : ℝ} (hr : 0 < r) (s : ℝ) + {f g : ((ι → ℂ) × ℂ) → F} + (hf : AnalyticOnNhd ℂ f (ball 0 1 ×ˢ ball 0 1)) + (hg : AnalyticOnNhd ℂ g (ball 0 1 ×ˢ ball 0 1)) + (heq : EqOn f g (hartogsFigure r s)) : EqOn f g (ball 0 1 ×ˢ ball 0 1) := by + apply hf.eqOn_of_preconnected_of_eventuallyEq hg + (isPreconnected_ball.prod isPreconnected_ball) + (show (0 : (ι → ℂ) × ℂ) ∈ ball 0 1 ×ˢ ball 0 1 from + ⟨mem_ball_self zero_lt_one, mem_ball_self zero_lt_one⟩) + exact Filter.mem_of_superset + ((isOpen_hartogsFigure r s).mem_nhds (zero_mem_hartogsFigure hr s)) heq + +/-- **Extension from a Hartogs figure.** A Banach-valued holomorphic function on the figure +extends to its full unit polydisc, by Hartogs continuation in the last coordinate. -/ +theorem exists_analyticOnNhd_extension_hartogsFigure + {r s : ℝ} (hr : 0 < r) (hr1 : r < 1) (hs : 0 < s) (hs1 : s < 1) + {f : ((ι → ℂ) × ℂ) → F} (hf : AnalyticOnNhd ℂ f (hartogsFigure r s)) : + ∃ g : ((ι → ℂ) × ℂ) → F, + AnalyticOnNhd ℂ g (ball 0 1 ×ˢ ball 0 1) ∧ EqOn g f (hartogsFigure r s) := by + obtain ⟨g, hg, he⟩ := exists_extension_hartogsCylinder + (D := ball (0 : ι → ℂ) 1) (D₀ := ball 0 r) isOpen_ball isPreconnected_ball + isOpen_ball ⟨0, mem_ball_self hr⟩ (ball_subset_ball hr1.le) hs.le hs1 + (by simpa only [hartogsCylinder, hartogsFigure, union_comm] using hf) + exact ⟨g, hg, by simpa only [hartogsCylinder, hartogsFigure, union_comm] using he⟩ + +end Figure + +/-- **Hartogs' compact-hole extension theorem.** In complex dimension at least two, a +holomorphic function extends across a compact subset if its complement in the domain is +connected. No boundedness of the function near the hole is required, and the domain itself +need not be connected. + +The dimension and connected-complement hypotheses are essential. The open domain itself need not +be bounded, and an empty domain or empty compact set is allowed. -/ +theorem exists_analyticOnNhd_extension_of_isCompact + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + (hdim : 2 ≤ Module.finrank ℂ E) {U K : Set E} + (hU : IsOpen U) (hK : IsCompact K) (hKU : K ⊆ U) + (hcompl : IsPreconnected (U \ K)) {f : E → F} + (hf : AnalyticOnNhd ℂ f (U \ K)) : + ∃ g : E → F, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ K) := by + obtain ⟨k, hk⟩ : ∃ k, Module.finrank ℂ E = k + 2 := ⟨Module.finrank ℂ E - 2, by omega⟩ + let b := Module.finBasisOfFinrankEq ℂ E hk + let e₂ : (Fin (k + 2) → ℂ) ≃L[ℂ] ℂ × (Fin (k + 1) → ℂ) := + (Fin.consLinearEquiv ℂ (fun _ : Fin (k + 1).succ => ℂ)).symm.toContinuousLinearEquiv + let e : E ≃L[ℂ] ℂ × (Fin (k + 1) → ℂ) := b.equivFunL.trans e₂ + set D' : Set (ℂ × (Fin (k + 1) → ℂ)) := e.symm ⁻¹' U with hD' + set K' : Set (ℂ × (Fin (k + 1) → ℂ)) := e.symm ⁻¹' K with hK' + have himg : ∀ s : Set E, e.symm ⁻¹' s = e '' s := fun s => by + ext w + constructor + · intro hw + exact ⟨e.symm w, hw, e.apply_symm_apply w⟩ + · rintro ⟨z, hz, rfl⟩ + simpa using hz + have hD'o : IsOpen D' := hU.preimage e.symm.continuous + have hK'c : IsCompact K' := by + rw [hK', himg] + exact hK.image e.continuous + have hK'D' : K' ⊆ D' := fun w hw => hKU hw + have hconn' : IsPreconnected (D' \ K') := by + have : D' \ K' = e '' (U \ K) := by rw [← himg]; rfl + rw [this] + exact hcompl.image e e.continuous.continuousOn + have hf' : AnalyticOnNhd ℂ (f ∘ e.symm) (D' \ K') := + hf.comp (e.symm.toContinuousLinearMap.analyticOnNhd _) fun w hw => hw + obtain ⟨g', hg', hg'f⟩ := + exists_analyticOnNhd_extension_of_isCompact_prod hD'o hK'c hK'D' hconn' hf' + refine ⟨g' ∘ e, hg'.comp (e.toContinuousLinearMap.analyticOnNhd _) fun z hz => ?_, ?_⟩ + · change e.symm (e z) ∈ U + simpa using hz + · intro z hz + have hz' : e z ∈ D' \ K' := by + refine ⟨?_, ?_⟩ <;> simp only [hD', hK', mem_preimage, e.symm_apply_apply] + · exact hz.1 + · exact hz.2 + have := hg'f hz' + simpa using this + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsLaurent.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsLaurent.lean new file mode 100644 index 0000000000..d57c7a29a8 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsLaurent.lean @@ -0,0 +1,212 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Algebra.InfiniteSum.NatInt +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform + +/-! +# Local estimates for Hartogs–Laurent series + +Compact circles inside a Hartogs set give uniform bounds for nearby fibers. Two such circles +bound the positive and negative Laurent terms by geometric series. At the zero section the +negative coefficients vanish. These estimates upgrade a pointwise fiber expansion to locally +uniform convergence. + +## Main results + +`IsHartogs.exists_circle_bound` is a uniform bound on nearby fibers from a compact circle in a +Hartogs set. `hasSumLocallyUniformlyOn_hartogsLaurent` upgrades a pointwise fiber expansion to +locally uniform convergence on the Hartogs set. +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {U : Set (E × ℂ)} + +omit [NormedSpace ℂ E] [FiniteDimensional ℂ E] in +/-- Each fiber point of an open Hartogs set has a larger positive radius in the same fiber. -/ +theorem IsHartogs.exists_larger_radius (hH : IsHartogs U) (hU : IsOpen U) + {p : E × ℂ} (hp : p ∈ U) : ∃ R : ℝ, ‖p.2‖ < R ∧ (p.1, (R : ℂ)) ∈ U := by + have hreal : (p.1, (‖p.2‖ : ℂ)) ∈ U := hH hp (by simp) + obtain ⟨ε, hε, hball⟩ := Metric.isOpen_iff.mp hU _ hreal + refine ⟨‖p.2‖ + ε / 2, by linarith, hball ?_⟩ + rw [mem_ball, Prod.dist_eq, max_lt_iff] + refine ⟨by simpa using hε, ?_⟩ + rw [dist_eq_norm, ← Complex.ofReal_sub, Complex.norm_real] + simp only [Real.norm_eq_abs, add_sub_cancel_left, abs_of_pos (half_pos hε)] + exact half_lt_self hε + +omit [NormedSpace ℂ E] [FiniteDimensional ℂ E] in +/-- A nonzero fiber point has a smaller positive radius in the same open Hartogs fiber. -/ +theorem IsHartogs.exists_smaller_radius (hH : IsHartogs U) (hU : IsOpen U) + {p : E × ℂ} (hp : p ∈ U) (hp0 : p.2 ≠ 0) : + ∃ r : ℝ, 0 < r ∧ r < ‖p.2‖ ∧ (p.1, (r : ℂ)) ∈ U := by + have hreal : (p.1, (‖p.2‖ : ℂ)) ∈ U := hH hp (by simp) + obtain ⟨ε, hε, hball⟩ := Metric.isOpen_iff.mp hU _ hreal + let t := min ε ‖p.2‖ / 2 + have ht : 0 < t := half_pos (lt_min hε (norm_pos_iff.mpr hp0)) + have htε : t < ε := (half_lt_self (lt_min hε (norm_pos_iff.mpr hp0))).trans_le (min_le_left _ _) + have htn : t < ‖p.2‖ := + (half_lt_self (lt_min hε (norm_pos_iff.mpr hp0))).trans_le (min_le_right _ _) + refine ⟨‖p.2‖ - t, sub_pos.mpr htn, by linarith, hball ?_⟩ + rw [mem_ball, Prod.dist_eq, max_lt_iff] + refine ⟨by simpa using hε, ?_⟩ + rw [dist_eq_norm, ← Complex.ofReal_sub, Complex.norm_real] + simpa only [Real.norm_eq_abs, sub_sub_cancel_left, abs_neg, abs_of_pos ht] using htε + +omit [NormedSpace ℂ F] [CompleteSpace F] in +/-- A compact fiber circle has a common bound for the function on all nearby fibers. -/ +theorem IsHartogs.exists_circle_bound (hH : IsHartogs U) (hU : IsOpen U) + {f : E × ℂ → F} (hf : ContinuousOn f U) {z : E} {r : ℝ} (hr : 0 < r) + (hz : (z, (r : ℂ)) ∈ U) : + ∃ δ M : ℝ, 0 < δ ∧ 0 ≤ M ∧ ∀ y ∈ ball z δ, ∀ w ∈ sphere (0 : ℂ) r, + (y, w) ∈ U ∧ ‖f (y, w)‖ ≤ M := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + have hnear : ∀ᶠ y in 𝓝 z, ∀ w ∈ sphere (0 : ℂ) r, (y, w) ∈ U := by + apply (isCompact_sphere (0 : ℂ) r).eventually_forall_of_forall_eventually + intro w hw + exact hU.eventually_mem (hH hz (by + rw [mem_sphere_zero_iff_norm.mp hw, Complex.norm_of_nonneg hr.le])) + obtain ⟨δ, hδ, hδsub⟩ := nhds_basis_closedBall.mem_iff.mp hnear + let K := closedBall z δ ×ˢ sphere (0 : ℂ) r + have hKU : K ⊆ U := fun p hp => hδsub hp.1 p.2 hp.2 + obtain ⟨M, hM⟩ := ((isCompact_closedBall z δ).prod (isCompact_sphere (0 : ℂ) r)).bddAbove_image + (hf.mono hKU).norm + exact ⟨δ, max M 0, hδ, le_max_right _ _, fun y hy w hw => + ⟨hδsub (ball_subset_closedBall hy) w hw, + (hM (mem_image_of_mem _ ⟨ball_subset_closedBall hy, hw⟩)).trans (le_max_left _ _)⟩⟩ + +omit [NormedSpace ℂ F] in +/-- Two geometric majorants, one for each half of the integers, give uniform convergence. -/ +private theorem hasSumUniformlyOn_of_geometric_int_bounds {X : Type*} {N : Set X} + {u : ℤ → X → F} {f : X → F} {M₁ M₂ q₁ q₂ : ℝ} + (hq₁ : 0 ≤ q₁) (hq₁1 : q₁ < 1) (hq₂ : 0 ≤ q₂) (hq₂1 : q₂ < 1) + (hsum : ∀ x ∈ N, HasSum (fun k => u k x) (f x)) + (hpos : ∀ n : ℕ, ∀ x ∈ N, ‖u n x‖ ≤ M₁ * q₁ ^ n) + (hneg : ∀ n : ℕ, ∀ x ∈ N, ‖u (Int.negSucc n) x‖ ≤ M₂ * q₂ ^ (n + 1)) : + HasSumUniformlyOn u f N := by + have hs₁ := (summable_geometric_of_lt_one hq₁ hq₁1).mul_left M₁ + have hs₂ : Summable (fun n : ℕ => M₂ * q₂ ^ (n + 1)) := by + simpa only [pow_succ, mul_assoc] using + ((summable_geometric_of_lt_one hq₂ hq₂1).mul_left M₂).mul_right q₂ + have hbound (k : ℤ) (x : X) (hx : x ∈ N) : + ‖u k x‖ ≤ Int.rec (fun n => M₁ * q₁ ^ n) (fun n => M₂ * q₂ ^ (n + 1)) k := by + cases k with + | ofNat n => exact hpos n x hx + | negSucc n => exact hneg n x hx + apply hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + exact (tendstoUniformlyOn_tsum (hs₁.int_rec hs₂) hbound).congr_right + (fun x hx => (hsum x hx).tsum_eq) + +variable {f : E × ℂ → F} {a : ℤ → E → F} + +/-- Near the zero section the positive terms have a common geometric bound and all negative terms +vanish. -/ +private theorem exists_uniform_laurent_neighborhood_zero (hH : IsHartogs U) (hU : IsOpen U) + (hf : ContinuousOn f U) + (hcoeff : ∀ (z : E) (r : ℝ), 0 < r → (z, (r : ℂ)) ∈ U → + ∀ k, a k z = circleLaurentCoeff (fun w => f (z, w)) r k) + (hzero : ∀ z, (z, 0) ∈ U → ∀ k : ℤ, k < 0 → a k z = 0) + (hsum : ∀ p ∈ U, HasSum (fun k : ℤ => p.2 ^ k • a k p.1) (f p)) + {z : E} (hz : (z, (0 : ℂ)) ∈ U) : + ∃ N ∈ 𝓝[U] (z, (0 : ℂ)), HasSumUniformlyOn (fun k p => p.2 ^ k • a k p.1) f N := by + obtain ⟨R, hR', hzR⟩ := hH.exists_larger_radius hU hz + have hR : 0 < R := by simpa using hR' + obtain ⟨δ, M, hδ, _, hcircle⟩ := hH.exists_circle_bound hU hf hR hzR + have hsection : Continuous (fun y : E => (y, (0 : ℂ))) := + continuous_id.prodMk continuous_const + obtain ⟨ε, hε, hεsub⟩ := Metric.mem_nhds_iff.mp ((hU.preimage hsection).mem_nhds hz) + let N := (ball z (min δ ε) ×ˢ ball (0 : ℂ) (R / 2)) ∩ U + have hN : N ∈ 𝓝[U] (z, (0 : ℂ)) := mem_nhdsWithin_of_mem_nhds + (((isOpen_ball.prod isOpen_ball).inter hU).mem_nhds + ⟨⟨mem_ball_self (lt_min hδ hε), mem_ball_self (half_pos hR)⟩, hz⟩) + refine ⟨N, hN, ?_⟩ + apply hasSumUniformlyOn_of_geometric_int_bounds + (M₁ := M) (q₁ := (R / 2) / R) (M₂ := 0) (q₂ := 0) + (by positivity) ((div_lt_one hR).mpr (half_lt_self hR)) le_rfl zero_lt_one + (fun p hp => hsum p hp.2) + · intro n p hp + have hc := hcircle p.1 ((ball_subset_ball (min_le_left δ ε)) hp.1.1) + have hpr : (p.1, (R : ℂ)) ∈ U := (hc (R : ℂ) (by simp [hR.le])).1 + rw [hcoeff p.1 R hR hpr] + exact norm_circleLaurentTerm_nat_le hR (fun w hw => (hc w hw).2) + (mem_ball_zero_iff.mp hp.1.2).le n + · intro n p hp + have hp0 := hεsub ((ball_subset_ball (min_le_right δ ε)) hp.1.1) + simp [hzero p.1 hp0 (Int.negSucc n) (by omega)] + +/-- Away from zero, circles on either side of the fiber modulus give geometric majorants for both +halves of the Laurent series. -/ +private theorem exists_uniform_laurent_neighborhood_ne_zero (hH : IsHartogs U) (hU : IsOpen U) + (hf : ContinuousOn f U) + (hcoeff : ∀ (z : E) (r : ℝ), 0 < r → (z, (r : ℂ)) ∈ U → + ∀ k, a k z = circleLaurentCoeff (fun w => f (z, w)) r k) + (hsum : ∀ p ∈ U, HasSum (fun k : ℤ => p.2 ^ k • a k p.1) (f p)) + {p : E × ℂ} (hp : p ∈ U) (hp0 : p.2 ≠ 0) : + ∃ N ∈ 𝓝[U] p, HasSumUniformlyOn (fun k q => q.2 ^ k • a k q.1) f N := by + obtain ⟨R, hpR, hzR⟩ := hH.exists_larger_radius hU hp + obtain ⟨r, hr, hrp, hzr⟩ := hH.exists_smaller_radius hU hp hp0 + have hR : 0 < R := (norm_nonneg _).trans_lt hpR + obtain ⟨δ₁, M₁, hδ₁, _, hc₁⟩ := hH.exists_circle_bound hU hf hR hzR + obtain ⟨δ₂, M₂, hδ₂, _, hc₂⟩ := hH.exists_circle_bound hU hf hr hzr + let t := (r + ‖p.2‖) / 2 + let T := (‖p.2‖ + R) / 2 + have ht : 0 < t := by dsimp [t]; positivity + have hrt : r < t := by dsimp [t]; linarith + have htp : t < ‖p.2‖ := by dsimp [t]; linarith + have hpT : ‖p.2‖ < T := by dsimp [T]; linarith + have hTR : T < R := by dsimp [T]; linarith + let V : Set ℂ := {w | t < ‖w‖ ∧ ‖w‖ < T} + have hV : IsOpen V := + (isOpen_lt continuous_const continuous_norm).inter (isOpen_lt continuous_norm continuous_const) + let N := (ball p.1 (min δ₁ δ₂) ×ˢ V) ∩ U + refine ⟨N, mem_nhdsWithin_of_mem_nhds + (((isOpen_ball.prod hV).inter hU).mem_nhds + ⟨⟨mem_ball_self (lt_min hδ₁ hδ₂), htp, hpT⟩, hp⟩), ?_⟩ + apply hasSumUniformlyOn_of_geometric_int_bounds + (M₁ := M₁) (q₁ := T / R) (M₂ := M₂) (q₂ := r / t) + (by dsimp [T]; positivity) ((div_lt_one hR).mpr hTR) + (by positivity) ((div_lt_one ht).mpr hrt) (fun q hq => hsum q hq.2) + · intro n q hq + have hc := hc₁ q.1 ((ball_subset_ball (min_le_left δ₁ δ₂)) hq.1.1) + have hqR : (q.1, (R : ℂ)) ∈ U := (hc (R : ℂ) (by simp [hR.le])).1 + rw [hcoeff q.1 R hR hqR] + exact norm_circleLaurentTerm_nat_le hR (fun w hw => (hc w hw).2) hq.1.2.2.le n + · intro n q hq + have hc := hc₂ q.1 ((ball_subset_ball (min_le_right δ₁ δ₂)) hq.1.1) + have hqr : (q.1, (r : ℂ)) ∈ U := (hc (r : ℂ) (by simp [hr.le])).1 + rw [hcoeff q.1 r hr hqr] + exact norm_circleLaurentTerm_negSucc_le hr ht (fun w hw => (hc w hw).2) hq.1.2.1.le n + +/-- A pointwise Hartogs–Laurent expansion with circle coefficients converges locally uniformly. This +estimate is independent of Laurent expansion existence. -/ +theorem hasSumLocallyUniformlyOn_hartogsLaurent (hH : IsHartogs U) (hU : IsOpen U) + (hf : ContinuousOn f U) + (hcoeff : ∀ (z : E) (r : ℝ), 0 < r → (z, (r : ℂ)) ∈ U → + ∀ k, a k z = circleLaurentCoeff (fun w => f (z, w)) r k) + (hzero : ∀ z, (z, 0) ∈ U → ∀ k : ℤ, k < 0 → a k z = 0) + (hsum : ∀ p ∈ U, HasSum (fun k : ℤ => p.2 ^ k • a k p.1) (f p)) : + HasSumLocallyUniformlyOn (fun k p => p.2 ^ k • a k p.1) f U := by + apply hasSumLocallyUniformlyOn_of_of_forall_exists_nhds + rintro ⟨z, w⟩ hp + by_cases hp0 : w = 0 + · subst w + exact exists_uniform_laurent_neighborhood_zero hH hU hf hcoeff hzero hsum hp + · exact exists_uniform_laurent_neighborhood_ne_zero hH hU hf hcoeff hsum hp hp0 + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsSeries.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsSeries.lean new file mode 100644 index 0000000000..8b0d67abda --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HartogsSeries.lean @@ -0,0 +1,298 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.IteratedDeriv.Defs +public import Mathlib.Analysis.Complex.Liouville +public import Mathlib.Analysis.Complex.TaylorSeries +public import Mathlib.Topology.Algebra.InfiniteSum.UniformOn +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsDomain +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsLaurent + +/-! +# Hartogs–Taylor and Hartogs–Laurent expansions + +Functions take values in a complex Banach space, and the base is a finite-dimensional complex +normed space (possibly zero dimensional). Taylor coefficients are the normalized iterated +derivatives in the fiber variable at zero. On an open complete Hartogs set these coefficients +are holomorphic on the base and the expansion converges locally uniformly. + +The Laurent theorem assumes Hartogs symmetry and, separately, preconnected fibers. Its +coefficients are single-valued holomorphic functions on the projected base. Without the fiber +assumption, coefficients need only be locally functions of the base variable; connectedness of +the total set does not repair that issue. Thus we make explicit the hypothesis needed for the +global-base interpretation of [Range][Range1986]'s Exercise E.1.10. Negative coefficients vanish +on fibers containing zero. Integer powers in Lean are totalized at zero, so this vanishing is +recorded as part of the Laurent statement. + +`HasSumLocallyUniformlyOn` uses finite subsets of the index type, including for the +integer-indexed Laurent series. It gives unconditional pointwise convergence and uniform +convergence on compact subsets. We use `ℤ → E → F`, rather than the algebraic `LaurentSeries`, +whose support must be bounded below and therefore excludes general essential singularities. +Neither theorem needs the base or the total set to be connected or nonempty. The Taylor theorem +is proved by fiber differentiation and uniform Cauchy estimates on local product neighborhoods. +The Laurent theorem uses the one-variable annular Cauchy formula, holomorphic dependence of +circle coefficients, and geometric bounds from `LaurentSeries.OneVariable` and `HartogsLaurent`. +Neither expansion depends on the multivariable Laurent theorem. + +References: [Shabat][Shabat1991] (1991), I §3.8, Theorem 1 and the Hartogs–Laurent expansion, +pp. 34–36; [Range][Range1986] (1986), Chapter I, E.1.9–E.1.10. + +## Main definitions + +* `hartogsTaylorCoeff`: The Taylor coefficient in the distinguished fiber coordinate, centered at + zero. + +## Main results + +* `differentiableOn_hartogsTaylorCoeff_and_hasSumLocallyUniformlyOn`: **Hartogs–Taylor expansion.** + Holomorphic functions on open complete Hartogs sets have holomorphic Taylor coefficients on the + base and a locally uniformly convergent fiber expansion. +* `exists_hartogsLaurent_expansion`: **Hartogs–Laurent expansion with connected nonempty fibers.** + The coefficients are holomorphic on the whole projected base, the series converges locally + uniformly, and negative coefficients vanish on every fiber containing zero. + +## References + +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [B. V. Shabat, *Introduction to Complex Analysis, Part II: Functions of Several + Variables*][Shabat1991] +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- The Taylor coefficient in the distinguished fiber coordinate, centered at zero. -/ +@[expose] def hartogsTaylorCoeff (f : E × ℂ → F) (k : ℕ) (z : E) : F := + ((k.factorial : ℂ)⁻¹) • iteratedDeriv k (fun w => f (z, w)) 0 + +/-- The constant coefficient is restriction to the zero section. -/ +@[simp] theorem hartogsTaylorCoeff_zero (f : E × ℂ → F) (z : E) : + hartogsTaylorCoeff f 0 z = f (z, 0) := by + simp [hartogsTaylorCoeff] + +variable [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [CompleteSpace F] {U : Set (E × ℂ)} {f : E × ℂ → F} + +omit [FiniteDimensional ℂ E] in +/-- All derivatives in the fiber variable remain jointly analytic on an open set. -/ +theorem analyticOnNhd_iteratedDeriv_fiber (hU : IsOpen U) (hf : AnalyticOnNhd ℂ f U) + (k : ℕ) : AnalyticOnNhd ℂ (fun p : E × ℂ => + iteratedDeriv k (fun w => f (p.1, w)) p.2) U := by + induction k with + | zero => simpa using hf + | succ k ih => + let g : E × ℂ → F := fun p => iteratedDeriv k (fun w => f (p.1, w)) p.2 + intro p hp + have hA : AnalyticAt ℂ (fun q => fderiv ℂ g q (0, 1)) p := by + exact ((ContinuousLinearMap.apply ℂ F (0, 1)).analyticAt _).comp (ih p hp).fderiv + apply hA.congr + filter_upwards [hU.eventually_mem hp] with q hq + have hs : HasDerivAt (fun w : ℂ => (q.1, w)) (0, 1) q.2 := + (hasDerivAt_const q.2 q.1).prodMk (hasDerivAt_id q.2) + have hd := (ih q hq).differentiableAt.hasFDerivAt.comp_hasDerivAt q.2 hs + simpa only [iteratedDeriv_succ, g, Function.comp_def] using hd.deriv.symm + +omit [NormedSpace ℂ E] [FiniteDimensional ℂ E] in +/-- Around each point of an open complete Hartogs set there is a product neighborhood whose closed +fiber disc has strictly larger radius than the given fiber coordinate. -/ +theorem IsCompleteHartogs.exists_product_closedBall (hH : IsCompleteHartogs U) + (hU : IsOpen U) {p : E × ℂ} (hp : p ∈ U) : + ∃ δ R : ℝ, 0 < δ ∧ ‖p.2‖ < R ∧ + ball p.1 δ ×ˢ closedBall (0 : ℂ) R ⊆ U := by + have hq : (p.1, (‖p.2‖ : ℂ)) ∈ U := + hH hp (by simp) + obtain ⟨ε, hε, hball⟩ := Metric.isOpen_iff.mp hU _ hq + refine ⟨ε / 2, ‖p.2‖ + ε / 2, half_pos hε, by linarith, ?_⟩ + rintro ⟨z, w⟩ ⟨hz, hw⟩ + have hR : 0 ≤ ‖p.2‖ + ε / 2 := by positivity + apply hH (hball (show (z, ((‖p.2‖ + ε / 2 : ℝ) : ℂ)) ∈ + ball (p.1, (‖p.2‖ : ℂ)) ε from ?_)) + · simpa only [mem_closedBall, dist_zero_right, Complex.norm_of_nonneg hR] using hw + · rw [mem_ball, Prod.dist_eq, max_lt_iff] + refine ⟨(mem_ball.mp hz).trans (half_lt_self hε), ?_⟩ + rw [dist_eq_norm, ← Complex.ofReal_sub, Complex.norm_real] + simp only [Real.norm_eq_abs, add_sub_cancel_left, abs_of_pos (half_pos hε)] + exact half_lt_self hε + +/-- **Hartogs–Taylor expansion.** Holomorphic functions on open complete Hartogs sets +have holomorphic Taylor coefficients on the base and a locally uniformly convergent +fiber expansion. Local product neighborhoods and Cauchy estimates give a summable +geometric majorant; the one-variable Taylor theorem identifies the sum. -/ +theorem differentiableOn_hartogsTaylorCoeff_and_hasSumLocallyUniformlyOn (hU : IsOpen U) + (hH : IsCompleteHartogs U) + (hf : DifferentiableOn ℂ f U) : + (∀ k, DifferentiableOn ℂ (hartogsTaylorCoeff f k) (hartogsBase U)) ∧ + HasSumLocallyUniformlyOn + (fun k (p : E × ℂ) => p.2 ^ k • hartogsTaylorCoeff f k p.1) f U := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + have hA := hf.analyticOnNhd_of_finiteDimensional hU + constructor + · intro k z hz + have ha := (analyticOnNhd_iteratedDeriv_fiber hU hA k) (z, 0) (hH.zero_mem_fiber hz) + have hc : AnalyticAt ℂ (fun z => iteratedDeriv k (fun w => f (z, w)) 0) z := + ha.comp (f := fun z : E => (z, (0 : ℂ))) (analyticAt_id.prod analyticAt_const) + exact (analyticAt_const.smul hc).differentiableAt.differentiableWithinAt + · apply hasSumLocallyUniformlyOn_of_of_forall_exists_nhds + intro p hp + obtain ⟨δ, R, hδ, hpR, hsub⟩ := hH.exists_product_closedBall hU hp + have hR : 0 < R := (norm_nonneg _).trans_lt hpR + let r := (‖p.2‖ + R) / 2 + have hr : 0 < r := by dsimp [r]; positivity + have hrR : r < R := by dsimp [r]; linarith + have hpr : ‖p.2‖ < r := by dsimp [r]; linarith + let N := ball p.1 (δ / 2) ×ˢ ball (0 : ℂ) r + let K := closedBall p.1 (δ / 2) ×ˢ closedBall (0 : ℂ) R + have hKU : K ⊆ U := + (Set.prod_mono (closedBall_subset_ball (half_lt_self hδ)) Subset.rfl).trans hsub + have hK : IsCompact K := (isCompact_closedBall _ _).prod (isCompact_closedBall _ _) + obtain ⟨M, hM⟩ := hK.bddAbove_image (hf.continuousOn.mono hKU).norm + let C := max M 0 + have hC : 0 ≤ C := le_max_right _ _ + have hbound : ∀ q ∈ K, ‖f q‖ ≤ C := + fun q hq => (hM (mem_image_of_mem _ hq)).trans (le_max_left _ _) + have hslice (z : E) (hz : z ∈ closedBall p.1 (δ / 2)) : + DifferentiableOn ℂ (fun w => f (z, w)) (closedBall 0 R) := by + apply hf.comp ((differentiable_const z).prodMk differentiable_id).differentiableOn + intro w hw + exact hKU ⟨hz, hw⟩ + have hsum (q : E × ℂ) (hq : q ∈ N) : + HasSum (fun k => q.2 ^ k • hartogsTaylorCoeff f k q.1) (f q) := by + have hs := Complex.hasSum_taylorSeries_on_ball + ((hslice q.1 (ball_subset_closedBall hq.1)).mono ball_subset_closedBall) + ((ball_subset_ball hrR.le) hq.2) + convert hs using 1 + funext k + simp only [sub_zero, hartogsTaylorCoeff] + exact smul_comm _ _ _ + have hterm (k : ℕ) (q : E × ℂ) (hq : q ∈ N) : + ‖q.2 ^ k • hartogsTaylorCoeff f k q.1‖ ≤ C * (r / R) ^ k := by + have hd := Complex.norm_iteratedDeriv_le_of_forall_mem_sphere_norm_le k hR + ((hslice q.1 (ball_subset_closedBall hq.1)).mono + closure_ball_subset_closedBall).diffContOnCl + (fun w hw => hbound (q.1, w) ⟨ball_subset_closedBall hq.1, sphere_subset_closedBall hw⟩) + have hfact : (k.factorial : ℝ) ≠ 0 := by positivity + have hc : ‖hartogsTaylorCoeff f k q.1‖ ≤ C / R ^ k := by + rw [hartogsTaylorCoeff, norm_smul, norm_inv, Complex.norm_natCast] + calc + (k.factorial : ℝ)⁻¹ * ‖iteratedDeriv k (fun w => f (q.1, w)) 0‖ ≤ + (k.factorial : ℝ)⁻¹ * (k.factorial * C / R ^ k) := + mul_le_mul_of_nonneg_left hd (by positivity) + _ = C / R ^ k := by field_simp + rw [norm_smul, norm_pow] + calc + ‖q.2‖ ^ k * ‖hartogsTaylorCoeff f k q.1‖ ≤ r ^ k * (C / R ^ k) := by + gcongr + exact (mem_ball_zero_iff.mp hq.2).le + _ = C * (r / R) ^ k := by simp only [div_eq_mul_inv, mul_pow, inv_pow]; ac_rfl + have hsummable : Summable (fun k : ℕ => C * (r / R) ^ k) := + (summable_geometric_of_lt_one (div_nonneg hr.le hR.le) ((div_lt_one hR).mpr hrR)).mul_left C + refine ⟨N, mem_nhdsWithin_of_mem_nhds ((isOpen_ball.prod isOpen_ball).mem_nhds + ⟨mem_ball_self (half_pos hδ), mem_ball_zero_iff.mpr hpr⟩), ?_⟩ + apply hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + exact (tendstoUniformlyOn_tsum hsummable hterm).congr_right + (fun q hq => (hsum q hq).tsum_eq) + +/-- The Hartogs–Taylor expansion converges locally uniformly on an open complete Hartogs set. -/ +theorem hasSumLocallyUniformlyOn_hartogsTaylor (hU : IsOpen U) (hH : IsCompleteHartogs U) + (hf : DifferentiableOn ℂ f U) : + HasSumLocallyUniformlyOn + (fun k (p : E × ℂ) => p.2 ^ k • hartogsTaylorCoeff f k p.1) f U := + (differentiableOn_hartogsTaylorCoeff_and_hasSumLocallyUniformlyOn hU hH hf).2 + +/-- The canonical Hartogs–Taylor coefficients are holomorphic on the projected base. This follows +from the Taylor expansion theorem. -/ +theorem differentiableOn_hartogsTaylorCoeff (hU : IsOpen U) (hH : IsCompleteHartogs U) + (hf : DifferentiableOn ℂ f U) (k : ℕ) : + DifferentiableOn ℂ (hartogsTaylorCoeff f k) (hartogsBase U) := + (differentiableOn_hartogsTaylorCoeff_and_hasSumLocallyUniformlyOn hU hH hf).1 k + +/-- The Hartogs–Taylor series sums to the function at every point of the set. This follows from the +Taylor expansion theorem. -/ +theorem hasSum_hartogsTaylor (hU : IsOpen U) (hH : IsCompleteHartogs U) + (hf : DifferentiableOn ℂ f U) {p : E × ℂ} (hp : p ∈ U) : + HasSum (fun k => p.2 ^ k • hartogsTaylorCoeff f k p.1) (f p) := + (differentiableOn_hartogsTaylorCoeff_and_hasSumLocallyUniformlyOn hU hH hf).2.hasSum hp + +/-- Hartogs–Taylor sums converge uniformly on each compact subset of the set. This follows from the +Taylor expansion theorem. -/ +theorem tendstoUniformlyOn_hartogsTaylor (hU : IsOpen U) (hH : IsCompleteHartogs U) + (hf : DifferentiableOn ℂ f U) {K : Set (E × ℂ)} (hK : IsCompact K) (hKU : K ⊆ U) : + TendstoUniformlyOn + (fun s : Finset ℕ => fun p : E × ℂ => ∑ k ∈ s, p.2 ^ k • hartogsTaylorCoeff f k p.1) + f Filter.atTop K := + (tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK).mp + ((differentiableOn_hartogsTaylorCoeff_and_hasSumLocallyUniformlyOn hU hH hf).2.mono hKU) + +/-- **Hartogs–Laurent expansion with connected nonempty fibers.** The coefficients are +holomorphic on the whole projected base, the series converges locally uniformly, and +negative coefficients vanish on every fiber containing zero. The one-variable Laurent +expansion follows from Cauchy’s formula on an annulus; fixed-circle integrals +give local holomorphic coefficients and geometric bounds give local uniform convergence. +The independent fiber hypothesis is essential for this global-base formulation. -/ +theorem exists_hartogsLaurent_expansion (hU : IsOpen U) (hH : IsHartogs U) + (hfib : HasPreconnectedFibers U) (hf : DifferentiableOn ℂ f U) : + ∃ a : ℤ → E → F, + (∀ k, DifferentiableOn ℂ (a k) (hartogsBase U)) ∧ + (∀ z, (z, 0) ∈ U → ∀ k : ℤ, k < 0 → a k z = 0) ∧ + HasSumLocallyUniformlyOn (fun k (p : E × ℂ) => p.2 ^ k • a k p.1) f U := by + classical + have hA := hf.analyticOnNhd_of_finiteDimensional hU + have hrad : ∀ z : E, ∃ r : ℝ, 0 < r ∧ (z ∈ hartogsBase U → (z, (r : ℂ)) ∈ U) := by + intro z + by_cases hz : z ∈ hartogsBase U + · obtain ⟨w, hw⟩ := mem_hartogsBase_iff.mp hz + obtain ⟨r, hwr, hrU⟩ := hH.exists_larger_radius hU hw + exact ⟨r, (norm_nonneg _).trans_lt hwr, fun _ => hrU⟩ + · exact ⟨1, zero_lt_one, fun h => (hz h).elim⟩ + choose R hR hRU using hrad + let a : ℤ → E → F := fun k z => circleLaurentCoeff (fun w => f (z, w)) (R z) k + have hLaurent (z : E) (hz : z ∈ hartogsBase U) := circleLaurent_expansion + (isOpen_hartogsFiber hU z) ⟨mem_hartogsBase_iff.mp hz, hfib z⟩ + (fun w hw v hv => hH hw hv) + (fun w hw => (hA (z, w) hw).comp (analyticAt_const.prod analyticAt_id)) + (hR z) (hRU z hz) + have hcoeff (z : E) (r : ℝ) (hr : 0 < r) (hzr : (z, (r : ℂ)) ∈ U) (k : ℤ) : + a k z = circleLaurentCoeff (fun w => f (z, w)) r k := by + exact (congrFun ((hLaurent z ⟨(z, (r : ℂ)), hzr, rfl⟩).2.1 r hr hzr) k).symm + have hzero (z : E) (hz : (z, 0) ∈ U) (k : ℤ) (hk : k < 0) : a k z = 0 := + (hLaurent z ⟨(z, 0), hz, rfl⟩).2.2 hz k hk + have hsum (p : E × ℂ) (hp : p ∈ U) : + HasSum (fun k : ℤ => p.2 ^ k • a k p.1) (f p) := + (hLaurent p.1 ⟨p, hp, rfl⟩).1 p.2 hp + refine ⟨a, ?_, hzero, hasSumLocallyUniformlyOn_hartogsLaurent hH hU hf.continuousOn + hcoeff hzero hsum⟩ + intro k z hz + obtain ⟨δ, _, hδ, _, hc⟩ := hH.exists_circle_bound hU hf.continuousOn (hR z) (hRU z hz) + have hcoeffA := analyticOnNhd_circleLaurentCoeff isOpen_ball hA (hR z) + (fun y hy w hw => (hc y hy w hw).1) k + have heq : (fun y => circleLaurentCoeff (fun w => f (y, w)) (R z) k) =ᶠ[𝓝 z] a k := by + filter_upwards [ball_mem_nhds z hδ] with y hy + exact (hcoeff y (R z) (hR z) (hc y hy (R z : ℂ) (by simp [(hR z).le])).1 k).symm + exact ((hcoeffA z (mem_ball_self hδ)).congr heq).differentiableAt.differentiableWithinAt + +/-- A pointwise version of the Hartogs–Laurent expansion, retaining global holomorphic coefficients +and their vanishing at the zero section. -/ +theorem exists_hasSum_hartogsLaurent (hU : IsOpen U) (hH : IsHartogs U) + (hfib : HasPreconnectedFibers U) (hf : DifferentiableOn ℂ f U) : + ∃ a : ℤ → E → F, + (∀ k, DifferentiableOn ℂ (a k) (hartogsBase U)) ∧ + (∀ z, (z, 0) ∈ U → ∀ k : ℤ, k < 0 → a k z = 0) ∧ + ∀ p ∈ U, HasSum (fun k => p.2 ^ k • a k p.1) (f p) := by + obtain ⟨a, ha, hzero, hsum⟩ := exists_hartogsLaurent_expansion hU hH hfib hf + exact ⟨a, ha, hzero, fun _ hp => hsum.hasSum hp⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity.lean new file mode 100644 index 0000000000..ef9c201bc6 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity.lean @@ -0,0 +1,16 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.BoundaryDistance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Exhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Transport + +/-! Supporting modules for Classical several complex variables. -/ + diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/BoundaryDistance.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/BoundaryDistance.lean new file mode 100644 index 0000000000..7821b14c17 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/BoundaryDistance.lean @@ -0,0 +1,129 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.MetricSpace.Thickening +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull + +/-! +# Boundary distance and compactness of holomorphic hulls + +Distance is taken to the complement and valued in `ℝ≥0∞`. In particular, `boundaryEDistance U ∅ += ∞` and `boundaryEDistance univ K = ∞`. On finite complex coordinate spaces the norm is the +supremum norm, so the balls here are equal-radius polydiscs. + +The radius formulation of hull-distance preservation implies holomorphic convexity by relative +closedness, boundedness, and positive distance from the complement. These purely topological +implications do not depend on Cartan–Thullen or Taylor continuation. + +## Main results + +`HasHolomorphicHullRadiusProperty` is uniform polydisc-radius preservation on hulls. +`HasHolomorphicHullDistanceProperty` is exact preservation of extended boundary distance. Each +implies the other, and each implies `IsHolomorphicallyConvex`. +-/ + +public noncomputable section + +open Set Metric +open scoped ENNReal + +namespace SeveralComplexVariables + +/-- The extended distance of a set to the complement of an ambient set. -/ +@[expose] noncomputable def boundaryEDistance {X : Type*} [PseudoMetricSpace X] (U K : Set X) + : ℝ≥0∞ := + ⨅ x ∈ K, infEDist x Uᶜ + +/-- Empty compact sets have infinite boundary distance. -/ +@[simp] theorem boundaryEDistance_empty {X : Type*} [PseudoMetricSpace X] (U : Set X) : + boundaryEDistance U ∅ = ⊤ := by simp [boundaryEDistance] + +/-- In the whole ambient space every set has infinite boundary distance. -/ +@[simp] theorem boundaryEDistance_univ {X : Type*} [PseudoMetricSpace X] (K : Set X) : + boundaryEDistance univ K = ⊤ := by simp [boundaryEDistance] + +/-- Enlarging a set decreases its distance to the complement. -/ +theorem boundaryEDistance_anti {X : Type*} [PseudoMetricSpace X] {U K L : Set X} + (hKL : K ⊆ L) : boundaryEDistance U L ≤ boundaryEDistance U K := by + exact le_iInf fun x => le_iInf fun hx => iInf₂_le x (hKL hx) + +/-- A lower bound for boundary distance means that all corresponding open balls stay inside the +ambient set. This formulation includes nonpositive radii and empty sets. -/ +theorem ofReal_le_boundaryEDistance_iff {X : Type*} [PseudoMetricSpace X] + {U K : Set X} {r : ℝ} : + ENNReal.ofReal r ≤ boundaryEDistance U K ↔ ∀ x ∈ K, ball x r ⊆ U := by + simp only [boundaryEDistance, le_iInf_iff, le_infEDist] + constructor + · intro h x hx y hy + by_contra hn + have hle := h x hx y hn + have hlt : edist x y < ENNReal.ofReal r := edist_lt_ofReal.mpr + (by simpa only [mem_ball, dist_comm] using hy) + exact (not_lt_of_ge hle) hlt + · intro h x hx y hy + apply le_of_not_gt + intro hlt + exact hy (h x hx (by simpa only [mem_ball, dist_comm] using edist_lt_ofReal.mp hlt)) + +variable {ι : Type*} [Fintype ι] + +/-- Uniform polydisc radii available on a compact set remain available on its holomorphic hull. +Openness is separate from this property. -/ +@[expose] def HasHolomorphicHullRadiusProperty (U : Set (ι → ℂ)) : Prop := + ∀ K, IsCompact K → K ⊆ U → ∀ r : ℝ, 0 < r → + (∀ x ∈ K, ball x r ⊆ U) → ∀ a ∈ holomorphicHull U K, ball a r ⊆ U + +/-- Preservation of the extended boundary distance under taking holomorphic hulls. -/ +@[expose] def HasHolomorphicHullDistanceProperty (U : Set (ι → ℂ)) : Prop := + ∀ K, IsCompact K → K ⊆ U → + boundaryEDistance U (holomorphicHull U K) = boundaryEDistance U K + +/-- The radius property implies exact boundary-distance preservation. -/ +theorem HasHolomorphicHullRadiusProperty.hasHolomorphicHullDistanceProperty {U : Set (ι → ℂ)} + (h : HasHolomorphicHullRadiusProperty U) : HasHolomorphicHullDistanceProperty U := by + intro K hK hKU + apply le_antisymm (boundaryEDistance_anti (subset_holomorphicHull hKU)) + apply ENNReal.le_of_forall_pos_nnreal_lt + intro r hr hrK + have hball : ∀ x ∈ K, ball x (r : ℝ) ⊆ U := + ofReal_le_boundaryEDistance_iff.mp (by simpa using hrK.le) + have hh := h K hK hKU r hr hball + simpa using ofReal_le_boundaryEDistance_iff.mpr hh + +/-- Boundary-distance preservation implies the uniform radius property. -/ +theorem HasHolomorphicHullDistanceProperty.hasHolomorphicHullRadiusProperty {U : Set (ι → ℂ)} + (h : HasHolomorphicHullDistanceProperty U) : HasHolomorphicHullRadiusProperty U := by + intro K hK hKU r _ hr + apply ofReal_le_boundaryEDistance_iff.mp + rw [h K hK hKU] + exact ofReal_le_boundaryEDistance_iff.mpr hr + +/-- Uniform preservation of positive hull radii makes every compact hull compact. -/ +theorem HasHolomorphicHullRadiusProperty.isHolomorphicallyConvex + {U : Set (ι → ℂ)} (h : HasHolomorphicHullRadiusProperty U) (ho : IsOpen U) : + IsHolomorphicallyConvex U := by + intro K hK hKU + obtain ⟨r, hr, hthick⟩ := hK.exists_thickening_subset_open ho hKU + have hb : ∀ x ∈ K, ball x r ⊆ U := by + intro x hx y hy + exact hthick (mem_thickening_iff.mpr ⟨x, hx, hy⟩) + have hH := h K hK hKU r hr hb + have hcl : closure (holomorphicHull U K) ⊆ U := by + intro a ha + obtain ⟨z, hz, hza⟩ := Metric.mem_closure_iff.mp ha r hr + exact hH z hz (by simpa only [mem_ball, dist_comm] using hza) + exact isCompact_holomorphicHull_of_subset_compact + (isBounded_holomorphicHull U hK.isBounded).isCompact_closure hcl subset_closure + +/-- The boundary-distance characterization implies holomorphic convexity. -/ +theorem HasHolomorphicHullDistanceProperty.isHolomorphicallyConvex + {U : Set (ι → ℂ)} (h : HasHolomorphicHullDistanceProperty U) (ho : IsOpen U) : + IsHolomorphicallyConvex U := h.hasHolomorphicHullRadiusProperty.isHolomorphicallyConvex ho + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Exhaustion.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Exhaustion.lean new file mode 100644 index 0000000000..a024810306 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Exhaustion.lean @@ -0,0 +1,264 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Baire.CompleteMetrizable +public import Mathlib.Topology.Baire.Lemmas +public import Mathlib.Topology.Compactness.SigmaCompact +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform + +/-! +# Holomorphically convex exhaustions and escaping sequences + +Separation outside a hull can be amplified by powers to make a function arbitrarily small on the +original set and arbitrarily large at the chosen point. This step is proved. The compact +exhaustion is constructed by repeatedly enlarging compact sets and taking their holomorphic +hulls. The escaping-sequence characterization follows from Baire's theorem in the complete space +of holomorphic functions. Exhaustions use Mathlib's `CompactExhaustion` on the open subtype, +rather than a new topological structure. + +References: [Range][Range1986] II §3.2; [Fritzsche–Grauert][FritzscheGrauert2002] II §6; +[Scheidemann][Scheidemann2005] §7.1. + +## Main results + +`IsHolomorphicallyConvex.exists_compactExhaustion` produces a compact exhaustion by hull-fixed +sets. `isHolomorphicallyConvex_iff_unbounded_on_escaping_sequences` is the escaping-sequence +characterization. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Powers of a separating function give arbitrary smallness on the set and an arbitrary large value +at an exterior hull point. Empty sets are included. -/ +theorem exists_small_large_separator {U K : Set E} {a : E} + (ha : a ∈ U) (hn : a ∉ holomorphicHull U K) {ε : ℝ} (hε : 0 < ε) (R : ℝ) : + ∃ f : E → ℂ, AnalyticOnNhd ℂ f U ∧ (∀ z ∈ K, ‖f z‖ < ε) ∧ R < ‖f a‖ := by + let A : ℝ := max R 0 + 1 + have hA : 0 < A := by dsimp [A]; positivity + have hRA : R < A := by dsimp [A]; linarith [le_max_left R 0] + rcases K.eq_empty_or_nonempty with hK | hK + · subst K + exact ⟨fun _ => (A : ℂ), analyticOnNhd_const, by simp, + by simpa only [Complex.norm_of_nonneg hA.le] using hRA⟩ + obtain ⟨f, hf, M, hM, hMa⟩ := exists_separator_of_notMem_holomorphicHull ha hn + obtain ⟨z₀, hz₀⟩ := hK + have hM0 : 0 ≤ M := (norm_nonneg _).trans (hM z₀ hz₀) + have hfa : 0 < ‖f a‖ := hM0.trans_lt hMa + have hq : M / ‖f a‖ < 1 := (div_lt_one hfa).mpr hMa + obtain ⟨k, hk⟩ := exists_pow_lt_of_lt_one (div_pos hε hA) hq + refine ⟨fun z => (A : ℂ) * (f z / f a) ^ k, + analyticOnNhd_const.mul (hf.div_const.pow k), ?_, ?_⟩ + · intro z hz + rw [norm_mul, Complex.norm_of_nonneg hA.le, norm_pow, norm_div] + calc + A * (‖f z‖ / ‖f a‖) ^ k ≤ A * (M / ‖f a‖) ^ k := by + gcongr + exact hM z hz + _ < ε := (lt_div_iff₀ hA).mp hk |> (by simpa [mul_comm] using ·) + · simpa [div_self (norm_pos_iff.mp hfa), Complex.norm_of_nonneg hA.le, abs_of_pos hA] using hRA + +variable [FiniteDimensional ℂ E] + +/-- Finite-dimensional source spaces are proper. -/ +local instance : ProperSpace E := FiniteDimensional.proper ℂ E + +/-- Finite-dimensional source spaces have countable bases. -/ +local instance : SecondCountableTopology E := + (Module.finBasis ℂ E).equivFunL.toHomeomorph.secondCountableTopology + +/-- A holomorphically convex open set has a compact exhaustion by sets fixed by the relative +holomorphic hull, by recursive refinement of a compact exhaustion. -/ +theorem IsHolomorphicallyConvex.exists_compactExhaustion {U : Set E} + (hU : IsHolomorphicallyConvex U) (ho : IsOpen U) : + ∃ K : CompactExhaustion U, ∀ j, + IsHolomorphicallyConvexIn U ((Subtype.val : U → E) '' K j) := by + let : LocallyCompactSpace U := ho.locallyCompactSpace + let B := CompactExhaustion.choice U + let H (S : Set U) : Set U := + (Subtype.val : U → E) ⁻¹' holomorphicHull U (Subtype.val '' S) + have himage (S : Set U) : Subtype.val '' H S = holomorphicHull U (Subtype.val '' S) := by + apply image_preimage_eq_of_subset + intro z hz + exact ⟨⟨z, hz.1⟩, rfl⟩ + have hcompact (S : Set U) (hS : IsCompact S) : IsCompact (H S) := by + apply Topology.IsEmbedding.subtypeVal.isCompact_iff.mpr + rw [himage] + exact hU _ (hS.image continuous_subtype_val) (by rintro _ ⟨z, _, rfl⟩; exact z.property) + have hsubset (S : Set U) : S ⊆ H S := by + intro z hz + exact subset_holomorphicHull (by rintro _ ⟨w, _, rfl⟩; exact w.property) ⟨z, hz, rfl⟩ + have hfixed (S : Set U) : IsHolomorphicallyConvexIn U (Subtype.val '' H S) := by + rw [himage] + exact isHolomorphicallyConvexIn_holomorphicHull _ _ + let enlarge (S : {S : Set U // IsCompact S}) : {S : Set U // IsCompact S} := + ⟨(exists_compact_superset S.property).choose, (exists_compact_superset + S.property).choose_spec.1⟩ + have henlarge (S : {S : Set U // IsCompact S}) : S.val ⊆ interior (enlarge S).val := + (exists_compact_superset S.property).choose_spec.2 + let K : ℕ → {S : Set U // IsCompact S} := fun j => + Nat.recOn j ⟨H (B 0), hcompact _ (B.isCompact 0)⟩ fun j S => + ⟨H ((enlarge S).val ∪ B (j + 1)), hcompact _ ((enlarge S).property.union (B.isCompact _))⟩ + have hBK (j : ℕ) : B j ⊆ (K j).val := by + cases j with + | zero => exact hsubset _ + | succ j => exact subset_union_right.trans (hsubset _) + refine ⟨{ toFun := fun j => (K j).val + isCompact' := fun j => (K j).property + subset_interior_succ' := ?_ + iUnion_eq' := ?_ }, ?_⟩ + · intro j + exact (henlarge (K j)).trans (interior_mono (subset_union_left.trans (hsubset _))) + · apply iUnion_eq_univ_iff.mpr + intro z + obtain ⟨j, hj⟩ := B.exists_mem z + exact ⟨j, hBK j hj⟩ + · intro j + cases j with + | zero => exact hfixed _ + | succ j => exact hfixed _ + +/-- A sequence escapes compact subsets when it eventually leaves every compact set in the ambient +domain. Its membership in the domain is a separate hypothesis. -/ +@[expose] def EscapesCompactSubsets (U : Set E) (p : ℕ → E) : Prop := + ∀ K : Set E, IsCompact K → K ⊆ U → ∀ᶠ j in atTop, p j ∉ K + +/-- A Baire argument turns functions tending to zero in the compact-open topology, but arbitrarily +large somewhere on a sequence, into one function unbounded there. -/ +private theorem exists_unbounded_of_small_functions + (V : TopologicalSpace.Opens E) (p : ℕ → V) + (hsmall : ∀ M : ℝ, ∃ F : ℕ → HolomorphicMap V ℂ, + Tendsto F atTop (𝓝 0) ∧ ∀ n, ∃ j, M < ‖(F n).val (p j)‖) : + ∃ f : HolomorphicMap V ℂ, ¬ BddAbove (range (fun j => ‖f.val (p j)‖)) := by + let : LocallyCompactSpace V := V.isOpen.locallyCompactSpace + have : (uniformity C(V, ℂ)).IsCountablyGenerated := inferInstance + have : (uniformity (HolomorphicMap V ℂ)).IsCountablyGenerated := + Filter.comap.isCountablyGenerated _ _ + have : TopologicalSpace.IsCompletelyPseudoMetrizableSpace (HolomorphicMap V ℂ) := + .of_completeSpace_pseudometrizable + let : BaireSpace (HolomorphicMap V ℂ) := BaireSpace.of_completelyPseudoMetrizable + by_contra! hb + let A (n : ℕ) : Set (HolomorphicMap V ℂ) := {f | ∀ j, ‖f.val (p j)‖ ≤ n} + have hclosed (n : ℕ) : IsClosed (A n) := by + simp only [A, ofPred_forall] + exact isClosed_iInter fun j => isClosed_le + (continuous_holomorphicMap_eval V (p j)).norm continuous_const + have hcover : ⋃ n, A n = univ := by + apply iUnion_eq_univ_iff.mpr + intro f + obtain ⟨M, hM⟩ := hb f + obtain ⟨n, hn⟩ := exists_nat_ge M + exact ⟨n, fun j => (hM (mem_range_self j)).trans hn⟩ + obtain ⟨N, g, hg⟩ := nonempty_interior_of_iUnion_of_closed hclosed hcover + have hgA : g ∈ A N := interior_subset hg + obtain ⟨F, hlim, hlarge⟩ := hsmall (2 * (N : ℝ)) + have hlim' : Tendsto (fun n => g + F n) atTop (𝓝 g) := by + simpa only [add_zero] using tendsto_const_nhds.add hlim + obtain ⟨n, hn⟩ := (hlim'.eventually (mem_interior_iff_mem_nhds.mp hg)).exists + obtain ⟨j, hj⟩ := hlarge n + have hsum : ‖g.val (p j) + (F n).val (p j)‖ ≤ N := hn j + have hgn := hgA j + have hnorm := norm_sub_le (g.val (p j) + (F n).val (p j)) (g.val (p j)) + simp only [add_sub_cancel_left] at hnorm + linarith + +/-- **Escaping-sequence characterization of holomorphic convexity.** Baire's theorem +and small separating functions give an unbounded holomorphic function on any escaping +sequence; conversely, a noncompact hull contains an escaping sequence. -/ +theorem isHolomorphicallyConvex_iff_unbounded_on_escaping_sequences + {U : Set E} (ho : IsOpen U) : + IsHolomorphicallyConvex U ↔ + ∀ p : ℕ → E, (∀ j, p j ∈ U) → EscapesCompactSubsets U p → + ∃ f : E → ℂ, AnalyticOnNhd ℂ f U ∧ + ¬ BddAbove (Set.range (fun j => ‖f (p j)‖)) := by + classical + let V : TopologicalSpace.Opens E := ⟨U, ho⟩ + let : LocallyCompactSpace V := ho.locallyCompactSpace + let K := CompactExhaustion.choice V + let C (n : ℕ) : Set E := Subtype.val '' K n + have hC (n : ℕ) : IsCompact (C n) := (K.isCompact n).image continuous_subtype_val + have hCU (n : ℕ) : C n ⊆ U := by + rintro _ ⟨z, _, rfl⟩ + exact z.property + have hcofinal {S : Set E} (hS : IsCompact S) (hSU : S ⊆ U) : + ∃ n, S ⊆ C n := by + have he : Subtype.val '' ((Subtype.val : V → E) ⁻¹' S) = S := + image_preimage_eq_of_subset (by intro z hz; exact ⟨⟨z, hSU hz⟩, rfl⟩) + have hc : IsCompact ((Subtype.val : V → E) ⁻¹' S) := + Topology.IsEmbedding.subtypeVal.isCompact_iff.mpr (he.symm ▸ hS) + obtain ⟨n, hn⟩ := K.exists_superset_of_isCompact hc + exact ⟨n, fun z hz => ⟨⟨z, hSU hz⟩, hn hz, rfl⟩⟩ + constructor + · intro hconv p hp hescape + obtain ⟨g, hg⟩ := exists_unbounded_of_small_functions V (fun j => ⟨p j, hp j⟩) (by + intro M + have hsep (n : ℕ) : ∃ f : E → ℂ, AnalyticOnNhd ℂ f U ∧ + (∀ z ∈ C n, ‖f z‖ < 1 / ((n : ℝ) + 1)) ∧ ∃ j, M < ‖f (p j)‖ := by + obtain ⟨j, hj⟩ := (hescape (holomorphicHull U (C n)) + (hconv _ (hC n) (hCU n)) (holomorphicHull_subset _ _)).exists + obtain ⟨f, hf, hs, hl⟩ := exists_small_large_separator (hp j) hj + (by positivity : 0 < 1 / ((n : ℝ) + 1)) (M) + exact ⟨f, hf, hs, j, hl⟩ + choose f hf hs j hj using hsep + let F (n : ℕ) : HolomorphicMap V ℂ := + ⟨⟨fun z => f n z, (hf n).continuousOn.domRestrict⟩, + (hf n).congr ho (fun z hz => by rw [openExtension_apply V _ hz]; rfl)⟩ + have hlim : Tendsto F atTop (𝓝 0) := by + rw [holomorphicMap_tendsto_iff, tendstoLocallyUniformlyOn_iff_forall_isCompact V.isOpen] + intro S hSU hS + obtain ⟨m, hm⟩ := hcofinal hS hSU + rw [Metric.tendstoUniformlyOn_iff] + intro ε hε + have ht := (tendsto_one_div_add_atTop_nhds_zero_nat (𝕜 := ℝ)).eventually + (gt_mem_nhds hε) + filter_upwards [eventually_ge_atTop m, ht] with n hn hεn + intro z hz + rw [openExtension_apply V _ (hSU hz), openExtension_apply V _ (hSU hz)] + change dist (0 : ℂ) (f n z) < ε + rw [dist_zero_left] + exact (hs n z (image_mono (K.subset hn) (hm hz))).trans hεn + exact ⟨F, hlim, fun n => ⟨j n, hj n⟩⟩) + refine ⟨openExtension V g.val, g.property, ?_⟩ + simpa only [openExtension_apply V _ (hp _)] using hg + · intro hseq S hS hSU + by_contra hn + have hex (n : ℕ) : ∃ z ∈ holomorphicHull U S, z ∉ C n := by + by_contra hh + apply hn + apply isCompact_holomorphicHull_of_subset_compact (hC n) (hCU n) + simpa only [not_exists, not_and, not_not, subset_def] using hh + choose p hp hnC using hex + have hpU (n : ℕ) : p n ∈ U := (hp n).1 + have he : EscapesCompactSubsets U p := by + intro T hT hTU + obtain ⟨n, hn⟩ := hcofinal hT hTU + filter_upwards [eventually_ge_atTop n] with m hm hpm + exact hnC m (image_mono (K.subset hm) (hn hpm)) + obtain ⟨f, hf, hnf⟩ := hseq p hpU he + obtain ⟨M, hM⟩ := hS.exists_bound_of_continuousOn (hf.continuousOn.mono hSU) + apply hnf + exact ⟨M, by rintro _ ⟨n, rfl⟩; exact (hp n).2 f hf M hM⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Hull.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Hull.lean new file mode 100644 index 0000000000..07d4d0bac3 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Hull.lean @@ -0,0 +1,266 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Group.Bounded +public import Mathlib.Analysis.Normed.Module.HahnBanach +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity + +/-! +# Holomorphic hulls relative to an ambient set + +The hull is tested by scalar analytic functions on the ambient set. On open sets these are +precisely holomorphic functions. The formulation uses all real upper bounds rather than a real +supremum, so empty sets and unbounded functions have the intended behavior. In particular the +empty hull is empty. Relative closedness is expressed on the ambient subtype; no ambient +closedness or compactness of the hull is assumed. + +References: [Range][Range1986] II §3.2; [Scheidemann][Scheidemann2005] §6.2; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] §2.7. + +## Main results + +`holomorphicHull` is the scalar hull relative to an ambient set, tested by all real modulus +bounds. `IsHolomorphicallyConvex` is the property that compact subsets of an open set have +compact hulls in that set. `exists_separator_of_notMem_holomorphicHull` separates a point +outside the hull. `holomorphicHull_idem` is idempotence. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- The scalar holomorphic hull of `K` relative to `U`, using all real modulus bounds. -/ +@[expose] def holomorphicHull (U K : Set E) : Set E := + {z | z ∈ U ∧ ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → + ∀ M : ℝ, (∀ w ∈ K, ‖f w‖ ≤ M) → ‖f z‖ ≤ M} + +/-- On an open finite-dimensional domain, the hull may equivalently be tested by complex +Fréchet-differentiable scalar functions. -/ +theorem mem_holomorphicHull_iff_differentiableOn [FiniteDimensional ℂ E] + {U K : Set E} (ho : IsOpen U) {z : E} : + z ∈ holomorphicHull U K ↔ z ∈ U ∧ + ∀ f : E → ℂ, DifferentiableOn ℂ f U → + ∀ M : ℝ, (∀ w ∈ K, ‖f w‖ ≤ M) → ‖f z‖ ≤ M := by + constructor + · intro hz + exact ⟨hz.1, fun f hf => hz.2 f (hf.analyticOnNhd_of_finiteDimensional ho)⟩ + · intro hz + exact ⟨hz.1, fun f hf => hz.2 f hf.differentiableOn⟩ + +/-- A holomorphic hull is contained in its ambient set. -/ +theorem holomorphicHull_subset (U K : Set E) : holomorphicHull U K ⊆ U := + fun _ hz => hz.1 + +/-- A set contained in the ambient set is contained in its holomorphic hull. -/ +theorem subset_holomorphicHull {U K : Set E} (hKU : K ⊆ U) : K ⊆ holomorphicHull U K := + fun z hz => ⟨hKU hz, fun _ _ _ h => h z hz⟩ + +/-- Modulus bounds transfer from a set to its holomorphic hull. -/ +theorem norm_le_on_holomorphicHull {U K : Set E} {f : E → ℂ} + (hf : AnalyticOnNhd ℂ f U) {M : ℝ} (hM : ∀ w ∈ K, ‖f w‖ ≤ M) : + ∀ z ∈ holomorphicHull U K, ‖f z‖ ≤ M := + fun _ hz => hz.2 f hf M hM + +/-- Norm bounds transfer from a set to its scalar holomorphic hull for Banach-valued holomorphic +maps, by norming functionals. -/ +theorem norm_le_on_holomorphicHull_vector {U K : Set E} {G : E → F} + (hG : AnalyticOnNhd ℂ G U) {M : ℝ} (hM : ∀ w ∈ K, ‖G w‖ ≤ M) : + ∀ z ∈ holomorphicHull U K, ‖G z‖ ≤ M := by + intro z hz + obtain ⟨ℓ, hℓ, hℓz⟩ := exists_dual_vector'' ℂ (G z) + have hcomp : AnalyticOnNhd ℂ (fun w => ℓ (G w)) U := + (ℓ.analyticOnNhd univ).comp hG (mapsTo_univ _ _) + have := hz.2 _ hcomp M fun w hw => + calc ‖ℓ (G w)‖ ≤ ‖ℓ‖ * ‖G w‖ := ℓ.le_opNorm _ + _ ≤ 1 * M := by + gcongr + exact hM w hw + _ = M := one_mul M + rwa [hℓz, RCLike.norm_ofReal, abs_norm] at this + +/-- Holomorphic hulls are monotone in the set being tested. -/ +theorem holomorphicHull_mono {U K L : Set E} (hKL : K ⊆ L) : + holomorphicHull U K ⊆ holomorphicHull U L := + fun _ hz => ⟨hz.1, fun f hf M h => hz.2 f hf M (fun w hw => h w (hKL hw))⟩ + +/-- Enlarging the ambient set enlarges its relative holomorphic hull. -/ +theorem holomorphicHull_mono_ambient {U V K : Set E} (hUV : U ⊆ V) : + holomorphicHull U K ⊆ holomorphicHull V K := + fun _ hz => ⟨hUV hz.1, fun f hf M h => hz.2 f (hf.mono hUV) M h⟩ + +/-- Taking a holomorphic hull twice has no further effect. -/ +@[simp] theorem holomorphicHull_idem (U K : Set E) : + holomorphicHull U (holomorphicHull U K) = holomorphicHull U K := by + apply Subset.antisymm + · intro z hz + exact ⟨hz.1, fun f hf M h => hz.2 f hf M (norm_le_on_holomorphicHull hf h)⟩ + · exact subset_holomorphicHull (holomorphicHull_subset U K) + +/-- The empty set has empty holomorphic hull, in every ambient set. -/ +@[simp] theorem holomorphicHull_empty (U : Set E) : holomorphicHull U ∅ = ∅ := by + apply eq_empty_iff_forall_notMem.mpr + intro z hz + have h := hz.2 (fun _ => 0) analyticOnNhd_const (-1) (by simp) + norm_num at h + +/-- The ambient set is fixed by its holomorphic hull. -/ +@[simp] theorem holomorphicHull_self (U : Set E) : holomorphicHull U U = U := + Subset.antisymm (holomorphicHull_subset _ _) (subset_holomorphicHull Subset.rfl) + +/-- The holomorphic hull is closed relative to its ambient set. -/ +theorem isClosed_holomorphicHull_preimage (U K : Set E) : + IsClosed ((Subtype.val : U → E) ⁻¹' holomorphicHull U K) := by + have he : (Subtype.val : U → E) ⁻¹' holomorphicHull U K = + ⋂ (f : E → ℂ) (hf : AnalyticOnNhd ℂ f U) (M : ℝ) + (_ : ∀ w ∈ K, ‖f w‖ ≤ M), {z : U | ‖f z‖ ≤ M} := by + ext z + simp [holomorphicHull] + rw [he] + exact isClosed_iInter fun f => isClosed_iInter fun hf => + isClosed_iInter fun M => isClosed_iInter fun _ => + isClosed_le (continuousOn_iff_continuous_domRestrict.mp hf.continuousOn).norm continuous_const + +/-- A point of the ambient set outside the hull is separated by a scalar holomorphic function and a +strict modulus bound. -/ +theorem exists_separator_of_notMem_holomorphicHull {U K : Set E} {z : E} + (hz : z ∈ U) (hn : z ∉ holomorphicHull U K) : + ∃ f : E → ℂ, AnalyticOnNhd ℂ f U ∧ ∃ M : ℝ, + (∀ w ∈ K, ‖f w‖ ≤ M) ∧ M < ‖f z‖ := by + simpa only [holomorphicHull, mem_ofPred_eq, hz, true_and, not_forall, not_le, + exists_prop] using hn + +/-- Holomorphic maps carry relative hulls into relative hulls. -/ +theorem mapsTo_holomorphicHull {U K : Set E} {V : Set F} {g : E → F} + (hg : AnalyticOnNhd ℂ g U) (hgV : MapsTo g U V) : + MapsTo g (holomorphicHull U K) (holomorphicHull V (g '' K)) := by + intro z hz + refine ⟨hgV hz.1, fun f hf M hM => ?_⟩ + exact hz.2 (f ∘ g) (hf.comp hg hgV) M (fun w hw => hM (g w) ⟨w, hw, rfl⟩) + +/-- A set is holomorphically convex relative to `U` when its hull equals itself. -/ +@[expose] def IsHolomorphicallyConvexIn (U K : Set E) : Prop := holomorphicHull U K = K + +/-- Every holomorphic hull is holomorphically convex relative to its ambient set. -/ +theorem isHolomorphicallyConvexIn_holomorphicHull (U K : Set E) : + IsHolomorphicallyConvexIn U (holomorphicHull U K) := holomorphicHull_idem U K + +/-- Holomorphic convexity of an ambient set means compactness of the hull of each compact subset. +Openness and connectedness are separate hypotheses. -/ +@[expose] def IsHolomorphicallyConvex (U : Set E) : Prop := + ∀ K : Set E, IsCompact K → K ⊆ U → IsCompact (holomorphicHull U K) + +/-- The empty ambient set is holomorphically convex. -/ +theorem isHolomorphicallyConvex_empty : IsHolomorphicallyConvex (∅ : Set E) := by + intro K _ _ + have : holomorphicHull (∅ : Set E) K = ∅ := + subset_empty_iff.mp (holomorphicHull_subset _ _) + rw [this] + exact isCompact_empty + +/-- A relative holomorphic hull contained in a compact subset of its ambient set is compact. -/ +theorem isCompact_holomorphicHull_of_subset_compact {U K C : Set E} + (hC : IsCompact C) (hCU : C ⊆ U) (hHC : holomorphicHull U K ⊆ C) : + IsCompact (holomorphicHull U K) := by + obtain ⟨S, hS, he⟩ := isClosed_induced_iff.mp (isClosed_holomorphicHull_preimage U K) + have heq : holomorphicHull U K = C ∩ S := by + ext z + constructor + · intro hz + refine ⟨hHC hz, ?_⟩ + have h := Set.ext_iff.mp he ⟨z, (holomorphicHull_subset U K) hz⟩ + exact h.mpr hz + · rintro ⟨hzC, hzS⟩ + have h := Set.ext_iff.mp he ⟨z, hCU hzC⟩ + exact h.mp hzS + rw [heq] + exact hC.inter_right hS + +/-- Finite intersections preserve holomorphic convexity of ambient sets. -/ +theorem IsHolomorphicallyConvex.inter {U V : Set E} + (hU : IsHolomorphicallyConvex U) (hV : IsHolomorphicallyConvex V) : + IsHolomorphicallyConvex (U ∩ V) := by + intro K hK hKU + apply isCompact_holomorphicHull_of_subset_compact + ((hU K hK (hKU.trans inter_subset_left)).inter + (hV K hK (hKU.trans inter_subset_right))) + · rintro z ⟨hzU, hzV⟩ + exact ⟨hzU.1, hzV.1⟩ + · intro z hz + exact ⟨holomorphicHull_mono_ambient inter_subset_left hz, + holomorphicHull_mono_ambient inter_subset_right hz⟩ + +/-- In finite coordinate spaces, the hull of a bounded set is bounded. -/ +theorem isBounded_holomorphicHull {ι : Type*} [Fintype ι] + (U : Set (ι → ℂ)) {K : Set (ι → ℂ)} (hK : Bornology.IsBounded K) : + Bornology.IsBounded (holomorphicHull U K) := by + obtain ⟨M, hM⟩ := hK.exists_norm_le + apply (isBounded_iff_forall_norm_le).mpr + refine ⟨max M 0, fun z hz => (pi_norm_le_iff_of_nonneg (le_max_right _ _)).mpr fun i => ?_⟩ + exact (hz.2 (fun w => w i) ((ContinuousLinearMap.proj i : (ι → ℂ) →L[ℂ] ℂ).analyticOnNhd U) M + (fun w hw => (norm_le_pi_norm w i).trans (hM w hw))).trans (le_max_left _ _) + +/-- A singleton has no additional hull points; if it lies outside the ambient set, its relative hull +is empty. Empty coordinate types are included. -/ +@[simp] theorem holomorphicHull_singleton {ι : Type*} [Fintype ι] + (U : Set (ι → ℂ)) (a : ι → ℂ) : holomorphicHull U {a} = U ∩ {a} := by + ext z + constructor + · intro hz + refine ⟨hz.1, ?_⟩ + have he : z = a := by + ext i + have hf : AnalyticOnNhd ℂ (fun w : ι → ℂ => w i - a i) U := + ((ContinuousLinearMap.proj i : (ι → ℂ) →L[ℂ] ℂ).analyticOnNhd U).sub analyticOnNhd_const + have h := hz.2 _ hf 0 (by simp) + exact sub_eq_zero.mp (norm_le_zero_iff.mp h) + exact mem_singleton_iff.mpr he + · rintro ⟨hz, rfl⟩ + exact ⟨hz, fun f hf M hM => hM z (mem_singleton z)⟩ + +/-- The full finite-dimensional coordinate space is holomorphically convex. -/ +theorem isHolomorphicallyConvex_univ {ι : Type*} [Fintype ι] : + IsHolomorphicallyConvex (univ : Set (ι → ℂ)) := by + intro K hK _ + obtain ⟨r, hr⟩ := (Metric.isBounded_iff_subset_closedBall (0 : ι → ℂ)).mp + (isBounded_holomorphicHull univ hK.isBounded) + exact isCompact_holomorphicHull_of_subset_compact (isCompact_closedBall 0 r) + (subset_univ _) hr + +/-- Continuous complex-linear equivalences preserve holomorphic convexity. -/ +theorem IsHolomorphicallyConvex.image_equiv {U : Set E} + (hU : IsHolomorphicallyConvex U) (L : E ≃L[ℂ] F) : + IsHolomorphicallyConvex (L '' U) := by + intro K hK hKU + have hmap : MapsTo L.symm (L '' U) U := by + rintro _ ⟨z, hz, rfl⟩ + simpa using hz + have hc := hU (L.symm '' K) (hK.image L.symm.continuous) + (by rintro _ ⟨z, hz, rfl⟩; exact hmap (hKU hz)) + apply isCompact_holomorphicHull_of_subset_compact (hc.image L.continuous) + · rintro _ ⟨z, hz, rfl⟩ + exact ⟨z, hz.1, rfl⟩ + · intro z hz + exact ⟨L.symm z, + mapsTo_holomorphicHull (L.symm.toContinuousLinearMap.analyticOnNhd _) hmap hz, + L.apply_symm_apply z⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Thullen.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Thullen.lean new file mode 100644 index 0000000000..dbaf7ab88d --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Thullen.lean @@ -0,0 +1,328 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Module.Ball.Pointwise +public import Mathlib.Analysis.Normed.Module.Connected +public import Mathlib.Analysis.Normed.Module.HahnBanach +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DomainOfHolomorphy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.BoundaryDistance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscTaylor +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Analytic + +/-! +# Thullen's lemma and the boundary distance of holomorphic hulls + +Cauchy bounds on compact families of smaller balls control Taylor coefficients weighted by +powers of a scalar holomorphic radius. These bounds transfer to the holomorphic hull, for +Banach-valued functions by norming functionals, and give Taylor continuation on the indicated +polydisc. Agreement is asserted near the center, not on unrelated components of the overlap. +This proves radius preservation, exact hull boundary distance, and holomorphic convexity for +domains of holomorphy. + +References: [Scheidemann][Scheidemann2005] §6.2 and §7.3; [Hörmander][Hormander1973] §2.5; +[Korevaar–Wiegerinck][KorevaarWiegerinck2017] §6.4. + +## Main results + +`taylor_continuation_on_holomorphicHull` is Thullen's Taylor continuation lemma for +Banach-valued functions. `IsDomainOfHolomorphy.holomorphic_radius_bound` is the weighted radius +bound. `IsDomainOfHolomorphy.hasHolomorphicHullRadiusProperty` and +`hasHolomorphicHullDistanceProperty` are the hull-radius and boundary-distance forms. +`IsDomainOfHolomorphy.isHolomorphicallyConvex` is the forward Cartan–Thullen implication. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology ENNReal Pointwise + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Mixed derivative bounds transfer to the holomorphic hull of the set on which they hold, for +Banach-valued functions. This elementary step is independent of the Taylor continuation theorem. -/ +theorem norm_multiIndexDeriv_le_on_holomorphicHull {U K : Set (Fin n → ℂ)} + (ho : IsOpen U) {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + (m : Fin n → ℕ) {M : ℝ} (hM : ∀ z ∈ K, ‖multiIndexDeriv m f z‖ ≤ M) : + ∀ z ∈ holomorphicHull U K, ‖multiIndexDeriv m f z‖ ≤ M := + norm_le_on_holomorphicHull_vector (hf.iteratedPartialDeriv ho (multiIndexList m)) hM + +/-- The Taylor sum of a Banach-valued function centered at an arbitrary point, using the normalized +multivariate Taylor coefficients. -/ +@[expose] def taylorSumAt (f : (Fin n → ℂ) → F) (a z : Fin n → ℂ) : F := + powerSeriesSum (holomorphicTaylorSeries f a) (z - a) + +omit [CompleteSpace F] in +/-- Separate analyticity on a closed polydisc from joint analyticity. -/ +theorem analyticAt_update_of_analyticOnNhd_closedPolydisc {f : (Fin n → ℂ) → F} + {a : Fin n → ℂ} {r : ℝ} (hA : AnalyticOnNhd ℂ f (closedPolydisc a (fun _ => r))) : + ∀ z ∈ closedPolydisc a (fun _ => r), ∀ i, + AnalyticAt ℂ (fun v => f (Function.update z i v)) (z i) := by + intro z hz i + exact hA.analyticAt_update hz i + +/-- A bound on a closed coordinate ball bounds each normalized Taylor coefficient. -/ +theorem norm_taylorCoeff_le {U : Set (Fin n → ℂ)} + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {a : Fin n → ℂ} {r M : ℝ} (hr : 0 < r) (hball : closedBall a r ⊆ U) + (hM : ∀ z ∈ closedBall a r, ‖f z‖ ≤ M) (m : Fin n →₀ ℕ) : + ‖holomorphicTaylorSeries f a m‖ ≤ M * ∏ i, r⁻¹ ^ m i := by + have he : closedPolydisc a (fun _ => r) = closedBall a r := by + rw [closedPolydisc_eq_closedBall hr.le] + have hA : AnalyticOnNhd ℂ f (closedPolydisc a (fun _ => r)) := + hf.mono (he ▸ hball) + rw [coeff_holomorphicTaylorSeries (fun _ => hr) hA.continuousOn + (analyticAt_update_of_analyticOnNhd_closedPolydisc hA)] + exact norm_polydiscCauchyCoeffWithRadii_le (fun _ => hr) (he ▸ hM) m + +/-- The normalized Taylor sum of an analytic germ agrees with its representative nearby. -/ +theorem taylorSumAt_eventuallyEq {f : (Fin n → ℂ) → F} {a : Fin n → ℂ} + (hf : AnalyticAt ℂ f a) : taylorSumAt f a =ᶠ[𝓝 a] f := by + classical + have hb := hf.continuousAt.norm.eventually_lt_const + (show ‖f a‖ < ‖f a‖ + 1 by linarith) + obtain ⟨r, hr, hball⟩ := Metric.mem_nhds_iff.mp (hf.eventually_analyticAt.and hb) + have hr₂ : 0 < r / 2 := half_pos hr + have hsub : closedPolydisc a (fun _ => r / 2) ⊆ ball a r := by + rw [closedPolydisc_eq_closedBall hr₂.le] + exact closedBall_subset_ball (half_lt_self hr) + have hA : AnalyticOnNhd ℂ f (closedPolydisc a (fun _ => r / 2)) := + fun z hz => (hball (hsub hz)).1 + have hs := analyticAt_update_of_analyticOnNhd_closedPolydisc hA + filter_upwards [ball_mem_nhds a hr₂] with z hz + have hh : ∀ i, ‖(z - a) i‖ < r / 2 := fun i => + (norm_le_pi_norm (z - a) i).trans_lt (by simpa only [mem_ball, dist_eq_norm] using hz) + have hsum := hasSum_polydiscTaylor (fun _ => hr₂) hh hA.continuousOn hs + (fun z hz => (hball (hsub hz)).2.le) + have hc (m : Fin n →₀ ℕ) : + polydiscCauchyCoeffWithRadii f a (fun _ => r / 2) (Finsupp.equivFunOnFinite m) = + holomorphicTaylorSeries f a m := + (coeff_holomorphicTaylorSeries (fun _ => hr₂) hA.continuousOn hs m).symm + have H := (Finsupp.equivFunOnFinite.hasSum_iff).mpr hsum + simpa only [taylorSumAt, powerSeriesSum, Pi.sub_apply, hc, + add_sub_cancel, Function.comp_apply, Finsupp.equivFunOnFinite_apply] using H.tsum_eq + +/-- Shrinking a continuous radius on a compact set gives uniform weighted Cauchy bounds. -/ +private theorem exists_bound_taylorCoeff_mul_radius {U K : Set (Fin n → ℂ)} + (hK : IsCompact K) (hKU : K ⊆ U) + {q : (Fin n → ℂ) → ℂ} {f : (Fin n → ℂ) → F} (hq : AnalyticOnNhd ℂ q U) + (hf : AnalyticOnNhd ℂ f U) + (hr : ∀ w ∈ K, ball w ‖q w‖ ⊆ U) {t : ℝ} (ht : 0 < t) (ht1 : t < 1) : + ∃ M : ℝ, 0 ≤ M ∧ ∀ (m : Fin n →₀ ℕ) w, w ∈ K → + ‖holomorphicTaylorSeries f w m‖ * (t * ‖q w‖) ^ (∑ i, m i) ≤ M := by + classical + let T := (fun p : (Fin n → ℂ) × (Fin n → ℂ) => p.1 + ((t : ℂ) * q p.1) • p.2) '' + (K ×ˢ closedBall 0 1) + have hTc : IsCompact T := (hK.prod (isCompact_closedBall _ _)).image_of_continuousOn + (continuous_fst.continuousOn.add ((continuousOn_const.mul + (hq.continuousOn.comp continuous_fst.continuousOn (fun _ h => hKU h.1))).smul + continuous_snd.continuousOn)) + have hTU : T ⊆ U := by + rintro _ ⟨⟨w, v⟩, ⟨hw, hv⟩, rfl⟩ + by_cases hq0 : q w = 0 + · simpa [hq0] using hKU hw + apply hr w hw + rw [mem_ball, dist_eq_norm, add_sub_cancel_left, norm_smul, norm_mul, + Complex.norm_of_nonneg ht.le] + have hv' : ‖v‖ ≤ 1 := by simpa only [mem_closedBall, dist_zero_right] using hv + calc + t * ‖q w‖ * ‖v‖ ≤ t * ‖q w‖ * 1 := mul_le_mul_of_nonneg_left hv' (by positivity) + _ < ‖q w‖ := by nlinarith [norm_pos_iff.mpr hq0] + have hballT (w) (hw : w ∈ K) : closedBall w (t * ‖q w‖) ⊆ T := by + intro z hz + have hz' : z - w ∈ ((t : ℂ) * q w) • closedBall (0 : Fin n → ℂ) 1 := by + rw [smul_unitClosedBall, norm_mul, Complex.norm_of_nonneg ht.le] + simpa only [mem_closedBall, dist_zero_right, dist_eq_norm, sub_zero] using hz + obtain ⟨v, hv, he⟩ := hz' + dsimp only at he + exact ⟨(w, v), ⟨hw, hv⟩, by dsimp; rw [he]; abel⟩ + obtain ⟨M, hM⟩ := hTc.exists_bound_of_continuousOn (hf.continuousOn.mono hTU) + refine ⟨max M 0, le_max_right _ _, fun m w hw => ?_⟩ + by_cases hq0 : q w = 0 + · by_cases hm : m = 0 + · subst m + simpa [holomorphicTaylorSeries, multiIndexDeriv, multiIndexList, iteratedPartialDeriv] + using (hM w (hballT w hw (mem_closedBall_self (by positivity)))).trans (le_max_left M 0) + · have hmpos : 0 < ∑ i, m i := by + obtain ⟨i, hi⟩ := Finsupp.ne_iff.mp hm + exact (Nat.pos_of_ne_zero hi).trans_le (Finset.single_le_sum (fun _ _ => Nat.zero_le _) + (Finset.mem_univ i)) + simp [hq0, zero_pow hmpos.ne'] + · have hR : 0 < t * ‖q w‖ := mul_pos ht (norm_pos_iff.mpr hq0) + have hb := norm_taylorCoeff_le hf hR ((hballT w hw).trans hTU) + (fun z hz => hM z (hballT w hw hz)) m + have hp : (∏ i, (t * ‖q w‖)⁻¹ ^ m i) * (t * ‖q w‖) ^ (∑ i, m i) = 1 := by + rw [Finset.prod_pow_eq_pow_sum, ← mul_pow, inv_mul_cancel₀ hR.ne', one_pow] + calc + _ ≤ (M * ∏ i, (t * ‖q w‖)⁻¹ ^ m i) * (t * ‖q w‖) ^ (∑ i, m i) := by + gcongr + _ = M := by rw [mul_assoc, hp, mul_one] + _ ≤ max M 0 := le_max_left _ _ + +/-- **Thullen's lemma, with a holomorphic radius bound.** For a Banach-valued function, +the Taylor series centered at a hull point converges locally uniformly on the indicated +polydisc and continues the original germ. The proof transfers uniform weighted Cauchy bounds +from compact families of smaller balls to the hull, then compares with a product of geometric +series. -/ +theorem taylor_continuation_on_holomorphicHull {U K : Set (Fin n → ℂ)} + (ho : IsOpen U) (hK : IsCompact K) (hKU : K ⊆ U) + {q : (Fin n → ℂ) → ℂ} {f : (Fin n → ℂ) → F} (hq : AnalyticOnNhd ℂ q U) + (hf : AnalyticOnNhd ℂ f U) + (hr : ∀ w ∈ K, ball w ‖q w‖ ⊆ U) {a : Fin n → ℂ} (ha : a ∈ holomorphicHull U K) : + AnalyticOnNhd ℂ (taylorSumAt f a) (ball a ‖q a‖) ∧ + taylorSumAt f a =ᶠ[𝓝 a] f ∧ + HasSumLocallyUniformlyOn + (fun (m : Fin n →₀ ℕ) z => (∏ i, (z i - a i) ^ m i) • holomorphicTaylorSeries f a m) + (taylorSumAt f a) (ball a ‖q a‖) := by + classical + have hbound {t : ℝ} (ht : 0 < t) (ht1 : t < 1) : + ∃ M : ℝ, 0 ≤ M ∧ ∀ m : Fin n →₀ ℕ, + ‖holomorphicTaylorSeries f a m‖ * (t * ‖q a‖) ^ (∑ i, m i) ≤ M := by + obtain ⟨M, hM0, hM⟩ := exists_bound_taylorCoeff_mul_radius hK hKU hq hf hr ht ht1 + refine ⟨M, hM0, fun m => ?_⟩ + have hg : AnalyticOnNhd ℂ + (fun w => ((t : ℂ) * q w) ^ (∑ i, m i) • holomorphicTaylorSeries f w m) U := + ((analyticOnNhd_const.mul hq).pow _).smul + (analyticOnNhd_const.smul (hf.iteratedPartialDeriv ho (multiIndexList m))) + have hnorm (w) : + ‖((t : ℂ) * q w) ^ (∑ i, m i) • holomorphicTaylorSeries f w m‖ = + ‖holomorphicTaylorSeries f w m‖ * (t * ‖q w‖) ^ (∑ i, m i) := by + rw [norm_smul, norm_pow, norm_mul, Complex.norm_of_nonneg ht.le, mul_comm] + exact (hnorm a) ▸ norm_le_on_holomorphicHull_vector hg + (fun w hw => (hnorm w).symm ▸ hM m w hw) a ha + have habs : ball (0 : Fin n → ℂ) ‖q a‖ ⊆ + powerSeriesAbsConvergenceSet (holomorphicTaylorSeries f a) := by + intro z hz + have hzq : ‖z‖ < ‖q a‖ := by simpa only [mem_ball, dist_zero_right] using hz + obtain ⟨r, hzr, hrq⟩ := exists_between hzq + have hr0 : 0 < r := (norm_nonneg z).trans_lt hzr + have hq0 : 0 < ‖q a‖ := hr0.trans hrq + obtain ⟨M, hM0, hM⟩ := hbound (div_pos hr0 hq0) ((div_lt_one hq0).mpr hrq) + simp only [div_mul_cancel₀ _ hq0.ne'] at hM + have hratio : ‖‖z‖ / r‖ < 1 := by + rw [Real.norm_eq_abs, abs_of_nonneg (div_nonneg (norm_nonneg _) hr0.le)] + exact (div_lt_one hr0).mpr hzr + have hsum := ((hasSum_pi_geometric (fun _ : Fin n => ‖z‖ / r) + (fun _ => hratio)).summable.mul_left M).comp_injective Finsupp.equivFunOnFinite.injective + apply hsum.of_nonneg_of_le (fun _ => by positivity) + intro m + calc + ‖holomorphicTaylorSeries f a m‖ * ∏ i, ‖z i‖ ^ m i ≤ + ‖holomorphicTaylorSeries f a m‖ * ∏ i, ‖z‖ ^ m i := by + gcongr + exact norm_le_pi_norm z _ + _ = (‖holomorphicTaylorSeries f a m‖ * r ^ (∑ i, m i)) * + ∏ i, (‖z‖ / r) ^ m i := by + rw [Finset.prod_pow_eq_pow_sum, Finset.prod_pow_eq_pow_sum, div_pow] + field_simp + _ ≤ M * ∏ i, (‖z‖ / r) ^ m i := by + apply mul_le_mul_of_nonneg_right (hM m) + positivity + have hdom : ball (0 : Fin n → ℂ) ‖q a‖ ⊆ + powerSeriesConvergenceDomain (holomorphicTaylorSeries f a) := + isOpen_ball.subset_interior_iff.mpr habs + have hmaps : MapsTo (fun z => z - a) (ball a ‖q a‖) + (powerSeriesConvergenceDomain (holomorphicTaylorSeries f a)) := by + intro z hz + apply hdom + simpa only [mem_ball, dist_zero_right, dist_eq_norm, sub_zero] using hz + refine ⟨(analyticOnNhd_powerSeriesSum _).comp + (analyticOnNhd_id.sub analyticOnNhd_const) hmaps, + taylorSumAt_eventuallyEq (hf a ha.1), ?_⟩ + have hs := (hasSumLocallyUniformlyOn_powerSeries (holomorphicTaylorSeries f a)).comp + (fun z => z - a) hmaps (continuous_id.sub continuous_const).continuousOn + unfold taylorSumAt + simpa only [HasSumLocallyUniformlyOn, Function.comp_def, Pi.sub_apply, + Finset.sum_apply] using hs + +/-- The constant-radius form of Thullen's continuation lemma, for Banach-valued functions. -/ +theorem exists_continuation_ball_of_mem_holomorphicHull {U K : Set (Fin n → ℂ)} + (ho : IsOpen U) (hK : IsCompact K) (hKU : K ⊆ U) {r : ℝ} (hr : 0 < r) + (hball : ∀ w ∈ K, ball w r ⊆ U) {a : Fin n → ℂ} (ha : a ∈ holomorphicHull U K) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) : + ∃ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (ball a r) ∧ g =ᶠ[𝓝 a] f := by + have hnorm : ‖(r : ℂ)‖ = r := Complex.norm_of_nonneg hr.le + have h := taylor_continuation_on_holomorphicHull ho hK hKU + (q := fun _ => (r : ℂ)) analyticOnNhd_const hf (by simpa only [hnorm] using hball) ha + exact ⟨taylorSumAt f a, by simpa only [hnorm] using h.1, h.2.1⟩ + +/-- On a domain of holomorphy, a ball supporting continuation of every germ at its center must lie +in the domain. The overlap is chosen uniformly, independently of the function. -/ +theorem IsDomainOfHolomorphy.ball_subset_of_continuation {U : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) {a : Fin n → ℂ} (ha : a ∈ U) + {r : ℝ} (hr : 0 < r) + (he : ∀ f : (Fin n → ℂ) → ℂ, AnalyticOnNhd ℂ f U → + ∃ g, AnalyticOnNhd ℂ g (ball a r) ∧ g =ᶠ[𝓝 a] f) : ball a r ⊆ U := by + obtain ⟨ε, hε, hεU⟩ := Metric.isOpen_iff.mp ho a ha + let W := ball a (min ε r) + have haW : a ∈ W := mem_ball_self (lt_min hε hr) + have hWU : W ⊆ U := (ball_subset_ball (min_le_left _ _)).trans hεU + have hWV : W ⊆ ball a r := ball_subset_ball (min_le_right _ _) + apply hU (ball a r) W isOpen_ball (isConnected_ball hr) isOpen_ball ⟨a, haW⟩ hWU hWV + intro f hf + obtain ⟨g, hg, heq⟩ := he f hf + exact ⟨g, hg, (hg.mono hWV).eqOn_of_preconnected_of_eventuallyEq + (hf.mono hWU) isPreconnected_ball haW heq⟩ + +/-- A domain of holomorphy preserves every radius bound supplied by a holomorphic function on a +compact set, by Thullen's continuation lemma. -/ +theorem IsDomainOfHolomorphy.holomorphic_radius_bound {U K : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) (hK : IsCompact K) (hKU : K ⊆ U) + {q : (Fin n → ℂ) → ℂ} (hq : AnalyticOnNhd ℂ q U) + (hr : ∀ w ∈ K, ball w ‖q w‖ ⊆ U) : + ∀ a ∈ holomorphicHull U K, ball a ‖q a‖ ⊆ U := by + intro a ha + by_cases hqa : ‖q a‖ = 0 + · simp [hqa] + · apply hU.ball_subset_of_continuation ho ha.1 (lt_of_le_of_ne (norm_nonneg _) (Ne.symm hqa)) + intro f hf + have h := taylor_continuation_on_holomorphicHull ho hK hKU hq hf hr ha + exact ⟨taylorSumAt f a, h.1, h.2.1⟩ + +/-- Domains of holomorphy preserve uniform polydisc radii on compact hulls. -/ +theorem IsDomainOfHolomorphy.hasHolomorphicHullRadiusProperty {U : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : HasHolomorphicHullRadiusProperty U := by + intro K hK hKU r hr hball a ha + exact hU.ball_subset_of_continuation ho ha.1 hr fun _ hf => + exists_continuation_ball_of_mem_holomorphicHull ho hK hKU hr hball ha hf + +/-- The boundary distance of a compact holomorphic hull equals that of the original compact set in a +domain of holomorphy. -/ +theorem IsDomainOfHolomorphy.hasHolomorphicHullDistanceProperty {U : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : HasHolomorphicHullDistanceProperty U := + (hU.hasHolomorphicHullRadiusProperty ho).hasHolomorphicHullDistanceProperty + +/-- **Cartan–Thullen, forward implication.** A domain of holomorphy is holomorphically +convex, by Thullen's Taylor continuation lemma and the hull-radius criterion. This coordinate +case supplies the proof for general finite-dimensional spaces below. -/ +private theorem IsDomainOfHolomorphy.isHolomorphicallyConvex_fin {U : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : IsHolomorphicallyConvex U := + (hU.hasHolomorphicHullRadiusProperty ho).isHolomorphicallyConvex ho + +/-- **Cartan–Thullen, forward implication.** An open domain of holomorphy in any +finite-dimensional complex normed space is holomorphically convex. Linear transport of hull +compactness is used here; no invariance of numerical boundary distance is asserted. -/ +theorem IsDomainOfHolomorphy.isHolomorphicallyConvex + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U : Set E} (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : + IsHolomorphicallyConvex U := by + let L := (Module.finBasis ℂ E).equivFunL + have h := (hU.image_equiv L).isHolomorphicallyConvex_fin + (L.toHomeomorph.isOpenMap U ho) + simpa only [Set.image_image, Function.comp_def, L.symm_apply_apply, Set.image_id'] using + h.image_equiv L.symm + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Transport.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Transport.lean new file mode 100644 index 0000000000..edde0d5d97 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicConvexity/Transport.lean @@ -0,0 +1,115 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull + +/-! +# Products and biholomorphic transport of holomorphic convexity + +Products preserve holomorphic convexity. Biholomorphic maps transport relative hulls exactly and +preserve holomorphic convexity of their open source and target. These results are proved +directly from the hull definition and compactness; they do not depend on Cartan–Thullen. + +References: [Range][Range1986] II §3.3; [Scheidemann][Scheidemann2005] §7.1; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] §2.7. + +## Main results + +`IsHolomorphicallyConvex.prod` is stability under products. `IsBiholomorphic.image_holomorphicHull` +transports relative hulls. `IsBiholomorphic.isHolomorphicallyConvex_iff` is invariance of +holomorphic convexity. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Set + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- Products of holomorphically convex ambient sets are holomorphically convex. -/ +theorem IsHolomorphicallyConvex.prod {U : Set E} {V : Set F} + (hU : IsHolomorphicallyConvex U) (hV : IsHolomorphicallyConvex V) : + IsHolomorphicallyConvex (U ×ˢ V) := by + intro K hK hKU + have hfst : MapsTo (Prod.fst : E × F → E) (U ×ˢ V) U := fun _ hz => hz.1 + have hsnd : MapsTo (Prod.snd : E × F → F) (U ×ˢ V) V := fun _ hz => hz.2 + apply isCompact_holomorphicHull_of_subset_compact + ((hU _ (hK.image continuous_fst) (by rintro _ ⟨z, hz, rfl⟩; exact (hKU hz).1)).prod + (hV _ (hK.image continuous_snd) (by rintro _ ⟨z, hz, rfl⟩; exact (hKU hz).2))) + · rintro z ⟨hzU, hzV⟩ + exact ⟨hzU.1, hzV.1⟩ + · intro z hz + exact ⟨mapsTo_holomorphicHull analyticOnNhd_fst hfst hz, + mapsTo_holomorphicHull analyticOnNhd_snd hsnd hz⟩ + +variable [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] + +/-- Biholomorphic maps transport relative holomorphic hulls exactly. -/ +theorem IsBiholomorphic.image_holomorphicHull {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) {K : Set E} (hK : K ⊆ e.source) : + e '' holomorphicHull e.source K = holomorphicHull e.target (e '' K) := by + let := FiniteDimensional.complete ℂ E + let := FiniteDimensional.complete ℂ F + have hf := he.1.analyticOnNhd_of_finiteDimensional e.open_source + have hg := he.2.analyticOnNhd_of_finiteDimensional e.open_target + have hback : e.symm '' (e '' K) = K := by + ext x + constructor + · rintro ⟨_, ⟨z, hz, rfl⟩, rfl⟩ + simpa only [e.left_inv (hK hz)] using hz + · intro hx + exact ⟨e x, ⟨x, hx, rfl⟩, e.left_inv (hK hx)⟩ + apply Subset.antisymm + · rintro _ ⟨z, hz, rfl⟩ + exact mapsTo_holomorphicHull hf (fun _ hx => e.map_source hx) hz + · intro z hz + have h := mapsTo_holomorphicHull hg (fun _ hx => e.map_target hx) hz + rw [hback] at h + exact ⟨e.symm z, h, e.right_inv hz.1⟩ + +/-- Holomorphic convexity passes from the target of a biholomorphism to its source. -/ +theorem IsBiholomorphic.isHolomorphicallyConvex_source {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) (hV : IsHolomorphicallyConvex e.target) : + IsHolomorphicallyConvex e.source := by + intro K hK hKU + let := FiniteDimensional.complete ℂ E + let := FiniteDimensional.complete ℂ F + have hf := he.1.analyticOnNhd_of_finiteDimensional e.open_source + have hg := he.2.analyticOnNhd_of_finiteDimensional e.open_target + have himage : e '' K ⊆ e.target := by + rintro _ ⟨z, hz, rfl⟩ + exact e.map_source (hKU hz) + have hc := hV _ (hK.image_of_continuousOn (hf.continuousOn.mono hKU)) himage + apply isCompact_holomorphicHull_of_subset_compact + (hc.image_of_continuousOn (hg.continuousOn.mono (holomorphicHull_subset _ _))) + · rintro _ ⟨z, hz, rfl⟩ + exact e.map_target hz.1 + · intro z hz + exact ⟨e z, mapsTo_holomorphicHull hf (fun _ hx => e.map_source hx) hz, e.left_inv hz.1⟩ + +/-- Holomorphic convexity is invariant under biholomorphic equivalence of open sets. -/ +theorem IsBiholomorphic.isHolomorphicallyConvex_iff {e : OpenPartialHomeomorph E F} + (he : IsBiholomorphic e) : + IsHolomorphicallyConvex e.source ↔ IsHolomorphicallyConvex e.target := + ⟨fun h => he.symm.isHolomorphicallyConvex_source h, + fun h => he.isHolomorphicallyConvex_source h⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicLp.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicLp.lean new file mode 100644 index 0000000000..b0e327f96e --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/HolomorphicLp.lean @@ -0,0 +1,243 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Constructions.Pi +public import Mathlib.MeasureTheory.Function.ConvergenceInMeasure +public import Mathlib.MeasureTheory.Function.L2Space +public import Mathlib.MeasureTheory.Function.LpSeminorm.CompareExp +public import Mathlib.MeasureTheory.Measure.Lebesgue.Complex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscMeanValue + +/-! +# Holomorphic Lp spaces + +The holomorphic Lp space on an open subset of `ι → ℂ` is the submodule of Lebesgue Lp classes +admitting a holomorphic representative. Such a representative is unique on the open set. Complex +Banach targets and empty coordinate types are allowed. + +[Jakóbczak–Jarnicki][JakobczakJarnicki2021], Lemma 1.4.20 and Corollary 1.4.21, motivate the +local Lp estimate and completeness for `1 ≤ p ≤ ∞`. The local estimate follows from the volume +mean-value formula and Hölder's inequality. It yields closedness and completeness. For Hilbert +targets, the space at `p = 2` inherits Mathlib's L2 inner product, with its convention of +linearity in the second argument. No boundedness or connectedness of the open set is required. + +## Main definitions + +* `holomorphicLpSubmodule`: The Lp classes which have a holomorphic representative on the open set. +* `HolomorphicLp`: Holomorphic Lp functions, represented as a subspace of Mathlib's Lebesgue Lp + space. + +## Main results + +* `exists_norm_le_mul_Lp_norm`: **Local Lp estimate ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] + 1.4.20).** On each compact subset of an open set, values of a holomorphic representative are + bounded by a fixed multiple of the norm of its Lp class. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public section + +open Filter Set MeasureTheory Metric +open scoped ENNReal Topology + +namespace SeveralComplexVariables + +variable {ι F : Type*} [Fintype ι] [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- The Lp classes which have a holomorphic representative on the open set. -/ +@[expose] def holomorphicLpSubmodule (U : TopologicalSpace.Opens (ι → ℂ)) (p : ℝ≥0∞) : + Submodule ℂ (Lp F p (volume.restrict (U : Set (ι → ℂ)))) where + carrier := {u | ∃ f : (ι → ℂ) → F, DifferentiableOn ℂ f U ∧ + f =ᵐ[volume.restrict (U : Set (ι → ℂ))] u} + zero_mem' := ⟨0, differentiableOn_const 0, (Lp.coeFn_zero F p _).symm⟩ + add_mem' := by + rintro u v ⟨f, hf, he⟩ ⟨g, hg, he'⟩ + exact ⟨f + g, hf.add hg, (he.add he').trans (Lp.coeFn_add u v).symm⟩ + smul_mem' := by + rintro c u ⟨f, hf, he⟩ + exact ⟨c • f, hf.const_smul c, (he.const_smul c).trans (Lp.coeFn_smul c u).symm⟩ + +/-- Holomorphic Lp functions, represented as a subspace of Mathlib's Lebesgue Lp space. For `1 ≤ p` +the norm and complex normed-space structure are inherited from Lp. -/ +abbrev HolomorphicLp (U : TopologicalSpace.Opens (ι → ℂ)) (F : Type*) + [NormedAddCommGroup F] [NormedSpace ℂ F] (p : ℝ≥0∞) : Type _ := + ↥(holomorphicLpSubmodule (F := F) U p) + +/-- Every element of the holomorphic Lp subspace has a holomorphic representative. -/ +theorem HolomorphicLp.exists_representative {U : TopologicalSpace.Opens (ι → ℂ)} + {p : ℝ≥0∞} (u : HolomorphicLp U F p) : + ∃ f : (ι → ℂ) → F, DifferentiableOn ℂ f U ∧ + f =ᵐ[volume.restrict (U : Set (ι → ℂ))] (u.val : Lp F p _) := u.property + +/-- Holomorphic representatives of the same Lp class agree everywhere on the open set. -/ +theorem holomorphicLp_representative_unique {U : TopologicalSpace.Opens (ι → ℂ)} + {p : ℝ≥0∞} {u : Lp F p (volume.restrict (U : Set (ι → ℂ)))} + {f g : (ι → ℂ) → F} (hf : DifferentiableOn ℂ f U) (hg : DifferentiableOn ℂ g U) + (he : f =ᵐ[volume.restrict (U : Set (ι → ℂ))] u) + (he' : g =ᵐ[volume.restrict (U : Set (ι → ℂ))] u) : EqOn f g U := + Measure.eqOn_open_of_ae_eq (he.trans he'.symm) U.isOpen hf.continuousOn hg.continuousOn + +variable [CompleteSpace F] + +/-- The volume mean-value formula and Hölder's inequality bound the center value by the global Lp +norm. Only holomorphy on the closed polydisc is needed here. -/ +theorem volume_mul_norm_le_Lp_norm (U : TopologicalSpace.Opens (ι → ℂ)) + (p : ℝ≥0∞) [Fact (1 ≤ p)] {c : ι → ℂ} {r : ℝ} (hr : 0 < r) + (hBU : closedBall c r ⊆ U) + (u : Lp F p (volume.restrict (U : Set (ι → ℂ)))) {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f (closedBall c r)) + (he : f =ᵐ[volume.restrict (U : Set (ι → ℂ))] u) : + volume.real (closedBall c r) * ‖f c‖ ≤ + ‖u‖ * volume.real (closedBall c r) ^ (1 - 1 / p.toReal) := by + let μ := volume.restrict (closedBall c r) + have hmeas : AEStronglyMeasurable f μ := + (hf.continuousOn.integrableOn_compact (isCompact_closedBall _ _)).aestronglyMeasurable + have hpu : eLpNorm f p μ ≤ eLpNorm u p (volume.restrict (U : Set (ι → ℂ))) := by + rw [← eLpNorm_congr_ae he] + exact eLpNorm_mono_measure f (Measure.restrict_mono hBU le_rfl) + have hvol0 := (measure_closedBall_pos (volume : Measure (ι → ℂ)) c hr).ne' + have hvoltop : volume (closedBall c r) ≠ ∞ := measure_closedBall_lt_top.ne + have hh : eLpNorm f 1 μ ≤ eLpNorm u p (volume.restrict (U : Set (ι → ℂ))) * + volume (closedBall c r) ^ (1 - 1 / p.toReal) := by + have h := eLpNorm_le_eLpNorm_mul_rpow_measure_univ (Fact.out : 1 ≤ p) hmeas + simp only [ENNReal.toReal_one, div_one, μ, Measure.restrict_apply_univ] at h + exact h.trans (mul_le_mul' hpu le_rfl) + have hfinite : eLpNorm u p (volume.restrict (U : Set (ι → ℂ))) * + volume (closedBall c r) ^ (1 - 1 / p.toReal) ≠ ∞ := + ENNReal.mul_ne_top (Lp.eLpNorm_ne_top u) (ENNReal.rpow_ne_top_of_ne_zero hvol0 hvoltop) + have hreal := ENNReal.toReal_mono hfinite hh + rw [ENNReal.toReal_mul, ← ENNReal.toReal_rpow, ← Lp.norm_def] at hreal + calc + volume.real (closedBall c r) * ‖f c‖ = ‖∫ z in closedBall c r, f z‖ := by + rw [integral_closedBall_eq_volume_smul hf, norm_smul, Real.norm_eq_abs, + abs_of_nonneg (show 0 ≤ volume.real (closedBall c r) from ENNReal.toReal_nonneg)] + _ ≤ ∫ z in closedBall c r, ‖f z‖ := norm_integral_le_integral_norm _ + _ = (eLpNorm f 1 μ).toReal := by + rw [eLpNorm_one_eq_lintegral_enorm hmeas] + exact integral_norm_eq_lintegral_enorm hmeas + _ ≤ ‖u‖ * volume.real (closedBall c r) ^ (1 - 1 / p.toReal) := hreal + +/-- **Local Lp estimate ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.4.20).** On each compact +subset of an +open set, values of a holomorphic representative are bounded by a fixed multiple of +the norm of its Lp class. A uniform polydisc radius, the volume mean-value formula, +and Hölder's inequality give a constant independent of the representative. -/ +theorem exists_norm_le_mul_Lp_norm (U : TopologicalSpace.Opens (ι → ℂ)) + (p : ℝ≥0∞) [Fact (1 ≤ p)] + {K : Set (ι → ℂ)} (hKU : K ⊆ U) (hK : IsCompact K) : + ∃ C : ℝ, 0 < C ∧ ∀ (u : Lp F p (volume.restrict (U : Set (ι → ℂ)))) + (f : (ι → ℂ) → F), DifferentiableOn ℂ f U → + f =ᵐ[volume.restrict (U : Set (ι → ℂ))] u → + ∀ z ∈ K, ‖f z‖ ≤ C * ‖u‖ := by + obtain ⟨r, hr, hsub⟩ := hK.exists_cthickening_subset_open U.isOpen hKU + let v := volume.real (closedBall (0 : ι → ℂ) r) + have hv : 0 < v := ENNReal.toReal_pos + (measure_closedBall_pos (volume : Measure (ι → ℂ)) 0 hr).ne' + measure_closedBall_lt_top.ne + refine ⟨v ^ (1 - 1 / p.toReal) / v, div_pos (Real.rpow_pos_of_pos hv _) hv, ?_⟩ + intro u f hf he z hz + have hBU : closedBall z r ⊆ U := (closedBall_subset_cthickening hz r).trans hsub + have hbound := volume_mul_norm_le_Lp_norm U p hr hBU u + ((hf.analyticOnNhd_of_finiteDimensional U.isOpen).mono hBU) he + have hvol : volume.real (closedBall z r) = v := by + have hpre : (fun w : ι → ℂ => z + w) ⁻¹' closedBall z r = closedBall 0 r := by + ext w + simp [mem_closedBall, dist_eq_norm] + dsimp [v, Measure.real] + rw [← hpre, measure_preimage_add] + rw [hvol] at hbound + calc + ‖f z‖ ≤ (‖u‖ * v ^ (1 - 1 / p.toReal)) / v := + (le_div_iff₀ hv).mpr (by simpa only [mul_comm] using hbound) + _ = v ^ (1 - 1 / p.toReal) / v * ‖u‖ := by ring + +/-- An Lp-convergent sequence of holomorphic representatives converges locally uniformly on the open +set to a holomorphic representative of its Lp limit. This uses the local Lp estimate; in +particular, no global finite-measure hypothesis is needed. -/ +theorem exists_holomorphic_representative_of_tendsto_Lp + {U : TopologicalSpace.Opens (ι → ℂ)} {p : ℝ≥0∞} [Fact (1 ≤ p)] + {u : ℕ → Lp F p (volume.restrict (U : Set (ι → ℂ)))} + {v : Lp F p (volume.restrict (U : Set (ι → ℂ)))} + {f : ℕ → (ι → ℂ) → F} (hf : ∀ n, DifferentiableOn ℂ (f n) U) + (he : ∀ n, f n =ᵐ[volume.restrict (U : Set (ι → ℂ))] u n) + (hu : Tendsto u atTop (𝓝 v)) : + ∃ g : (ι → ℂ) → F, DifferentiableOn ℂ g U ∧ + g =ᵐ[volume.restrict (U : Set (ι → ℂ))] v ∧ + TendstoLocallyUniformlyOn f g atTop U := by + classical + have hc : ∀ K ⊆ (U : Set (ι → ℂ)), IsCompact K → UniformCauchySeqOn f atTop K := by + intro K hKU hK + obtain ⟨C, hC, hbound⟩ := exists_norm_le_mul_Lp_norm (F := F) U p hKU hK + rw [Metric.uniformCauchySeqOn_iff] + intro ε hε + obtain ⟨N, hN⟩ := Metric.cauchySeq_iff.mp hu.cauchySeq (ε / C) (div_pos hε hC) + refine ⟨N, fun m hm n hn z hz => ?_⟩ + have hb := hbound (u m - u n) (f m - f n) ((hf m).sub (hf n)) + (((he m).sub (he n)).trans (Lp.coeFn_sub _ _).symm) z hz + rw [dist_eq_norm] + have hdist := hN m hm n hn + rw [dist_eq_norm] at hdist + exact hb.trans_lt ((lt_div_iff₀' hC).mp hdist) + have hex : ∀ z : U, ∃ y : F, Tendsto (fun n => f n z) atTop (𝓝 y) := by + intro z + exact cauchySeq_tendsto_of_complete + ((hc {z.val} (singleton_subset_iff.mpr z.property) isCompact_singleton).cauchySeq + (mem_singleton z.val)) + choose g hg using hex + let G : (ι → ℂ) → F := fun z => if hz : z ∈ U then g ⟨z, hz⟩ else 0 + have hG : ∀ z ∈ U, Tendsto (fun n => f n z) atTop (𝓝 (G z)) := by + intro z hz + simpa only [G, dite_eq_left hz] using hg ⟨z, hz⟩ + have hloc : TendstoLocallyUniformlyOn f G atTop U := by + rw [tendstoLocallyUniformlyOn_iff_forall_isCompact U.isOpen] + intro K hKU hK + exact (hc K hKU hK).tendstoUniformlyOn_of_tendsto fun z hz => hG z (hKU hz) + refine ⟨G, (hloc.analyticOnNhd_pi + (.of_forall fun n => (hf n).analyticOnNhd_of_finiteDimensional U.isOpen) + U.isOpen).differentiableOn, ?_, hloc⟩ + obtain ⟨φ, hφ, hv⟩ := (tendstoInMeasure_of_tendsto_Lp hu).exists_seq_tendsto_ae + filter_upwards [hv, ae_all_iff.mpr he, ae_restrict_mem U.isOpen.measurableSet] with z hz hez hzU + have ht : Tendsto (fun n => u (φ n) z) atTop (𝓝 (G z)) := by + simpa only [Function.comp_def, ← hez] using (hG z hzU).comp hφ.tendsto_atTop + exact tendsto_nhds_unique ht hz + +/-- The holomorphic Lp submodule is closed for `1 ≤ p ≤ ∞`, by the local Lp estimate and Weierstrass +convergence. -/ +theorem isClosed_holomorphicLpSubmodule (U : TopologicalSpace.Opens (ι → ℂ)) + (p : ℝ≥0∞) [Fact (1 ≤ p)] : + IsClosed (holomorphicLpSubmodule (F := F) U p : Set (Lp F p + (volume.restrict (U : Set (ι → ℂ))))) := by + apply isSeqClosed_iff_isClosed.mp + intro u v hu hv + choose f hf he using hu + obtain ⟨g, hg, heq, _⟩ := exists_holomorphic_representative_of_tendsto_Lp hf he hv + exact ⟨g, hg, heq⟩ + +/-- **[Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.4.21.** Holomorphic Lp is a complex Banach space +for +`1 ≤ p ≤ ∞`. Completeness follows from closedness in Mathlib's complete Lp space. -/ +instance (U : TopologicalSpace.Opens (ι → ℂ)) (p : ℝ≥0∞) + [Fact (1 ≤ p)] : CompleteSpace (HolomorphicLp U F p) := + (isClosed_holomorphicLpSubmodule (F := F) U p).isComplete.completeSpace_coe + +/-- Holomorphic L2 inherits the integral inner product of Mathlib's L2 space. Together with +completeness this gives Corollary 1.4.21's Hilbert-space assertion, including Hilbert-valued +functions and Mathlib's linear-in-the-second-argument convention. -/ +theorem holomorphicL2_inner {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] + {U : TopologicalSpace.Opens (ι → ℂ)} (f g : HolomorphicLp U H 2) : + inner ℂ f g = ∫ z, inner ℂ (f.val z) (g.val z) + ∂volume.restrict (U : Set (ι → ℂ)) := + L2.inner_def f.val g.val + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/IdentityPrinciple.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/IdentityPrinciple.lean new file mode 100644 index 0000000000..f5cfd56923 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/IdentityPrinciple.lean @@ -0,0 +1,76 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity + +/-! +# The identity theorem for holomorphic functions in several variables + +Holomorphic maps on a preconnected open subset of a finite-dimensional complex normed space +agree everywhere if they agree near one point, equivalently on a nonempty open subset. The +target may be a complex Banach space. The proofs use the project's holomorphic–analytic +equivalence and Mathlib's analytic identity principle. + +`DifferentiableOn.eqOn_of_preconnected_of_eqOn` is +[Fritzsche–Grauert][FritzscheGrauert2002] (2002), I.4.10, p. 22, +with Banach-valued targets. Finite coordinate spaces `ι → ℂ` are covered as finite-dimensional +spaces, including empty coordinate types. The agreement set must be nonempty; agreement merely on a +set with a cluster point does not suffice in several variables. + +## Main results + +* `DifferentiableOn.eqOn_of_preconnected_of_eqOn`: **Identity theorem + ([Fritzsche–Grauert][FritzscheGrauert2002] I.4.10).** Two holomorphic maps on an open, + preconnected set agree everywhere if they agree on a nonempty open subset. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +-/ + +public section + +open Set Filter +open scoped Topology + +namespace DifferentiableOn + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- The holomorphic identity principle from equality near one point of an open, preconnected set. +The target may be any complex Banach space. -/ +theorem eqOn_of_preconnected_of_eventuallyEq {U : Set E} (hU : IsOpen U) + (hconn : IsPreconnected U) {f g : E → F} + (hf : DifferentiableOn ℂ f U) (hg : DifferentiableOn ℂ g U) + {a : E} (ha : a ∈ U) (heq : f =ᶠ[𝓝 a] g) : EqOn f g U := + (hf.analyticOnNhd_of_finiteDimensional hU).eqOn_of_preconnected_of_eventuallyEq + (hg.analyticOnNhd_of_finiteDimensional hU) hconn ha heq + +/-- **Identity theorem ([Fritzsche–Grauert][FritzscheGrauert2002] I.4.10).** Two holomorphic maps on +an open, preconnected set agree everywhere if they agree on a nonempty open subset. -/ +theorem eqOn_of_preconnected_of_eqOn {U V : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) + {f g : E → F} (hf : DifferentiableOn ℂ f U) (hg : DifferentiableOn ℂ g U) + (hV : IsOpen V) (hne : V.Nonempty) (hVU : V ⊆ U) (heq : EqOn f g V) : + EqOn f g U := by + obtain ⟨a, ha⟩ := hne + exact hf.eqOn_of_preconnected_of_eventuallyEq hU hconn hg (hVU ha) + (Filter.mem_of_superset (hV.mem_nhds ha) (fun _ hx => heq hx)) + +/-- A holomorphic map vanishing on a nonempty open subset vanishes throughout the open, preconnected +domain. -/ +theorem eqOn_zero_of_preconnected_of_eqOn_zero {U V : Set E} (hU : IsOpen U) + (hconn : IsPreconnected U) + {f : E → F} (hf : DifferentiableOn ℂ f U) + (hV : IsOpen V) (hne : V.Nonempty) (hVU : V ⊆ U) (heq : EqOn f 0 V) : + EqOn f 0 U := + hf.eqOn_of_preconnected_of_eqOn hU hconn (differentiableOn_const 0) hV hne hVU heq + +end DifferentiableOn + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ImplicitGraph.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ImplicitGraph.lean new file mode 100644 index 0000000000..88ef9c82ca --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ImplicitGraph.lean @@ -0,0 +1,56 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Graph + +/-! +# Local zero sets as graphs + +The implicit mapping theorem supplies a homeomorphism from a regular local zero set to the +parameter neighborhood. This is an elementary statement about subsets of product spaces, without +a manifold or analytic-space structure. Reference: [Scheidemann][Scheidemann2005] (2005), +Corollary 3.1.5. + +## Main results + +`Homeomorph.implicitGraph` is the local graph homeomorphism of a regular zero set in a product. +`exists_implicit_zero_homeomorph` packages existence of that homeomorphism from the implicit +mapping theorem. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set + +namespace SeveralComplexVariables + +variable {P Q R : Type*} [NormedAddCommGroup P] [NormedSpace ℂ P] + [NormedAddCommGroup Q] [NormedSpace ℂ Q] [NormedAddCommGroup R] [NormedSpace ℂ R] + +/-- Near a regular zero, projection identifies the zero set homeomorphically with an open parameter +neighborhood. This retains the analytic graph and its explicit projection. -/ +theorem exists_implicit_zero_homeomorph [FiniteDimensional ℂ P] [FiniteDimensional ℂ Q] + [CompleteSpace R] {D : Set (P × Q)} (hD : IsOpen D) + {f : P × Q → R} (hf : DifferentiableOn ℂ f D) {a : P} {b : Q} + (hab : (a, b) ∈ D) (hz : f (a, b) = 0) + (hi : ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).IsInvertible) : + ∃ (U : Set P) (V : Set Q), IsOpen U ∧ a ∈ U ∧ IsOpen V ∧ b ∈ V ∧ U ×ˢ V ⊆ D ∧ + ∃ e : {p : P × Q // p ∈ U ×ˢ V ∧ f p = 0} ≃ₜ U, + ∀ p, (e p).val = p.val.1 := by + obtain ⟨U, V, g, hU, ha, hV, hb, hsub, hg, hm, _, hgraph⟩ := + exists_holomorphic_implicit_zero hD hf hab hz hi + exact ⟨U, V, hU, ha, hV, hb, hsub, Homeomorph.implicitGraph hg.continuousOn hm hgraph, + fun _ => rfl⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ImplicitMapping.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ImplicitMapping.lean new file mode 100644 index 0000000000..5f38fe1681 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ImplicitMapping.lean @@ -0,0 +1,152 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.ImplicitContDiff +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Graph + +/-! +# Holomorphic implicit mappings + +For `f : P × Q → R`, invertibility of the derivative in the `Q` variable gives a local +holomorphic solution `y = g x` of the level equation `f (x, y) = f (a, b)`. The conclusion uses +open product neighborhoods inside the original domain, includes uniqueness of every solution +there, and identifies the derivative of `g`. + +The analytic theorem works in complex Banach spaces. The holomorphic version uses the project's +finite-dimensional holomorphic–analytic equivalence. No connectedness assumptions or positive +dimension restrictions are imposed; zero-dimensional parameter spaces include isolated +solutions. We reuse Mathlib's implicit function theorem at regularity `ω`. + +Reference: [Range][Range1986] (1986), I §2.3, Theorem 2.4. + +## Main results + +* `exists_analytic_implicit_mapping`: **Analytic implicit mapping theorem.** Near a point where the + partial derivative in the second variable is invertible, the level set is precisely an analytic + graph. +* `exists_holomorphic_implicit_mapping`: **Holomorphic implicit mapping theorem.** The level set of + a holomorphic map with invertible partial derivative is locally a unique holomorphic graph. + +## References + +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology ContDiff + +namespace SeveralComplexVariables + +variable {P Q R : Type*} [NormedAddCommGroup P] [NormedSpace ℂ P] + [NormedAddCommGroup Q] [NormedSpace ℂ Q] [NormedAddCommGroup R] [NormedSpace ℂ R] + +section Analytic + +variable [CompleteSpace P] [CompleteSpace Q] [CompleteSpace R] + +/-- **Analytic implicit mapping theorem.** Near a point where the partial derivative +in the second variable is invertible, the level set is precisely an analytic graph. +Both neighborhoods lie in the supplied domain, and the derivative is `-(D₂f)⁻¹ ∘ D₁f`. -/ +theorem exists_analytic_implicit_mapping {D : Set (P × Q)} (hD : IsOpen D) + {f : P × Q → R} {a : P} {b : Q} (hab : (a, b) ∈ D) + (hf : AnalyticAt ℂ f (a, b)) + (hi : ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).IsInvertible) : + ∃ (U : Set P) (V : Set Q) (g : P → Q), + IsOpen U ∧ a ∈ U ∧ IsOpen V ∧ b ∈ V ∧ U ×ˢ V ⊆ D ∧ + AnalyticOnNhd ℂ g U ∧ MapsTo g U V ∧ g a = b ∧ + HasFDerivAt g + (-((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).inverse |>.comp + ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inl ℂ P Q))) a ∧ + ∀ x ∈ U, ∀ y ∈ V, f (x, y) = f (a, b) ↔ y = g x := by + have hc : ContDiffAt ℂ ω f (a, b) := hf.contDiffAt + let g := hc.implicitFunction (by simp) hi + have hga : g a = b := hc.implicitFunction_apply_self (by simp) hi + have hg : AnalyticAt ℂ g a := (hc.contDiffAt_implicitFunction (by simp) hi).analyticAt + have heq : ∀ᶠ p in 𝓝 (a, b), f p = f (a, b) ↔ g p.1 = p.2 := + hc.eventually_apply_eq_iff_implicitFunction (by simp) hi + obtain ⟨U₀, V, hU₀, ha₀, hV, hb, hsub⟩ := + mem_nhds_prod_iff'.mp (inter_mem (hD.mem_nhds hab) heq) + have hgV : g ⁻¹' V ∈ 𝓝 a := + hg.continuousAt.preimage_mem_nhds (hga.symm ▸ hV.mem_nhds hb) + obtain ⟨U, hUU, hU, ha⟩ := mem_nhds_iff.mp + (inter_mem (inter_mem (hU₀.mem_nhds ha₀) hg.eventually_analyticAt) hgV) + refine ⟨U, V, g, hU, ha, hV, hb, ?_, ?_, ?_, hga, ?_, ?_⟩ + · exact fun p hp => (hsub ⟨(hUU hp.1).1.1, hp.2⟩).1 + · exact fun x hx => (hUU hx).1.2 + · exact fun x hx => (hUU hx).2 + · exact (hc.hasStrictFDerivAt_implicitFunction (by simp) hi).hasFDerivAt + · intro x hx y hy + exact (hsub ⟨(hUU hx).1.1, hy⟩).2.trans eq_comm + +end Analytic + +section Holomorphic + +variable [FiniteDimensional ℂ P] [FiniteDimensional ℂ Q] [CompleteSpace R] + +/-- **Holomorphic implicit mapping theorem.** The level set of a holomorphic map +with invertible partial derivative is locally a unique holomorphic graph. +The target may be a complex Banach space; invertibility supplies the required dimension match. -/ +theorem exists_holomorphic_implicit_mapping {D : Set (P × Q)} (hD : IsOpen D) + {f : P × Q → R} (hf : DifferentiableOn ℂ f D) {a : P} {b : Q} + (hab : (a, b) ∈ D) + (hi : ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).IsInvertible) : + ∃ (U : Set P) (V : Set Q) (g : P → Q), + IsOpen U ∧ a ∈ U ∧ IsOpen V ∧ b ∈ V ∧ U ×ˢ V ⊆ D ∧ + DifferentiableOn ℂ g U ∧ MapsTo g U V ∧ g a = b ∧ + HasFDerivAt g + (-((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).inverse |>.comp + ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inl ℂ P Q))) a ∧ + ∀ x ∈ U, ∀ y ∈ V, f (x, y) = f (a, b) ↔ y = g x := by + let := FiniteDimensional.complete ℂ P + let := FiniteDimensional.complete ℂ Q + obtain ⟨U, V, g, hU, ha, hV, hb, hsub, hg, hm, hga, hd, heq⟩ := + exists_analytic_implicit_mapping hD hab (hf.analyticOnNhd_of_finiteDimensional hD _ hab) hi + exact ⟨U, V, g, hU, ha, hV, hb, hsub, hg.differentiableOn, hm, hga, hd, heq⟩ + +/-- [Range][Range1986]'s zero-set formulation: near a regular zero the zero set is a holomorphic +graph. -/ +theorem exists_holomorphic_implicit_zero {D : Set (P × Q)} (hD : IsOpen D) + {f : P × Q → R} (hf : DifferentiableOn ℂ f D) {a : P} {b : Q} + (hab : (a, b) ∈ D) (hzero : f (a, b) = 0) + (hi : ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).IsInvertible) : + ∃ (U : Set P) (V : Set Q) (g : P → Q), + IsOpen U ∧ a ∈ U ∧ IsOpen V ∧ b ∈ V ∧ U ×ˢ V ⊆ D ∧ + DifferentiableOn ℂ g U ∧ MapsTo g U V ∧ g a = b ∧ + ∀ x ∈ U, ∀ y ∈ V, f (x, y) = 0 ↔ y = g x := by + obtain ⟨U, V, g, hU, ha, hV, hb, hsub, hg, hm, hga, _, heq⟩ := + exists_holomorphic_implicit_mapping hD hf hab hi + exact ⟨U, V, g, hU, ha, hV, hb, hsub, hg, hm, hga, by simpa only [hzero] using heq⟩ + +end Holomorphic + +/-- The determinant-of-a-minor formulation of the implicit mapping theorem. The chosen coordinates +are the second factor; their Jacobian is the Jacobian of the corresponding slice. -/ +theorem exists_holomorphic_implicit_zero_of_det [FiniteDimensional ℂ P] + {ι : Type*} [Fintype ι] [DecidableEq ι] {D : Set (P × (ι → ℂ))} (hD : IsOpen D) + {f : P × (ι → ℂ) → (ι → ℂ)} (hf : DifferentiableOn ℂ f D) + {a : P} {b : ι → ℂ} (hab : (a, b) ∈ D) (hzero : f (a, b) = 0) + (hdet : (complexJacobian (fun y => f (a, y)) b).det ≠ 0) : + ∃ (U : Set P) (V : Set (ι → ℂ)) (g : P → (ι → ℂ)), + IsOpen U ∧ a ∈ U ∧ IsOpen V ∧ b ∈ V ∧ U ×ˢ V ⊆ D ∧ + DifferentiableOn ℂ g U ∧ MapsTo g U V ∧ g a = b ∧ + ∀ x ∈ U, ∀ y ∈ V, f (x, y) = 0 ↔ y = g x := by + have hd := ((hf (a, b) hab).differentiableAt (hD.mem_nhds hab)).hasFDerivAt + have hs := hd.comp b (hasFDerivAt_prodMk_right a b (𝕜 := ℂ)) + apply exists_holomorphic_implicit_zero hD hf hab hzero + have hi := (det_complexJacobian_ne_zero_iff hs.differentiableAt).mp hdet + rwa [hs.fderiv] at hi + + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping.lean new file mode 100644 index 0000000000..b2f6b27f55 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping.lean @@ -0,0 +1,144 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CriticalSet + +/-! +# Injective holomorphic maps in equal dimensions + +An injective holomorphic map between equal-dimensional finite-dimensional complex spaces has +invertible derivative and is biholomorphic onto its open image. No connectedness or nonemptiness +is required. The critical-set argument proves nonsingularity; the inverse mapping theorem then +gives the global inverse onto the image. Supporting modules separate one-variable +nonsingularity, immersion points, the codimension-one reduction, and exclusion of the critical +set. + +Reference: [Fritzsche–Grauert][FritzscheGrauert2002] I, Theorem 8.5 and Corollary 8.6. + +## Main results + +`isInvertible_fderiv_of_injOn` is nonsingularity of an injective holomorphic map in equal +dimensions. `exists_biholomorphic_of_injOn` produces a biholomorphism onto the image. +`isOpen_image_of_holomorphic_injOn` is openness of the image. `det_complexJacobian_ne_zero_of_injOn` +is the Jacobian form in coordinates. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] + +/-- An injective holomorphic map in equal dimensions has invertible complex derivative. Equal +dimensions are essential: an injective parametrization of a cusp can have zero derivative. The +proof includes dimension zero and arbitrary finite-dimensional complex normed spaces. -/ +theorem isInvertible_fderiv_of_injOn (hdim : Module.finrank ℂ E = Module.finrank ℂ F) + {U : Set E} (hU : IsOpen U) {f : E → F} (hf : DifferentiableOn ℂ f U) + (hi : InjOn f U) {a : E} (ha : a ∈ U) : (fderiv ℂ f a).IsInvertible := by + let n := Module.finrank ℂ E + let A : E ≃L[ℂ] (Fin n → ℂ) := (Module.finBasis ℂ E).equivFunL + let B : F ≃L[ℂ] (Fin n → ℂ) := ContinuousLinearEquiv.ofFinrankEq (by simpa [n] using hdim.symm) + let g := B ∘ f ∘ A.symm + let V := A.symm ⁻¹' U + have hV : IsOpen V := hU.preimage A.symm.continuous + have hg : DifferentiableOn ℂ g V := + B.differentiable.comp_differentiableOn + (hf.comp A.symm.differentiable.differentiableOn (fun _ hz => hz)) + have hgi : InjOn g V := by + intro z hz w hw he + apply A.symm.injective + exact hi hz hw (B.injective he) + have haV : A a ∈ V := by simpa [V] + obtain ⟨T, hT⟩ := isInvertible_fderiv_of_injOn_coordinates hV hg hgi haV + have hda : fderiv ℂ g (A a) = + B.toContinuousLinearMap.comp ((fderiv ℂ f a).comp A.symm.toContinuousLinearMap) := by + have hfa : HasFDerivAt f (fderiv ℂ f a) (A.symm (A a)) := by + simpa only [A.symm_apply_apply] using + ((hf a ha).differentiableAt (hU.mem_nhds ha)).hasFDerivAt + exact (B.hasFDerivAt.comp (A a) (hfa.comp (A a) A.symm.hasFDerivAt)).fderiv + refine ⟨A.trans (T.trans B.symm), ?_⟩ + ext v + change B.symm (T (A v)) = (fderiv ℂ f a) v + apply B.injective + have he := DFunLike.congr_fun hT (A v) + simpa only [hda, ContinuousLinearMap.comp_apply, ContinuousLinearEquiv.coe_coe, + A.symm_apply_apply, B.apply_symm_apply] using he + +/-- An injective holomorphic map between equal-dimensional spaces gives a biholomorphic map with +source exactly `U` and target exactly its image. This follows from nonsingularity. -/ +theorem exists_biholomorphic_of_injOn (hdim : Module.finrank ℂ E = Module.finrank ℂ F) + {U : Set E} (hU : IsOpen U) {f : E → F} (hf : DifferentiableOn ℂ f U) + (hi : InjOn f U) : + ∃ e : OpenPartialHomeomorph E F, IsBiholomorphic e ∧ e.source = U ∧ + e.target = f '' U ∧ (e : E → F) = f := by + let g := Function.invFunOn f U + have hlocal : ∀ a ∈ U, ∃ e : OpenPartialHomeomorph E F, IsBiholomorphic e ∧ + a ∈ e.source ∧ e.source ⊆ U ∧ (e : E → F) = f := fun a ha => + exists_biholomorphic_of_isInvertible_fderiv hU hf ha + (isInvertible_fderiv_of_injOn hdim hU hf hi ha) + have ho : IsOpen (f '' U) := by + rw [isOpen_iff_mem_nhds] + rintro y ⟨a, ha, rfl⟩ + obtain ⟨e, _, hae, heU, heq⟩ := hlocal a ha + have htar : e.target ⊆ f '' U := by + intro z hz + exact ⟨e.symm z, heU (e.map_target hz), by rw [← heq]; exact e.right_inv hz⟩ + exact mem_of_superset (e.open_target.mem_nhds (by rw [← heq]; exact e.map_source hae)) htar + have hg : DifferentiableOn ℂ g (f '' U) := by + rintro y ⟨a, ha, rfl⟩ + obtain ⟨e, he, hae, heU, heq⟩ := hlocal a ha + have hfa : f a ∈ e.target := by rw [← heq]; exact e.map_source hae + have heqg : g =ᶠ[𝓝 (f a)] e.symm := by + filter_upwards [e.open_target.mem_nhds hfa] with z hz + have hzU : z ∈ f '' U := ⟨e.symm z, heU (e.map_target hz), + by rw [← heq]; exact e.right_inv hz⟩ + apply hi (Function.invFunOn_mem hzU) (heU (e.map_target hz)) + exact (Function.invFunOn_eq hzU).trans (by rw [← heq]; exact (e.right_inv hz).symm) + exact ((he.symm.differentiableAt hfa).congr_of_eventuallyEq heqg).differentiableWithinAt + let e : OpenPartialHomeomorph E F := + { toFun := f + invFun := g + source := U + target := f '' U + map_source' := fun x hx => mem_image_of_mem f hx + map_target' := fun y hy => Function.invFunOn_mem hy + left_inv' := hi.leftInvOn_invFunOn + right_inv' := fun y hy => Function.invFunOn_eq hy + open_source := hU + open_target := ho + continuousOn_toFun := hf.continuousOn + continuousOn_invFun := hg.continuousOn } + exact ⟨e, ⟨hf, hg⟩, rfl, rfl, rfl⟩ + +/-- The image of an injective holomorphic map in equal dimensions is open. -/ +theorem isOpen_image_of_holomorphic_injOn (hdim : Module.finrank ℂ E = Module.finrank ℂ F) + {U : Set E} (hU : IsOpen U) {f : E → F} (hf : DifferentiableOn ℂ f U) + (hi : InjOn f U) : IsOpen (f '' U) := by + obtain ⟨e, _, _, ht, _⟩ := exists_biholomorphic_of_injOn hdim hU hf hi + exact ht ▸ e.open_target + +/-- The coordinate Jacobian determinant of an injective holomorphic map never vanishes. -/ +theorem det_complexJacobian_ne_zero_of_injOn {ι : Type*} [Fintype ι] [DecidableEq ι] + {U : Set (ι → ℂ)} (hU : IsOpen U) {f : (ι → ℂ) → (ι → ℂ)} + (hf : DifferentiableOn ℂ f U) (hi : InjOn f U) {a : ι → ℂ} (ha : a ∈ U) : + (complexJacobian f a).det ≠ 0 := + (det_complexJacobian_ne_zero_iff ((hf a ha).differentiableAt (hU.mem_nhds ha))).mpr + (isInvertible_fderiv_of_injOn rfl hU hf hi ha) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/CorankOne.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/CorankOne.lean new file mode 100644 index 0000000000..163e0c4af9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/CorankOne.lean @@ -0,0 +1,194 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ImplicitMapping +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.OneVariable + +/-! +# Nonsingularity in the presence of an invertible transverse minor + +The implicit function theorem reduces an injective map to an injective scalar function on a +one-dimensional level set. Its nonzero derivative completes an invertible minor to the full +derivative. These results are independent of the general injective-mapping theorem. + +## Main results + +`isInvertible_fderiv_of_injOn_of_invertible_partial` completes an invertible transverse minor. +`isInvertible_fderiv_of_injOn_of_hyperplane` is the corresponding statement after restricting to +a level hyperplane. `injective_of_injective_vertical_of_transverse_vector` is the +one-dimensional reduction. +-/ + +public noncomputable section + +open Set Filter Function +open scoped Topology + +namespace SeveralComplexVariables + +variable {P : Type*} [NormedAddCommGroup P] [NormedSpace ℂ P] + +/-- An injective vertical block and a nonzero transverse image imply injectivity. -/ +theorem injective_of_injective_vertical_of_transverse_vector + (L : (ℂ × P) →L[ℂ] (ℂ × P)) + (hi : Injective (fun p : P => (L (0, p)).2)) {b : P} + (hs : (L (1, b)).2 = 0) (ht : (L (1, b)).1 ≠ 0) : Injective L := by + apply (injective_iff_map_eq_zero L).mpr + intro v hv + have he : (0, v.2 - v.1 • b) = v - v.1 • (1, b) := by + ext <;> simp + have hz : (L (0, v.2 - v.1 • b)).2 = 0 := by + rw [he, map_sub, map_smul, hv] + simp [hs] + have hb : v.2 - v.1 • b = 0 := + hi (by simpa only [Prod.mk_zero_zero, map_zero, Prod.snd_zero] using hz) + have hv' : v = v.1 • (1, b) := by + ext + · simp + · exact sub_eq_zero.mp hb + have him : L v = v.1 • L (1, b) := by + conv_lhs => rw [hv'] + rw [map_smul] + have hc : v.1 * (L (1, b)).1 = 0 := by + simpa only [Prod.smul_fst, smul_eq_mul, Prod.fst_zero] using + congrArg Prod.fst (him.symm.trans hv) + have h0 : v.1 = 0 := (mul_eq_zero.mp hc).resolve_right ht + rw [hv', h0, zero_smul] + +variable [FiniteDimensional ℂ P] + +/-- An injective holomorphic map with an invertible codimension-one minor is nonsingular. -/ +theorem isInvertible_fderiv_of_injOn_of_invertible_partial + {D : Set (ℂ × P)} (hD : IsOpen D) {f : (ℂ × P) → (ℂ × P)} + (hf : DifferentiableOn ℂ f D) (hi : InjOn f D) {a : ℂ} {b : P} + (hab : (a, b) ∈ D) + (hpart : ((fderiv ℂ (fun z => (f z).2) (a, b)).comp + (ContinuousLinearMap.inr ℂ ℂ P)).IsInvertible) : + (fderiv ℂ f (a, b)).IsInvertible := by + let := FiniteDimensional.complete ℂ P + have hfs : DifferentiableOn ℂ (fun z => (f z).2) D := hf.snd + obtain ⟨U, V, g, hU, ha, hV, hb, hUV, hg, hm, hga, _, heq⟩ := + exists_holomorphic_implicit_mapping hD hfs hab hpart + let γ : ℂ → ℂ × P := fun w => (w, g w) + have hγ : DifferentiableOn ℂ γ U := differentiableOn_id.prodMk hg + have hγD : MapsTo γ U D := fun w hw => hUV ⟨hw, hm hw⟩ + have hfg : DifferentiableOn ℂ (f ∘ γ) U := hf.comp hγ hγD + have hscalar : InjOn (fun w => (f (γ w)).1) U := by + intro w hw z hz he + have hs : (f (γ w)).2 = (f (γ z)).2 := + ((heq w hw (g w) (hm hw)).mpr rfl).trans + ((heq z hz (g z) (hm hz)).mpr rfl).symm + exact congrArg Prod.fst (hi (hγD hw) (hγD hz) (Prod.ext he hs)) + have hne := deriv_ne_zero_of_injOn hU hfg.fst hscalar ha + have hγa : HasDerivAt γ (1, deriv g a) a := + (hasDerivAt_id a).prodMk ((hg a ha).differentiableAt (hU.mem_nhds ha)).hasDerivAt + have hfa := ((hf (a, b) hab).differentiableAt (hD.mem_nhds hab)).hasFDerivAt + have hc := hfa.comp_hasDerivAt_of_eq a hγa (by simp [γ, hga]) + have hcf := (ContinuousLinearMap.fst ℂ ℂ P).hasFDerivAt.comp_hasDerivAt a hc + have hcs := (ContinuousLinearMap.snd ℂ ℂ P).hasFDerivAt.comp_hasDerivAt a hc + change HasDerivAt (fun w => (f (γ w)).1) + (fderiv ℂ f (a, b) (1, deriv g a)).1 a at hcf + change HasDerivAt (fun w => (f (γ w)).2) + (fderiv ℂ f (a, b) (1, deriv g a)).2 a at hcs + have hs : (fderiv ℂ f (a, b) (1, deriv g a)).2 = 0 := by + rw [← hcs.deriv] + apply (Filter.EventuallyEq.deriv_eq ?_).trans (deriv_const a (f (a, b)).2) + filter_upwards [hU.mem_nhds ha] with w hw + exact (heq w hw (g w) (hm hw)).mpr rfl + have ht : (fderiv ℂ f (a, b) (1, deriv g a)).1 ≠ 0 := by + rwa [← hcf.deriv] + have hA : Injective (fun p : P => (fderiv ℂ f (a, b) (0, p)).2) := by + obtain ⟨A, hA⟩ := hpart + have he : (fun p : P => (fderiv ℂ f (a, b) (0, p)).2) = A := by + funext p + change _ = (A : P →L[ℂ] P) p + rw [hA] + rw [hfa.snd.fderiv] + rfl + rw [he] + exact A.injective + have hinj := injective_of_injective_vertical_of_transverse_vector + (fderiv ℂ f (a, b)) hA hs ht + exact ⟨(LinearEquiv.ofBijective (fderiv ℂ f (a, b)).toLinearMap + ⟨hinj, (LinearMap.injective_iff_surjective).mp hinj⟩).toContinuousLinearEquiv, rfl⟩ + +/-- An embedding of a hyperplane extends to linear coordinates with one extra scalar variable. -/ +theorem exists_linearEquiv_prod_extension + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + (i : P →L[ℂ] E) (hi : Injective i) + (hdim : Module.finrank ℂ P + 1 = Module.finrank ℂ E) : + ∃ A : (ℂ × P) ≃L[ℂ] E, ∀ p, A (0, p) = i p := by + let R := LinearMap.range i.toLinearMap + let e : P ≃ₗ[ℂ] R := LinearEquiv.ofInjective i.toLinearMap hi + obtain ⟨Q, hQ⟩ := R.exists_isCompl + have hdimQ : Module.finrank ℂ Q = 1 := by + have hh := Submodule.finrank_add_eq_of_isCompl hQ + have he := e.finrank_eq + omega + let c : ℂ ≃ₗ[ℂ] Q := LinearEquiv.ofFinrankEq ℂ Q (by simpa using hdimQ.symm) + let A := ((c.prodCongr e).trans (Q.prodEquivOfIsCompl R hQ.symm)).toContinuousLinearEquiv + refine ⟨A, fun p => ?_⟩ + change (c 0 : E) + (e p : E) = i p + simp only [map_zero, Submodule.coe_zero, zero_add] + rfl + +/-- If the derivative of an injective holomorphic map is injective on a hyperplane, then its full +derivative is invertible. -/ +theorem isInvertible_fderiv_of_injOn_of_hyperplane + {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [FiniteDimensional ℂ F] + (hdim : Module.finrank ℂ E = Module.finrank ℂ F) + {U : Set E} (hU : IsOpen U) {f : E → F} (hf : DifferentiableOn ℂ f U) + (hi : InjOn f U) {a : E} (ha : a ∈ U) (S : P →L[ℂ] E) + (hS : Injective S) (hP : Module.finrank ℂ P + 1 = Module.finrank ℂ E) + (hdfS : Injective ((fderiv ℂ f a).comp S)) : (fderiv ℂ f a).IsInvertible := by + obtain ⟨A, hA⟩ := exists_linearEquiv_prod_extension S hS hP + obtain ⟨B, hB⟩ := exists_linearEquiv_prod_extension ((fderiv ℂ f a).comp S) hdfS + (hP.trans hdim) + let g := B.symm ∘ f ∘ A + let D := A ⁻¹' U + have hD : IsOpen D := hU.preimage A.continuous + have hg : DifferentiableOn ℂ g D := + B.symm.differentiable.comp_differentiableOn + (hf.comp A.differentiable.differentiableOn (fun _ hz => hz)) + have hgi : InjOn g D := by + intro z hz w hw he + apply A.injective + apply hi hz hw + exact B.symm.injective he + have haD : A.symm a ∈ D := by simpa [D] + have hda : fderiv ℂ g (A.symm a) = + B.symm.toContinuousLinearMap.comp ((fderiv ℂ f a).comp A.toContinuousLinearMap) := by + have hfa : HasFDerivAt f (fderiv ℂ f a) (A (A.symm a)) := by + simpa only [A.apply_symm_apply] using + ((hf a ha).differentiableAt (hU.mem_nhds ha)).hasFDerivAt + exact (B.symm.hasFDerivAt.comp (A.symm a) (hfa.comp (A.symm a) A.hasFDerivAt)).fderiv + have hpartial : (fderiv ℂ (fun z => (g z).2) (A.symm a)).comp + (ContinuousLinearMap.inr ℂ ℂ P) = ContinuousLinearMap.id ℂ P := by + rw [((hg _ haD).differentiableAt (hD.mem_nhds haD)).hasFDerivAt.snd.fderiv, hda] + ext p + change (B.symm ((fderiv ℂ f a) (A (0, p)))).2 = p + rw [hA, ← ContinuousLinearMap.comp_apply, ← hB, B.symm_apply_apply] + have hinv : (fderiv ℂ g (A.symm a)).IsInvertible := + isInvertible_fderiv_of_injOn_of_invertible_partial hD hg hgi haD + (by + change ((fderiv ℂ (fun z => (g z).2) (A.symm a)).comp + (ContinuousLinearMap.inr ℂ ℂ P)).IsInvertible + rw [hpartial] + exact ⟨ContinuousLinearEquiv.refl ℂ P, rfl⟩) + obtain ⟨T, hT⟩ := hinv + refine ⟨A.symm.trans (T.trans B), ?_⟩ + ext v + change B (T (A.symm v)) = (fderiv ℂ f a) v + apply B.symm.injective + have he := DFunLike.congr_fun hT (A.symm v) + simpa only [hda, ContinuousLinearMap.comp_apply, ContinuousLinearEquiv.coe_coe, + A.apply_symm_apply, B.symm_apply_apply] using he + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/CriticalSet.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/CriticalSet.lean new file mode 100644 index 0000000000..0c7fa22530 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/CriticalSet.lean @@ -0,0 +1,128 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticSet.Regular +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.CorankOne +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.Immersion + +/-! +# Excluding critical points of injective holomorphic maps + +The critical set cannot have a regular hypersurface point: restriction to that hypersurface has +an immersion point, where an invertible transverse minor forces nonsingularity. The Jacobian +determinant is not identically zero, and any nonempty zero set of it has a regular hypersurface +point. Thus the critical set is empty. + +## Main results + +`not_isRegularAnalyticSetAt_criticalSet` excludes a regular hypersurface point of the critical +set. `analyticOnNhd_det_complexJacobian` is holomorphy of the Jacobian determinant. +`isInvertible_fderiv_of_injOn_coordinates` is nonsingularity in coordinates, by emptiness of +that critical set. +-/ + +public noncomputable section + +open Set Filter Function Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] + +/-- A critical set of an injective holomorphic map cannot contain a regular hypersurface. -/ +theorem not_isRegularAnalyticSetAt_criticalSet + (hdim : Module.finrank ℂ E = Module.finrank ℂ F) + {U : Set E} (hU : IsOpen U) {f : E → F} (hf : DifferentiableOn ℂ f U) + (hi : InjOn f U) {A : Set E} (hAU : A ⊆ U) + (hcrit : ∀ x ∈ A, ¬ (fderiv ℂ f x).IsInvertible) {a : E} : + ¬ IsRegularAnalyticSetAt A a 1 := by + rintro ⟨haA, e, L, he, hae, hLs, heA⟩ + let K := L.ker + let V : Set K := K.subtypeL ⁻¹' e.target + have hV : IsOpen V := e.open_target.preimage K.subtypeL.continuous + have hLa : e a ∈ K := (heA a hae).mp haA + have hVne : V.Nonempty := ⟨⟨e a, hLa⟩, e.map_source hae⟩ + let G : K → F := fun z => f (e.symm z) + have hxA (z : K) (hz : z ∈ V) : e.symm z ∈ A := by + apply (heA _ (e.map_target hz)).mpr + rw [e.right_inv hz] + exact z.property + have hG : DifferentiableOn ℂ G V := by + intro z hz + exact (((hf _ (hAU (hxA z hz))).differentiableAt (hU.mem_nhds (hAU (hxA z hz)))).comp + z ((he.symm.differentiableAt hz).comp z K.subtypeL.differentiableAt)).differentiableWithinAt + have hGi : InjOn G V := by + intro z hz w hw hzw + apply Subtype.val_injective + exact e.symm.injOn hz hw (hi (hAU (hxA z hz)) (hAU (hxA w hw)) hzw) + obtain ⟨z, hz, hzi⟩ := exists_injective_fderiv_of_injOn hV hVne hG hGi + let S := (fderiv ℂ e.symm (z : E)).comp K.subtypeL + have hS : Injective S := + (he.symm.isInvertible_fderiv hz).injective.comp Subtype.val_injective + have hP : Module.finrank ℂ K + 1 = Module.finrank ℂ E := by + have hh := L.toLinearMap.finrank_range_add_finrank_ker + rw [LinearMap.range_eq_top.mpr hLs, finrank_top] at hh + simpa [K, add_comm] using hh + have hd : fderiv ℂ G z = (fderiv ℂ f (e.symm z)).comp S := by + exact (((hf _ (hAU (hxA z hz))).differentiableAt + (hU.mem_nhds (hAU (hxA z hz)))).hasFDerivAt.comp z + ((he.symm.differentiableAt hz).hasFDerivAt.comp z K.subtypeL.hasFDerivAt)).fderiv + exact hcrit _ (hxA z hz) (isInvertible_fderiv_of_injOn_of_hyperplane hdim hU hf hi + (hAU (hxA z hz)) S hS hP (by rwa [← hd])) + +/-- The determinant of the complex Jacobian is analytic on a holomorphic map's open domain. -/ +theorem analyticOnNhd_det_complexJacobian {ι : Type*} [Fintype ι] [DecidableEq ι] + {U : Set (ι → ℂ)} (hU : IsOpen U) {f : (ι → ℂ) → (ι → ℂ)} + (hf : AnalyticOnNhd ℂ f U) : AnalyticOnNhd ℂ (fun z => (complexJacobian f z).det) U := by + classical + intro a ha + simp only [Matrix.det_apply', complexJacobian] + apply Finset.analyticAt_fun_sum + intro σ _ + apply analyticAt_const.mul + apply Finset.analyticAt_fun_prod + intro i _ + exact ((analyticOnNhd_pi_iff.mp hf (σ i)).partialDeriv hU i) a ha + +/-- An injective holomorphic map between equal complex coordinate spaces has no critical points. -/ +theorem isInvertible_fderiv_of_injOn_coordinates {ι : Type*} [Finite ι] + {U : Set (ι → ℂ)} (hU : IsOpen U) {f : (ι → ℂ) → (ι → ℂ)} + (hf : DifferentiableOn ℂ f U) (hi : InjOn f U) {a : ι → ℂ} (ha : a ∈ U) : + (fderiv ℂ f a).IsInvertible := by + classical + let := Fintype.ofFinite ι + classical + obtain ⟨r, hr, hball⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds ha) + let V := Metric.ball a r + have haV : a ∈ V := Metric.mem_ball_self hr + have hV : IsOpen V := Metric.isOpen_ball + have hfV := hf.mono hball + let J := fun z => (complexJacobian f z).det + have hJ : AnalyticOnNhd ℂ J V := + analyticOnNhd_det_complexJacobian hV (hfV.analyticOnNhd_of_finiteDimensional hV) + obtain ⟨b, hb, hbi⟩ := exists_injective_fderiv_of_injOn hV ⟨a, haV⟩ hfV (hi.mono hball) + have hJb : J b ≠ 0 := (det_complexJacobian_ne_zero_iff + ((hfV b hb).differentiableAt (hV.mem_nhds hb))).mpr + ⟨(LinearEquiv.ofBijective (fderiv ℂ f b).toLinearMap + ⟨hbi, LinearMap.surjective_of_injective hbi⟩).toContinuousLinearEquiv, rfl⟩ + apply (det_complexJacobian_ne_zero_iff + ((hf a ha).differentiableAt (hU.mem_nhds ha))).mp + intro hJa + obtain ⟨c, hc⟩ := exists_regularPoint_zeroSet hV isPreconnected_ball hJ + ⟨b, hb, hJb⟩ ⟨a, haV, hJa⟩ + apply not_isRegularAnalyticSetAt_criticalSet rfl hU hf hi + (fun z hz => hball hz.1) (a := c) _ hc + intro z hz hinv + exact ((det_complexJacobian_ne_zero_iff + ((hf z (hball hz.1)).differentiableAt (hU.mem_nhds (hball hz.1)))).mpr hinv) hz.2 + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/Immersion.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/Immersion.lean new file mode 100644 index 0000000000..f6a284bad3 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/Immersion.lean @@ -0,0 +1,193 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.LinearAlgebra.Dual.Lemmas +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.InjectiveMapping.OneVariable + +/-! +# Immersion points of injective holomorphic maps + +Scalar projections with nonzero differential admit local coordinates. Restricting to a level +hyperplane lowers the source dimension and preserves injectivity. This gives immersion points +without assuming that source and target dimensions agree. + +## Main results + +`exists_fderiv_ne_zero_of_injOn` finds a point of nonzero derivative on a nonempty open set in +positive dimension. `exists_scalar_projection_fderiv_ne_zero` produces a scalar coordinate with +nonzero derivative. `exists_injective_fderiv_of_injOn` is the immersion-point theorem after +restricting to a level hyperplane. +-/ + +public noncomputable section + +open Set Filter Metric Function +open scoped Topology + +namespace SeveralComplexVariables + +universe u + +variable {E : Type u} {F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] + +omit [FiniteDimensional ℂ E] [FiniteDimensional ℂ F] in +/-- An injective holomorphic map on a nonempty open set in positive dimension has nonzero +differential somewhere. -/ +theorem exists_fderiv_ne_zero_of_injOn [Nontrivial E] + {U : Set E} (hU : IsOpen U) (hne : U.Nonempty) {f : E → F} + (hf : DifferentiableOn ℂ f U) (hi : InjOn f U) : + ∃ a ∈ U, fderiv ℂ f a ≠ 0 := by + by_contra! hz + obtain ⟨a, ha⟩ := hne + obtain ⟨r, hr, hball⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds ha) + have hs : ({a} : Set E) ∈ 𝓝 a := by + filter_upwards [ball_mem_nhds a hr] with z hzball + apply hi (hball hzball) ha + exact isOpen_ball.is_const_of_fderiv_eq_zero isPreconnected_ball + (hf.mono hball) (fun w hw => hz w (hball hw)) hzball (mem_ball_self hr) + have := mem_interior_iff_mem_nhds.mpr hs + simp at this + +omit [FiniteDimensional ℂ E] in +/-- Some scalar projection of an injective holomorphic map has nonzero differential at a point of +any nonempty open domain of positive dimension. -/ +theorem exists_scalar_projection_fderiv_ne_zero [Nontrivial E] + {U : Set E} (hU : IsOpen U) (hne : U.Nonempty) {f : E → F} + (hf : DifferentiableOn ℂ f U) (hi : InjOn f U) : + ∃ a ∈ U, ∃ ℓ : F →L[ℂ] ℂ, fderiv ℂ (ℓ ∘ f) a ≠ 0 := by + obtain ⟨a, ha, hdfa⟩ := exists_fderiv_ne_zero_of_injOn hU hne hf hi + obtain ⟨v, hv⟩ := DFunLike.ne_iff.mp hdfa + obtain ⟨l, hl⟩ := Module.Projective.exists_dual_ne_zero ℂ hv + let ℓ : F →L[ℂ] ℂ := l.toContinuousLinearMap + refine ⟨a, ha, ℓ, ?_⟩ + have hd : fderiv ℂ (ℓ ∘ f) a = ℓ.comp (fderiv ℂ f a) := + (ℓ.hasFDerivAt.comp a ((hf a ha).differentiableAt (hU.mem_nhds ha)).hasFDerivAt).fderiv + intro hz + apply hl + change ℓ (fderiv ℂ f a v) = 0 + rw [← ContinuousLinearMap.comp_apply, ← hd, hz, zero_apply] + +/-- A scalar holomorphic submersion becomes its own differential in suitable local coordinates. -/ +theorem exists_biholomorphic_scalar_normalization {U : Set E} (hU : IsOpen U) + {f : E → ℂ} (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) + (hn : fderiv ℂ f a ≠ 0) : + ∃ e : OpenPartialHomeomorph E E, IsBiholomorphic e ∧ a ∈ e.source ∧ e.source ⊆ U ∧ + ∀ z ∈ e.source, (fderiv ℂ f a) (e z) = f z := by + let L := fderiv ℂ f a + have hL : L.toLinearMap ≠ 0 := fun h => hn (by ext z; exact DFunLike.congr_fun h z) + obtain ⟨R, hR⟩ := L.toLinearMap.exists_rightInverse_of_surjective + (LinearMap.range_eq_top.mpr (LinearMap.surjective hL)) + let B : ℂ →L[ℂ] E := R.toContinuousLinearMap + have hLB (w : ℂ) : L (B w) = w := DFunLike.congr_fun hR w + let g : E → E := fun z => z + B (f z - L z) + have hg : DifferentiableOn ℂ g U := + differentiableOn_id.add (B.differentiable.comp_differentiableOn + (hf.sub L.differentiable.differentiableOn)) + have hd : HasFDerivAt g (ContinuousLinearMap.id ℂ E) a := by + simpa only [g, L, Pi.add_def, Pi.sub_def, Function.comp_def, id_eq, + sub_self, ContinuousLinearMap.comp_zero, add_zero] using + (hasFDerivAt_id a).add (B.hasFDerivAt.comp a + (((hf a ha).differentiableAt (hU.mem_nhds ha)).hasFDerivAt.sub L.hasFDerivAt)) + obtain ⟨e, he, hae, heU, heq⟩ := exists_biholomorphic_of_isInvertible_fderiv hU hg ha + (by rw [hd.fderiv]; exact ⟨ContinuousLinearEquiv.refl ℂ E, rfl⟩) + refine ⟨e, he, hae, heU, fun z _ => ?_⟩ + rw [heq] + change L (z + B (f z - L z)) = f z + rw [map_add, hLB] + abel + +omit [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] in +/-- Dimension induction for the existence of immersion points. -/ +private theorem exists_injective_fderiv_aux (n : ℕ) : + ∀ {E : Type u} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E], + Module.finrank ℂ E = n → ∀ {U : Set E}, IsOpen U → U.Nonempty → + ∀ {f : E → F}, DifferentiableOn ℂ f U → InjOn f U → + ∃ a ∈ U, Injective (fderiv ℂ f a) := by + induction n using Nat.strong_induction_on with + | h n ih => + intro E _ _ _ hn U hU hne f hf hi + by_cases hzero : Module.finrank ℂ E = 0 + · have : Subsingleton E := Module.finrank_zero_iff.mp hzero + obtain ⟨a, ha⟩ := hne + exact ⟨a, ha, fun _ _ _ => Subsingleton.elim _ _⟩ + have : Nontrivial E := not_subsingleton_iff_nontrivial.mp + (fun hs => hzero (@Module.finrank_zero_of_subsingleton ℂ E _ _ _ _ hs)) + obtain ⟨a, ha, ℓ, hL⟩ := exists_scalar_projection_fderiv_ne_zero hU hne hf hi + let φ := ℓ ∘ f + have hφ : DifferentiableOn ℂ φ U := ℓ.differentiable.comp_differentiableOn hf + let L := fderiv ℂ φ a + obtain ⟨e, he, hae, heU, heφ⟩ := exists_biholomorphic_scalar_normalization hU hφ ha hL + let G := f ∘ e.symm + have hG : DifferentiableOn ℂ G e.target := + hf.comp he.2 (fun y hy => heU (e.map_target hy)) + have hGL : EqOn (ℓ ∘ G) L e.target := by + intro y hy + exact (heφ (e.symm y) (e.map_target hy)).symm.trans (by rw [e.right_inv hy]) + let K := L.ker + let κ : K → E := fun z => e a + z + have hκ : ∀ z, HasFDerivAt κ K.subtypeL z := by + intro z + simpa only [zero_add, κ, Pi.add_def, Submodule.subtypeL_apply] using + (hasFDerivAt_const (e a) z).add K.subtypeL.hasFDerivAt + let V := κ ⁻¹' e.target + have hV : IsOpen V := e.open_target.preimage + (continuous_const.add continuous_subtype_val) + have hVne : V.Nonempty := ⟨0, by simpa [V, κ] using e.map_source hae⟩ + have hGK : DifferentiableOn ℂ (G ∘ κ) V := + hG.comp (fun z _ => (hκ z).differentiableAt.differentiableWithinAt) (fun _ hz => hz) + have hGKi : InjOn (G ∘ κ) V := by + intro z hz w hw hzw + apply Subtype.val_injective + apply add_left_cancel (a := e a) + apply e.symm.injOn hz hw + exact hi (heU (e.map_target hz)) (heU (e.map_target hw)) hzw + have hL' : L.toLinearMap ≠ 0 := fun h => hL (by ext z; exact DFunLike.congr_fun h z) + have hdim : Module.finrank ℂ K < n := by + have hh := Module.Dual.finrank_ker_add_one_of_ne_zero hL' + change Module.finrank ℂ K + 1 = Module.finrank ℂ E at hh + omega + obtain ⟨z, hz, hzi⟩ := ih (Module.finrank ℂ K) hdim rfl hV hVne hGK hGKi + have hGd := (hG (κ z) hz).differentiableAt (e.open_target.mem_nhds hz) + have hLG : ℓ.comp (fderiv ℂ G (κ z)) = L := by + rw [← (ℓ.hasFDerivAt.comp (κ z) hGd.hasFDerivAt).fderiv] + have hh : (ℓ ∘ G) =ᶠ[𝓝 (κ z)] L := + Filter.mem_of_superset (e.open_target.mem_nhds hz) hGL + exact hh.fderiv_eq.trans L.fderiv + have hKG : fderiv ℂ (G ∘ κ) z = (fderiv ℂ G (κ z)).comp K.subtypeL := + (hGd.hasFDerivAt.comp z (hκ z)).fderiv + have hinjG : Injective (fderiv ℂ G (κ z)) := by + apply (injective_iff_map_eq_zero _).mpr + intro v hv + have hvK : v ∈ K := by + change L v = 0 + rw [← hLG, ContinuousLinearMap.comp_apply, hv, map_zero] + have hvz : (⟨v, hvK⟩ : K) = 0 := hzi (by simp [hKG, hv]) + exact congrArg Subtype.val hvz + refine ⟨e.symm (κ z), heU (e.map_target hz), ?_⟩ + have hd : fderiv ℂ G (κ z) = + (fderiv ℂ f (e.symm (κ z))).comp (fderiv ℂ e.symm (κ z)) := + fderiv_comp _ ((hf _ (heU (e.map_target hz))).differentiableAt + (hU.mem_nhds (heU (e.map_target hz)))) (he.symm.differentiableAt hz) + have hsurj := (he.symm.isInvertible_fderiv hz).bijective.surjective + intro v w hvw + obtain ⟨v', rfl⟩ := hsurj v + obtain ⟨w', rfl⟩ := hsurj w + exact congrArg (fderiv ℂ e.symm (κ z)) (hinjG (by simpa only [hd, + ContinuousLinearMap.comp_apply] using hvw)) + +/-- Every nonempty open restriction of an injective holomorphic map has an immersion point. The +source and target dimensions need not agree. -/ +theorem exists_injective_fderiv_of_injOn {U : Set E} (hU : IsOpen U) (hne : U.Nonempty) + {f : E → F} (hf : DifferentiableOn ℂ f U) (hi : InjOn f U) : + ∃ a ∈ U, Injective (fderiv ℂ f a) := + exists_injective_fderiv_aux (Module.finrank ℂ E) rfl hU hne hf hi + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/OneVariable.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/OneVariable.lean new file mode 100644 index 0000000000..1f63d8aa22 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/InjectiveMapping/OneVariable.lean @@ -0,0 +1,100 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.InverseFunctionTheorem.Deriv +public import Mathlib.Analysis.Calculus.MeanValue +public import Mathlib.Analysis.Complex.OpenMapping +public import Mathlib.Analysis.Complex.RemovableSingularity +public import Mathlib.Analysis.Normed.Module.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Biholomorphic + +/-! +# Nonsingularity of injective holomorphic functions of one variable + +The open mapping theorem makes the inverse continuous. Isolated zeros of the derivative make it +holomorphic off the image of the base point, so the removable singularity theorem makes it +holomorphic there too. The chain rule then excludes a zero derivative. + +## Main results + +`deriv_ne_zero_of_injOn` is nonsingularity of an injective holomorphic function of one complex +variable. `not_eventually_constant_of_injOn_complex` and `not_eventually_deriv_eq_zero_of_injOn` +exclude a locally constant germ and a locally vanishing derivative. +-/ + +public noncomputable section + +open Set Filter Metric Function +open scoped Topology + +namespace SeveralComplexVariables + +/-- A function injective on a neighborhood in the complex plane is not locally constant. -/ +theorem not_eventually_constant_of_injOn_complex {f : ℂ → ℂ} {U : Set ℂ} {a : ℂ} + (hU : U ∈ 𝓝 a) (hi : InjOn f U) : ¬ ∀ᶠ z in 𝓝 a, f z = f a := by + intro hc + have hs : ({a} : Set ℂ) ∈ 𝓝 a := by + filter_upwards [hU, hc] with z hz he + exact hi hz (mem_of_mem_nhds hU) he + have := mem_interior_iff_mem_nhds.mpr hs + simp at this + +/-- The derivative of a locally injective analytic function is not locally identically zero. -/ +theorem not_eventually_deriv_eq_zero_of_injOn {f : ℂ → ℂ} {U : Set ℂ} {a : ℂ} + (hU : U ∈ 𝓝 a) (hi : InjOn f U) (hf : AnalyticAt ℂ f a) : + ¬ deriv f =ᶠ[𝓝 a] 0 := by + intro hz + obtain ⟨r, hr, hball⟩ := Metric.mem_nhds_iff.mp + (inter_mem hU (hf.eventually_analyticAt.and hz)) + apply not_eventually_constant_of_injOn_complex hU hi + filter_upwards [ball_mem_nhds a hr] with z hz + exact isOpen_ball.is_const_of_deriv_eq_zero isPreconnected_ball + (fun w hw => ((hball hw).2.1).differentiableAt.differentiableWithinAt) + (fun w hw => (hball hw).2.2) hz (mem_ball_self hr) + +/-- An injective holomorphic function of one complex variable has nonzero derivative. -/ +theorem deriv_ne_zero_of_injOn {U : Set ℂ} (hU : IsOpen U) {f : ℂ → ℂ} + (hf : DifferentiableOn ℂ f U) (hi : InjOn f U) {a : ℂ} (ha : a ∈ U) : + deriv f a ≠ 0 := by + have hfa := hf.analyticOnNhd hU a ha + have hopen : 𝓝 (f a) ≤ map f (𝓝 a) := + hfa.eventually_constant_or_nhds_le_map_nhds.resolve_left + (not_eventually_constant_of_injOn_complex (hU.mem_nhds ha) hi) + let g := invFunOn f U + have hleft : (g ∘ f) =ᶠ[𝓝 a] id := + Filter.mem_of_superset (hU.mem_nhds ha) (fun _ hz => hi.leftInvOn_invFunOn hz) + have hga : g (f a) = a := hi.leftInvOn_invFunOn ha + have hgcont : ContinuousAt g (f a) := by + rw [ContinuousAt, hga] + have ht : Tendsto (g ∘ f) (𝓝 a) (𝓝 a) := tendsto_id.congr' hleft.symm + change map (g ∘ f) (𝓝 a) ≤ 𝓝 a at ht + exact (Filter.map_mono hopen).trans (by rwa [map_map]) + have hisol : ∀ᶠ z in 𝓝[≠] a, deriv f z ≠ 0 := + hfa.deriv.eventually_eq_zero_or_eventually_ne_zero.resolve_left + (not_eventually_deriv_eq_zero_of_injOn (hU.mem_nhds ha) hi hfa) + have hV : {z | z ∈ U ∧ (z ≠ a → deriv f z ≠ 0)} ∈ 𝓝 a := + inter_mem (hU.mem_nhds ha) (eventually_nhdsWithin_iff.mp hisol) + have hW : f '' {z | z ∈ U ∧ (z ≠ a → deriv f z ≠ 0)} ∈ 𝓝 (f a) := + hopen (image_mem_map hV) + have hgd : ∀ᶠ w in 𝓝[≠] (f a), DifferentiableAt ℂ g w := by + filter_upwards [nhdsWithin_le_nhds hW, self_mem_nhdsWithin] with w hw hwne + obtain ⟨z, ⟨hz, hdz⟩, rfl⟩ := hw + have hzane : z ≠ a := fun h => hwne (by simp [h]) + have hstrict := (hf.analyticOnNhd hU z hz).contDiffAt.hasStrictDerivAt (n := 1) one_ne_zero + exact (hstrict.to_local_left_inverse (hdz hzane) + (Filter.mem_of_superset (hU.mem_nhds hz) + (fun _ ht => hi.leftInvOn_invFunOn ht))).hasDerivAt.differentiableAt + have hgan := Complex.analyticAt_of_differentiable_on_punctured_nhds_of_continuousAt hgd hgcont + have hder : deriv g (f a) * deriv f a = 1 := by + have hc := hgan.differentiableAt.hasDerivAt.comp a hfa.differentiableAt.hasDerivAt + exact hc.deriv.symm.trans ((Filter.EventuallyEq.deriv_eq hleft).trans (deriv_id a)) + intro hz + simp [hz] at hder + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Integral.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Integral.lean new file mode 100644 index 0000000000..5cfc7c47eb --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Integral.lean @@ -0,0 +1,12 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Integral.Circle + +/-! Supporting modules for Classical several complex variables. -/ + diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Integral/Circle.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Integral/Circle.lean new file mode 100644 index 0000000000..a280584388 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Integral/Circle.lean @@ -0,0 +1,47 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Integral.CircleAverage +public import Mathlib.MeasureTheory.Integral.CircleIntegral + +/-! +# Circle integrability of maxima and reflection invariance of circle averages + +The maximum of two real-valued functions integrable on a circle is integrable there, and circle +averages are invariant under the antipodal reflection of the circle. + +## Main results + +* `CircleIntegrable.max`: Maxima of circle-integrable functions are circle integrable. +* `Real.circleAverage_reflect`: The circle average is invariant under the antipodal reflection of + the circle. +-/ + +public section + +open Complex MeasureTheory Real + +/-- Maxima of circle-integrable functions are circle integrable. -/ +theorem CircleIntegrable.max {u v : ℂ → ℝ} {c : ℂ} {R : ℝ} (hu : CircleIntegrable u c R) + (hv : CircleIntegrable v c R) : CircleIntegrable (fun z => max (u z) (v z)) c R := by + rw [circleIntegrable_def] at hu hv ⊢ + exact ⟨hu.1.sup hv.1, hu.2.sup hv.2⟩ + +/-- The circle average is invariant under the antipodal reflection of the circle. -/ +theorem Real.circleAverage_reflect (u : ℂ → ℝ) (c : ℂ) (r : ℝ) : + circleAverage (fun t => u (2 * c - t)) c r = circleAverage u c r := by + rw [circleAverage_eq_integral_add (f := u) π, circleAverage_def] + congr 1 + refine intervalIntegral.integral_congr fun θ _ => ?_ + simp only [circleMap] + congr 1 + rw [Complex.ofReal_add, add_mul, Complex.exp_add, Complex.exp_pi_mul_I] + ring + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/IsolatedSingularity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/IsolatedSingularity.lean new file mode 100644 index 0000000000..7a98646936 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/IsolatedSingularity.lean @@ -0,0 +1,102 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SphericalShell + +/-! +# Removal of isolated singularities + +An arbitrary finite-dimensional complex normed source is reduced by a continuous linear +coordinate equivalence to the proved punctured-polydisc theorem. The extension is then glued to +the original function. No boundedness hypothesis is imposed near the puncture. Reference: +[Scheidemann][Scheidemann2005] (2005), Corollary 2.3.2. + +## Main results + +`exists_analyticOnNhd_extension_diff_singleton` removes an isolated singularity of a Banach-valued +holomorphic map on an open set in complex dimension at least two, without a local boundedness +hypothesis. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Metric Filter +open scoped Topology + +namespace SeveralComplexVariables + +/-- An isolated singularity is removable on any open set in complex dimension at least two. The +target is any complex Banach space, and the domain need not be connected. -/ +theorem exists_analyticOnNhd_extension_diff_singleton + {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + (hdim : 2 ≤ Module.finrank ℂ E) {U : Set E} (ho : IsOpen U) + {a : E} (ha : a ∈ U) {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ {a})) : + ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ {a}) := by + classical + let d := Module.finrank ℂ E - 1 + have hd : 0 < d := by dsimp [d]; omega + let : Nonempty (Fin d) := ⟨⟨0, hd⟩⟩ + have hdim' : Module.finrank ℂ E = Module.finrank ℂ ((Fin d → ℂ) × ℂ) := by + simp only [Module.finrank_prod, Module.finrank_pi, Module.finrank_self, Fintype.card_fin] + dsimp [d] + omega + let L : E ≃L[ℂ] ((Fin d → ℂ) × ℂ) := ContinuousLinearEquiv.ofFinrankEq hdim' + have hc : Continuous (fun p => a + L.symm p) := continuous_const.add L.symm.continuous + have hn : {p | a + L.symm p ∈ U} ∈ 𝓝 (0 : (Fin d → ℂ) × ℂ) := + hc.continuousAt.preimage_mem_nhds (by simpa using ho.mem_nhds ha) + obtain ⟨r, hr, hrU⟩ := Metric.mem_nhds_iff.mp hn + have hfun : AnalyticOnNhd ℂ (fun p => f (a + L.symm p)) + ((ball 0 r ×ˢ ball 0 r) \ {0}) := by + intro p hp + have hpU : a + L.symm p ∈ U := + hrU (by simpa only [Prod.zero_eq_mk, ball_prod_same] using hp.1) + have hpne : a + L.symm p ≠ a := by + intro he + apply hp.2 + have he' : L.symm p = 0 := by simpa only [add_eq_left] using he + simpa using congrArg L he' + exact (hf _ ⟨hpU, hpne⟩).comp (f := fun q => a + L.symm q) + (analyticAt_const.add (L.symm.toContinuousLinearMap.analyticAt p)) + obtain ⟨g, hg, heq⟩ := exists_extension_punctured_polydisc hr hr hfun + let G := Function.update f a (g 0) + refine ⟨G, ?_, ?_⟩ + · intro x hx + by_cases hxa : x = a + · subst x + have hga : AnalyticAt ℂ (fun x => g (L (x - a))) a := + (hg 0 ⟨mem_ball_self hr, mem_ball_self hr⟩).comp_of_eq + ((L.toContinuousLinearMap.analyticAt (a - a)).comp (f := fun x : E => x - a) + (analyticAt_id.sub analyticAt_const)) (by simp) + apply hga.congr + have hn' : {x | L (x - a) ∈ ball 0 r} ∈ 𝓝 a := + (L.continuous.comp (continuous_id.sub continuous_const)).continuousAt.preimage_mem_nhds + (by simpa using ball_mem_nhds (0 : (Fin d → ℂ) × ℂ) hr) + filter_upwards [hn'] with x hx + by_cases hxa : x = a + · subst x; simp [G] + · have hp : L (x - a) ∈ (ball 0 r ×ˢ ball 0 r) \ {0} := by + refine ⟨by simpa only [Prod.zero_eq_mk, ball_prod_same] using hx, ?_⟩ + intro hzero + apply hxa + apply sub_eq_zero.mp + have h := congrArg L.symm hzero + simpa using h + simpa [G, hxa] using heq hp + · apply (hf x ⟨hx, hxa⟩).congr + filter_upwards [isOpen_compl_singleton.mem_nhds hxa] with y hy + exact (Function.update_of_ne hy _ _).symm + · intro x hx + exact Function.update_of_ne hx.2 _ _ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentApproximation.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentApproximation.lean new file mode 100644 index 0000000000..b455b9f130 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentApproximation.lean @@ -0,0 +1,226 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Function.LpSpace.ContinuousFunctions +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries + +/-! +# Laurent approximation and coefficient projections + +Finite Laurent sums approximate holomorphic functions uniformly on compact subsets. The +coefficient functionals are continuous independently of Laurent expansion. The projections, +their mutual orthogonality, and convergence in the compact-open holomorphic space are derived +from the Laurent expansion theorem. Only the elementary analytic consequences of +[Scheidemann][Scheidemann2005] (2005), Section 2.2, are used; no representation theory of +compact groups is introduced. + +## Main results + +`exists_finite_laurent_approximation` approximates a holomorphic function uniformly on a compact +set by a finite Laurent sum. `exists_laurentCoeffCLM` and `exists_laurentTermCLM` are the +continuous coefficient and term projections on the compact-open holomorphic space. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter MeasureTheory Complex +open scoped Topology + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Integration on a fixed coordinate torus is a continuous linear coefficient functional on the +compact-open space of holomorphic maps. This construction does not require Laurent expansion or +connectedness. -/ +theorem exists_laurentCoeffCLM (U : TopologicalSpace.Opens (Fin n → ℂ)) + (hR : IsReinhardt (U : Set (Fin n → ℂ))) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + (m : Fin n → ℤ) : + ∃ A : HolomorphicMap U F →L[ℂ] F, ∀ f, + A f = multivariableLaurentCoeff (openExtension U f.val) r m := by + classical + let := U.isOpen.locallyCompactSpace + let K := Icc (0 : Fin n → ℝ) (fun _ => 2 * Real.pi) + have hK : IsCompact K := isCompact_Icc + let : CompactSpace K := isCompact_iff_compactSpace.mp hK + let : MeasureSpace K := Measure.Subtype.measureSpace + let : IsFiniteMeasure (volume : Measure K) := ⟨by + rw [Measure.Subtype.volume_univ hK.measurableSet.nullMeasurableSet] + exact hK.measure_lt_top⟩ + have htor (θ : Fin n → ℝ) : torusMap 0 r θ ∈ U := by + apply hR hrU + intro i + simpa only [Pi.zero_apply, sub_zero, Complex.norm_of_nonneg (hr i).le] using + norm_torusMap_sub (c := 0) (fun i => (hr i).le) θ i + let γ : C(K, U) := ⟨fun θ => ⟨torusMap 0 r θ, htor θ⟩, + ((continuous_torusMap 0 r).comp continuous_subtype_val).subtype_mk _⟩ + have hnz (θ : K) (i : Fin n) : torusMap 0 r θ i ≠ 0 := + torusMap_apply_ne_of_norm_sub_lt (c := 0) (w := 0) hr (by simpa using hr i) + let b : C(K, ℂ) := ⟨fun θ => + (∏ i, (r i : ℂ) * exp ((θ.val i : ℂ) * I) * I) * + ∏ i, torusMap 0 r θ i ^ (-m i - 1), by + apply Continuous.mul + · apply continuous_finsetProd + intro i _ + exact ((continuous_const.mul + (Complex.continuous_exp.comp ((Complex.continuous_ofReal.comp + ((continuous_apply i).comp continuous_subtype_val)).mul continuous_const))).mul + continuous_const) + · apply continuous_finsetProd + intro i _ + exact ((continuous_apply i).comp ((continuous_torusMap 0 r).comp + continuous_subtype_val)).zpow₀ (-m i - 1) (fun θ => Or.inl (hnz θ i))⟩ + let T : HolomorphicMap U F →L[ℂ] C(K, F) := + { toFun := fun f => ⟨fun θ => b θ • f.val (γ θ), + b.continuous.smul (f.val.continuous.comp γ.continuous)⟩ + map_add' := by intros; ext; simp + map_smul' := by + intro c f + ext θ + exact smul_comm (b θ) c (f.val (γ θ)) + cont := by + apply ContinuousMap.continuous_of_continuous_uncurry + exact (b.continuous.comp continuous_snd).smul + (continuous_eval.comp + ((continuous_subtype_val.comp continuous_fst).prodMk + (γ.continuous.comp continuous_snd))) } + let J : C(K, F) →L[ℂ] F := + (L1.integralCLM' ℂ).comp (ContinuousMap.toLp 1 volume ℂ) + let A : HolomorphicMap U F →L[ℂ] F := + ((2 * Real.pi * I : ℂ) ^ n)⁻¹ • J.comp T + refine ⟨A, fun f => ?_⟩ + have hJ : J (T f) = ∫ θ : K, T f θ := by + change L1.integralCLM' ℂ (ContinuousMap.toLp 1 volume ℂ (T f)) = _ + rw [← L1.integral_eq' ℂ, L1.integral_eq_integral] + exact integral_congr_ae (ContinuousMap.coeFn_toLp (𝕜 := ℂ) volume (T f)) + change ((2 * Real.pi * I : ℂ) ^ n)⁻¹ • J (T f) = _ + rw [hJ, multivariableLaurentCoeff, torusIntegral, ← integral_subtype hK.measurableSet] + congr 1 + apply integral_congr_ae + filter_upwards with θ + change b θ • f.val (γ θ) = _ + rw [openExtension_apply U _ (htor θ)] + exact mul_smul _ _ _ + +/-- Each Laurent term defines a continuous operator with values in holomorphic maps. Vanishing of +forbidden coefficients uses the Laurent expansion theorem. -/ +theorem exists_laurentTermCLM (U : TopologicalSpace.Opens (Fin n → ℂ)) + (hc : IsConnected (U : Set (Fin n → ℂ))) (hR : IsReinhardt (U : Set (Fin n → ℂ))) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + (m : Fin n → ℤ) : + ∃ P : HolomorphicMap U F →L[ℂ] HolomorphicMap U F, ∀ f z, + (P f).val z = multivariableLaurentTerm + (multivariableLaurentCoeff (openExtension U f.val) r) m z := by + classical + obtain ⟨A, hA⟩ := exists_laurentCoeffCLM (F := F) U hR hr hrU m + by_cases hm : ∀ i, m i < 0 → ∀ z ∈ U, z i ≠ 0 + · let a : (Fin n → ℂ) → ℂ := fun z => ∏ i, z i ^ m i + have ha : AnalyticOnNhd ℂ a U := by + intro z hz + apply Finset.analyticAt_fun_prod + intro i _ + by_cases hi : 0 ≤ m i + · exact ((ContinuousLinearMap.proj (R := ℂ) i).analyticAt z).zpow_nonneg hi + · exact ((ContinuousLinearMap.proj (R := ℂ) i).analyticAt z).zpow + (hm i (lt_of_not_ge hi) z hz) + let B : F →L[ℂ] HolomorphicMap U F := + { toFun := fun v => + ⟨⟨fun z => a z • v, ha.continuousOn.domRestrict.smul continuous_const⟩, by + apply AnalyticOnNhd.congr U.isOpen (ha.smul (analyticOnNhd_const (v := v))) + intro z hz + rw [openExtension_apply U _ hz] + rfl⟩ + map_add' := by intros; ext; exact smul_add _ _ _ + map_smul' := by intros; ext; exact smul_comm _ _ _ + cont := by + apply Continuous.subtype_mk + apply ContinuousMap.continuous_of_continuous_uncurry + exact (ha.continuousOn.domRestrict.comp continuous_snd).smul continuous_fst } + refine ⟨B.comp A, fun f z => ?_⟩ + change a z • A f = _ + rw [hA] + rfl + · push Not at hm + obtain ⟨i, hi, z, hz, hzi⟩ := hm + refine ⟨0, fun f w => ?_⟩ + have hzero := (multivariableLaurent_expansion U.isOpen hc.isPreconnected hR f.property hr + hrU).2.2.1 + m i ⟨z, hz, hzi⟩ hi + simp [multivariableLaurentTerm, hzero] + +/-- Finite canonical Laurent sums approximate uniformly on any given compact subset. Depends on the +Laurent expansion theorem, with no finite-dimensional target restriction. -/ +theorem exists_finite_laurent_approximation {U K : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsConnected U) (hR : IsReinhardt U) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + (hK : IsCompact K) (hKU : K ⊆ U) {ε : ℝ} (hε : 0 < ε) : + ∃ s : Finset (Fin n → ℤ), ∀ z ∈ K, + ‖f z - ∑ m ∈ s, multivariableLaurentTerm (multivariableLaurentCoeff f r) m z‖ < ε := by + have h := hasSumUniformlyOn_iff_tendstoUniformlyOn.mp + (hasSumUniformlyOn_multivariableLaurent ho hc.isPreconnected hR hf hr hrU hK hKU) + obtain ⟨s, hs⟩ := (Metric.tendstoUniformlyOn_iff.mp h ε hε).exists + exact ⟨s, fun z hz => by simpa [dist_eq_norm] using hs z hz⟩ + +/-- Continuous Laurent projections, their coefficient formulas, and their mutual orthogonality +follow from continuity of torus integration, holomorphy of permitted monomials, and Laurent +uniqueness. Terms with forbidden negative exponents are zero. The finite partial sums converge +in the existing compact-open topology. This deduction depends on the Laurent expansion theorem. -/ +theorem exists_laurentProjections (U : TopologicalSpace.Opens (Fin n → ℂ)) + (hc : IsConnected (U : Set (Fin n → ℂ))) (hR : IsReinhardt (U : Set (Fin n → ℂ))) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) : + ∃ P : (Fin n → ℤ) → HolomorphicMap U F →L[ℂ] HolomorphicMap U F, + (∀ m f z, (P m f).val z = + multivariableLaurentTerm (multivariableLaurentCoeff (openExtension U f.val) r) m z) ∧ + (∀ m k f, P m (P k f) = if m = k then P m f else 0) ∧ + (∀ f, Tendsto (fun s : Finset (Fin n → ℤ) => ∑ m ∈ s, P m f) atTop (𝓝 f)) := by + classical + choose P hP using fun m => exists_laurentTermCLM (F := F) U hc hR hr hrU m + refine ⟨P, hP, ?_, ?_⟩ + · intro m k f + let c : (Fin n → ℤ) → F := fun j => if j = k then + multivariableLaurentCoeff (openExtension U f.val) r k else 0 + have hsingle : HasSum (fun j => if j = k then P k f else 0) (P k f) := + hasSum_ite_eq k (P k f) + have hs : HasSumLocallyUniformlyOn (multivariableLaurentTerm c) + (openExtension U (P k f).val) U := by + apply (holomorphicMap_tendsto_iff.mp hsingle).congr + intro s z hz + rw [openExtension_apply U _ hz] + simp only [Submodule.coe_sum, ContinuousMap.sum_apply] + apply Finset.sum_congr rfl + intro j _ + by_cases hj : j = k + · subst j + simp only [ite_true, hP, multivariableLaurentTerm, c] + · simp [hj, c, multivariableLaurentTerm] + have hcoeff := (multivariableLaurent_expansion U.isOpen hc.isPreconnected hR + (P k f).property hr hrU).2.2.2.2 c hs + ext z + rw [hP, ← hcoeff] + by_cases hmk : m = k + · subst m + simp only [c, ite_true, multivariableLaurentTerm] + exact (hP k f z).symm + · simp [c, hmk, multivariableLaurentTerm] + · intro f + rw [holomorphicMap_tendsto_iff] + apply (multivariableLaurent_expansion U.isOpen hc.isPreconnected hR f.property hr hrU).1.congr + intro s z hz + rw [openExtension_apply U _ hz] + simp only [Submodule.coe_sum, ContinuousMap.sum_apply] + exact Finset.sum_congr rfl (fun m _ => (hP m f ⟨z, hz⟩).symm) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries.lean new file mode 100644 index 0000000000..67ed9d24a3 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries.lean @@ -0,0 +1,97 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductExpansion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Uniqueness + +/-! +# Multivariable analytic Laurent series + +Coefficients are arbitrary families indexed by integer multi-indices, not algebraic +`LaurentSeries`, whose support is bounded below. Sums use finite subsets of the index type. The +main expansion theorem includes coordinate hyperplanes: coefficients with negative exponent in a +coordinate vanish when the domain meets that hyperplane. This makes the statement compatible +with Lean's totalized integer powers at zero. + +The proof combines successive circle expansions, independence of coefficient tori, and summable +local geometric bounds. References: [Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), +Theorem 2.7.1 and Lemma 2.8.1. + +## Main results + +`multivariableLaurent_expansion` is the expansion theorem on a connected open Reinhardt domain. +`hasSumUniformlyOn_multivariableLaurent` is uniform convergence on compact subsets of the +domain. `multivariableLaurentCoeff_eq_zero_of_not_nonneg` vanishes coefficients with a negative +exponent in a coordinate that meets a hyperplane. Supporting lemmas live in the `LaurentSeries` +submodules. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Complex Set MeasureTheory +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- **Multivariable Laurent expansion on a connected Reinhardt domain.** The expansion is +absolutely and locally uniformly convergent, its coefficients are independent of the torus, +and they are unique. Negative exponents disappear in any coordinate whose hyperplane is met. -/ +theorem multivariableLaurent_expansion {U : Set (Fin n → ℂ)} (ho : IsOpen U) + (hc : IsPreconnected U) (hR : IsReinhardt U) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) + (hrU : (fun i => (r i : ℂ)) ∈ U) : + HasSumLocallyUniformlyOn (multivariableLaurentTerm (multivariableLaurentCoeff f r)) f U ∧ + (∀ z ∈ U, Summable (fun m => ‖multivariableLaurentTerm (multivariableLaurentCoeff f r) m z‖)) ∧ + (∀ (m : Fin n → ℤ) (i : Fin n), (∃ z ∈ U, z i = 0) → m i < 0 → + multivariableLaurentCoeff f r m = 0) ∧ + (∀ s : Fin n → ℝ, (∀ i, 0 < s i) → (fun i => (s i : ℂ)) ∈ U → + multivariableLaurentCoeff f s = multivariableLaurentCoeff f r) ∧ + (∀ c : (Fin n → ℤ) → F, + HasSumLocallyUniformlyOn (multivariableLaurentTerm c) f U → + c = multivariableLaurentCoeff f r) := by + refine ⟨hasSumLocallyUniformlyOn_multivariableLaurent_of_pointwise ho hc hR hf hr hrU + (fun z hz => hasSum_multivariableLaurent ho hc hR hf hr hrU hz), + fun z hz => summable_norm_multivariableLaurent ho hc hR hf hr hrU hz, + multivariableLaurentCoeff_neg_eq_zero ho hc hR hf hr hrU, + fun s hs hsU => multivariableLaurentCoeff_eq_of_radii ho hc hR hf hr hs hrU hsU, + fun c hs => eq_multivariableLaurentCoeff_of_hasSumLocallyUniformlyOn hf.continuousOn hr ?_ hs⟩ + intro z hz + apply hR hrU + intro i + simpa [abs_of_pos (hr i)] using hz i + +/-- Laurent expansion converges uniformly on compact subsets of the original domain. -/ +theorem hasSumUniformlyOn_multivariableLaurent {U K : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) + (hrU : (fun i => (r i : ℂ)) ∈ U) (hK : IsCompact K) (hKU : K ⊆ U) : + HasSumUniformlyOn (multivariableLaurentTerm (multivariableLaurentCoeff f r)) f K := + hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + ((tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK).mp + (((multivariableLaurent_expansion ho hc hR hf hr hrU).1).mono hKU)) + +/-- If a Reinhardt domain meets every coordinate hyperplane, only nonnegative exponents occur in its +Laurent expansion. This is Lemma 2.8.1 applied in each coordinate. -/ +theorem multivariableLaurentCoeff_eq_zero_of_not_nonneg {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) + (hmeet : ∀ i, ∃ z ∈ U, z i = 0) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) + (hrU : (fun i => (r i : ℂ)) ∈ U) {m : Fin n → ℤ} (hm : ¬ ∀ i, 0 ≤ m i) : + multivariableLaurentCoeff f r m = 0 := by + push Not at hm + obtain ⟨i, hi⟩ := hm + exact multivariableLaurentCoeff_neg_eq_zero ho hc hR hf hr hrU m i (hmeet i) hi + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Annulus.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Annulus.lean new file mode 100644 index 0000000000..0a5be50c73 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Annulus.lean @@ -0,0 +1,137 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.CauchyIntegral +public import Mathlib.Analysis.Normed.Group.Bounded +public import Mathlib.Topology.Algebra.InfiniteSum.NatInt + +/-! +# Cauchy's formula on an annulus + +Subtracting the value at the evaluation point removes the singularity of the Cauchy kernel. +Cauchy–Goursat on an annulus then gives the difference of the outer and inner Cauchy integrals. + +## Main results + +`circleIntegral_sub_inv_smul_sub_of_analyticOnNhd_annulus` is the annulus formula. +`circleIntegral_sub_inv_eq_zero_of_lt_norm` vanishes the inner integral when the evaluation +point lies outside the inner circle. `hasSum_circleIntegral_geometric` expands the outer kernel +as a geometric series. +-/ + +public noncomputable section + +open Complex Set Metric Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Integrating a divided difference separates the function and constant terms. -/ +private theorem circleIntegral_dslope {f : ℂ → F} {r : ℝ} (hr : 0 ≤ r) + (hf : ContinuousOn f (sphere (0 : ℂ) r)) {z : ℂ} + (hz : ∀ w ∈ sphere (0 : ℂ) r, w ≠ z) : + (∮ w in C(0, r), dslope f z w) = + (∮ w in C(0, r), (w - z)⁻¹ • f w) - + (∮ w in C(0, r), (w - z)⁻¹) • f z := by + have hk : ContinuousOn (fun w : ℂ => (w - z)⁻¹) (sphere 0 r) := + (continuousOn_id.sub continuousOn_const).inv₀ fun w hw => sub_ne_zero.mpr (hz w hw) + have h₁ : CircleIntegrable (fun w => (w - z)⁻¹ • f w) 0 r := + (hk.smul hf).circleIntegrable hr + have h₂ : CircleIntegrable (fun w => (w - z)⁻¹ • f z) 0 r := + (hk.smul continuousOn_const).circleIntegrable hr + rw [← circleIntegral.integral_smul_const, ← circleIntegral.integral_sub h₁ h₂] + apply circleIntegral.integral_congr hr + intro w hw + rw [dslope_of_ne _ (hz w hw), slope_def_module, smul_sub] + +/-- The Cauchy kernel has zero integral on a circle that does not enclose its pole. -/ +theorem circleIntegral_sub_inv_eq_zero_of_lt_norm {r : ℝ} (hr : 0 ≤ r) {z : ℂ} + (hz : r < ‖z‖) : (∮ w in C(0, r), (w - z)⁻¹) = 0 := by + have hd : DifferentiableOn ℂ (fun w : ℂ => (w - z)⁻¹) (closedBall 0 r) := by + intro w hw + apply ((differentiableAt_id.sub_const z).inv ?_).differentiableWithinAt + apply sub_ne_zero.mpr + intro he + change w = z at he + subst w + exact (not_le.mpr hz) (mem_closedBall_zero_iff.mp hw) + exact (hd.mono closure_ball_subset_closedBall).diffContOnCl.circleIntegral_eq_zero hr + +/-- Cauchy's formula between two concentric circles, for Banach-valued functions. -/ +theorem circleIntegral_sub_inv_smul_sub_of_analyticOnNhd_annulus + {f : ℂ → F} {r R : ℝ} (hr : 0 < r) {z : ℂ} + (hzr : r < ‖z‖) (hzR : ‖z‖ < R) + (hf : AnalyticOnNhd ℂ f (closedBall 0 R \ ball 0 r)) : + (∮ w in C(0, R), (w - z)⁻¹ • f w) - + (∮ w in C(0, r), (w - z)⁻¹ • f w) = (2 * Real.pi * I : ℂ) • f z := by + have hz : z ∈ closedBall (0 : ℂ) R \ ball 0 r := by + simp only [Set.mem_sdiff, mem_closedBall_zero_iff, mem_ball_zero_iff, not_lt] + exact ⟨hzR.le, hzr.le⟩ + have hn : closedBall (0 : ℂ) R \ ball 0 r ∈ 𝓝 z := + inter_mem (closedBall_mem_nhds_of_mem (mem_ball_zero_iff.mpr hzR)) + (mem_of_superset + (isClosed_closedBall.isOpen_compl.mem_nhds + (show z ∈ (closedBall (0 : ℂ) r)ᶜ by simpa using hzr)) + (compl_subset_compl.mpr ball_subset_closedBall)) + have hcont := (continuousOn_dslope hn).mpr ⟨hf.continuousOn, (hf z hz).differentiableAt⟩ + have he := circleIntegral_eq_of_differentiable_on_annulus_off_countable hr + (hzr.trans hzR).le (countable_singleton z) hcont (by + intro w hw + apply (differentiableAt_dslope_of_ne (by simpa using hw.2)).mpr + exact (hf w ⟨ball_subset_closedBall hw.1.1, + fun hb => hw.1.2 (ball_subset_closedBall hb)⟩).differentiableAt) + have hs (t : ℝ) (ht : t = r ∨ t = R) : sphere (0 : ℂ) t ⊆ closedBall 0 R \ ball 0 r := by + rintro w hw + have hw' := mem_sphere_zero_iff_norm.mp hw + simp only [Set.mem_sdiff, mem_closedBall_zero_iff, mem_ball_zero_iff, not_lt, hw'] + rcases ht with rfl | rfl <;> constructor <;> linarith + rw [circleIntegral_dslope (hr.trans (hzr.trans hzR)).le + (hf.continuousOn.mono (hs R (Or.inr rfl))) (by + intro w hw he; subst w; exact (ne_of_lt hzR) (mem_sphere_zero_iff_norm.mp hw)), + circleIntegral_dslope hr.le (hf.continuousOn.mono (hs r (Or.inl rfl))) (by + intro w hw he; subst w; exact (ne_of_gt hzr) (mem_sphere_zero_iff_norm.mp hw)), + circleIntegral.integral_sub_inv_of_mem_ball (mem_ball_zero_iff.mpr hzR), + circleIntegral_sub_inv_eq_zero_of_lt_norm hr.le hzr, zero_smul, sub_zero] at he + exact sub_eq_iff_eq_add.mpr (sub_eq_iff_eq_add.mp he |>.trans (add_comm _ _)) + +omit [CompleteSpace F] in +/-- A uniformly contracting scalar kernel can be summed under a circle integral. -/ +theorem hasSum_circleIntegral_geometric {f : ℂ → F} {g : ℂ → ℂ} {r q : ℝ} + (hr : 0 ≤ r) (hf : ContinuousOn f (sphere (0 : ℂ) r)) + (hg : ContinuousOn g (sphere (0 : ℂ) r)) (hq₀ : 0 ≤ q) (hq : q < 1) + (hbound : ∀ w ∈ sphere (0 : ℂ) r, ‖g w‖ ≤ q) : + HasSum (fun n : ℕ => ∮ w in C(0, r), g w ^ n • f w) + (∮ w in C(0, r), (1 - g w)⁻¹ • f w) := by + obtain ⟨M, hM⟩ := (isCompact_sphere (0 : ℂ) r).exists_bound_of_continuousOn hf + have hfc : Continuous (fun θ => f (circleMap 0 r θ)) := + hf.comp_continuous (continuous_circleMap _ _) (circleMap_mem_sphere _ hr) + have hgc : Continuous (fun θ => g (circleMap 0 r θ)) := + hg.comp_continuous (continuous_circleMap _ _) (circleMap_mem_sphere _ hr) + refine intervalIntegral.hasSum_integral_of_dominated_convergence + (fun n _ => r * (q ^ n * M)) (fun n => ?_) (fun n => ?_) ?_ ?_ ?_ + · apply Continuous.aestronglyMeasurable + simp only [deriv_circleMap] + exact ((continuous_circleMap 0 r).mul_const I).smul ((hgc.pow n).smul hfc) + · refine .of_forall fun θ _ => ?_ + simp only [norm_smul, norm_pow] + have hd : ‖deriv (circleMap 0 r) θ‖ = r := by simp [deriv_circleMap, abs_of_nonneg hr] + rw [hd] + gcongr + · exact hbound _ (circleMap_mem_sphere _ hr θ) + · exact hM _ (circleMap_mem_sphere _ hr θ) + · exact .of_forall fun _ _ => + ((summable_geometric_of_lt_one hq₀ hq).mul_right M).mul_left r + · exact intervalIntegrable_const + · refine .of_forall fun θ _ => ?_ + exact ((hasSum_geometric_of_norm_lt_one + ((hbound _ (circleMap_mem_sphere _ hr θ)).trans_lt hq)).smul_const _).const_smul _ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Basic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Basic.lean new file mode 100644 index 0000000000..2d1ce3bd0c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Basic.lean @@ -0,0 +1,216 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Integral.Pi +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.OneVariable +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc + +/-! +# Torus coefficients for Laurent series + +Integer-indexed coefficients are defined by integration on a coordinate torus. Their bounds and +their action on monomials do not require a Laurent expansion theorem. Negative powers are +written `z i ^ (-m i - 1)` in the integrand; this is compatible with Lean's totalized integer +powers at zero once the torus avoids the coordinate hyperplanes. + +## Main results + +`multivariableLaurentCoeff` is the coefficient of multi-index `m` on the torus of radii `r`. +`multivariableLaurentTerm` is the corresponding monomial term. +`norm_multivariableLaurentCoeff_le` is the Cauchy bound. `multivariableLaurentCoeff_monomial` +evaluates the coefficient on a monomial. `multivariableLaurentCoeff_fin_one` recovers the +one-variable `circleLaurentCoeff`. +-/ + +public noncomputable section + +open Complex Set MeasureTheory Metric +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- The Laurent coefficient obtained by integrating over a positive-radius coordinate torus. -/ +@[expose] def multivariableLaurentCoeff (f : (Fin n → ℂ) → F) (r : Fin n → ℝ) + (m : Fin n → ℤ) : F := + ((2 * π * I : ℂ) ^ n)⁻¹ • + torusIntegral (fun z => (∏ i, z i ^ (-m i - 1)) • f z) 0 r + +omit [CompleteSpace F] in +/-- The multivariable circle coefficient in dimension one is the ordinary Laurent coefficient. -/ +theorem multivariableLaurentCoeff_fin_one (f : ℂ → F) (r : ℝ) (k : ℤ) : + multivariableLaurentCoeff (fun z : Fin 1 → ℂ => f (z 0)) (fun _ => r) (fun _ => k) = + circleLaurentCoeff f r k := by + simp [multivariableLaurentCoeff, torusIntegral_dim1, circleLaurentCoeff] + +/-- An integer-indexed Laurent term. Negative powers at zero are totalized; the expansion theorem +separately forces their coefficients to vanish whenever necessary. -/ +@[expose] def multivariableLaurentTerm (c : (Fin n → ℤ) → F) (m : Fin n → ℤ) (z : Fin n → ℂ) : F := + (∏ i, z i ^ m i) • c m + +omit [CompleteSpace F] in +/-- Cauchy's bound for an integer-indexed torus coefficient. -/ +theorem norm_multivariableLaurentCoeff_le {f : (Fin n → ℂ) → F} {r : Fin n → ℝ} + (hr : ∀ i, 0 < r i) {M : ℝ} (hM : ∀ θ, ‖f (torusMap 0 r θ)‖ ≤ M) + (m : Fin n → ℤ) : ‖multivariableLaurentCoeff f r m‖ ≤ M * ∏ i, r i ^ (-m i) := by + have hker (θ : Fin n → ℝ) : ‖∏ i, torusMap 0 r θ i ^ (-m i - 1)‖ = + ∏ i, r i ^ (-m i - 1) := by + simp [norm_prod, norm_zpow, torusMap, abs_of_pos (hr _)] + rw [multivariableLaurentCoeff, norm_smul] + refine (mul_le_mul_of_nonneg_left (norm_torusIntegral_le_of_norm_le_const + (C := M * ∏ i, r i ^ (-m i - 1)) ?_) (norm_nonneg _)).trans_eq ?_ + · intro θ + rw [norm_smul, hker] + exact (mul_le_mul_of_nonneg_left (hM θ) + (Finset.prod_nonneg fun i _ => zpow_nonneg (hr i).le _)).trans_eq (mul_comm _ _) + · simp only [norm_inv, norm_pow, norm_mul, norm_ofNat, norm_real, norm_I, mul_one, + Real.norm_eq_abs, abs_of_pos Real.pi_pos, abs_of_pos (hr _)] + have hp : (∏ i, r i) * (∏ i, r i ^ (-m i - 1)) = ∏ i, r i ^ (-m i) := by + rw [← Finset.prod_mul_distrib] + apply Finset.prod_congr rfl + intro i _ + calc + r i * r i ^ (-m i - 1) = r i ^ (1 : ℤ) * r i ^ (-m i - 1) := by rw [zpow_one] + _ = r i ^ (-m i) := by rw [← zpow_add₀ (hr i).ne']; congr 1; omega + calc + ((2 * π) ^ n)⁻¹ * (((2 * π) ^ n * ∏ i, r i) * (M * ∏ i, r i ^ (-m i - 1))) = + M * ((∏ i, r i) * ∏ i, r i ^ (-m i - 1)) := by field_simp + _ = _ := by rw [hp] + +/-- A product of scalar functions separates into a product of circle integrals. -/ +theorem torusIntegral_prod (g : Fin n → ℂ → ℂ) (r : Fin n → ℝ) : + torusIntegral (fun z => ∏ i, g i (z i)) 0 r = + ∏ i, ∮ w in C(0, r i), g i w := by + have hbox : Icc (0 : Fin n → ℝ) (fun _ => 2 * π) = + Set.pi univ (fun _ : Fin n => Icc (0 : ℝ) (2 * π)) := by ext θ; simp [Set.mem_Icc, Pi.le_def] + simp only [torusIntegral, smul_eq_mul, ← Finset.prod_mul_distrib] + simp only [torusMap, Pi.zero_apply, zero_add] + rw [hbox, volume_pi, Measure.restrict_pi_pi, integral_fintype_prod_eq_prod + (fun i (θ : ℝ) => (r i : ℂ) * exp (θ * I) * I * g i ((r i : ℂ) * exp (θ * I)))] + apply Finset.prod_congr rfl + intro i _ + rw [circleIntegral_def_Icc] + congr 1 + funext θ + simp [circleMap, deriv_circleMap] + +/-- Integer monomials have zero torus integral unless every exponent is `-1`. -/ +theorem torusIntegral_zpow_prod (r : Fin n → ℝ) (hr : ∀ i, 0 < r i) (m : Fin n → ℤ) : + torusIntegral (fun z => ∏ i, z i ^ m i) 0 r = + ∏ i, if m i = -1 then (2 * π * I : ℂ) else 0 := by + rw [torusIntegral_prod (fun i w => w ^ m i)] + apply Finset.prod_congr rfl + intro i _ + by_cases hi : m i = -1 + · simp only [hi, ite_true, zpow_neg_one] + simpa using circleIntegral.integral_sub_inv_of_mem_ball (mem_ball_self (x := (0 : ℂ)) (hr i)) + · simp only [hi, ite_false] + simpa using circleIntegral.integral_sub_zpow_of_ne hi 0 0 (r i) + +omit [CompleteSpace F] in +/-- Torus integrals depend only on values on the parametrized torus. -/ +theorem torusIntegral_congr {f g : (Fin n → ℂ) → F} {r : Fin n → ℝ} + (h : ∀ θ, f (torusMap 0 r θ) = g (torusMap 0 r θ)) : + torusIntegral f 0 r = torusIntegral g 0 r := by + unfold torusIntegral + apply integral_congr_ae + exact Filter.Eventually.of_forall fun θ => congrArg (_ • ·) (h θ) + +/-- A constant vector can be taken outside a scalar torus integral. -/ +theorem torusIntegral_smul_const (f : (Fin n → ℂ) → ℂ) (r : Fin n → ℝ) (v : F) : + torusIntegral (fun z => f z • v) 0 r = torusIntegral f 0 r • v := by + simp only [torusIntegral, ← smul_assoc, integral_smul_const] + +/-- A Laurent monomial has exactly its prescribed coefficient on every positive torus. -/ +theorem multivariableLaurentCoeff_monomial (r : Fin n → ℝ) (hr : ∀ i, 0 < r i) + (k m : Fin n → ℤ) (v : F) : + multivariableLaurentCoeff (fun z => (∏ i, z i ^ k i) • v) r m = + if m = k then v else 0 := by + classical + have he : torusIntegral (fun z => (∏ i, z i ^ (-m i - 1)) • ((∏ i, z i ^ k i) • v)) 0 r = + torusIntegral (fun z => (∏ i, z i ^ (k i - m i - 1)) • v) 0 r := by + apply torusIntegral_congr + intro θ + rw [smul_smul, ← Finset.prod_mul_distrib] + congr 1 + apply Finset.prod_congr rfl + intro i _ + have hi : torusMap 0 r θ i ≠ 0 := by simp [torusMap, (hr i).ne'] + rw [← zpow_add₀ hi] + congr 1 + omega + rw [multivariableLaurentCoeff, he, torusIntegral_smul_const, torusIntegral_zpow_prod r hr] + by_cases hmk : m = k + · subst m + simp only [sub_self, zero_sub, ite_true, Fin.prod_const] + exact inv_smul_smul₀ (pow_ne_zero _ two_pi_I_ne_zero) v + · rw [ite_eq_right hmk] + have hi : ∃ i, m i ≠ k i := Function.ne_iff.mp hmk + obtain ⟨i, hi⟩ := hi + have hp : (∏ i, if k i - m i - 1 = -1 then (2 * π * I : ℂ) else 0) = 0 := by + apply Finset.prod_eq_zero (Finset.mem_univ i) + rw [ite_eq_right (by omega)] + rw [hp, zero_smul, smul_zero] + +omit [CompleteSpace F] in +/-- Multiplying by an integer monomial preserves continuity along a positive torus. -/ +theorem continuous_laurentMonomial_smul_torus {f : (Fin n → ℂ) → F} {r : Fin n → ℝ} + (hr : ∀ i, 0 < r i) (hf : Continuous (fun θ => f (torusMap 0 r θ))) (m : Fin n → ℤ) : + Continuous (fun θ => (∏ i, torusMap 0 r θ i ^ m i) • f (torusMap 0 r θ)) := by + apply Continuous.smul _ hf + apply continuous_finsetProd + intro i _ + exact ((continuous_apply i).comp (continuous_torusMap 0 r)).zpow₀ _ + (fun θ => Or.inl (by simp [torusMap, (hr i).ne'])) + +omit [CompleteSpace F] in +/-- A continuous function on a positive torus has integrable Laurent kernels. -/ +theorem torusIntegrable_laurentKernel {f : (Fin n → ℂ) → F} {r : Fin n → ℝ} + (hr : ∀ i, 0 < r i) (hf : Continuous (fun θ => f (torusMap 0 r θ))) (m : Fin n → ℤ) : + TorusIntegrable (fun z => (∏ i, z i ^ (-m i - 1)) • f z) 0 r := + ((continuous_laurentMonomial_smul_torus hr hf (fun i => -m i - + 1)).continuousOn).integrableOn_compact + isCompact_Icc + +omit [CompleteSpace F] in +/-- Laurent coefficients commute with finite sums of functions continuous on the torus. -/ +theorem multivariableLaurentCoeff_sum {α : Type*} (s : Finset α) + {f : α → (Fin n → ℂ) → F} {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) + (hf : ∀ a ∈ s, Continuous (fun θ => f a (torusMap 0 r θ))) (m : Fin n → ℤ) : + multivariableLaurentCoeff (fun z => ∑ a ∈ s, f a z) r m = + ∑ a ∈ s, multivariableLaurentCoeff (f a) r m := by + simp only [multivariableLaurentCoeff, torusIntegral, Finset.smul_sum] + rw [integral_finsetSum] + · exact Finset.smul_sum + · intro a ha + exact (torusIntegrable_laurentKernel hr (hf a ha) m).function_integrable + +omit [CompleteSpace F] in +/-- Laurent coefficients commute with subtraction for functions continuous on the torus. -/ +theorem multivariableLaurentCoeff_sub {f g : (Fin n → ℂ) → F} {r : Fin n → ℝ} + (hr : ∀ i, 0 < r i) (hf : Continuous (fun θ => f (torusMap 0 r θ))) + (hg : Continuous (fun θ => g (torusMap 0 r θ))) (m : Fin n → ℤ) : + multivariableLaurentCoeff (fun z => f z - g z) r m = + multivariableLaurentCoeff f r m - multivariableLaurentCoeff g r m := by + simp only [multivariableLaurentCoeff, smul_sub] + rw [torusIntegral_sub (torusIntegrable_laurentKernel hr hf m) + (torusIntegrable_laurentKernel hr hg m), smul_sub] + +omit [CompleteSpace F] in +/-- Laurent coefficients depend only on values on their coefficient torus. -/ +theorem multivariableLaurentCoeff_congr {f g : (Fin n → ℂ) → F} {r : Fin n → ℝ} + (h : ∀ θ, f (torusMap 0 r θ) = g (torusMap 0 r θ)) : + multivariableLaurentCoeff f r = multivariableLaurentCoeff g r := by + funext m + unfold multivariableLaurentCoeff + congr 1 + exact torusIntegral_congr fun θ => congrArg (_ • ·) (h θ) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Coefficients.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Coefficients.lean new file mode 100644 index 0000000000..f17b09b56e --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Coefficients.lean @@ -0,0 +1,114 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.LocallyConstant.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Neighborhoods +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.ProductCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Connected + +/-! +# Global Laurent coefficients on Reinhardt domains + +The space of admissible positive radii is connected. Local independence on circular product +neighborhoods therefore gives global independence of the coefficient torus. + +## Main results + +`IsReinhardt.isConnected_positive_radii` is connectedness of the positive radius vectors in a +connected open Reinhardt domain. `multivariableLaurentCoeff_eq_of_radii` is independence of the +torus. `multivariableLaurentCoeff_neg_eq_zero` vanishes coefficients with a negative exponent in +a coordinate that meets a hyperplane. +-/ + +public noncomputable section + +open Complex Set Metric Filter +open scoped Topology NNReal + +namespace SeveralComplexVariables + +/-- Positive radius vectors of a connected open Reinhardt domain form a connected set. -/ +theorem IsReinhardt.isConnected_positive_radii {n : ℕ} {U : Set (Fin n → ℂ)} + (hR : IsReinhardt U) (ho : IsOpen U) (hc : IsPreconnected U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) : + IsConnected {s : Fin n → ℝ | (∀ i, 0 < s i) ∧ (fun i => (s i : ℂ)) ∈ U} := by + have hp : AnalyticOnNhd ℂ (fun z : Fin n → ℂ => ∏ i, z i) U := by + intro z _ + apply Finset.analyticAt_fun_prod + intro i _ + exact (ContinuousLinearMap.proj (R := ℂ) i).analyticAt z + have hconn := isConnected_nonzero_of_analyticOnNhd ho hc hp + ⟨fun i => (r i : ℂ), hrU, Finset.prod_ne_zero_iff.mpr (fun i _ => by exact_mod_cast (hr i).ne')⟩ + have he : (fun z : Fin n → ℂ => fun i => ‖z i‖) '' (U \ (fun z => ∏ i, z i) ⁻¹' {0}) = + {s : Fin n → ℝ | (∀ i, 0 < s i) ∧ (fun i => (s i : ℂ)) ∈ U} := by + ext s + constructor + · rintro ⟨z, ⟨hz, hn⟩, rfl⟩ + have hn' : ∏ i, z i ≠ 0 := hn + exact ⟨fun i => norm_pos_iff.mpr ((Finset.prod_ne_zero_iff.mp hn') i (Finset.mem_univ _)), + hR hz (fun i => by simp)⟩ + · rintro ⟨hs, hsU⟩ + refine ⟨fun i => (s i : ℂ), ⟨hsU, ?_⟩, ?_⟩ + · exact Finset.prod_ne_zero_iff.mpr (fun i _ => by exact_mod_cast (hs i).ne') + · funext i; simp [abs_of_pos (hs i)] + rw [← he] + exact hconn.image _ (by fun_prop) + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Laurent coefficients on a connected Reinhardt domain are independent of the torus. The proof +uses local Cauchy–Goursat and connectedness, not Laurent expansion. -/ +theorem multivariableLaurentCoeff_eq_of_radii {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {r s : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hs : ∀ i, 0 < s i) + (hrU : (fun i => (r i : ℂ)) ∈ U) (hsU : (fun i => (s i : ℂ)) ∈ U) : + multivariableLaurentCoeff f s = multivariableLaurentCoeff f r := by + let D : Set (Fin n → ℝ) := {t | (∀ i, 0 < t i) ∧ (fun i => (t i : ℂ)) ∈ U} + have hD : IsConnected D := hR.isConnected_positive_radii ho hc hr hrU + let : PreconnectedSpace D := isPreconnected_iff_preconnectedSpace.mp hD.isPreconnected + let g : D → ((Fin n → ℤ) → F) := fun t => multivariableLaurentCoeff f t.val + have hg : IsLocallyConstant g := by + apply (IsLocallyConstant.iff_eventually_eq g).mpr + intro t + obtain ⟨V, hVo, hVc, hVr, htV, hVU⟩ := + hR.exists_circular_product_neighborhood ho t.property.2 + have hv : IsOpen (Set.pi univ V) := isOpen_set_pi finite_univ (fun i _ => hVo i) + have ht : ∀ᶠ u : D in 𝓝 t, (fun i => (u.val i : ℂ)) ∈ Set.pi univ V := + (hv.preimage (continuous_pi fun i => Complex.continuous_ofReal.comp + ((continuous_apply i).comp continuous_subtype_val))).mem_nhds htV + filter_upwards [ht] with u hu + exact multivariableLaurentCoeff_eq_on_product hVo hVc hVr (hf.mono hVU) + t.property.1 u.property.1 (fun i => htV i (mem_univ _)) (fun i => hu i (mem_univ _)) + exact hg.apply_eq_of_preconnectedSpace ⟨s, hs, hsU⟩ ⟨r, hr, hrU⟩ + +/-- Meeting a coordinate hyperplane forces every negative coefficient in that coordinate to vanish. +This follows from the circle Cauchy theorem on a local product neighborhood. -/ +theorem multivariableLaurentCoeff_neg_eq_zero {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + (m : Fin n → ℤ) (i : Fin n) (hzero : ∃ z ∈ U, z i = 0) (hm : m i < 0) : + multivariableLaurentCoeff f r m = 0 := by + obtain ⟨z, hz, hzi⟩ := hzero + obtain ⟨V, hVo, hVc, hVr, hzV, hVU⟩ := hR.exists_circular_product_neighborhood ho hz + have hprod : IsReinhardt (Set.pi univ V) := by + intro x hx y hy j _ + exact hVr j _ (hx j (mem_univ _)) _ (hy j) + obtain ⟨s, hsV, hs⟩ := hprod.exists_strict_modulus_majorant + (isOpen_set_pi finite_univ (fun i _ => hVo i)) hzV + have hspos (j : Fin n) : 0 < (s j : ℝ) := by + exact_mod_cast (show (0 : ℝ≥0) ≤ ‖z j‖₊ from zero_le).trans_lt (hs j) + have he := multivariableLaurentCoeff_eq_of_radii ho hc hR hf hr hspos hrU (hVU hsV) + rw [← he] + exact multivariableLaurentCoeff_neg_on_product hVo hVc hVr (hf.mono hVU) hspos + (fun j => hsV j (mem_univ _)) m i (by simpa only [hzi] using hzV i (mem_univ _)) hm + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Convergence.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Convergence.lean new file mode 100644 index 0000000000..8c9052bfdf --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Convergence.lean @@ -0,0 +1,229 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Ring.InfiniteSum +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Coefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform + +/-! +# Normal convergence of Laurent coefficient families + +Inner and outer coefficient tori bound the two halves of each coordinate series by geometric +sequences. Their finite products give summable local majorants. + +## Main results + +`exists_local_laurent_majorant` produces a geometric bound from inner and outer tori. +`summable_norm_multivariableLaurent` is absolute summability of the terms. +`hasSumLocallyUniformlyOn_multivariableLaurent_of_pointwise` upgrades a pointwise summable +expansion to locally uniform convergence. +-/ + +public noncomputable section + +open Complex Set Metric Filter +open scoped Real Topology + +namespace SeveralComplexVariables + +/-- A finite product of nonnegative summable families is summable over all tuples. -/ +private theorem summable_fin_prod_of_nonneg {n : ℕ} (b : Fin n → ℤ → ℝ) + (hb : ∀ i, Summable (b i)) (hb₀ : ∀ i k, 0 ≤ b i k) : + Summable (fun m : Fin n → ℤ => ∏ i, b i (m i)) := by + induction n with + | zero => exact Summable.of_finite + | succ n ih => + have h := (hb 0).mul_of_nonneg (ih (fun i => b i.succ) (fun i => hb i.succ) + (fun i => hb₀ i.succ)) (hb₀ 0) (fun m => Finset.prod_nonneg (fun i _ => hb₀ i.succ (m i))) + apply (Fin.consEquiv (fun _ : Fin (n + 1) => ℤ)).summable_iff.mp + simpa [Fin.consEquiv, Fin.prod_univ_succ, Function.comp_def] using h + +/-- Positive and negative geometric tails give a summable integer-indexed family. -/ +private theorem summable_two_sided_geometric {p q : ℝ} + (hp₀ : 0 ≤ p) (hp : p < 1) (hq₀ : 0 ≤ q) (hq : q < 1) : + Summable (Int.rec (fun n => p ^ n) (fun n => q ^ (n + 1))) := by + apply (summable_geometric_of_lt_one hp₀ hp).int_rec + simpa only [pow_succ] using (summable_geometric_of_lt_one hq₀ hq).mul_right q + +/-- A scalar Laurent factor is controlled by its inner or outer geometric ratio. -/ +private theorem zpow_mul_corner_le {a b t T u : ℝ} + (ha : 0 < a) (hb : 0 < b) (ht : 0 < t) (hu : 0 ≤ u) + (huT : u ≤ T) (k : ℤ) (htu : k < 0 → t ≤ u) : + u ^ k * (if k < 0 then a else b) ^ (-k) ≤ + Int.rec (fun n => (T / b) ^ n) (fun n => (a / t) ^ (n + 1)) k := by + cases k with + | ofNat n => + simp only [zpow_neg] + calc + u ^ n * (b ^ n)⁻¹ ≤ T ^ n * (b ^ n)⁻¹ := by gcongr + _ = (T / b) ^ n := by simp [div_eq_mul_inv, mul_pow] + | negSucc n => + have htu' := htu (by omega) + simp only [Int.negSucc_lt_zero, ite_true, Int.neg_negSucc, zpow_natCast, zpow_negSucc] + calc + (u ^ (n + 1))⁻¹ * a ^ (n + 1) ≤ (t ^ (n + 1))⁻¹ * a ^ (n + 1) := by gcongr + _ = (a / t) ^ (n + 1) := by simp only [div_eq_mul_inv]; ring + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- Corner coefficient bounds give a product geometric bound for every Laurent term. -/ +private theorem norm_laurentTerm_le_geometric {c : (Fin n → ℤ) → F} + {a b t T : Fin n → ℝ} (ha : ∀ i, 0 < a i) (hb : ∀ i, 0 < b i) + (ht : ∀ i, 0 < t i) (hT : ∀ i, 0 ≤ T i) {M : ℝ} (hM : 0 ≤ M) + {z w : Fin n → ℂ} (hwT : ∀ i, ‖w i‖ ≤ T i) + (htw : ∀ i, z i ≠ 0 → t i ≤ ‖w i‖) (m : Fin n → ℤ) + (hzero : ∀ i, z i = 0 → m i < 0 → c m = 0) + (hc : ‖c m‖ ≤ M * ∏ i, (if m i < 0 then a i else b i) ^ (-m i)) : + ‖multivariableLaurentTerm c m w‖ ≤ + M * ∏ i, Int.rec (fun n => (T i / b i) ^ n) (fun n => (a i / t i) ^ (n + 1)) (m i) := by + have hgeom (i : Fin n) : + (0 : ℝ) ≤ Int.rec (fun n => (T i / b i) ^ n) (fun n => (a i / t i) ^ (n + 1)) (m i) := by + cases m i with + | ofNat k => exact pow_nonneg (div_nonneg (hT i) (hb i).le) _ + | negSucc k => exact pow_nonneg (div_nonneg (ha i).le (ht i).le) _ + by_cases hbad : ∃ i, z i = 0 ∧ m i < 0 + · obtain ⟨i, hi, hm⟩ := hbad + rw [multivariableLaurentTerm, hzero i hi hm, smul_zero, norm_zero] + exact mul_nonneg hM (Finset.prod_nonneg fun i _ => hgeom i) + · rw [multivariableLaurentTerm, norm_smul, norm_prod] + simp only [norm_zpow] + calc + (∏ i, ‖w i‖ ^ m i) * ‖c m‖ ≤ + (∏ i, ‖w i‖ ^ m i) * (M * ∏ i, (if m i < 0 then a i else b i) ^ (-m i)) := + mul_le_mul_of_nonneg_left hc (Finset.prod_nonneg fun i _ => zpow_nonneg (norm_nonneg _) _) + _ = M * ∏ i, ‖w i‖ ^ m i * (if m i < 0 then a i else b i) ^ (-m i) := by + rw [Finset.prod_mul_distrib]; ring + _ ≤ _ := by + apply mul_le_mul_of_nonneg_left _ hM + apply Finset.prod_le_prod₀ + · intro i _ + apply mul_nonneg (zpow_nonneg (norm_nonneg _) _) + apply zpow_nonneg + split_ifs + · exact (ha i).le + · exact (hb i).le + · intro i _ + exact zpow_mul_corner_le (ha i) (hb i) (ht i) (norm_nonneg _) (hwT i) (m i) + (fun hm => htw i (fun hi => hbad ⟨i, hi, hm⟩)) + +omit [NormedSpace ℂ F] in +/-- The finitely many corner tori of a circular product share a bound for a continuous function. -/ +private theorem exists_bound_torus_corners {V : Fin n → Set ℂ} + (hrot : ∀ i, ∀ v ∈ V i, ∀ w : ℂ, ‖w‖ = ‖v‖ → w ∈ V i) + {a b : Fin n → ℝ} (ha : ∀ i, 0 < a i) (hb : ∀ i, 0 < b i) + (haV : ∀ i, (a i : ℂ) ∈ V i) (hbV : ∀ i, (b i : ℂ) ∈ V i) + {f : (Fin n → ℂ) → F} (hf : ContinuousOn f (Set.pi univ V)) : + ∃ M : ℝ, 0 ≤ M ∧ ∀ p : Fin n → Bool, ∀ θ, + ‖f (torusMap 0 (fun i => if p i then a i else b i) θ)‖ ≤ M := by + let r (p : Fin n → Bool) (i : Fin n) := if p i then a i else b i + have hr (p : Fin n → Bool) (i : Fin n) : 0 < r p i := by + dsimp [r]; split_ifs <;> [exact ha i; exact hb i] + have hrV (p : Fin n → Bool) (i : Fin n) : (r p i : ℂ) ∈ V i := by + dsimp [r]; split_ifs <;> [exact haV i; exact hbV i] + let K (p : Fin n → Bool) := {w : Fin n → ℂ | ∀ i, w i ∈ sphere 0 (r p i)} + have hKV (p : Fin n → Bool) : K p ⊆ Set.pi univ V := by + intro w hw i _ + apply hrot i _ (hrV p i) _ + simpa [abs_of_pos (hr p i)] using hw i + have hbound (p : Fin n → Bool) : ∃ M : ℝ, ∀ w ∈ K p, ‖f w‖ ≤ M := + (isCompact_pi_infinite fun i => isCompact_sphere (0 : ℂ) (r p i)).exists_bound_of_continuousOn + (hf.mono (hKV p)) + choose M hM using hbound + refine ⟨∑ p, max (M p) 0, Finset.sum_nonneg (fun p _ => le_max_right _ _), ?_⟩ + intro p θ + apply (hM p _ (fun i => by + change torusMap 0 (r p) θ i ∈ sphere 0 (r p i) + simp [torusMap, abs_of_pos (hr p i)])).trans + exact (le_max_left _ _).trans (Finset.single_le_sum + (fun q _ => le_max_right (M q) 0) (Finset.mem_univ p)) + +variable [CompleteSpace F] + +/-- Every point has a neighborhood on which the Laurent terms admit a summable majorant. -/ +theorem exists_local_laurent_majorant {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + {z : Fin n → ℂ} (hz : z ∈ U) : + ∃ N : Set (Fin n → ℂ), N ∈ 𝓝 z ∧ N ⊆ U ∧ + ∃ B : (Fin n → ℤ) → ℝ, Summable B ∧ ∀ m, ∀ w ∈ N, + ‖multivariableLaurentTerm (multivariableLaurentCoeff f r) m w‖ ≤ B m := by + obtain ⟨V, hVo, hVc, hVr, hzV, hVU⟩ := hR.exists_circular_product_neighborhood ho hz + choose a b t T ha hat hT hTb haV hbV hzT htz using + fun i => exists_circular_radii_bounds (hVo i) (hVr i) (hzV i (mem_univ _)) + have hb (i) : 0 < b i := (hT i).trans (hTb i) + have ht (i) : 0 < t i := (ha i).trans (hat i) + obtain ⟨M, hM, hcorner⟩ := exists_bound_torus_corners hVr ha hb haV hbV (hf.continuousOn.mono hVU) + let W : Fin n → Set ℂ := fun i => {w | ‖w‖ < T i ∧ (z i ≠ 0 → t i < ‖w‖)} + have hWo (i) : IsOpen (W i) := by + by_cases hzi : z i = 0 + · simpa [W, hzi] using isOpen_lt (f := fun w : ℂ => ‖w‖) continuous_norm + (g := fun _ => T i) continuous_const + · simp only [W, hzi, ne_eq, not_false_eq_true, true_implies] + exact (isOpen_lt (f := fun w : ℂ => ‖w‖) continuous_norm + (g := fun _ => T i) continuous_const).inter + (isOpen_lt (f := fun _ : ℂ => t i) continuous_const continuous_norm) + let B (m : Fin n → ℤ) := + M * ∏ i, Int.rec (fun k => (T i / b i) ^ k) (fun k => (a i / t i) ^ (k + 1)) (m i) + have hB : Summable B := by + apply Summable.mul_left M + apply summable_fin_prod_of_nonneg + · intro i + exact summable_two_sided_geometric (div_nonneg (hT i).le (hb i).le) + ((div_lt_one (hb i)).mpr (hTb i)) (div_nonneg (ha i).le (ht i).le) + ((div_lt_one (ht i)).mpr (hat i)) + · intro i k + cases k with + | ofNat k => exact pow_nonneg (div_nonneg (hT i).le (hb i).le) _ + | negSucc k => exact pow_nonneg (div_nonneg (ha i).le (ht i).le) _ + refine ⟨Set.pi univ W ∩ U, + ((isOpen_set_pi finite_univ (fun i _ => hWo i)).inter ho).mem_nhds + ⟨fun i _ => ⟨hzT i, htz i⟩, hz⟩, inter_subset_right, B, hB, ?_⟩ + intro m w hw + apply norm_laurentTerm_le_geometric ha hb ht (fun i => (hT i).le) hM + (fun i => (hw.1 i (mem_univ _)).1.le) + (fun i hi => ((hw.1 i (mem_univ _)).2 hi).le) m + · intro i hzi hmi + exact multivariableLaurentCoeff_neg_eq_zero ho hc hR hf hr hrU m i ⟨z, hz, hzi⟩ hmi + · let q (i : Fin n) := if m i < 0 then a i else b i + have hq (i) : 0 < q i := by dsimp [q]; split_ifs <;> [exact ha i; exact hb i] + have hqV : (fun i => (q i : ℂ)) ∈ Set.pi univ V := by + intro i _; dsimp [q]; split_ifs <;> [exact haV i; exact hbV i] + rw [← multivariableLaurentCoeff_eq_of_radii ho hc hR hf hr hq hrU (hVU hqV)] + apply norm_multivariableLaurentCoeff_le hq + intro θ + simpa [q] using hcorner (fun i => decide (m i < 0)) θ + +/-- The Laurent expansion family is absolutely summable at every point of the domain. -/ +theorem summable_norm_multivariableLaurent {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + {z : Fin n → ℂ} (hz : z ∈ U) : + Summable (fun m => ‖multivariableLaurentTerm (multivariableLaurentCoeff f r) m z‖) := by + obtain ⟨N, hN, _, B, hB, hb⟩ := exists_local_laurent_majorant ho hc hR hf hr hrU hz + exact hB.of_nonneg_of_le (fun _ => norm_nonneg _) (fun m => hb m z (mem_of_mem_nhds hN)) + +/-- Pointwise Laurent expansion with torus coefficients automatically converges locally +uniformly. -/ +theorem hasSumLocallyUniformlyOn_multivariableLaurent_of_pointwise {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + (hsum : ∀ z ∈ U, HasSum (fun m => multivariableLaurentTerm (multivariableLaurentCoeff f r) m + z) (f z)) : + HasSumLocallyUniformlyOn (multivariableLaurentTerm (multivariableLaurentCoeff f r)) f U := by + apply hasSumLocallyUniformlyOn_of_of_forall_exists_nhds + intro z hz + obtain ⟨N, hN, hNU, B, hB, hb⟩ := exists_local_laurent_majorant ho hc hR hf hr hrU hz + refine ⟨N, mem_nhdsWithin_of_mem_nhds hN, ?_⟩ + apply hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + exact (tendstoUniformlyOn_tsum hB hb).congr_right (fun w hw => (hsum w (hNU hw)).tsum_eq) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Iterated.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Iterated.lean new file mode 100644 index 0000000000..849e637c12 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Iterated.lean @@ -0,0 +1,99 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Basic + +/-! +# Iterated Laurent coefficients + +Fubini's theorem writes a torus integral with the first circle integrated first. Consequently +Laurent coefficients can be computed one coordinate at a time. + +## Main results + +`torusIntegral_succ_inner` is Fubini for the first circle of a coordinate torus. +`multivariableLaurentCoeff_succ` identifies the multivariable coefficient with an iterated +one-variable coefficient in the remaining coordinates. +-/ + +public noncomputable section + +open Complex Set MeasureTheory Function +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +omit [CompleteSpace F] in +/-- A torus integral can be evaluated by first integrating the first coordinate circle. -/ +theorem torusIntegral_succ_inner {f : (Fin (n + 1) → ℂ) → F} + {c : Fin (n + 1) → ℂ} {r : Fin (n + 1) → ℝ} (hf : TorusIntegrable f c r) : + torusIntegral f c r = torusIntegral + (fun y => ∮ x in C(c 0, r 0), f (Fin.cons x y)) (c ∘ Fin.succ) (r ∘ Fin.succ) := by + let e : ℝ × (Fin n → ℝ) ≃ᵐ (Fin (n + 1) → ℝ) := + (MeasurableEquiv.piFinSuccAbove (fun _ => ℝ) 0).symm + have hem : MeasurePreserving e := + (volume_preserving_piFinSuccAbove (fun _ : Fin (n + 1) => ℝ) 0).symm _ + have heπ : e ⁻¹' Icc 0 (fun _ => 2 * π) = + Icc 0 (2 * π) ×ˢ Icc (0 : Fin n → ℝ) (fun _ => 2 * π) := + ((Fin.insertNthOrderIso (fun _ => ℝ) 0).preimage_Icc _ _).trans (Icc_prod_eq _ _) + rw [torusIntegral, ← hem.map_eq, setIntegral_map_equiv, heπ, Measure.volume_eq_prod, + ← setIntegral_prod_swap, setIntegral_prod] + · rw [torusIntegral] + refine setIntegral_congr_fun measurableSet_Icc fun Θ _ => ?_ + simp only [circleIntegral_def_Icc, ← integral_smul] + refine setIntegral_congr_fun measurableSet_Icc fun θ _ => ?_ + simp only [e, MeasurableEquiv.piFinSuccAbove_symm_apply, Fin.insertNth_zero, + Fin.insertNthEquiv, Equiv.coe_fn_mk, Fin.prod_univ_succ, Fin.cons_zero, Fin.cons_succ, + Function.comp_apply, deriv_circleMap, smul_smul] + congr 1 + · simp [circleMap, mul_assoc, mul_comm] + · congr 1 + funext i + refine Fin.cases ?_ (fun j => ?_) i <;> simp [torusMap, circleMap] + · have h := hf.function_integrable + rw [← hem.integrableOn_comp_preimage e.measurableEmbedding, heπ] at h + exact h.swap + +omit [CompleteSpace F] in +/-- A multivariable Laurent coefficient is obtained by taking a circle coefficient first. -/ +theorem multivariableLaurentCoeff_succ {f : (Fin (n + 1) → ℂ) → F} + {r : Fin (n + 1) → ℝ} (hr : ∀ i, 0 < r i) + (hf : Continuous (fun θ => f (torusMap 0 r θ))) (m : Fin (n + 1) → ℤ) : + multivariableLaurentCoeff f r m = + multivariableLaurentCoeff + (fun y => circleLaurentCoeff (fun x => f (Fin.cons x y)) (r 0) (m 0)) + (r ∘ Fin.succ) (m ∘ Fin.succ) := by + let g (y : Fin n → ℂ) := ∮ x in C(0, r 0), x ^ (-m 0 - 1) • f (Fin.cons x y) + let b (y : Fin n → ℂ) := ∏ i, y i ^ (-m i.succ - 1) + have hcircle (y : Fin n → ℂ) : + (∮ x in C(0, r 0), (∏ i, (Fin.cons x y : Fin (n + 1) → ℂ) i ^ (-m i - 1)) • f (Fin.cons x + y)) = + b y • g y := by + rw [← circleIntegral.integral_smul] + apply circleIntegral.integral_congr (hr 0).le + intro x _ + dsimp only [b, g] + rw [Fin.prod_univ_succ] + simp only [Fin.cons_zero, Fin.cons_succ, mul_smul] + exact smul_comm _ _ _ + rw [multivariableLaurentCoeff, torusIntegral_succ_inner (torusIntegrable_laurentKernel hr hf m)] + simp only [Pi.zero_apply] + simp_rw [hcircle] + change ((2 * π * I : ℂ) ^ (n + 1))⁻¹ • torusIntegral (fun y => b y • g y) 0 (r ∘ Fin.succ) = _ + have he : (fun y => b y • ((2 * π * I : ℂ)⁻¹ • g y)) = + (fun y => (2 * π * I : ℂ)⁻¹ • (b y • g y)) := by + funext y + exact smul_comm _ _ _ + change _ = ((2 * π * I : ℂ) ^ n)⁻¹ • torusIntegral + (fun y => b y • ((2 * π * I : ℂ)⁻¹ • g y)) 0 (r ∘ Fin.succ) + rw [he, torusIntegral_smul, smul_smul, pow_succ, mul_inv] + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Neighborhoods.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Neighborhoods.lean new file mode 100644 index 0000000000..83dfa80103 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Neighborhoods.lean @@ -0,0 +1,120 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Module.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc + +/-! +# Circular product neighborhoods in Reinhardt sets + +An open Reinhardt set contains a product of connected circular domains around each point, +including points on coordinate hyperplanes. + +## Main results + +`IsReinhardt.exists_circular_product_neighborhood` produces such a product neighborhood of any +point. `isConnected_complex_annulus` and `isConnected_norm_preimage_ball` record connectedness +of the circular factors, including degenerate annuli that meet a coordinate hyperplane. +-/ + +public noncomputable section + +open Complex Set Metric +open scoped Topology + +namespace SeveralComplexVariables + +/-- An open annulus with nonnegative inner radius is connected. -/ +theorem isConnected_complex_annulus {a b : ℝ} (ha : 0 ≤ a) (hab : a < b) : + IsConnected {z : ℂ | a < ‖z‖ ∧ ‖z‖ < b} := by + have hc := (isConnected_Ioo hab).prod (isConnected_univ : IsConnected (univ : Set ℝ)) + have hcont : Continuous (fun p : ℝ × ℝ => (p.1 : ℂ) * exp (p.2 * I)) := by fun_prop + have he : (fun p : ℝ × ℝ => (p.1 : ℂ) * exp (p.2 * I)) '' (Ioo a b ×ˢ univ) = + {z : ℂ | a < ‖z‖ ∧ ‖z‖ < b} := by + ext z + constructor + · rintro ⟨⟨r, θ⟩, ⟨hr, _⟩, rfl⟩ + simpa [abs_of_pos (ha.trans_lt hr.1)] using hr + · intro hz + exact ⟨(‖z‖, z.arg), ⟨hz, mem_univ _⟩, norm_mul_exp_arg_mul_I z⟩ + rw [← he] + exact hc.image _ hcont.continuousOn + +/-- A positive-width neighborhood of a nonnegative radius is a connected circular domain. -/ +theorem isConnected_norm_preimage_ball {a δ : ℝ} (ha : 0 ≤ a) (hδ : 0 < δ) : + IsConnected ((norm : ℂ → ℝ) ⁻¹' ball a δ) := by + by_cases h : a < δ + · have he : (norm : ℂ → ℝ) ⁻¹' ball a δ = ball 0 (a + δ) := by + ext z + simp only [mem_preimage, mem_ball, Real.dist_eq, dist_zero_right, abs_sub_lt_iff] + constructor + · intro hz; linarith + · intro hz; constructor <;> linarith [norm_nonneg z] + rw [he] + exact isConnected_ball (by linarith) + · have he : (norm : ℂ → ℝ) ⁻¹' ball a δ = + {z : ℂ | a - δ < ‖z‖ ∧ ‖z‖ < a + δ} := by + ext z + simp only [mem_preimage, mem_ball, Real.dist_eq, mem_ofPred_eq, abs_sub_lt_iff] + constructor <;> intro hz <;> constructor <;> linarith [hz.1, hz.2] + rw [he] + exact isConnected_complex_annulus (by linarith) (by linarith) + +/-- Every point of an open Reinhardt set has a circular product neighborhood with connected factors. +The factors containing zero are discs. -/ +theorem IsReinhardt.exists_circular_product_neighborhood {n : ℕ} {U : Set (Fin n → ℂ)} + (hR : IsReinhardt U) (ho : IsOpen U) {z : Fin n → ℂ} (hz : z ∈ U) : + ∃ V : Fin n → Set ℂ, + (∀ i, IsOpen (V i)) ∧ (∀ i, IsConnected (V i)) ∧ + (∀ i, ∀ v ∈ V i, ∀ w : ℂ, ‖w‖ = ‖v‖ → w ∈ V i) ∧ + z ∈ Set.pi univ V ∧ Set.pi univ V ⊆ U := by + have hz' : (fun i => (‖z i‖ : ℂ)) ∈ U := hR hz (fun i => by simp) + obtain ⟨δ, hδ, hball⟩ := Metric.isOpen_iff.mp ho _ hz' + let V : Fin n → Set ℂ := fun i => (norm : ℂ → ℝ) ⁻¹' ball ‖z i‖ δ + refine ⟨V, fun i => isOpen_ball.preimage continuous_norm, + fun i => isConnected_norm_preimage_ball (norm_nonneg _) hδ, ?_, ?_, ?_⟩ + · intro i v hv w hw + change ‖w‖ ∈ ball ‖z i‖ δ + rwa [hw] + · intro i _ + exact mem_ball_self hδ + · intro w hw + apply hR (z := fun i => (‖w i‖ : ℂ)) (hball ?_) (fun i => by simp) + rw [mem_ball, dist_pi_lt_iff hδ] + intro i + rw [dist_eq_norm, ← Complex.ofReal_sub, Complex.norm_real, Real.norm_eq_abs] + simpa only [V, mem_preimage, mem_ball, Real.dist_eq] using hw i (mem_univ _) + +/-- Choose inner and outer coefficient circles and stricter evaluation bounds. At zero only the +upper evaluation bound is required. -/ +theorem exists_circular_radii_bounds {V : Set ℂ} (ho : IsOpen V) + (hrot : ∀ z ∈ V, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V) {z : ℂ} (hz : z ∈ V) : + ∃ a b t T : ℝ, 0 < a ∧ a < t ∧ 0 < T ∧ T < b ∧ + (a : ℂ) ∈ V ∧ (b : ℂ) ∈ V ∧ ‖z‖ < T ∧ (z ≠ 0 → t < ‖z‖) := by + by_cases hz0 : z = 0 + · subst z + obtain ⟨δ, hδ, hball⟩ := Metric.isOpen_iff.mp ho _ hz + have hb : ((δ / 2 : ℝ) : ℂ) ∈ V := hball (by + simpa [abs_of_pos hδ] using half_lt_self hδ) + refine ⟨δ / 2, δ / 2, δ, δ / 4, by positivity, by linarith, + by positivity, by linarith, hb, hb, ?_, ?_⟩ + · simp only [norm_zero]; positivity + · simp + · have hn : 0 < ‖z‖ := norm_pos_iff.mpr hz0 + have hzV : (‖z‖ : ℂ) ∈ V := hrot z hz _ (by simp) + obtain ⟨l, u, hlu, hsub⟩ := mem_nhds_iff_exists_Ioo_subset.mp + ((ho.preimage continuous_ofReal).mem_nhds hzV) + obtain ⟨a, ha, haz⟩ := exists_between (max_lt hn hlu.1) + obtain ⟨b, hzb, hb⟩ := exists_between hlu.2 + refine ⟨a, b, (a + ‖z‖) / 2, (‖z‖ + b) / 2, + (le_max_left _ _).trans_lt ha, by linarith, by linarith, by linarith, + hsub ⟨(le_max_right _ _).trans_lt ha, haz.trans hlu.2⟩, + hsub ⟨hlu.1.trans hzb, hb⟩, by linarith, fun _ => by linarith⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/OneVariable.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/OneVariable.lean new file mode 100644 index 0000000000..4da9ab2b9b --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/OneVariable.lean @@ -0,0 +1,306 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Annulus +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy + +/-! +# Circle coefficients for analytic Laurent series + +Laurent coefficients on a circle satisfy Cauchy bounds and depend holomorphically on holomorphic +parameters. Cauchy's formula on an annulus proves the Laurent expansion, independence of radius, +and vanishing of negative coefficients on a disc. These results are independent of the +multivariable Laurent expansion. + +## Main results + +`circleLaurentCoeff` is the coefficient of `z ^ k` on the circle of radius `r`. +`circleLaurentCoeff_eq_of_connected` is independence of radius on a connected set of admissible +radii. `circleLaurentCoeff_neg_eq_zero` is vanishing of negative coefficients on a disc. +`circleLaurent_expansion` is the two-sided series on an annulus. +-/ + +public noncomputable section + +open Complex Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- The coefficient of exponent `k` obtained by integrating on the circle of radius `r`. -/ +@[expose] def circleLaurentCoeff (f : ℂ → F) (r : ℝ) (k : ℤ) : F := + (2 * Real.pi * I : ℂ)⁻¹ • ∮ w in C(0, r), w ^ (-k - 1) • f w + +omit [CompleteSpace F] in +/-- Cauchy's bound for an arbitrary integer Laurent coefficient. No analyticity assumption is needed +for this integral estimate. -/ +theorem norm_circleLaurentCoeff_le {f : ℂ → F} {r M : ℝ} (hr : 0 < r) + (hM : ∀ w ∈ sphere (0 : ℂ) r, ‖f w‖ ≤ M) (k : ℤ) : + ‖circleLaurentCoeff f r k‖ ≤ M * r ^ (-k) := by + have h := circleIntegral.norm_two_pi_i_inv_smul_integral_le_of_norm_le_const hr.le + (C := r ^ (-k - 1) * M) (f := fun w => w ^ (-k - 1) • f w) (by + intro w hw + have hn : ‖w‖ = r := mem_sphere_zero_iff_norm.mp hw + rw [norm_smul, norm_zpow, hn] + exact mul_le_mul_of_nonneg_left (hM w hw) (zpow_nonneg hr.le _)) + apply h.trans_eq + have he : r * r ^ (-k - 1) = r ^ (-k) := by + calc + r * r ^ (-k - 1) = r ^ (1 : ℤ) * r ^ (-k - 1) := by rw [zpow_one] + _ = r ^ (-k) := by rw [← zpow_add₀ hr.ne']; congr 1; omega + rw [mul_comm (r ^ (-k - 1)) M, ← mul_assoc, mul_comm r M, mul_assoc, + he] + +/-- A fixed-circle Laurent coefficient is analytic in any finite-dimensional complex parameter on +which the integrand depends holomorphically. -/ +theorem analyticOnNhd_circleLaurentCoeff {E : Type*} [NormedAddCommGroup E] + [NormedSpace ℂ E] [FiniteDimensional ℂ E] {V : Set E} (hV : IsOpen V) + {U : Set (E × ℂ)} {f : E × ℂ → F} (hf : AnalyticOnNhd ℂ f U) + {r : ℝ} (hr : 0 < r) (hsub : ∀ z ∈ V, ∀ w ∈ sphere (0 : ℂ) r, (z, w) ∈ U) + (k : ℤ) : AnalyticOnNhd ℂ (fun z => circleLaurentCoeff (fun w => f (z, w)) r k) V := by + let W := U ∩ {p : E × ℂ | p.2 ≠ 0} + have hH : AnalyticOnNhd ℂ (fun p : E × ℂ => p.2 ^ (-k - 1) • f p) W := by + intro p hp + exact (analyticAt_snd.zpow (n := -k - 1) hp.2).smul (hf p hp.1) + apply (analyticOnNhd_circleIntegral_kernel hV hH hr.le ?_).const_smul + intro z hz w hw + refine ⟨hsub z hz w hw, ?_⟩ + exact norm_pos_iff.mp (by rw [mem_sphere_zero_iff_norm.mp hw]; exact hr) + +omit [CompleteSpace F] in +/-- The nonnegative Laurent terms admit a geometric bound inside the coefficient circle. -/ +theorem norm_circleLaurentTerm_nat_le {f : ℂ → F} {R M t : ℝ} (hR : 0 < R) + (hbound : ∀ w ∈ sphere (0 : ℂ) R, ‖f w‖ ≤ M) + {z : ℂ} (hz : ‖z‖ ≤ t) (n : ℕ) : + ‖z ^ (n : ℤ) • circleLaurentCoeff f R n‖ ≤ M * (t / R) ^ n := by + have hc := norm_circleLaurentCoeff_le hR hbound (n : ℤ) + have ht : 0 ≤ t := (norm_nonneg z).trans hz + rw [zpow_neg, zpow_natCast] at hc + rw [norm_smul, norm_zpow, zpow_natCast] + calc + ‖z‖ ^ n * ‖circleLaurentCoeff f R n‖ ≤ t ^ n * (M * (R ^ n)⁻¹) := by + gcongr + _ = M * (t / R) ^ n := by simp only [div_eq_mul_inv]; ring + +omit [CompleteSpace F] in +/-- The negative Laurent terms admit a geometric bound outside the coefficient circle. -/ +theorem norm_circleLaurentTerm_negSucc_le {f : ℂ → F} {r M t : ℝ} (hr : 0 < r) + (ht : 0 < t) (hbound : ∀ w ∈ sphere (0 : ℂ) r, ‖f w‖ ≤ M) + {z : ℂ} (hz : t ≤ ‖z‖) (n : ℕ) : + ‖z ^ (Int.negSucc n) • circleLaurentCoeff f r (Int.negSucc n)‖ ≤ + M * (r / t) ^ (n + 1) := by + have hc := norm_circleLaurentCoeff_le hr hbound (Int.negSucc n) + simp only [Int.neg_negSucc, zpow_natCast] at hc + rw [norm_smul, norm_zpow, zpow_negSucc] + calc + (‖z‖ ^ (n + 1))⁻¹ * ‖circleLaurentCoeff f r (Int.negSucc n)‖ ≤ + (t ^ (n + 1))⁻¹ * (M * r ^ (n + 1)) := by + gcongr + _ = M * (r / t) ^ (n + 1) := by simp only [div_eq_mul_inv]; ring + +/-- A connected rotation-invariant set contains all intermediate radii. -/ +private theorem mem_of_norm_between {V : Set ℂ} (hc : IsConnected V) + (hrot : ∀ z ∈ V, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V) + {a b w : ℂ} (ha : a ∈ V) (hb : b ∈ V) + (haw : ‖a‖ ≤ ‖w‖) (hwb : ‖w‖ ≤ ‖b‖) : w ∈ V := by + obtain ⟨v, hv, he⟩ := (hc.isPreconnected.image norm continuous_norm.continuousOn).Icc_subset + (mem_image_of_mem _ ha) (mem_image_of_mem _ hb) ⟨haw, hwb⟩ + exact hrot v hv w he.symm + +omit [CompleteSpace F] in +/-- Laurent coefficients are unchanged between two circles in an analytic annulus. -/ +theorem circleLaurentCoeff_eq_of_analyticOnNhd_annulus {f : ℂ → F} {r R : ℝ} + (hr : 0 < r) (hrR : r ≤ R) + (hf : AnalyticOnNhd ℂ f (closedBall 0 R \ ball 0 r)) : + circleLaurentCoeff f R = circleLaurentCoeff f r := by + funext k + have ha : AnalyticOnNhd ℂ (fun w => w ^ (-k - 1) • f w) + (closedBall 0 R \ ball 0 r) := by + intro w hw + have hw0 : w ≠ 0 := by + intro he + subst w + exact hw.2 (mem_ball_self hr) + exact (analyticAt_id.zpow hw0).smul (hf w hw) + unfold circleLaurentCoeff + congr 1 + exact circleIntegral_eq_of_differentiable_on_annulus_off_countable hr hrR countable_empty + ha.continuousOn (fun w hw => (ha w ⟨ball_subset_closedBall hw.1.1, + fun hb => hw.1.2 (ball_subset_closedBall hb)⟩).differentiableAt) + +omit [CompleteSpace F] in +/-- On a connected rotation-invariant set, the Laurent coefficients do not depend on radius. -/ +theorem circleLaurentCoeff_eq_of_connected {V : Set ℂ} (hc : IsConnected V) + (hrot : ∀ z ∈ V, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V) + {f : ℂ → F} (hf : AnalyticOnNhd ℂ f V) {r s : ℝ} + (hr : 0 < r) (hs : 0 < s) (hrV : (r : ℂ) ∈ V) (hsV : (s : ℂ) ∈ V) : + circleLaurentCoeff f s = circleLaurentCoeff f r := by + have hordered {a b : ℝ} (ha : 0 < a) (hab : a ≤ b) + (haV : (a : ℂ) ∈ V) (hbV : (b : ℂ) ∈ V) : + circleLaurentCoeff f b = circleLaurentCoeff f a := by + apply circleLaurentCoeff_eq_of_analyticOnNhd_annulus ha hab (hf.mono ?_) + intro w hw + apply mem_of_norm_between hc hrot haV hbV + · simpa [abs_of_pos ha] using (not_lt.mp (mem_ball_zero_iff.not.mp hw.2)) + · simpa [abs_of_pos (ha.trans_le hab)] using mem_closedBall_zero_iff.mp hw.1 + rcases le_total r s with h | h + · exact hordered hr h hrV hsV + · exact (hordered hs h hsV hrV).symm + +omit [CompleteSpace F] in +/-- Negative Laurent coefficients vanish if the coefficient circle bounds an analytic disc. -/ +theorem circleLaurentCoeff_neg_eq_zero {f : ℂ → F} {r : ℝ} (hr : 0 ≤ r) + (hf : AnalyticOnNhd ℂ f (closedBall 0 r)) {k : ℤ} (hk : k < 0) : + circleLaurentCoeff f r k = 0 := by + have he : -k - 1 = ((-k - 1).toNat : ℤ) := (Int.toNat_of_nonneg (by omega)).symm + have ha : AnalyticOnNhd ℂ (fun w => w ^ (-k - 1) • f w) (closedBall 0 r) := by + have ha' : AnalyticOnNhd ℂ (fun w => w ^ (-k - 1).toNat • f w) (closedBall 0 r) := + fun w hw => (analyticAt_id.pow _).smul (hf w hw) + convert ha' using 1 + funext w + rw [he, zpow_natCast, Int.toNat_natCast] + rw [circleLaurentCoeff, + (ha.differentiableOn.mono closure_ball_subset_closedBall).diffContOnCl.circleIntegral_eq_zero + hr, + smul_zero] + +omit [CompleteSpace F] in +/-- The nonnegative Laurent terms sum to the outer Cauchy integral. -/ +theorem hasSum_circleLaurentCoeff_nat {f : ℂ → F} {R : ℝ} + (hf : CircleIntegrable f 0 R) {z : ℂ} (hz : ‖z‖ < R) : + HasSum (fun n : ℕ => z ^ (n : ℤ) • circleLaurentCoeff f R n) + ((2 * Real.pi * I : ℂ)⁻¹ • ∮ w in C(0, R), (w - z)⁻¹ • f w) := by + have hR : 0 < R := (norm_nonneg z).trans_lt hz + have hs := (hasSum_two_pi_I_cauchyPowerSeries_integral hf hz).const_smul + (2 * Real.pi * I : ℂ)⁻¹ + simp only [zero_add, sub_zero] at hs + apply hs.congr_fun + intro n + rw [circleLaurentCoeff, smul_comm (z ^ (n : ℤ)), ← circleIntegral.integral_smul] + congr 1 + apply circleIntegral.integral_congr hR.le + intro w _ + dsimp only + rw [show -(n : ℤ) - 1 = -((n + 1 : ℕ) : ℤ) by omega, zpow_neg, + zpow_natCast, zpow_natCast, smul_smul, smul_smul] + congr 1 + simp [div_eq_mul_inv, mul_pow, pow_succ, mul_left_comm, mul_comm] + +omit [CompleteSpace F] in +/-- The negative Laurent terms sum to the inner Cauchy integral with reversed kernel. -/ +theorem hasSum_circleLaurentCoeff_negSucc {f : ℂ → F} {r : ℝ} (hr : 0 ≤ r) + (hf : ContinuousOn f (sphere (0 : ℂ) r)) {z : ℂ} (hz : r < ‖z‖) : + HasSum (fun n : ℕ => z ^ (Int.negSucc n) • circleLaurentCoeff f r (Int.negSucc n)) + ((2 * Real.pi * I : ℂ)⁻¹ • ∮ w in C(0, r), (z - w)⁻¹ • f w) := by + have hz0 : z ≠ 0 := norm_pos_iff.mp (hr.trans_lt hz) + have hs := (hasSum_circleIntegral_geometric hr (hf.const_smul z⁻¹) + (g := fun w => w / z) (continuousOn_id.div_const z) + (div_nonneg hr (norm_nonneg z)) ((div_lt_one (hr.trans_lt hz)).mpr hz) (by + intro w hw + simp [mem_sphere_zero_iff_norm.mp hw])).const_smul (2 * Real.pi * I : ℂ)⁻¹ + have he : (∮ w in C(0, r), (1 - w / z)⁻¹ • z⁻¹ • f w) = + ∮ w in C(0, r), (z - w)⁻¹ • f w := by + apply circleIntegral.integral_congr hr + intro w _ + dsimp only + rw [smul_smul] + congr 1 + rw [← mul_inv, sub_mul, one_mul, div_mul_cancel₀ _ hz0] + simp only [Pi.smul_apply] at hs + rw [he] at hs + apply hs.congr_fun + intro n + rw [circleLaurentCoeff, smul_comm (z ^ (Int.negSucc n)), + ← circleIntegral.integral_smul] + congr 1 + apply circleIntegral.integral_congr hr + intro w _ + dsimp only + rw [show -(Int.negSucc n) - 1 = (n : ℤ) by omega, zpow_natCast, + zpow_negSucc, smul_smul, smul_smul] + congr 1 + simp [div_eq_mul_inv, mul_pow, pow_succ, mul_left_comm, mul_comm] + +/-- Laurent expansion at a point strictly between two analytic coefficient circles. -/ +theorem hasSum_circleLaurentCoeff_annulus {f : ℂ → F} {r R : ℝ} + (hr : 0 < r) {z : ℂ} (hzr : r < ‖z‖) (hzR : ‖z‖ < R) + (hf : AnalyticOnNhd ℂ f (closedBall 0 R \ ball 0 r)) : + HasSum (fun k : ℤ => z ^ k • circleLaurentCoeff f r k) (f z) := by + have hs (t : ℝ) (ht : t = r ∨ t = R) : sphere (0 : ℂ) t ⊆ closedBall 0 R \ ball 0 r := by + intro w hw + have hw' := mem_sphere_zero_iff_norm.mp hw + simp only [Set.mem_sdiff, mem_closedBall_zero_iff, mem_ball_zero_iff, not_lt, hw'] + rcases ht with rfl | rfl <;> constructor <;> linarith + have hp := hasSum_circleLaurentCoeff_nat + ((hf.continuousOn.mono (hs R (Or.inr rfl))).circleIntegrable (hr.trans (hzr.trans hzR)).le) hzR + rw [circleLaurentCoeff_eq_of_analyticOnNhd_annulus hr (hzr.trans hzR).le hf] at hp + have hn := hasSum_circleLaurentCoeff_negSucc hr.le (hf.continuousOn.mono (hs r (Or.inl rfl))) hzr + have hi : (∮ w in C(0, r), (z - w)⁻¹ • f w) = + -(∮ w in C(0, r), (w - z)⁻¹ • f w) := by + calc + _ = ∮ w in C(0, r), -((w - z)⁻¹ • f w) := by + congr 1 + funext w + rw [← neg_sub w z, inv_neg, neg_smul] + _ = _ := by simp only [circleIntegral, smul_neg, intervalIntegral.integral_neg] + have hsum := hp.int_rec hn + rw [hi, ← smul_add, ← sub_eq_add_neg, + circleIntegral_sub_inv_smul_sub_of_analyticOnNhd_annulus hr hzr hzR hf, + inv_smul_smul₀ two_pi_I_ne_zero] at hsum + exact hsum.congr_fun fun k => by cases k <;> rfl + +/-- One-variable Laurent expansion on a connected rotation-invariant open set, including +independence of radius and vanishing of negative coefficients at zero. -/ +theorem circleLaurent_expansion {V : Set ℂ} (hV : IsOpen V) (hc : IsConnected V) + (hrot : ∀ z ∈ V, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V) + {f : ℂ → F} (hf : AnalyticOnNhd ℂ f V) {r : ℝ} (hr : 0 < r) (hrV : (r : ℂ) ∈ V) : + (∀ z ∈ V, HasSum (fun k : ℤ => z ^ k • circleLaurentCoeff f r k) (f z)) ∧ + (∀ s : ℝ, 0 < s → (s : ℂ) ∈ V → circleLaurentCoeff f s = circleLaurentCoeff f r) ∧ + (0 ∈ V → ∀ k : ℤ, k < 0 → circleLaurentCoeff f r k = 0) := by + have hind (s : ℝ) (hs : 0 < s) (hsV : (s : ℂ) ∈ V) : + circleLaurentCoeff f s = circleLaurentCoeff f r := + circleLaurentCoeff_eq_of_connected hc hrot hf hr hs hrV hsV + have hdisc (h0 : 0 ∈ V) : AnalyticOnNhd ℂ f (closedBall 0 r) := by + apply hf.mono + intro w hw + apply mem_of_norm_between hc hrot h0 hrV + · simp + · simpa [abs_of_pos hr] using mem_closedBall_zero_iff.mp hw + refine ⟨?_, hind, fun h0 k hk => circleLaurentCoeff_neg_eq_zero hr.le (hdisc h0) hk⟩ + intro z hz + by_cases hz0 : z = 0 + · subst z + have he : circleLaurentCoeff f r 0 = f 0 := by + have hdc := ((hdisc hz).differentiableOn.mono closure_ball_subset_closedBall).diffContOnCl + simpa [circleLaurentCoeff] using + hdc.two_pi_i_inv_smul_circleIntegral_sub_inv_smul (mem_ball_self hr) + simpa [he] using (hasSum_single (0 : ℤ) + (f := fun k : ℤ => (0 : ℂ) ^ k • circleLaurentCoeff f r k) (by + intro k hk + simp [zero_zpow k hk])) + · have hn : 0 < ‖z‖ := norm_pos_iff.mpr hz0 + have hzV : (‖z‖ : ℂ) ∈ V := hrot z hz _ (by simp) + obtain ⟨a, b, hab, hsub⟩ := mem_nhds_iff_exists_Ioo_subset.mp + ((hV.preimage continuous_ofReal).mem_nhds hzV) + obtain ⟨s, hs₁, hs₂⟩ := exists_between (max_lt hn hab.1) + obtain ⟨R, hR₁, hR₂⟩ := exists_between hab.2 + have hs : 0 < s := (le_max_left _ _).trans_lt hs₁ + have hsV : (s : ℂ) ∈ V := hsub ⟨(le_max_right _ _).trans_lt hs₁, hs₂.trans hab.2⟩ + have hRV : (R : ℂ) ∈ V := hsub ⟨hab.1.trans hR₁, hR₂⟩ + have ha : AnalyticOnNhd ℂ f (closedBall 0 R \ ball 0 s) := by + apply hf.mono + intro w hw + apply mem_of_norm_between hc hrot hsV hRV + · simpa [abs_of_pos hs] using (not_lt.mp (mem_ball_zero_iff.not.mp hw.2)) + · simpa [abs_of_pos (hn.trans hR₁)] using mem_closedBall_zero_iff.mp hw.1 + simpa only [hind s hs hsV] using hasSum_circleLaurentCoeff_annulus hs hs₂ hR₁ ha + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/ProductCoefficients.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/ProductCoefficients.lean new file mode 100644 index 0000000000..9fc9c651b0 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/ProductCoefficients.lean @@ -0,0 +1,157 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Iterated + +/-! +# Laurent coefficients on products of circular domains + +Circle coefficients are analytic in the remaining coordinates. Iteration therefore proves +independence of the coordinate radii on products of connected circular domains. + +## Main results + +`analyticOnNhd_circleLaurentCoeff_cons` is holomorphy of a circle coefficient in the remaining +coordinates. `multivariableLaurentCoeff_eq_on_product` is independence of radii on a product of +connected circular domains. `multivariableLaurentCoeff_neg_on_product` vanishes negative +exponents in a factor that is a disc. +-/ + +public noncomputable section + +open Complex Set Metric Function +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Combining an analytic first coordinate and analytic remaining coordinates is analytic. -/ +private theorem analyticAt_fin_cons {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + {a : E} {f : E → ℂ} {g : E → (Fin n → ℂ)} + (hf : AnalyticAt ℂ f a) (hg : AnalyticAt ℂ g a) : + AnalyticAt ℂ (fun x => (Fin.cons (f x) (g x) : Fin (n + 1) → ℂ)) a := by + apply AnalyticAt.pi + intro i + refine Fin.cases ?_ (fun j => ?_) i + · exact hf + · exact ((ContinuousLinearMap.proj (R := ℂ) j).analyticAt (g a)).comp hg + +/-- Rotation invariance of each factor puts the entire coefficient torus in the product. -/ +theorem torusMap_mem_product {V : Fin n → Set ℂ} + (hrot : ∀ i, ∀ z ∈ V i, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V i) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrV : ∀ i, (r i : ℂ) ∈ V i) + (θ : Fin n → ℝ) : torusMap 0 r θ ∈ Set.pi univ V := by + intro i _ + apply hrot i _ (hrV i) + simp [torusMap, abs_of_pos (hr i)] + +/-- Taking the first circle coefficient preserves analyticity in the remaining coordinates. -/ +theorem analyticOnNhd_circleLaurentCoeff_cons {V : Fin (n + 1) → Set ℂ} + (ho : ∀ i, IsOpen (V i)) + (hrot : ∀ i, ∀ z ∈ V i, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V i) + {f : (Fin (n + 1) → ℂ) → F} (hf : AnalyticOnNhd ℂ f (Set.pi univ V)) + {r : ℝ} (hr : 0 < r) (hrV : (r : ℂ) ∈ V 0) (k : ℤ) : + AnalyticOnNhd ℂ (fun y => circleLaurentCoeff (fun x => f (Fin.cons x y)) r k) + (Set.pi univ (V ∘ Fin.succ)) := by + let W := {p : (Fin n → ℂ) × ℂ | Fin.cons p.2 p.1 ∈ Set.pi univ V} + have hH : AnalyticOnNhd ℂ (fun p : (Fin n → ℂ) × ℂ => f (Fin.cons p.2 p.1)) W := + fun p hp => (hf _ hp).comp_of_eq (analyticAt_fin_cons (f := Prod.snd) (g := Prod.fst) (a := p) + analyticAt_snd analyticAt_fst) rfl + apply analyticOnNhd_circleLaurentCoeff + (isOpen_set_pi finite_univ (fun i _ => ho i.succ)) hH hr + intro y hy w hw + change Fin.cons w y ∈ Set.pi univ V + intro i _ + refine Fin.cases ?_ (fun j => ?_) i + · exact hrot 0 _ hrV w (by simpa [abs_of_pos hr] using mem_sphere_zero_iff_norm.mp hw) + · exact hy j (mem_univ _) + +/-- In a product of connected circular domains, Laurent coefficients are independent of radii. -/ +theorem multivariableLaurentCoeff_eq_on_product {V : Fin n → Set ℂ} + (ho : ∀ i, IsOpen (V i)) (hc : ∀ i, IsConnected (V i)) + (hrot : ∀ i, ∀ z ∈ V i, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V i) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f (Set.pi univ V)) + {r s : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hs : ∀ i, 0 < s i) + (hrV : ∀ i, (r i : ℂ) ∈ V i) (hsV : ∀ i, (s i : ℂ) ∈ V i) : + multivariableLaurentCoeff f s = multivariableLaurentCoeff f r := by + induction n with + | zero => rw [Subsingleton.elim s r] + | succ n ih => + have hcont (t : Fin (n + 1) → ℝ) (ht : ∀ i, 0 < t i) (htV : ∀ i, (t i : ℂ) ∈ V i) : + Continuous (fun θ => f (torusMap 0 t θ)) := + hf.continuousOn.comp_continuous (continuous_torusMap 0 t) + (torusMap_mem_product hrot ht htV) + funext m + rw [multivariableLaurentCoeff_succ hs (hcont s hs hsV), + multivariableLaurentCoeff_succ hr (hcont r hr hrV)] + let a (t : ℝ) (y : Fin n → ℂ) := circleLaurentCoeff (fun x => f (Fin.cons x y)) t (m 0) + have ha : AnalyticOnNhd ℂ (a (r 0)) (Set.pi univ (V ∘ Fin.succ)) := + analyticOnNhd_circleLaurentCoeff_cons ho hrot hf (hr 0) (hrV 0) (m 0) + have heq : EqOn (a (s 0)) (a (r 0)) (Set.pi univ (V ∘ Fin.succ)) := by + intro y hy + have hfy : AnalyticOnNhd ℂ (fun x => f (Fin.cons x y)) (V 0) := by + intro x hx + apply (hf _ ?_).comp_of_eq + (analyticAt_fin_cons (f := id) (g := fun _ : ℂ => y) analyticAt_id analyticAt_const) rfl + intro i _ + exact Fin.cases hx (fun j => hy j (mem_univ _)) i + exact congrFun (circleLaurentCoeff_eq_of_connected (hc 0) (hrot 0) hfy + (hr 0) (hs 0) (hrV 0) (hsV 0)) (m 0) + have he := multivariableLaurentCoeff_congr (r := s ∘ Fin.succ) (fun θ => + heq (torusMap_mem_product (fun i => hrot i.succ) (fun i => hs i.succ) + (fun i => hsV i.succ) θ)) + change multivariableLaurentCoeff (a (s 0)) (s ∘ Fin.succ) (m ∘ Fin.succ) = _ + rw [he] + exact congrFun (ih (fun i => ho i.succ) (fun i => hc i.succ) (fun i => hrot i.succ) ha + (r := r ∘ Fin.succ) (s := s ∘ Fin.succ) + (fun i => hr i.succ) (fun i => hs i.succ) (fun i => hrV i.succ) (fun i => hsV i.succ)) + (m ∘ Fin.succ) + +/-- Negative coefficients vanish in a product when the corresponding factor contains zero. -/ +theorem multivariableLaurentCoeff_neg_on_product {V : Fin n → Set ℂ} + (ho : ∀ i, IsOpen (V i)) (hc : ∀ i, IsConnected (V i)) + (hrot : ∀ i, ∀ z ∈ V i, ∀ w : ℂ, ‖w‖ = ‖z‖ → w ∈ V i) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f (Set.pi univ V)) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrV : ∀ i, (r i : ℂ) ∈ V i) + (m : Fin n → ℤ) (i : Fin n) (hi : 0 ∈ V i) (hm : m i < 0) : + multivariableLaurentCoeff f r m = 0 := by + induction n with + | zero => exact Fin.elim0 i + | succ n ih => + have hcont : Continuous (fun θ => f (torusMap 0 r θ)) := + hf.continuousOn.comp_continuous (continuous_torusMap 0 r) + (torusMap_mem_product hrot hr hrV) + rw [multivariableLaurentCoeff_succ hr hcont] + cases i using Fin.cases with + | zero => + have he : multivariableLaurentCoeff + (fun y => circleLaurentCoeff (fun x => f (Fin.cons x y)) (r 0) (m 0)) + (r ∘ Fin.succ) = multivariableLaurentCoeff (fun _ => (0 : F)) (r ∘ Fin.succ) := by + apply multivariableLaurentCoeff_congr + intro θ + let y := torusMap 0 (r ∘ Fin.succ) θ + have hy := torusMap_mem_product (fun i => hrot i.succ) (fun i => hr i.succ) + (fun i => hrV i.succ) θ + have hfy : AnalyticOnNhd ℂ (fun x => f (Fin.cons x y)) (V 0) := by + intro x hx + apply (hf _ ?_).comp_of_eq + (analyticAt_fin_cons (f := id) (g := fun _ : ℂ => y) analyticAt_id analyticAt_const) rfl + intro i _ + exact Fin.cases hx (fun j => hy j (mem_univ _)) i + exact (circleLaurent_expansion (ho 0) (hc 0) (hrot 0) hfy (hr 0) (hrV 0)).2.2 hi (m 0) hm + rw [he] + simp [multivariableLaurentCoeff, torusIntegral] + | succ j => + exact ih (fun i => ho i.succ) (fun i => hc i.succ) (fun i => hrot i.succ) + (analyticOnNhd_circleLaurentCoeff_cons ho hrot hf (hr 0) (hrV 0) (m 0)) + (r := r ∘ Fin.succ) (fun i => hr i.succ) (fun i => hrV i.succ) + (m ∘ Fin.succ) j hi hm + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/ProductExpansion.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/ProductExpansion.lean new file mode 100644 index 0000000000..2725139486 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/ProductExpansion.lean @@ -0,0 +1,128 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Convergence + +/-! +# Laurent expansion by successive circle expansions + +On circular products, induction on the number of coordinates combines the circle Laurent theorem +with Fubini for absolutely summable families. Circular product neighborhoods then give pointwise +expansion on every Reinhardt domain. + +## Main results + +`hasSum_multivariableLaurent_on_product` is the expansion on a finite product of circular +domains. `hasSum_multivariableLaurent` is the pointwise expansion at an arbitrary point of an +open Reinhardt domain. +-/ + +public noncomputable section + +open Complex Set Filter +open scoped Topology NNReal + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +omit [CompleteSpace F] in +/-- Fixing all but the first coordinate preserves analyticity on a product. -/ +private theorem analyticOnNhd_first_slice {V : Fin (n + 1) → Set ℂ} + {f : (Fin (n + 1) → ℂ) → F} (hf : AnalyticOnNhd ℂ f (Set.pi univ V)) + {y : Fin n → ℂ} (hy : y ∈ Set.pi univ (V ∘ Fin.succ)) : + AnalyticOnNhd ℂ (fun x => f (Fin.cons x y)) (V 0) := by + intro x hx + have hg : AnalyticAt ℂ (fun x : ℂ => (Fin.cons x y : Fin (n + 1) → ℂ)) x := by + apply AnalyticAt.pi + intro i + exact Fin.cases analyticAt_id (fun _ => analyticAt_const) i + apply (hf _ ?_).comp_of_eq hg rfl + intro i _ + exact Fin.cases hx (fun j => hy j (mem_univ _)) i + +/-- Successive one-variable Laurent expansions give the expansion on a circular product. -/ +theorem hasSum_multivariableLaurent_on_product {V : Fin n → Set ℂ} + (ho : ∀ i, IsOpen (V i)) (hc : ∀ i, IsConnected (V i)) + (hrot : ∀ i, ∀ x ∈ V i, ∀ w : ℂ, ‖w‖ = ‖x‖ → w ∈ V i) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f (Set.pi univ V)) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrV : ∀ i, (r i : ℂ) ∈ V i) + {z : Fin n → ℂ} (hz : z ∈ Set.pi univ V) : + HasSum (fun m => multivariableLaurentTerm (multivariableLaurentCoeff f r) m z) (f z) := by + induction n with + | zero => + convert hasSum_fintype (fun m => multivariableLaurentTerm (multivariableLaurentCoeff f r) m z) + using 1 + simp only [multivariableLaurentTerm, multivariableLaurentCoeff, torusIntegral_dim0, + Fin.prod_univ_zero, pow_zero, inv_one, one_smul, Finset.sum_const, Finset.card_univ, + Fintype.card_unique] + congr 1 + exact Subsingleton.elim _ _ + | succ n ih => + let a (k : ℤ) (y : Fin n → ℂ) := circleLaurentCoeff (fun x => f (Fin.cons x y)) (r 0) k + have ha (k : ℤ) : AnalyticOnNhd ℂ (a k) (Set.pi univ (V ∘ Fin.succ)) := + analyticOnNhd_circleLaurentCoeff_cons ho hrot hf (hr 0) (hrV 0) k + have hz' : z ∘ Fin.succ ∈ Set.pi univ (V ∘ Fin.succ) := fun i _ => hz i.succ (mem_univ _) + have hinner (k : ℤ) : HasSum + (fun m => z 0 ^ k • multivariableLaurentTerm + (multivariableLaurentCoeff (a k) (r ∘ Fin.succ)) m (z ∘ Fin.succ)) + (z 0 ^ k • a k (z ∘ Fin.succ)) := by + apply HasSum.const_smul + exact ih (V := V ∘ Fin.succ) (f := a k) (z := z ∘ Fin.succ) + (fun i => ho i.succ) (fun i => hc i.succ) (fun i => hrot i.succ) (ha k) + (r := r ∘ Fin.succ) (fun i => hr i.succ) (fun i => hrV i.succ) hz' + have houter := (circleLaurent_expansion (ho 0) (hc 0) (hrot 0) + (analyticOnNhd_first_slice hf hz') (hr 0) (hrV 0)).1 (z 0) (hz 0 (mem_univ _)) + have hR : IsReinhardt (Set.pi univ V) := by + intro x hx w hw i _ + exact hrot i _ (hx i (mem_univ _)) _ (hw i) + have habs := summable_norm_multivariableLaurent + (isOpen_set_pi finite_univ (fun i _ => ho i)) + (isPreconnected_univ_pi (fun i => (hc i).isPreconnected)) hR hf hr + (fun i _ => hrV i) hz + let e := Fin.consEquiv (fun _ : Fin (n + 1) => ℤ) + have hp := e.summable_iff.mpr habs.of_norm + have hcont : Continuous (fun θ => f (torusMap 0 r θ)) := + hf.continuousOn.comp_continuous (continuous_torusMap 0 r) + (torusMap_mem_product hrot hr hrV) + have hterm (k : ℤ) (m : Fin n → ℤ) : + multivariableLaurentTerm (multivariableLaurentCoeff f r) (e (k, m)) z = + z 0 ^ k • multivariableLaurentTerm (multivariableLaurentCoeff (a k) (r ∘ Fin.succ)) m + (z ∘ Fin.succ) := by + rw [multivariableLaurentTerm, multivariableLaurentCoeff_succ hr hcont] + simp [multivariableLaurentTerm, e, Fin.consEquiv, Fin.prod_univ_succ, a, + Function.comp_def, smul_smul] + have hsum := hp.hasSum.prod_fiberwise (fun k => + (hinner k).congr_fun (fun m => hterm k m)) + have heq := hsum.unique houter + apply e.hasSum_iff.mp + convert hp.hasSum using 1 + have hzcons : Fin.cons (z 0) (z ∘ Fin.succ) = z := Fin.cons_self_tail z + simpa only [hzcons] using heq.symm + +/-- Every analytic function on an open connected Reinhardt set equals its Laurent series. -/ +theorem hasSum_multivariableLaurent {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsPreconnected U) (hR : IsReinhardt U) + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hrU : (fun i => (r i : ℂ)) ∈ U) + {z : Fin n → ℂ} (hz : z ∈ U) : + HasSum (fun m => multivariableLaurentTerm (multivariableLaurentCoeff f r) m z) (f z) := by + obtain ⟨V, hVo, hVc, hVr, hzV, hVU⟩ := hR.exists_circular_product_neighborhood ho hz + have hprod : IsReinhardt (Set.pi univ V) := by + intro x hx y hy j _ + exact hVr j _ (hx j (mem_univ _)) _ (hy j) + obtain ⟨s, hsV, hs⟩ := hprod.exists_strict_modulus_majorant + (isOpen_set_pi finite_univ (fun i _ => hVo i)) hzV + have hspos (j : Fin n) : 0 < (s j : ℝ) := by + exact_mod_cast (show (0 : ℝ≥0) ≤ ‖z j‖₊ from zero_le).trans_lt (hs j) + rw [← multivariableLaurentCoeff_eq_of_radii ho hc hR hf hr hspos hrU (hVU hsV)] + exact hasSum_multivariableLaurent_on_product hVo hVc hVr (hf.mono hVU) hspos + (fun i => hsV i (mem_univ _)) hzV + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Uniqueness.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Uniqueness.lean new file mode 100644 index 0000000000..246b74a9e9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LaurentSeries/Uniqueness.lean @@ -0,0 +1,108 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform + +/-! +# Uniqueness of analytic Laurent expansions + +Uniform convergence on one positive coordinate torus permits coefficient extraction. The +coefficients of a locally uniformly convergent Laurent series are therefore unique, +independently of the existence theorem and without a connectedness hypothesis. + +## Main results + +`tendsto_multivariableLaurentCoeff` extracts coefficients from uniform convergence on a torus. +`eq_multivariableLaurentCoeff_of_hasSumLocallyUniformlyOn` is uniqueness of the coefficient +family of a locally uniformly convergent expansion. +-/ + +public noncomputable section + +open Complex Set MeasureTheory Metric Filter +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +omit [CompleteSpace F] in +/-- Uniform convergence on a torus implies convergence of each Laurent coefficient. -/ +theorem tendsto_multivariableLaurentCoeff {α : Type*} {l : Filter α} + {f : α → (Fin n → ℂ) → F} {g : (Fin n → ℂ) → F} {K : Set (Fin n → ℂ)} + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (hK : ∀ θ, torusMap 0 r θ ∈ K) + (hf : ∀ᶠ a in l, Continuous (fun θ => f a (torusMap 0 r θ))) + (hg : Continuous (fun θ => g (torusMap 0 r θ))) + (hu : TendstoUniformlyOn f g l K) (m : Fin n → ℤ) : + Tendsto (fun a => multivariableLaurentCoeff (f a) r m) l + (𝓝 (multivariableLaurentCoeff g r m)) := by + let C := ∏ i, r i ^ (-m i) + have hC : 0 ≤ C := Finset.prod_nonneg fun i _ => zpow_nonneg (hr i).le _ + rw [Metric.tendsto_nhds] + intro ε hε + have hδ : 0 < ε / (C + 1) := div_pos hε (by positivity) + filter_upwards [Metric.tendstoUniformlyOn_iff.mp hu _ hδ, hf] with a ha hfa + rw [dist_eq_norm, ← multivariableLaurentCoeff_sub hr hfa hg] + calc + ‖multivariableLaurentCoeff (fun z => f a z - g z) r m‖ ≤ ε / (C + 1) * C := + norm_multivariableLaurentCoeff_le hr (fun θ => by + rw [norm_sub_rev] + simpa only [dist_eq_norm] using (ha _ (hK θ)).le) m + _ < ε := by + have he := div_mul_cancel₀ ε (show C + 1 ≠ 0 by positivity) + nlinarith + +/-- The coefficient of a finite Laurent sum is its corresponding summand coefficient. -/ +theorem multivariableLaurentCoeff_sum_terms (c : (Fin n → ℤ) → F) + (s : Finset (Fin n → ℤ)) {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) (m : Fin n → ℤ) : + multivariableLaurentCoeff (fun z => ∑ k ∈ s, multivariableLaurentTerm c k z) r m = + if m ∈ s then c m else 0 := by + classical + rw [multivariableLaurentCoeff_sum s hr (fun k _ => + show Continuous (fun θ => multivariableLaurentTerm c k (torusMap 0 r θ)) from + continuous_laurentMonomial_smul_torus (f := fun _ => c k) hr continuous_const k)] + change (∑ k ∈ s, multivariableLaurentCoeff (fun z => (∏ i, z i ^ k i) • c k) r m) = _ + simp [multivariableLaurentCoeff_monomial r hr] + +/-- A locally uniformly convergent Laurent expansion has the torus integral coefficients. Only +continuity of the limit and containment of a positive torus are needed. -/ +theorem eq_multivariableLaurentCoeff_of_hasSumLocallyUniformlyOn + {U : Set (Fin n → ℂ)} {f : (Fin n → ℂ) → F} (hf : ContinuousOn f U) + {r : Fin n → ℝ} (hr : ∀ i, 0 < r i) + (hTU : ∀ z, (∀ i, ‖z i‖ = r i) → z ∈ U) + {c : (Fin n → ℤ) → F} + (hs : HasSumLocallyUniformlyOn (multivariableLaurentTerm c) f U) : + c = multivariableLaurentCoeff f r := by + classical + let T : Set (Fin n → ℂ) := {z | ∀ i, z i ∈ sphere 0 (r i)} + have hT : IsCompact T := isCompact_pi_infinite (fun i => isCompact_sphere 0 (r i)) + have hTU' : T ⊆ U := fun z hz => hTU z (fun i => mem_sphere_zero_iff_norm.mp (hz i)) + have htor (θ : Fin n → ℝ) : torusMap 0 r θ ∈ T := by + intro i + simp [torusMap, abs_of_pos (hr i)] + have hfc : Continuous (fun θ => f (torusMap 0 r θ)) := + hf.comp_continuous (continuous_torusMap 0 r) (fun θ => hTU' (htor θ)) + have hcont (s : Finset (Fin n → ℤ)) : + Continuous (fun θ => ∑ k ∈ s, multivariableLaurentTerm c k (torusMap 0 r θ)) := + continuous_finsetSum s (fun k _ => + continuous_laurentMonomial_smul_torus (f := fun _ => c k) hr continuous_const k) + have hu := (tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hT).mp (hs.mono hTU') + funext m + have hlim := tendsto_multivariableLaurentCoeff hr htor (.of_forall hcont) hfc hu m + have hvalue : Tendsto + (fun s : Finset (Fin n → ℤ) => + multivariableLaurentCoeff (fun z => ∑ k ∈ s, multivariableLaurentTerm c k z) r m) + atTop (𝓝 (c m)) := by + apply tendsto_const_nhds.congr' + filter_upwards [eventually_finset_mem_atTop m] with s hsm + rw [multivariableLaurentCoeff_sum_terms c s hr m, ite_eq_left hsm] + exact tendsto_nhds_unique hvalue hlim + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity.lean new file mode 100644 index 0000000000..d7f890949b --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity.lean @@ -0,0 +1,274 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.RCLike.Extend +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.LinearFunctional +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Frontier + +/-! +# Levi convex boundaries + +A local `C²` defining function for an open set `U` at a boundary point `p` is a `C²` function +`ρ` on an open neighborhood `V` of `p`, vanishing at `p`, with nonzero derivative at `p`, such +that `U ∩ V` is the set where `ρ` is negative. The complex tangent space at `p` is the kernel of +the complex-linear part of the derivative of `ρ`. The set `U` satisfies the Levi condition at +`p` if the Levi form of every local defining function is positive semidefinite on the complex +tangent space; it is Levi pseudoconvex if this holds at every boundary point. Quantifying over +all defining functions avoids the lemma that two defining functions differ by a positive factor. + +This file proves that convex open sets are Levi pseudoconvex: along a real tangent line the +defining function vanishes to first order at `p`, so a negative second derivative would put two +symmetric points of the line into `U` and, by convexity, the boundary point itself. + +It also provides the complex-linear part `complexPart ℓ` of a real functional `ℓ`, with `ℓ (ζ • +c) = Re (ζ * complexPart ℓ c)`, and the decomposition of a symmetric real bilinear form along a +complex line into a Hermitian part, the Levi form, and the real part of a complex quadratic +term. Both are used for the Levi polynomial in `LeviConvexity.Necessity`. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 4; +[Range][Range1986] (1986), Chapter II, Sections 2.4–2.6. + +## Main definitions + +* `complexPart`: The complex-linear part of a real functional: `ℓ c - I * ℓ (I • c)`. +* `IsLocalDefiningFunction`: A local `C²` defining function for `U` at `p` on the open neighborhood + `V`: `ρ p = 0`, the real derivative of `ρ` at `p` is nonzero, and `U ∩ V` is the negative sublevel + set of `ρ` in `V`. +* `HasC2Boundary`: A set has `C²` boundary if every boundary point has a local defining function. +* `IsComplexTangent`: The complex tangent space of the level set of `ρ` at `p`: the kernel of the + complex-linear part of the derivative. +* `IsLeviPseudoconvexAt`: The Levi condition at a boundary point: the Levi form of every local + defining function is positive semidefinite on the complex tangent space. +* `IsLeviPseudoconvex`: Levi pseudoconvexity: the Levi condition at every boundary point. + +## Main results + +* `bilinear_smul_smul_eq`: **Quadratic decomposition along a complex line.** For a symmetric real + bilinear form `B`, `B (ζ • w) (ζ • w) / 2` is `‖ζ‖ ^ 2` times the Hermitian part `(B w w + B (I • + w) (I • w)) / 4` plus the real part of `ζ ^ 2` times the complex quadratic coefficient `(B w w - B + (I • w) (I • w)) / 4 - I / 2 * B w (I • w)`. +* `Convex.isLeviPseudoconvex`: **Convex open sets are Levi pseudoconvex** ([Range][Range1986], Lemma + 2.10). + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +section ComplexPart + +/-- The complex-linear part `c ↦ ℓ c - I * ℓ (I • c)` of a real functional: Mathlib's +`StrongDual.extendRCLike` with the scalar field fixed to `ℂ`. -/ +abbrev complexPart (ℓ : E →L[ℝ] ℝ) : E →L[ℂ] ℂ := StrongDual.extendRCLike ℓ + +/-- The defining formula of the complex-linear part. -/ +theorem complexPart_apply (ℓ : E →L[ℝ] ℝ) (c : E) : + complexPart ℓ c = (ℓ c : ℂ) - I * (ℓ (I • c) : ℂ) := rfl + +/-- A real functional on a complex multiple is the real part of the complex multiple of its +complex-linear part. -/ +theorem apply_smul_eq_re_mul_complexPart (ℓ : E →L[ℝ] ℝ) (ζ : ℂ) (c : E) : + ℓ (ζ • c) = (ζ * complexPart ℓ c).re := by + rw [Complex.smul_eq_re_smul_add_im_smul, map_add, map_smul, map_smul, smul_eq_mul, smul_eq_mul, + complexPart_apply] + simp [Complex.mul_re, Complex.mul_im] + +/-- The real part of the complex part of a real functional is the functional itself. -/ +theorem re_complexPart (ℓ : E →L[ℝ] ℝ) (c : E) : (complexPart ℓ c).re = ℓ c := by + simp [complexPart_apply] + +/-- A nonzero real functional has a vector on which its complex-linear part is nonzero. -/ +theorem exists_complexPart_ne_zero {ℓ : E →L[ℝ] ℝ} (hℓ : ℓ ≠ 0) : ∃ c, complexPart ℓ c ≠ 0 := by + obtain ⟨c, hc⟩ : ∃ c, ℓ c ≠ 0 := by + by_contra h + push Not at h + exact hℓ (ContinuousLinearMap.ext h) + refine ⟨c, fun h => hc ?_⟩ + rw [← re_complexPart, h, Complex.zero_re] + +/-- Every complex value is attained by the complex-linear part of a nonzero real functional. -/ +theorem exists_complexPart_eq {ℓ : E →L[ℝ] ℝ} (hℓ : ℓ ≠ 0) (q : ℂ) : + ∃ c, complexPart ℓ c = q := by + obtain ⟨c₀, hc₀⟩ := exists_complexPart_ne_zero hℓ + refine ⟨(q / complexPart ℓ c₀) • c₀, ?_⟩ + rw [map_smul, smul_eq_mul, div_mul_cancel₀ _ hc₀] + +/-- **Quadratic decomposition along a complex line.** For a symmetric real bilinear form `B`, +`B (ζ • w) (ζ • w) / 2` is `‖ζ‖ ^ 2` times the Hermitian part +`(B w w + B (I • w) (I • w)) / 4` plus the real part of `ζ ^ 2` times the complex quadratic +coefficient `(B w w - B (I • w) (I • w)) / 4 - I / 2 * B w (I • w)`. -/ +theorem bilinear_smul_smul_eq (B : E →L[ℝ] E →L[ℝ] ℝ) {w : E} + (hsymm : B w (I • w) = B (I • w) w) (ζ : ℂ) : + (1 / 2 : ℝ) * B (ζ • w) (ζ • w) = + ‖ζ‖ ^ 2 * ((B w w + B (I • w) (I • w)) / 4) + + (ζ ^ 2 * (((B w w - B (I • w) (I • w)) / 4 : ℝ) - I / 2 * B w (I • w))).re := by + rw [Complex.smul_eq_re_smul_add_im_smul] + simp only [map_add, map_smul, add_apply, smul_apply, smul_eq_mul, hsymm] + rw [Complex.sq_norm, Complex.normSq_apply] + simp [Complex.mul_re, Complex.mul_im, pow_two] + ring + +end ComplexPart + +section Defining + +/-- A local `C²` defining function for `U` at `p` on the open neighborhood `V`: `ρ p = 0`, the real +derivative of `ρ` at `p` is nonzero, and `U ∩ V` is the negative sublevel set of `ρ` in `V`. -/ +structure IsLocalDefiningFunction (U : Set E) (p : E) (ρ : E → ℝ) (V : Set E) : Prop where + /-- The defining neighborhood is open. -/ + isOpen : IsOpen V + /-- The boundary point lies in the defining neighborhood. -/ + mem : p ∈ V + /-- The defining function is twice continuously real differentiable. -/ + contDiffOn : ContDiffOn ℝ 2 ρ V + /-- The defining function vanishes at the boundary point. -/ + eq_zero : ρ p = 0 + /-- The real derivative is nonzero at the boundary point. -/ + fderiv_ne : fderiv ℝ ρ p ≠ 0 + /-- The domain is the negative sublevel set in the defining neighborhood. -/ + inter_eq : U ∩ V = {z | ρ z < 0} ∩ V + +/-- A set has `C²` boundary if every boundary point has a local defining function. -/ +@[expose] def HasC2Boundary (U : Set E) : Prop := + ∀ p ∈ frontier U, ∃ (ρ : E → ℝ) (V : Set E), IsLocalDefiningFunction U p ρ V + +/-- The complex tangent space of the level set of `ρ` at `p`: the kernel of the complex-linear part +of the derivative. -/ +@[expose] def IsComplexTangent (ρ : E → ℝ) (p w : E) : Prop := + fderiv ℝ ρ p w = 0 ∧ fderiv ℝ ρ p (I • w) = 0 + +/-- The Levi condition at a boundary point: the Levi form of every local defining function is +positive semidefinite on the complex tangent space. -/ +@[expose] def IsLeviPseudoconvexAt (U : Set E) (p : E) : Prop := + ∀ (ρ : E → ℝ) (V : Set E), IsLocalDefiningFunction U p ρ V → + ∀ w, IsComplexTangent ρ p w → 0 ≤ leviForm ρ p w + +/-- Levi pseudoconvexity: the Levi condition at every boundary point. -/ +@[expose] def IsLeviPseudoconvex (U : Set E) : Prop := + ∀ p ∈ frontier U, IsLeviPseudoconvexAt U p + +/-- The complex tangent space is closed under multiplication by `I`. -/ +theorem IsComplexTangent.smul_I {ρ : E → ℝ} {p w : E} (h : IsComplexTangent ρ p w) : + IsComplexTangent ρ p (I • w) := by + refine ⟨h.2, ?_⟩ + rw [smul_smul, Complex.I_mul_I, neg_one_smul, map_neg, h.1, neg_zero] + +/-- Points near `p` where the defining function is negative lie in `U`. -/ +theorem IsLocalDefiningFunction.mem_of_neg {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + (h : IsLocalDefiningFunction U p ρ V) {z : E} (hz : z ∈ V) (hρ : ρ z < 0) : z ∈ U := by + have : z ∈ {z | ρ z < 0} ∩ V := ⟨hρ, hz⟩ + rw [← h.inter_eq] at this + exact this.1 + +/-- Points of `V` in `U` have negative defining function. -/ +theorem IsLocalDefiningFunction.neg_of_mem {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + (h : IsLocalDefiningFunction U p ρ V) {z : E} (hz : z ∈ V) (hU : z ∈ U) : ρ z < 0 := by + have : z ∈ U ∩ V := ⟨hU, hz⟩ + rw [h.inter_eq] at this + exact this.1 + +end Defining + +section Convex + +variable {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + +/-- Along a real tangent direction, the second derivative of a defining function of a convex open +set is nonnegative. -/ +theorem IsLocalDefiningFunction.fderiv_fderiv_nonneg_of_convex (hU : IsOpen U) + (hconv : Convex ℝ U) (hp : p ∈ frontier U) (h : IsLocalDefiningFunction U p ρ V) + {w : E} (hw : fderiv ℝ ρ p w = 0) : 0 ≤ fderiv ℝ (fderiv ℝ ρ) p w w := by + by_contra hneg + push Not at hneg + set A := fderiv ℝ (fderiv ℝ ρ) p w w with hA + -- the slice along the complex line through `p` in direction `w` + set g : ℂ → ℝ := fun t => ρ (p + t • w) with hg + have hρp : ContDiffAt ℝ 2 ρ (p + (0 : ℂ) • w) := by + simpa using h.contDiffOn.contDiffAt (h.isOpen.mem_nhds h.mem) + have hgc : ContDiffAt ℝ 2 g 0 := hρp.comp 0 + (by fun_prop : ContDiff ℝ 2 fun t : ℂ => p + t • w).contDiffAt + obtain ⟨δ₁, hδ₁, htaylor⟩ := exists_taylor_bound hgc (ε := -A / 4) (by linarith) + obtain ⟨δ₂, hδ₂, hV⟩ := Metric.mem_nhds_iff.mp + ((by fun_prop : Continuous fun t : ℂ => p + t • w).continuousAt.preimage_mem_nhds (by + change V ∈ 𝓝 ((fun t : ℂ => p + t • w) 0) + simpa using h.isOpen.mem_nhds h.mem)) + have hD1 : fderiv ℝ g 0 = (fderiv ℝ ρ p).comp ((ContinuousLinearMap.id ℝ ℂ).smulRight w) := by + have := fderiv_slice (f := ρ) (a := p) (w := w) (t₀ := 0) (hρp.differentiableAt (by norm_num)) + simpa using this + have hD2 : ∀ s s' : ℂ, fderiv ℝ (fderiv ℝ g) 0 s s' = fderiv ℝ (fderiv ℝ ρ) p (s • w) (s' • w) + := by + intro s s' + have := fderiv_fderiv_slice (f := ρ) (a := p) (w := w) (t₀ := 0) hρp s s' + simpa using this + -- the slice is negative at small nonzero real parameters + have hneg' : ∀ x : ℝ, x ≠ 0 → |x| < min δ₁ δ₂ → p + (x : ℂ) • w ∈ U := by + intro x hx hxδ + have hxδ₁ : ‖(x : ℂ)‖ < δ₁ := by simpa using hxδ.trans_le (min_le_left _ _) + have hxδ₂ : (x : ℂ) ∈ ball (0 : ℂ) δ₂ := by + simpa using hxδ.trans_le (min_le_right _ _) + have ht := htaylor (x : ℂ) hxδ₁ + have hg0 : g 0 = 0 := by simp [hg, h.eq_zero] + have hlin : fderiv ℝ g 0 (x : ℂ) = 0 := by + rw [hD1, ContinuousLinearMap.comp_apply, ContinuousLinearMap.smulRight_apply, + ContinuousLinearMap.id_apply, Complex.coe_smul, map_smul, hw, + smul_zero] + have hquad : fderiv ℝ (fderiv ℝ g) 0 (x : ℂ) (x : ℂ) = x ^ 2 * A := by + rw [hD2, Complex.coe_smul, map_smul, map_smul] + simp only [smul_apply, smul_eq_mul] + rw [hA] + ring + rw [hg0, hlin, hquad, sub_zero, sub_zero, zero_add] at ht + have hxn : ‖(x : ℂ)‖ ^ 2 = x ^ 2 := by simp [sq_abs] + rw [hxn] at ht + have hx2 : 0 < x ^ 2 := by positivity + have : g (x : ℂ) < 0 := by + have := (abs_le.mp ht).2 + nlinarith + exact h.mem_of_neg (hV hxδ₂) this + -- convexity puts `p` into `U` + set x : ℝ := min δ₁ δ₂ / 2 with hx + have hx0 : 0 < x := by positivity + have hxlt : |x| < min δ₁ δ₂ := by + rw [abs_of_pos hx0, hx] + linarith [lt_min hδ₁ hδ₂] + have h1 := hneg' x hx0.ne' hxlt + have h2 := hneg' (-x) (neg_ne_zero.mpr hx0.ne') (by rwa [abs_neg]) + have hmid : p = (1 / 2 : ℝ) • (p + (x : ℂ) • w) + (1 / 2 : ℝ) • (p + ((-x : ℝ) : ℂ) • w) := by + simp only [Complex.coe_smul] + module + have : p ∈ U := by + rw [hmid] + exact hconv h1 h2 (by norm_num) (by norm_num) (by norm_num) + exact hU.notMem_of_mem_frontier hp this + +/-- **Convex open sets are Levi pseudoconvex** ([Range][Range1986], Lemma 2.10). -/ +theorem _root_.Convex.isLeviPseudoconvex (hU : IsOpen U) (hconv : Convex ℝ U) : + IsLeviPseudoconvex U := by + intro p hp ρ V h w hw + have h1 := h.fderiv_fderiv_nonneg_of_convex hU hconv hp hw.1 + have h2 := h.fderiv_fderiv_nonneg_of_convex hU hconv hp hw.smul_I.1 + rw [leviForm_eq_fderiv] + linarith + +end Convex + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Independence.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Independence.lean new file mode 100644 index 0000000000..9d705fda1b --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Independence.lean @@ -0,0 +1,318 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.Deriv.Comp +public import Mathlib.Analysis.Calculus.Deriv.Slope +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.LinearFunctional +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.SmoothCriterion + +/-! +# Independence of the defining function + +Two local `C²` defining functions of the same open set at the same boundary point have +positively proportional derivatives, and their second derivatives are proportional by the same +factor on tangent vectors. Consequently the complex tangent space and the sign of the Levi form +on it do not depend on the choice of defining function, and the Levi condition can be verified +on a single defining function. + +The proofs avoid the implicit function theorem and the positive-factor lemma of +[Range][Range1986] (Lemma 2.5). First derivatives are compared through one-sided difference +quotients along lines entering the set; second derivatives through second-order expansions along +parabolic curves `t ↦ p + t v + β t² ν`, whose sign is controlled by the defining property. + +References: [Range][Range1986] (1986), Chapter II, Lemma 2.5 and the discussion after (2.19); +[Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Lemma 4.1. + +## Main results + +* `IsLocalDefiningFunction.exists_fderiv_eq_smul`: **First-order comparison.** The derivatives of + two defining functions at the same boundary point are positively proportional. +* `IsLocalDefiningFunction.fderiv_fderiv_eq`: **Second-order comparison.** On tangent vectors, the + second derivatives of two defining functions are proportional with the same positive factor as + their first derivatives. +* `isLeviPseudoconvexAt_iff_of_defining`: **The Levi condition can be checked on one defining + function.** + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +open TaylorBounds + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + + +section Comparison + +variable {U : Set E} {p : E} {ρ ρ₁ ρ₂ : E → ℝ} {V V₁ V₂ : Set E} + +/-- Second-order expansion of a `C²` function along the parabolic curve `t ↦ p + t • v + (β * t ^ 2) +• ν`. -/ +theorem exists_parabola_bound (hρ : ContDiffAt ℝ 2 ρ p) (v ν : E) (β : ℝ) {η : ℝ} (hη : 0 < η) : + ∃ δ > 0, ∀ t : ℝ, 0 < t → t < δ → + |ρ (p + t • v + (β * t ^ 2) • ν) - ρ p - (t * fderiv ℝ ρ p v + β * t ^ 2 * fderiv ℝ ρ p ν + + t ^ 2 / 2 * fderiv ℝ (fderiv ℝ ρ) p v v)| ≤ η * t ^ 2 := by + set B := fderiv ℝ (fderiv ℝ ρ) p with hB + set M₀ : ℝ := ‖v‖ + |β| * ‖ν‖ with hM₀ + set M₁ : ℝ := |β| * ‖B‖ * ‖v‖ * ‖ν‖ + β ^ 2 * ‖B‖ * ‖ν‖ ^ 2 / 2 with hM₁ + have hM₀0 : 0 ≤ M₀ := by positivity + have hM₁0 : 0 ≤ M₁ := by positivity + obtain ⟨δ', hδ', htaylor⟩ := exists_taylor_bound hρ (ε := η / (2 * (M₀ ^ 2 + 1))) (by positivity) + refine ⟨min 1 (min (η / (2 * (M₁ + 1))) (δ' / (2 * (M₀ + 1)))), by positivity, fun t ht htδ => ?_⟩ + obtain ⟨ht1, htM₁, htδ'⟩ := + le_one_and_mul_add_le_of_le_min hM₀0 hM₁0 ht (le_of_lt htδ) + set k : E := t • v + (β * t ^ 2) • ν with hk + have hkn : ‖k‖ ≤ t * M₀ := by + calc ‖k‖ ≤ ‖t • v‖ + ‖(β * t ^ 2) • ν‖ := norm_add_le _ _ + _ = t * ‖v‖ + |β| * t ^ 2 * ‖ν‖ := by + rw [norm_smul, norm_smul, Real.norm_eq_abs, Real.norm_eq_abs, abs_of_pos ht, abs_mul, + abs_of_pos (by positivity : (0:ℝ) < t ^ 2)] + _ ≤ t * ‖v‖ + |β| * t * ‖ν‖ := by + have : t ^ 2 ≤ t := by nlinarith + gcongr + _ = t * M₀ := by rw [hM₀]; ring + have hklt : ‖k‖ < δ' := hkn.trans_lt (by nlinarith) + have htay : |ρ (p + k) - ρ p - fderiv ℝ ρ p k - (1 / 2 : ℝ) * B k k| ≤ + η / (2 * (M₀ ^ 2 + 1)) * ‖k‖ ^ 2 := htaylor k hklt + have hsplit : p + t • v + (β * t ^ 2) • ν = p + k := by rw [hk]; abel + have hlin : fderiv ℝ ρ p k = t * fderiv ℝ ρ p v + β * t ^ 2 * fderiv ℝ ρ p ν := by + rw [hk, map_add, map_smul, map_smul, smul_eq_mul, smul_eq_mul] + have hquad : (1 / 2 : ℝ) * B k k - t ^ 2 / 2 * B v v = + (1 / 2 : ℝ) * (β * t ^ 3 * (B v ν + B ν v) + β ^ 2 * t ^ 4 * B ν ν) := by + rw [hk] + simp only [map_add, map_smul, add_apply, smul_apply, smul_eq_mul] + ring + have hBn : 0 ≤ ‖B‖ := ContinuousLinearMap.opNorm_nonneg B + have hquad_bd : |(1 / 2 : ℝ) * B k k - t ^ 2 / 2 * B v v| ≤ M₁ * t ^ 3 := by + rw [hquad, abs_mul, abs_of_pos (by norm_num : (0:ℝ) < 1 / 2)] + have h1 : |B v ν| ≤ ‖B‖ * ‖v‖ * ‖ν‖ := by + have := B.le_opNorm₂ v ν; rwa [Real.norm_eq_abs] at this + have h2 : |B ν v| ≤ ‖B‖ * ‖ν‖ * ‖v‖ := by + have := B.le_opNorm₂ ν v; rwa [Real.norm_eq_abs] at this + have h3 : |B ν ν| ≤ ‖B‖ * ‖ν‖ * ‖ν‖ := by + have := B.le_opNorm₂ ν ν; rwa [Real.norm_eq_abs] at this + have ht3 : 0 ≤ t ^ 3 := by positivity + have ht4 : t ^ 4 ≤ t ^ 3 := by + calc t ^ 4 = t ^ 3 * t := by ring + _ ≤ t ^ 3 * 1 := by gcongr + _ = t ^ 3 := mul_one _ + calc 1 / 2 * |β * t ^ 3 * (B v ν + B ν v) + β ^ 2 * t ^ 4 * B ν ν| + ≤ 1 / 2 * (|β| * t ^ 3 * (|B v ν| + |B ν v|) + β ^ 2 * t ^ 4 * |B ν ν|) := by + gcongr + calc |β * t ^ 3 * (B v ν + B ν v) + β ^ 2 * t ^ 4 * B ν ν| + ≤ |β * t ^ 3 * (B v ν + B ν v)| + |β ^ 2 * t ^ 4 * B ν ν| := abs_add_le _ _ + _ = |β| * t ^ 3 * |B v ν + B ν v| + β ^ 2 * t ^ 4 * |B ν ν| := by + rw [abs_mul, abs_mul, abs_mul, abs_mul, abs_of_nonneg ht3, abs_pow, + abs_of_nonneg (by positivity : (0:ℝ) ≤ t ^ 4)] + simp [sq_abs] + _ ≤ |β| * t ^ 3 * (|B v ν| + |B ν v|) + β ^ 2 * t ^ 4 * |B ν ν| := by + gcongr + exact abs_add_le _ _ + _ ≤ 1 / 2 * (|β| * t ^ 3 * (‖B‖ * ‖v‖ * ‖ν‖ + ‖B‖ * ‖ν‖ * ‖v‖) + + β ^ 2 * t ^ 3 * (‖B‖ * ‖ν‖ * ‖ν‖)) := by + gcongr + _ = M₁ * t ^ 3 := by rw [hM₁]; ring + have hR : |ρ (p + k) - ρ p - fderiv ℝ ρ p k - (1 / 2 : ℝ) * B k k| ≤ + η / (2 * (M₀ ^ 2 + 1)) * (t * M₀) ^ 2 := by + refine htay.trans ?_ + gcongr + rw [hsplit] + have hkey : ρ (p + k) - ρ p - (t * fderiv ℝ ρ p v + β * t ^ 2 * fderiv ℝ ρ p ν + + t ^ 2 / 2 * B v v) = (ρ (p + k) - ρ p - fderiv ℝ ρ p k - (1 / 2 : ℝ) * B k k) + + ((1 / 2 : ℝ) * B k k - t ^ 2 / 2 * B v v) := by + rw [hlin]; ring + rw [hkey] + exact taylor_remainder_add_cubic_le ht hη htM₁ hR hquad_bd + +/-- A defining function is negative along a line entering the set, and the derivative of any other +defining function in that direction is nonpositive. -/ +theorem IsLocalDefiningFunction.fderiv_nonpos_of_fderiv_neg (h₁ : IsLocalDefiningFunction U p ρ₁ V₁) + (h₂ : IsLocalDefiningFunction U p ρ₂ V₂) {v : E} (hv : fderiv ℝ ρ₂ p v < 0) : + fderiv ℝ ρ₁ p v ≤ 0 := by + have hd : ∀ (ρ : E → ℝ) (V : Set E), IsLocalDefiningFunction U p ρ V → + HasDerivAt (fun t : ℝ => ρ (p + t • v)) (fderiv ℝ ρ p v) 0 := by + intro ρ V h + have hρ : DifferentiableAt ℝ ρ (p + (0 : ℝ) • v) := by + simpa using (h.contDiffOn.contDiffAt (h.isOpen.mem_nhds h.mem)).differentiableAt (by norm_num) + have hl : HasDerivAt (fun t : ℝ => p + t • v) v 0 := by + simpa using ((hasDerivAt_id (0 : ℝ)).smul_const v).const_add p + have := hρ.hasFDerivAt.comp_hasDerivAt (0 : ℝ) hl + convert this using 2 <;> simp + have h1 := (hasDerivAt_iff_tendsto_slope_zero.mp (hd ρ₁ V₁ h₁)).mono_left (nhdsGT_le_nhdsNE 0) + have h2 := (hasDerivAt_iff_tendsto_slope_zero.mp (hd ρ₂ V₂ h₂)).mono_left (nhdsGT_le_nhdsNE 0) + simp only [zero_add, zero_smul, add_zero, h₁.eq_zero, h₂.eq_zero, sub_zero, smul_eq_mul] at h1 h2 + -- the slopes of `ρ₂` are eventually negative, so the points lie in `U` + have hneg : ∀ᶠ t in 𝓝[>] (0 : ℝ), t⁻¹ * ρ₂ (p + t • v) < 0 := + h2.eventually (eventually_lt_nhds hv) + have hV : ∀ᶠ t in 𝓝[>] (0 : ℝ), p + t • v ∈ V₁ ∩ V₂ := by + have hc : ContinuousAt (fun t : ℝ => p + t • v) 0 := by fun_prop + have hVp : V₁ ∩ V₂ ∈ 𝓝 p := inter_mem (h₁.isOpen.mem_nhds h₁.mem) (h₂.isOpen.mem_nhds h₂.mem) + have := hc.preimage_mem_nhds (by convert hVp using 2; simp) + exact nhdsWithin_le_nhds this + have hle : ∀ᶠ t in 𝓝[>] (0 : ℝ), t⁻¹ * ρ₁ (p + t • v) ≤ 0 := by + filter_upwards [hneg, hV, self_mem_nhdsWithin] with t ht htV htpos + have ht0 : 0 < t := htpos + have hρ₂ : ρ₂ (p + t • v) < 0 := by + by_contra hcon + push Not at hcon + have : 0 ≤ t⁻¹ * ρ₂ (p + t • v) := mul_nonneg (inv_nonneg.mpr ht0.le) hcon + linarith + have hU : p + t • v ∈ U := h₂.mem_of_neg htV.2 hρ₂ + have hρ₁ : ρ₁ (p + t • v) < 0 := h₁.neg_of_mem htV.1 hU + exact mul_nonpos_of_nonneg_of_nonpos (inv_nonneg.mpr ht0.le) hρ₁.le + exact le_of_tendsto h1 hle + +/-- **First-order comparison.** The derivatives of two defining functions at the same boundary +point are positively proportional. -/ +theorem IsLocalDefiningFunction.exists_fderiv_eq_smul (h₁ : IsLocalDefiningFunction U p ρ₁ V₁) + (h₂ : IsLocalDefiningFunction U p ρ₂ V₂) : + ∃ c : ℝ, 0 < c ∧ fderiv ℝ ρ₁ p = c • fderiv ℝ ρ₂ p := + ContinuousLinearMap.exists_pos_smul_eq_of_neg_imp_nonpos h₁.fderiv_ne h₂.fderiv_ne fun _ hv => + h₁.fderiv_nonpos_of_fderiv_neg h₂ hv + +/-- One half of the second-order comparison on tangent vectors. -/ +theorem IsLocalDefiningFunction.fderiv_fderiv_le (h₁ : IsLocalDefiningFunction U p ρ₁ V₁) + (h₂ : IsLocalDefiningFunction U p ρ₂ V₂) {c : ℝ} (hc : 0 < c) + (hℓ : fderiv ℝ ρ₁ p = c • fderiv ℝ ρ₂ p) {v : E} (hv : fderiv ℝ ρ₂ p v = 0) : + fderiv ℝ (fderiv ℝ ρ₁) p v v ≤ c * fderiv ℝ (fderiv ℝ ρ₂) p v v := by + by_contra hlt + push Not at hlt + set a₁ := fderiv ℝ (fderiv ℝ ρ₁) p v v with ha₁ + set a₂ := fderiv ℝ (fderiv ℝ ρ₂) p v v with ha₂ + -- an inward direction for `ρ₂` + obtain ⟨u, hu⟩ : ∃ u, fderiv ℝ ρ₂ p u ≠ 0 := by + by_contra hcon + push Not at hcon + exact h₂.fderiv_ne (ContinuousLinearMap.ext hcon) + set ν : E := (1 / fderiv ℝ ρ₂ p u) • u with hν + have hν₂ : fderiv ℝ ρ₂ p ν = 1 := by + rw [hν, map_smul, smul_eq_mul, one_div, inv_mul_cancel₀ hu] + have hν₁ : fderiv ℝ ρ₁ p ν = c := by rw [hℓ, smul_apply, hν₂, smul_eq_mul, mul_one] + have hv₁ : fderiv ℝ ρ₁ p v = 0 := by rw [hℓ, smul_apply, hv, smul_zero] + -- the parabola parameter + set β : ℝ := (-a₂ / 2 + -a₁ / (2 * c)) / 2 with hβ + have hβ₂ : β + a₂ / 2 < 0 := by + rw [hβ] + have : -a₁ / (2 * c) < -a₂ / 2 := by + rw [div_lt_div_iff₀ (by positivity) (by norm_num)] + nlinarith + linarith + have hβ₁ : 0 < c * β + a₁ / 2 := by + rw [hβ] + have : -a₂ / 2 > -a₁ / (2 * c) := by + rw [gt_iff_lt, div_lt_div_iff₀ (by positivity) (by norm_num)] + nlinarith + have hc' : c * (-a₁ / (2 * c)) = -a₁ / 2 := by field_simp + nlinarith + set η : ℝ := min (-(β + a₂ / 2) / 2) ((c * β + a₁ / 2) / 2) with hη + have hη0 : 0 < η := lt_min (by linarith) (by linarith) + have hρ₁c : ContDiffAt ℝ 2 ρ₁ p := h₁.contDiffOn.contDiffAt (h₁.isOpen.mem_nhds h₁.mem) + have hρ₂c : ContDiffAt ℝ 2 ρ₂ p := h₂.contDiffOn.contDiffAt (h₂.isOpen.mem_nhds h₂.mem) + obtain ⟨δ₁, hδ₁, hb₁⟩ := exists_parabola_bound hρ₁c v ν β hη0 + obtain ⟨δ₂, hδ₂, hb₂⟩ := exists_parabola_bound hρ₂c v ν β hη0 + have hcont : ContinuousAt (fun t : ℝ => p + t • v + (β * t ^ 2) • ν) 0 := by fun_prop + have hVp : V₁ ∩ V₂ ∈ 𝓝 p := inter_mem (h₁.isOpen.mem_nhds h₁.mem) (h₂.isOpen.mem_nhds h₂.mem) + obtain ⟨δ₃, hδ₃, hV⟩ := Metric.mem_nhds_iff.mp (hcont.preimage_mem_nhds (by + convert hVp using 2 + simp)) + set t : ℝ := min δ₁ (min δ₂ δ₃) / 2 with ht + have ht0 : 0 < t := by positivity + have ht₁ : t < δ₁ := by + have := min_le_left δ₁ (min δ₂ δ₃) + rw [ht]; linarith [lt_min hδ₁ (lt_min hδ₂ hδ₃)] + have ht₂ : t < δ₂ := by + have := (min_le_right δ₁ (min δ₂ δ₃)).trans (min_le_left δ₂ δ₃) + rw [ht]; linarith [lt_min hδ₁ (lt_min hδ₂ hδ₃)] + have ht₃ : t < δ₃ := by + have := (min_le_right δ₁ (min δ₂ δ₃)).trans (min_le_right δ₂ δ₃) + rw [ht]; linarith [lt_min hδ₁ (lt_min hδ₂ hδ₃)] + set z := p + t • v + (β * t ^ 2) • ν with hz + have hzV : z ∈ V₁ ∩ V₂ := hV (by + rw [mem_ball, dist_zero_right, Real.norm_eq_abs, abs_of_pos ht0] + exact ht₃) + have e₁ := hb₁ t ht0 ht₁ + have e₂ := hb₂ t ht0 ht₂ + rw [h₁.eq_zero, hv₁, hν₁] at e₁ + rw [h₂.eq_zero, hv, hν₂] at e₂ + have hρ₂ : ρ₂ z < 0 := by + have := (abs_le.mp e₂).2 + have hη' : η ≤ -(β + a₂ / 2) / 2 := min_le_left _ _ + have ht2 : 0 < t ^ 2 := by positivity + nlinarith + have hρ₁ : 0 < ρ₁ z := by + have := (abs_le.mp e₁).1 + have hη' : η ≤ (c * β + a₁ / 2) / 2 := min_le_right _ _ + have ht2 : 0 < t ^ 2 := by positivity + nlinarith + have hU : z ∈ U := h₂.mem_of_neg hzV.2 hρ₂ + have := h₁.neg_of_mem hzV.1 hU + linarith + +/-- **Second-order comparison.** On tangent vectors, the second derivatives of two defining +functions are proportional with the same positive factor as their first derivatives. -/ +theorem IsLocalDefiningFunction.fderiv_fderiv_eq (h₁ : IsLocalDefiningFunction U p ρ₁ V₁) + (h₂ : IsLocalDefiningFunction U p ρ₂ V₂) {c : ℝ} (hc : 0 < c) + (hℓ : fderiv ℝ ρ₁ p = c • fderiv ℝ ρ₂ p) {v : E} (hv : fderiv ℝ ρ₂ p v = 0) : + fderiv ℝ (fderiv ℝ ρ₁) p v v = c * fderiv ℝ (fderiv ℝ ρ₂) p v v := by + have h1 := h₁.fderiv_fderiv_le h₂ hc hℓ hv + have hℓ' : fderiv ℝ ρ₂ p = c⁻¹ • fderiv ℝ ρ₁ p := by + rw [hℓ, smul_smul, inv_mul_cancel₀ hc.ne', one_smul] + have hv₁ : fderiv ℝ ρ₁ p v = 0 := by rw [hℓ, smul_apply, hv, smul_zero] + have h2 := h₂.fderiv_fderiv_le h₁ (inv_pos.mpr hc) hℓ' hv₁ + have : c * fderiv ℝ (fderiv ℝ ρ₂) p v v ≤ fderiv ℝ (fderiv ℝ ρ₁) p v v := by + have := mul_le_mul_of_nonneg_left h2 hc.le + rwa [← mul_assoc, mul_inv_cancel₀ hc.ne', one_mul] at this + exact le_antisymm h1 this + +/-- The complex tangent space does not depend on the defining function. -/ +theorem IsLocalDefiningFunction.isComplexTangent_iff (h₁ : IsLocalDefiningFunction U p ρ₁ V₁) + (h₂ : IsLocalDefiningFunction U p ρ₂ V₂) (w : E) : + IsComplexTangent ρ₁ p w ↔ IsComplexTangent ρ₂ p w := by + obtain ⟨c, hc, hℓ⟩ := h₁.exists_fderiv_eq_smul h₂ + simp only [IsComplexTangent, hℓ, smul_apply, smul_eq_mul, + mul_eq_zero, hc.ne', false_or] + +/-- On complex tangent vectors, the Levi forms of two defining functions are positively +proportional. -/ +theorem IsLocalDefiningFunction.exists_leviForm_eq (h₁ : IsLocalDefiningFunction U p ρ₁ V₁) + (h₂ : IsLocalDefiningFunction U p ρ₂ V₂) : + ∃ c : ℝ, 0 < c ∧ ∀ w, IsComplexTangent ρ₂ p w → leviForm ρ₁ p w = c * leviForm ρ₂ p w := by + obtain ⟨c, hc, hℓ⟩ := h₁.exists_fderiv_eq_smul h₂ + refine ⟨c, hc, fun w hw => ?_⟩ + rw [leviForm_eq_fderiv, leviForm_eq_fderiv, h₁.fderiv_fderiv_eq h₂ hc hℓ hw.1, + h₁.fderiv_fderiv_eq h₂ hc hℓ hw.smul_I.1] + ring + +/-- **The Levi condition can be checked on one defining function.** -/ +theorem isLeviPseudoconvexAt_iff_of_defining (h : IsLocalDefiningFunction U p ρ V) : + IsLeviPseudoconvexAt U p ↔ ∀ w, IsComplexTangent ρ p w → 0 ≤ leviForm ρ p w := by + constructor + · intro hL w hw + exact hL ρ V h w hw + · intro hL ρ' V' h' w hw + obtain ⟨c, hc, hlev⟩ := h'.exists_leviForm_eq h + have hw' : IsComplexTangent ρ p w := (h'.isComplexTangent_iff h w).mp hw + rw [hlev w hw'] + exact mul_nonneg hc.le (hL w hw') + +end Comparison + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Invariance.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Invariance.lean new file mode 100644 index 0000000000..4b5164c01a --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Invariance.lean @@ -0,0 +1,122 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm.Holomorphic + +/-! +# Invariance of the Levi condition under holomorphic maps + +A local defining function pulls back along a holomorphic map with surjective derivative to a +local defining function of the preimage. Complex tangent vectors correspond under the +derivative, and the Levi form transforms by the chain rule of `LeviForm.Holomorphic`. +Consequently, for a holomorphic map with invertible derivative at `p`, the Levi condition for a +defining function at `Φ p` is equivalent to the Levi condition for its pullback at `p`. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 4, Remark +after the definition of Levi convexity; [Range][Range1986] (1986), Chapter II, Lemma 2.12. + +## Main results + +* `leviCondition_comp_iff`: **Invariance of the Levi condition.** For a holomorphic map with + invertible derivative at `p`, the Levi condition for a defining function at `Φ p` holds exactly + when it holds for the pullback at `p`. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- The derivative of a composition with a holomorphic map, over the reals. -/ +theorem fderiv_comp_analytic {ρ : F → ℝ} {Φ : E → F} {p : E} (hΦ : AnalyticAt ℂ Φ p) + (hρ : DifferentiableAt ℝ ρ (Φ p)) : + fderiv ℝ (ρ ∘ Φ) p = (fderiv ℝ ρ (Φ p)).comp ((fderiv ℂ Φ p).restrictScalars ℝ) := + (hρ.hasFDerivAt.comp p (hΦ.differentiableAt.hasFDerivAt.restrictScalars ℝ)).fderiv + +/-- Complex tangent vectors of a pullback correspond to complex tangent vectors of the image under +the derivative. -/ +theorem isComplexTangent_comp_iff {ρ : F → ℝ} {Φ : E → F} {p : E} (hΦ : AnalyticAt ℂ Φ p) + (hρ : DifferentiableAt ℝ ρ (Φ p)) (w : E) : + IsComplexTangent (ρ ∘ Φ) p w ↔ IsComplexTangent ρ (Φ p) (fderiv ℂ Φ p w) := by + simp only [IsComplexTangent, fderiv_comp_analytic hΦ hρ, ContinuousLinearMap.comp_apply, + ContinuousLinearMap.coe_restrictScalars', map_smul] + +variable {U : Set F} {q : F} {ρ : F → ℝ} {V : Set F} + +/-- A local defining function pulls back along a holomorphic map with surjective derivative to a +local defining function of the preimage. -/ +theorem IsLocalDefiningFunction.comp_analytic (h : IsLocalDefiningFunction U q ρ V) + {Φ : E → F} {W : Set E} (hW : IsOpen W) {p : E} (hp : p ∈ W) (hΦ : AnalyticOnNhd ℂ Φ W) + (hΦp : Φ p = q) (hsurj : Function.Surjective (fderiv ℂ Φ p)) : + IsLocalDefiningFunction (Φ ⁻¹' U) p (ρ ∘ Φ) (W ∩ Φ ⁻¹' V) := by + have hρd : DifferentiableAt ℝ ρ (Φ p) := by + rw [hΦp] + exact (h.contDiffOn.contDiffAt (h.isOpen.mem_nhds h.mem)).differentiableAt (by norm_num) + refine ⟨hΦ.continuousOn.isOpen_inter_preimage hW h.isOpen, ⟨hp, by simp [hΦp, h.mem]⟩, ?_, + by simp [Function.comp, hΦp, h.eq_zero], ?_, ?_⟩ + · exact h.contDiffOn.comp + (((hΦ.contDiffOn hW.uniqueDiffOn (n := 2)).restrict_scalars ℝ).mono inter_subset_left) + fun z hz => hz.2 + · intro hzero + apply h.fderiv_ne + ext v + obtain ⟨u, hu⟩ := hsurj v + have := congrArg (fun L : E →L[ℝ] ℝ => L u) hzero + simp only [fderiv_comp_analytic (hΦ p hp) hρd, ContinuousLinearMap.comp_apply, + ContinuousLinearMap.coe_restrictScalars', zero_apply] at this + rw [hΦp, hu] at this + simpa using this + · ext z + simp only [mem_inter_iff, mem_preimage, mem_ofPred_eq, Function.comp] + constructor + · rintro ⟨hzU, hzW, hzV⟩ + exact ⟨h.neg_of_mem hzV hzU, hzW, hzV⟩ + · rintro ⟨hneg, hzW, hzV⟩ + exact ⟨h.mem_of_neg hzV hneg, hzW, hzV⟩ + +/-- **Invariance of the Levi condition.** For a holomorphic map with invertible derivative +at `p`, the Levi condition for a defining function at `Φ p` holds exactly when it holds for +the pullback at `p`. -/ +theorem leviCondition_comp_iff [CompleteSpace F] (h : IsLocalDefiningFunction U q ρ V) + {Φ : E → F} {p : E} + (hΦ : AnalyticAt ℂ Φ p) (hΦp : Φ p = q) (L : E ≃L[ℂ] F) + (hL : HasFDerivAt Φ (L : E →L[ℂ] F) p) : + (∀ w, IsComplexTangent (ρ ∘ Φ) p w → 0 ≤ leviForm (ρ ∘ Φ) p w) ↔ + (∀ v, IsComplexTangent ρ q v → 0 ≤ leviForm ρ q v) := by + subst hΦp + have hρ2 : ContDiffAt ℝ 2 ρ (Φ p) := h.contDiffOn.contDiffAt (h.isOpen.mem_nhds h.mem) + have hfd : fderiv ℂ Φ p = L := hL.fderiv + have hlev : ∀ w, leviForm (ρ ∘ Φ) p w = leviForm ρ (Φ p) (L w) := fun w => by + rw [leviForm_comp_analytic hρ2 hΦ, hfd] + rfl + have htan : ∀ w, IsComplexTangent (ρ ∘ Φ) p w ↔ IsComplexTangent ρ (Φ p) (L w) := fun w => by + rw [isComplexTangent_comp_iff hΦ (hρ2.differentiableAt (by norm_num)), hfd] + rfl + constructor + · intro hcond v hv + have := hcond (L.symm v) ((htan _).mpr (by simpa using hv)) + rwa [hlev, L.apply_symm_apply] at this + · intro hcond w hw + rw [hlev] + exact hcond _ ((htan w).mp hw) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Necessity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Necessity.lean new file mode 100644 index 0000000000..8b3abdce9f --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Necessity.lean @@ -0,0 +1,521 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.Deriv.MeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Invariance +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Pseudoconvexity + +/-! +# Levi's necessary condition + +A domain of holomorphy in any finite-dimensional complex normed space with `C²` boundary is Levi +pseudoconvex. The proof in coordinates is transported by a continuous linear equivalence. This is E. +E. Levi's theorem ([Range][Range1986], Theorem 2.11; [Fritzsche–Grauert][FritzscheGrauert2002], +Theorem 4.7, first half). + +The proof avoids holomorphic coordinate changes. If the Levi form of a defining function `ρ` +were negative in a complex tangent direction `w` at a boundary point `p`, the Levi polynomial +provides a quadratic analytic disc `ζ ↦ p + ζ • w + ζ ^ 2 • c + ε • ν` tangent to the boundary +from inside, on which `ρ` behaves like `-ε + ‖ζ‖ ^ 2 L` with `L < 0`. Its boundary circle is +therefore much deeper inside the domain than its center. The boundary distance is comparable to +`|ρ|` near `p`, the center lies in the holomorphic hull of the boundary circle by the maximum +modulus principle, and Thullen's radius bound for domains of holomorphy then forces the center +to be as deep as the circle, a contradiction for small radii. + +References: [Range][Range1986] (1986), Chapter II, Theorems 2.9 and 2.11; +[Hörmander][Hormander1973] (1973), Section 2.6; [Fritzsche–Grauert][FritzscheGrauert2002] +(2002), Chapter II, Theorem 4.7. + +## Main definitions + +* `leviQuadratic`: The complex quadratic coefficient of a real bilinear form along a complex line. + +## Main results + +* `IsLocalDefiningFunction.exists_disc_estimate`: **Disc estimate along the Levi polynomial.** With + `c` cancelling the complex quadratic term and `ν` an inward direction, the defining function along + the disc `ζ ↦ p + ζ • w + ζ ^ 2 • c + (κ r ^ 2) • ν` is `-κ r ^ 2 + ‖ζ‖ ^ 2 L` up to `η r ^ 2`, + for `‖ζ‖ ≤ r` and `r` small, and the disc lies in any prescribed neighborhood of `p`. +* `IsDomainOfHolomorphy.isLeviPseudoconvex_fin`: **Levi's theorem in coordinates.** A domain of + holomorphy in `Fin n → ℂ` is Levi pseudoconvex: the Levi form of every local defining function is + positive semidefinite on the complex tangent space at every boundary point. +* `IsDomainOfHolomorphy.isLeviPseudoconvex`: **Levi's theorem.** A domain of holomorphy in a + finite-dimensional complex normed space is Levi pseudoconvex: the Levi form of every local + defining function is positive semidefinite on the complex tangent space at every boundary point. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +open TaylorBounds + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +variable {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + +/-- An inward direction for a defining function: the real derivative equals `1`. -/ +theorem IsLocalDefiningFunction.exists_inward_direction (h : IsLocalDefiningFunction U p ρ V) : + ∃ ν : E, fderiv ℝ ρ p ν = 1 ∧ 0 < ‖ν‖ := + ContinuousLinearMap.exists_apply_eq_one_of_ne_zero h.fderiv_ne + +/-- A neighborhood of `p` on which the derivative is Lipschitz-bounded and still points inward. -/ +theorem IsLocalDefiningFunction.exists_ball_fderiv_bound_and_inward + (h : IsLocalDefiningFunction U p ρ V) {ν : E} (hν : fderiv ℝ ρ p ν = 1) : + ∃ Lip δ₀ : ℝ, 0 < Lip ∧ 0 < δ₀ ∧ ball p δ₀ ⊆ + {y | y ∈ V ∧ ‖fderiv ℝ ρ y‖ ≤ Lip ∧ (1 / 2 : ℝ) ≤ fderiv ℝ ρ y ν} := by + set ℓ := fderiv ℝ ρ p + set Lip := ‖ℓ‖ + 1 + have hLip0 : 0 < Lip := by positivity + have hDcont : ContinuousOn (fderiv ℝ ρ) V := + h.contDiffOn.continuousOn_fderiv_of_isOpen h.isOpen (by norm_num) + have hcontp : ContinuousAt (fderiv ℝ ρ) p := hDcont.continuousAt (h.isOpen.mem_nhds h.mem) + have hev : ∀ᶠ y in 𝓝 p, y ∈ V ∧ ‖fderiv ℝ ρ y‖ ≤ Lip ∧ (1 / 2 : ℝ) ≤ fderiv ℝ ρ y ν := by + have h1 : ∀ᶠ y in 𝓝 p, y ∈ V := h.isOpen.mem_nhds h.mem + have h2 : ∀ᶠ y in 𝓝 p, ‖fderiv ℝ ρ y‖ ≤ Lip := + (continuous_norm.continuousAt.comp hcontp).eventually + (eventually_le_nhds (show ‖fderiv ℝ ρ p‖ < Lip by linarith)) + have h3 : ∀ᶠ y in 𝓝 p, (1 / 2 : ℝ) ≤ fderiv ℝ ρ y ν := by + have hc : ContinuousAt (fun y => fderiv ℝ ρ y ν) p := + (ContinuousLinearMap.apply ℝ ℝ ν).continuous.continuousAt.comp hcontp + exact hc.eventually (eventually_ge_nhds (show (1 / 2 : ℝ) < fderiv ℝ ρ p ν by + rw [hν]; norm_num)) + exact h1.and (h2.and h3) |>.mono fun y hy => ⟨hy.1, hy.2.1, hy.2.2⟩ + obtain ⟨δ₀, hδ₀, hball₀⟩ := Metric.mem_nhds_iff.mp hev + exact ⟨Lip, δ₀, hLip0, hδ₀, hball₀⟩ + +/-- Lower bound: distance to the complement is at least a multiple of `|ρ|`. -/ +theorem IsLocalDefiningFunction.mul_abs_le_infDist (hU : IsOpen U) (hp : p ∈ frontier U) + (h : IsLocalDefiningFunction U p ρ V) {Lip δ₀ : ℝ} (hLip0 : 0 < Lip) (hδ₀ : 0 < δ₀) + (hball₀ : ball p δ₀ ⊆ {y | y ∈ V ∧ ‖fderiv ℝ ρ y‖ ≤ Lip}) + {z : E} (hz : z ∈ ball p (δ₀ / 2)) (hzU : z ∈ U) + (hρsmall : |ρ z| < Lip * δ₀ / 2) : |ρ z| / Lip ≤ infDist z Uᶜ := by + have hUc : Uᶜ.Nonempty := ⟨p, hU.notMem_of_mem_frontier hp⟩ + have hdiff : ∀ y ∈ V, DifferentiableAt ℝ ρ y := fun y hy => + (h.contDiffOn.contDiffAt (h.isOpen.mem_nhds hy)).differentiableAt (by norm_num) + have hρz : ρ z < 0 := h.neg_of_mem (hball₀ (ball_subset_ball (half_le_self hδ₀.le) hz)).1 hzU + have hρabs : |ρ z| = -ρ z := abs_of_neg hρz + rw [le_infDist hUc] + intro y hy + by_cases hyV : y ∈ ball p δ₀ + · have hρy : 0 ≤ ρ y := by + by_contra hneg + push Not at hneg + exact hy (h.mem_of_neg (hball₀ hyV).1 hneg) + have hmv := Convex.norm_image_sub_le_of_norm_fderiv_le (f := ρ) (s := ball p δ₀) (C := Lip) + (fun x hx => hdiff x (hball₀ hx).1) (fun x hx => (hball₀ hx).2) (convex_ball p δ₀) + (ball_subset_ball (half_le_self hδ₀.le) hz) hyV + rw [Real.norm_eq_abs, ← dist_eq_norm, dist_comm] at hmv + have : |ρ z| ≤ |ρ y - ρ z| := by + rw [hρabs, abs_of_nonneg (by linarith)] + linarith + rw [div_le_iff₀ hLip0] + linarith + · have hdz : δ₀ / 2 ≤ dist z y := by + have h1 : δ₀ ≤ dist y p := not_lt.mp (by simpa [mem_ball] using hyV) + have h2 : dist z p < δ₀ / 2 := mem_ball.mp hz + have := dist_triangle y z p + rw [dist_comm y z] at this + linarith + have : |ρ z| / Lip ≤ δ₀ / 2 := by + rw [div_le_iff₀ hLip0] + linarith + exact this.trans hdz + +/-- Upper bound: walking inward along `ν` reaches the complement at distance `O(|ρ|)`. -/ +theorem IsLocalDefiningFunction.infDist_le_mul_abs (h : IsLocalDefiningFunction U p ρ V) + {ν : E} {Lip δ₀ : ℝ} (hδ₀ : 0 < δ₀) (hν0 : 0 < ‖ν‖) + (hball₀ : ball p δ₀ ⊆ + {y | y ∈ V ∧ ‖fderiv ℝ ρ y‖ ≤ Lip ∧ (1 / 2 : ℝ) ≤ fderiv ℝ ρ y ν}) + {z : E} (hz : z ∈ ball p (δ₀ / 2)) (hzU : z ∈ U) + (hρsmall : |ρ z| < δ₀ / (4 * ‖ν‖)) : infDist z Uᶜ ≤ 2 * ‖ν‖ * |ρ z| := by + have hdiff : ∀ y ∈ V, DifferentiableAt ℝ ρ y := fun y hy => + (h.contDiffOn.contDiffAt (h.isOpen.mem_nhds hy)).differentiableAt (by norm_num) + have hzV : z ∈ V := (hball₀ (ball_subset_ball (half_le_self hδ₀.le) hz)).1 + have hρz : ρ z < 0 := h.neg_of_mem hzV hzU + have hρabs : |ρ z| = -ρ z := abs_of_neg hρz + set T : ℝ := 2 * |ρ z| + have hT0 : 0 ≤ T := by positivity + have hseg : ∀ t ∈ Icc (0 : ℝ) T, z + t • ν ∈ ball p δ₀ := by + intro t ht + have h1 : ‖t • ν‖ ≤ T * ‖ν‖ := by + rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg ht.1] + exact mul_le_mul_of_nonneg_right ht.2 (norm_nonneg _) + have h2 : T * ‖ν‖ < δ₀ / 2 := by + rw [lt_div_iff₀ (by positivity)] at hρsmall + nlinarith + rw [mem_ball, dist_eq_norm] + calc ‖z + t • ν - p‖ ≤ ‖z - p‖ + ‖t • ν‖ := by + rw [add_sub_right_comm]; exact norm_add_le _ _ + _ < δ₀ / 2 + δ₀ / 2 := by + have := mem_ball.mp hz + rw [dist_eq_norm] at this + linarith + _ = δ₀ := by ring + have hderiv : ∀ t ∈ Icc (0 : ℝ) T, HasDerivAt (fun t : ℝ => ρ (z + t • ν)) + (fderiv ℝ ρ (z + t • ν) ν) t := by + intro t ht + have hl : HasDerivAt (fun t : ℝ => z + t • ν) ν t := by + simpa using ((hasDerivAt_id t).smul_const ν).const_add z + exact (hdiff _ (hball₀ (hseg t ht)).1).hasFDerivAt.comp_hasDerivAt t hl + have hmono := Convex.mul_sub_le_image_sub_of_le_deriv (convex_Icc 0 T) + (f := fun t : ℝ => ρ (z + t • ν)) (C := 1 / 2) + (fun t ht => (hderiv t ht).continuousAt.continuousWithinAt) + (fun t ht => (hderiv t (interior_subset ht)).differentiableAt.differentiableWithinAt) + (fun t ht => by + rw [(hderiv t (interior_subset ht)).deriv] + exact (hball₀ (hseg t (interior_subset ht))).2.2) + 0 (left_mem_Icc.mpr hT0) T (right_mem_Icc.mpr hT0) hT0 + simp only [zero_smul, add_zero, sub_zero] at hmono + have hρT : 0 ≤ ρ (z + T • ν) := by + dsimp [T] at hmono ⊢ + rw [hρabs] at hmono ⊢ + linarith + have hnot : z + T • ν ∉ U := fun hmem => + absurd (h.neg_of_mem (hball₀ (hseg T (right_mem_Icc.mpr hT0))).1 hmem) (not_lt.mpr hρT) + calc infDist z Uᶜ ≤ dist z (z + T • ν) := infDist_le_dist_of_mem hnot + _ = T * ‖ν‖ := by + rw [dist_eq_norm, sub_add_cancel_left, norm_neg, norm_smul, Real.norm_eq_abs, + abs_of_nonneg hT0] + _ = 2 * ‖ν‖ * |ρ z| := by dsimp [T]; ring + +/-- Near a boundary point, a defining function is comparable to the distance to the complement: `c₂ +* |ρ z| ≤ infDist z Uᶜ ≤ C₁ * |ρ z|` for `z ∈ U` near `p`. -/ +theorem IsLocalDefiningFunction.exists_infDist_bounds (hU : IsOpen U) (hp : p ∈ frontier U) + (h : IsLocalDefiningFunction U p ρ V) : + ∃ C₁ c₂ δ : ℝ, 0 < C₁ ∧ 0 < c₂ ∧ 0 < δ ∧ ∀ z ∈ ball p δ, z ∈ U → + c₂ * |ρ z| ≤ infDist z Uᶜ ∧ infDist z Uᶜ ≤ C₁ * |ρ z| := by + obtain ⟨ν, hℓν, hν0⟩ := h.exists_inward_direction + obtain ⟨Lip, δ₀, hLip0, hδ₀, hball₀⟩ := h.exists_ball_fderiv_bound_and_inward hℓν + have hdiff : ∀ y ∈ V, DifferentiableAt ℝ ρ y := fun y hy => + (h.contDiffOn.contDiffAt (h.isOpen.mem_nhds hy)).differentiableAt (by norm_num) + have hρcont : ContinuousAt ρ p := (hdiff p h.mem).continuousAt + have hsmall : ∀ᶠ z in 𝓝 p, |ρ z| < min (Lip * δ₀ / 2) (δ₀ / (4 * ‖ν‖)) := by + have hcabs : ContinuousAt (fun z => |ρ z|) p := hρcont.abs + exact hcabs.eventually (eventually_lt_nhds (show |ρ p| < min (Lip * δ₀ / 2) (δ₀ / (4 * ‖ν‖)) by + rw [h.eq_zero, abs_zero]; exact lt_min (by positivity) (by positivity))) + obtain ⟨δ₁, hδ₁, hball₁⟩ := Metric.mem_nhds_iff.mp hsmall + refine ⟨2 * ‖ν‖, 1 / Lip, min (δ₀ / 2) δ₁, by positivity, by positivity, by positivity, ?_⟩ + intro z hz hzU + have hzδ₀ : z ∈ ball p (δ₀ / 2) := ball_subset_ball (min_le_left _ _) hz + have hρsmall : |ρ z| < min (Lip * δ₀ / 2) (δ₀ / (4 * ‖ν‖)) := + hball₁ (ball_subset_ball (min_le_right _ _) hz) + refine ⟨?_, ?_⟩ + · rw [div_mul_eq_mul_div, one_mul] + exact h.mul_abs_le_infDist hU hp hLip0 hδ₀ + (fun y hy => ⟨(hball₀ hy).1, (hball₀ hy).2.1⟩) hzδ₀ hzU (lt_min_iff.mp hρsmall).1 + · exact h.infDist_le_mul_abs hδ₀ hν0 hball₀ hzδ₀ hzU (lt_min_iff.mp hρsmall).2 + +/-- The complex quadratic coefficient of a real bilinear form along a complex line. -/ +@[expose] def leviQuadratic (B : E →L[ℝ] E →L[ℝ] ℝ) (w : E) : ℂ := + (((B w w - B (I • w) (I • w)) / 4 : ℝ) : ℂ) - I / 2 * (B w (I • w) : ℝ) + +/-- **Disc estimate along the Levi polynomial.** With `c` cancelling the complex quadratic +term and `ν` an inward direction, the defining function along the disc +`ζ ↦ p + ζ • w + ζ ^ 2 • c + (κ r ^ 2) • ν` is `-κ r ^ 2 + ‖ζ‖ ^ 2 L` up to `η r ^ 2`, for +`‖ζ‖ ≤ r` and `r` small, and the disc lies in any prescribed neighborhood of `p`. -/ +theorem IsLocalDefiningFunction.exists_disc_estimate (h : IsLocalDefiningFunction U p ρ V) + {w : E} (hw : IsComplexTangent ρ p w) {c ν : E} + (hc : complexPart (fderiv ℝ ρ p) c = -leviQuadratic (fderiv ℝ (fderiv ℝ ρ) p) w) + (hν : fderiv ℝ ρ p ν = -1) {κ η : ℝ} (hκ : 0 ≤ κ) (hη : 0 < η) {W : Set E} (hW : W ∈ 𝓝 p) : + ∃ r₀ > 0, ∀ r, 0 < r → r ≤ r₀ → ∀ ζ : ℂ, ‖ζ‖ ≤ r → + p + ζ • w + ζ ^ 2 • c + (κ * r ^ 2) • ν ∈ W ∧ + |ρ (p + ζ • w + ζ ^ 2 • c + (κ * r ^ 2) • ν) - (-(κ * r ^ 2) + ‖ζ‖ ^ 2 * leviForm ρ p w)| + ≤ η * r ^ 2 := by + set ℓ := fderiv ℝ ρ p with hℓ + set B := fderiv ℝ (fderiv ℝ ρ) p with hB + have hρp : ContDiffAt ℝ 2 ρ p := h.contDiffOn.contDiffAt (h.isOpen.mem_nhds h.mem) + -- symmetry of the second derivative + have hev : ∀ᶠ y in 𝓝 p, HasFDerivAt ρ (fderiv ℝ ρ y) y := by + filter_upwards [h.isOpen.mem_nhds h.mem] with y hy + exact ((h.contDiffOn.contDiffAt (h.isOpen.mem_nhds hy)).differentiableAt (by + norm_num)).hasFDerivAt + have hBd : HasFDerivAt (fderiv ℝ ρ) B p := + ((hρp.fderiv_right (m := 1) (by norm_num)).differentiableAt (by norm_num)).hasFDerivAt + have hsymm : ∀ v v', B v v' = B v' v := second_derivative_symmetric_of_eventually hev hBd + -- constants + set M₀ : ℝ := ‖w‖ + ‖c‖ + κ * ‖ν‖ with hM₀ + have hM₀0 : 0 ≤ M₀ := by positivity + set M₁ : ℝ := ‖B‖ * ‖w‖ * (‖c‖ + κ * ‖ν‖) + ‖B‖ * (‖c‖ + κ * ‖ν‖) ^ 2 / 2 with hM₁ + have hM₁0 : 0 ≤ M₁ := by positivity + obtain ⟨δ', hδ', htaylor⟩ := exists_taylor_bound hρp (ε := η / (2 * (M₀ ^ 2 + 1))) (by positivity) + obtain ⟨δW, hδW, hballW⟩ := Metric.mem_nhds_iff.mp hW + set δt := min δ' δW + have hδt : 0 < δt := lt_min hδ' hδW + refine ⟨min 1 (min (η / (2 * (M₁ + 1))) (δt / (2 * (M₀ + 1)))), by positivity, + fun r hr hr₀ ζ hζ => ?_⟩ + obtain ⟨hr1, hrM₁, hrδt⟩ := le_one_and_mul_add_le_of_le_min hM₀0 hM₁0 hr hr₀ + have hrδ' : r * (M₀ + 1) < δ' := hrδt.trans_le (min_le_left _ _) + have hrδW : r * (M₀ + 1) < δW := hrδt.trans_le (min_le_right _ _) + -- the increment and its pieces + set h₁ : E := ζ • w with hh₁ + set h₂ : E := ζ ^ 2 • c + (κ * r ^ 2) • ν with hh₂ + have hsplit : p + ζ • w + ζ ^ 2 • c + (κ * r ^ 2) • ν = p + (h₁ + h₂) := by + rw [hh₁, hh₂]; abel + have hζr2 : ‖ζ‖ ^ 2 ≤ r ^ 2 := by gcongr + have hn₁ : ‖h₁‖ ≤ r * ‖w‖ := by + rw [hh₁, norm_smul] + exact mul_le_mul_of_nonneg_right hζ (norm_nonneg _) + have hn₂ : ‖h₂‖ ≤ r ^ 2 * (‖c‖ + κ * ‖ν‖) := by + rw [hh₂] + calc ‖ζ ^ 2 • c + (κ * r ^ 2) • ν‖ ≤ ‖ζ ^ 2 • c‖ + ‖(κ * r ^ 2) • ν‖ := norm_add_le _ _ + _ = ‖ζ‖ ^ 2 * ‖c‖ + κ * r ^ 2 * ‖ν‖ := by + rw [norm_smul, norm_smul, norm_pow, Real.norm_eq_abs, abs_of_nonneg (by positivity)] + _ ≤ r ^ 2 * ‖c‖ + κ * r ^ 2 * ‖ν‖ := by gcongr + _ = r ^ 2 * (‖c‖ + κ * ‖ν‖) := by ring + have hn₂' : ‖h₂‖ ≤ r * (‖c‖ + κ * ‖ν‖) := by + refine hn₂.trans ?_ + have : r ^ 2 ≤ r := by nlinarith + exact mul_le_mul_of_nonneg_right this (by positivity) + have hn : ‖h₁ + h₂‖ ≤ r * M₀ := by + calc ‖h₁ + h₂‖ ≤ ‖h₁‖ + ‖h₂‖ := norm_add_le _ _ + _ ≤ r * ‖w‖ + r * (‖c‖ + κ * ‖ν‖) := add_le_add hn₁ hn₂' + _ = r * M₀ := by rw [hM₀]; ring + have hnlt : ‖h₁ + h₂‖ < δ' := hn.trans_lt (by nlinarith) + constructor + · rw [hsplit] + apply hballW + rw [mem_ball, dist_eq_norm, add_sub_cancel_left] + exact hn.trans_lt (by nlinarith) + -- the Taylor expansion + have ht := htaylor (h₁ + h₂) hnlt + -- linear term + have hℓw : complexPart ℓ w = 0 := by + have h1 : ℓ w = 0 := hw.1 + have h2 : ℓ (I • w) = 0 := hw.2 + simp [complexPart_apply, h1, h2] + have hlin : ℓ (h₁ + h₂) = (ζ ^ 2 * (-leviQuadratic B w)).re - κ * r ^ 2 := by + rw [hh₁, hh₂, map_add, map_add, apply_smul_eq_re_mul_complexPart ℓ ζ w, + apply_smul_eq_re_mul_complexPart ℓ (ζ ^ 2) c, hℓw, hc, map_smul, smul_eq_mul, hν] + simp + ring + -- quadratic term + have hquad : (1 / 2 : ℝ) * B (h₁ + h₂) (h₁ + h₂) = + (1 / 2 : ℝ) * B h₁ h₁ + B h₁ h₂ + (1 / 2 : ℝ) * B h₂ h₂ := by + simp only [map_add, add_apply, hsymm h₂ h₁] + ring + have hquad₁ : (1 / 2 : ℝ) * B h₁ h₁ = ‖ζ‖ ^ 2 * leviForm ρ p w + (ζ ^ 2 * leviQuadratic B w).re + := by + rw [hh₁, bilinear_smul_smul_eq B (hsymm w (I • w)) ζ, leviForm_eq_fderiv, leviQuadratic] + -- cancellation of the complex quadratic terms + have hcancel : (ζ ^ 2 * (-leviQuadratic B w)).re + (ζ ^ 2 * leviQuadratic B w).re = 0 := by + rw [mul_neg, Complex.neg_re]; ring + -- error bounds + have hBn : 0 ≤ ‖B‖ := ContinuousLinearMap.opNorm_nonneg B + have hB₁₂ : |B h₁ h₂| ≤ ‖B‖ * ‖w‖ * (‖c‖ + κ * ‖ν‖) * r ^ 3 := by + have := B.le_opNorm₂ h₁ h₂ + rw [Real.norm_eq_abs] at this + refine this.trans ?_ + calc ‖B‖ * ‖h₁‖ * ‖h₂‖ ≤ ‖B‖ * (r * ‖w‖) * (r ^ 2 * (‖c‖ + κ * ‖ν‖)) := + mul_le_mul (mul_le_mul_of_nonneg_left hn₁ hBn) hn₂ (norm_nonneg _) (by positivity) + _ = ‖B‖ * ‖w‖ * (‖c‖ + κ * ‖ν‖) * r ^ 3 := by ring + have hB₂₂ : |(1 / 2 : ℝ) * B h₂ h₂| ≤ ‖B‖ * (‖c‖ + κ * ‖ν‖) ^ 2 / 2 * r ^ 3 := by + rw [abs_mul, abs_of_pos (by norm_num : (0:ℝ) < 1 / 2)] + have := B.le_opNorm₂ h₂ h₂ + rw [Real.norm_eq_abs] at this + have h2 : ‖B‖ * ‖h₂‖ * ‖h₂‖ ≤ ‖B‖ * (r * (‖c‖ + κ * ‖ν‖)) * (r ^ 2 * (‖c‖ + κ * ‖ν‖)) := + mul_le_mul (mul_le_mul_of_nonneg_left hn₂' hBn) hn₂ (norm_nonneg _) (by positivity) + calc 1 / 2 * |B h₂ h₂| ≤ 1 / 2 * (‖B‖ * (r * (‖c‖ + κ * ‖ν‖)) * (r ^ 2 * (‖c‖ + κ * ‖ν‖))) := + mul_le_mul_of_nonneg_left (this.trans h2) (by norm_num) + _ = ‖B‖ * (‖c‖ + κ * ‖ν‖) ^ 2 / 2 * r ^ 3 := by ring + have hR : |ρ (p + (h₁ + h₂)) - ρ p - ℓ (h₁ + h₂) - (1 / 2 : ℝ) * B (h₁ + h₂) (h₁ + h₂)| + ≤ η / (2 * (M₀ ^ 2 + 1)) * (r * M₀) ^ 2 := + ht.trans (mul_le_mul_of_nonneg_left (pow_le_pow_left₀ (norm_nonneg _) hn 2) (by positivity)) + have hcub : |B h₁ h₂ + (1 / 2 : ℝ) * B h₂ h₂| ≤ M₁ * r ^ 3 := + (abs_add_le _ _).trans (by rw [hM₁, add_mul]; exact add_le_add hB₁₂ hB₂₂) + rw [hsplit] + have hkey : ρ (p + (h₁ + h₂)) - (-(κ * r ^ 2) + ‖ζ‖ ^ 2 * leviForm ρ p w) = + (ρ (p + (h₁ + h₂)) - ρ p - ℓ (h₁ + h₂) - (1 / 2 : ℝ) * B (h₁ + h₂) (h₁ + h₂)) + + (B h₁ h₂ + (1 / 2 : ℝ) * B h₂ h₂) := by + rw [h.eq_zero, hlin, hquad, hquad₁] + linarith [hcancel] + rw [hkey] + exact taylor_remainder_add_cubic_le hr hη hrM₁ hR hcub + +variable {n : ℕ} + +/-- The Levi polynomial disc of small radius lies in `U` when the Levi form is negative. -/ +theorem IsLocalDefiningFunction.disc_subset_of_estimate {U : Set (Fin n → ℂ)} + {p : Fin n → ℂ} {ρ : (Fin n → ℂ) → ℝ} {V : Set (Fin n → ℂ)} + (h : IsLocalDefiningFunction U p ρ V) {φ : ℂ → Fin n → ℂ} {r κ η L : ℝ} + (hr : 0 < r) (hκ : 0 < κ) (hL : L < 0) (hηκ : η ≤ κ / 2) + (hest : ∀ ζ, ‖ζ‖ ≤ r → φ ζ ∈ V ∧ + |ρ (φ ζ) - (-(κ * r ^ 2) + ‖ζ‖ ^ 2 * L)| ≤ η * r ^ 2) : + ∀ ζ ∈ closedBall (0 : ℂ) r, φ ζ ∈ U := by + intro ζ hζ + obtain ⟨hmem, hρ⟩ := hest ζ (mem_closedBall_zero_iff.mp hζ) + apply h.mem_of_neg hmem + have h1 := (abs_le.mp hρ).2 + have h2 : ‖ζ‖ ^ 2 * L ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hL.le + have h3 : η * r ^ 2 ≤ κ / 2 * r ^ 2 := mul_le_mul_of_nonneg_right hηκ (by positivity) + have h4 : 0 < κ / 2 * r ^ 2 := by positivity + linarith + +/-- **Levi's theorem in coordinates.** A domain of holomorphy in `Fin n → ℂ` is Levi +pseudoconvex: the Levi form of every local defining function is positive semidefinite on the +complex tangent space at every boundary point. The coordinate-free version is +`IsDomainOfHolomorphy.isLeviPseudoconvex`. -/ +theorem IsDomainOfHolomorphy.isLeviPseudoconvex_fin {U : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : IsLeviPseudoconvex U := by + intro p hp ρ V h w hw + by_contra hneg + push Not at hneg + set L := leviForm ρ p w + set ℓ := fderiv ℝ ρ p + set B := fderiv ℝ (fderiv ℝ ρ) p + obtain ⟨c, hc⟩ := exists_complexPart_eq h.fderiv_ne (-leviQuadratic B w) + obtain ⟨ν0, hν0, _⟩ := ContinuousLinearMap.exists_apply_eq_one_of_ne_zero h.fderiv_ne + set ν : Fin n → ℂ := -ν0 + have hℓν : ℓ ν = -1 := by rw [map_neg, hν0] + obtain ⟨C₁, c₂, δ, hC₁, hc₂, hδ, hdist⟩ := h.exists_infDist_bounds ho hp + set κ : ℝ := c₂ * (-L) / (8 * C₁) with hκ + have hκ0 : 0 < κ := by + rw [hκ] + have : 0 < -L := by linarith + positivity + set η : ℝ := min (κ / 2) (-L / 2) with hη + have hη0 : 0 < η := lt_min (by positivity) (by linarith) + have hηκ : η ≤ κ / 2 := min_le_left _ _ + have hηL : η ≤ -L / 2 := min_le_right _ _ + obtain ⟨r, hr, hest⟩ := h.exists_disc_estimate hw hc hℓν hκ0.le hη0 + (W := V ∩ ball p δ) (inter_mem (h.isOpen.mem_nhds h.mem) (ball_mem_nhds p hδ)) + set φ : ℂ → Fin n → ℂ := fun ζ => p + ζ • w + ζ ^ 2 • c + (κ * r ^ 2) • ν with hφ + have hφan : AnalyticOnNhd ℂ φ (closedBall 0 r) := fun ζ _ => + ((analyticAt_const.add (analyticAt_id.smul analyticAt_const)).add + ((analyticAt_id.pow 2).smul analyticAt_const)).add analyticAt_const + have hest' : ∀ ζ : ℂ, ‖ζ‖ ≤ r → φ ζ ∈ V ∩ ball p δ ∧ + |ρ (φ ζ) - (-(κ * r ^ 2) + ‖ζ‖ ^ 2 * L)| ≤ η * r ^ 2 := hest r hr le_rfl + have hdiscU : ∀ ζ ∈ closedBall (0 : ℂ) r, φ ζ ∈ U := + h.disc_subset_of_estimate hr hκ0 hneg hηκ fun ζ hζ => + ⟨(hest' ζ hζ).1.1, (hest' ζ hζ).2⟩ + -- the boundary circle is deep inside + set m : ℝ := c₂ * (-L) / 2 * r ^ 2 with hm + have hm0 : 0 < m := by + have : 0 < -L := by linarith + positivity + have hcircle : ∀ ζ ∈ sphere (0 : ℂ) r, m ≤ infDist (φ ζ) Uᶜ := by + intro ζ hζ + have hζ' : ‖ζ‖ = r := mem_sphere_zero_iff_norm.mp hζ + obtain ⟨hmem, hρ⟩ := hest' ζ hζ'.le + have hin := hdiscU ζ (sphere_subset_closedBall hζ) + have hlow := (hdist (φ ζ) hmem.2 hin).1 + have h1 := (abs_le.mp hρ).2 + rw [hζ'] at h1 + have hρneg : ρ (φ ζ) ≤ L / 2 * r ^ 2 := by + have h3 : η * r ^ 2 ≤ -L / 2 * r ^ 2 := mul_le_mul_of_nonneg_right hηL (by positivity) + have h4 : 0 ≤ κ * r ^ 2 := by positivity + linarith + have habs : -L / 2 * r ^ 2 ≤ |ρ (φ ζ)| := by + rw [abs_of_nonpos (by nlinarith [pow_pos hr 2])] + linarith + calc m = c₂ * (-L / 2 * r ^ 2) := by rw [hm]; ring + _ ≤ c₂ * |ρ (φ ζ)| := mul_le_mul_of_nonneg_left habs hc₂.le + _ ≤ infDist (φ ζ) Uᶜ := hlow + -- the center is shallow + have hcenter : infDist (φ 0) Uᶜ ≤ C₁ * (2 * κ * r ^ 2) := by + obtain ⟨hmem, hρ⟩ := hest' 0 (by simp [hr.le]) + have hin := hdiscU 0 (mem_closedBall_self hr.le) + have hup := (hdist (φ 0) hmem.2 hin).2 + have habs : |ρ (φ 0)| ≤ 2 * κ * r ^ 2 := by + have h0 : ‖(0 : ℂ)‖ ^ 2 * L = 0 := by simp + rw [h0, add_zero, sub_neg_eq_add] at hρ + have h3 : η * r ^ 2 ≤ κ / 2 * r ^ 2 := mul_le_mul_of_nonneg_right hηκ (by positivity) + have hκr : 0 ≤ κ * r ^ 2 := by positivity + have := abs_le.mp hρ + rw [abs_le] + constructor <;> linarith + exact hup.trans (mul_le_mul_of_nonneg_left habs hC₁.le) + -- Thullen's radius bound + have hhull := mem_holomorphicHull_of_analytic_disc hr hφan hdiscU (mem_closedBall_self hr.le) + have hK : IsCompact (φ '' sphere 0 r) := + (isCompact_sphere (0 : ℂ) r).image_of_continuousOn + (hφan.continuousOn.mono sphere_subset_closedBall) + have hKU : φ '' sphere 0 r ⊆ U := by + rintro _ ⟨ζ, hζ, rfl⟩ + exact hdiscU ζ (sphere_subset_closedBall hζ) + have hrad := hU.holomorphic_radius_bound ho hK hKU (q := fun _ => (m : ℂ)) analyticOnNhd_const + (fun z hz => by + obtain ⟨ζ, hζ, rfl⟩ := hz + have : ‖(m : ℂ)‖ = m := by rw [Complex.norm_real, Real.norm_eq_abs, abs_of_pos hm0] + rw [this] + exact (ball_subset_ball (hcircle ζ hζ)).trans + (by simpa using ball_infDist_subset_compl (x := φ ζ) (s := Uᶜ))) + (φ 0) hhull + have hm' : ‖(m : ℂ)‖ = m := by rw [Complex.norm_real, Real.norm_eq_abs, abs_of_pos hm0] + rw [hm'] at hrad + have hUc : Uᶜ.Nonempty := ⟨p, ho.notMem_of_mem_frontier hp⟩ + have hmle : m ≤ infDist (φ 0) Uᶜ := by + by_contra hlt + push Not at hlt + obtain ⟨y, hy, hdy⟩ := (infDist_lt_iff hUc).mp hlt + exact hy (hrad (by rwa [mem_ball, dist_comm])) + have hfinal : m ≤ C₁ * (2 * κ * r ^ 2) := hmle.trans hcenter + rw [hm, hκ] at hfinal + have hC₁' : C₁ * (2 * (c₂ * (-L) / (8 * C₁)) * r ^ 2) = c₂ * (-L) / 4 * r ^ 2 := by + field_simp + ring + rw [hC₁'] at hfinal + have : 0 < c₂ * (-L) / 4 * r ^ 2 := by + have : 0 < -L := by linarith + positivity + linarith + +section Transport + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- Levi pseudoconvexity pulls back along a continuous linear equivalence. -/ +theorem IsLeviPseudoconvex.of_image_equiv {U : Set E} (L : E ≃L[ℂ] F) + (h : IsLeviPseudoconvex (L '' U)) : IsLeviPseudoconvex U := by + intro p hp ρ V hρ + have hfr : L p ∈ frontier (L '' U) := by + have hfr' := L.toHomeomorph.image_frontier U + rw [ContinuousLinearEquiv.coe_toHomeomorph] at hfr' + rw [← hfr'] + exact mem_image_of_mem _ hp + have himg : L.symm ⁻¹' U = L '' U := by + ext z + constructor + · intro hz + exact ⟨L.symm z, hz, L.apply_symm_apply z⟩ + · rintro ⟨x, hx, rfl⟩ + simpa using hx + have hdef : IsLocalDefiningFunction (L '' U) (L p) (ρ ∘ L.symm) (univ ∩ L.symm ⁻¹' V) := by + rw [← himg] + exact hρ.comp_analytic isOpen_univ (mem_univ _) (L.symm.toContinuousLinearMap.analyticOnNhd _) + (L.symm_apply_apply p) (by rw [L.symm.fderiv]; exact L.symm.surjective) + have hcond := h (L p) hfr (ρ ∘ L.symm) _ hdef + exact (leviCondition_comp_iff hρ (L.symm.toContinuousLinearMap.analyticOnNhd univ _ (mem_univ _)) + (L.symm_apply_apply p) L.symm L.symm.hasFDerivAt).mp hcond + +/-- **Levi's theorem.** A domain of holomorphy in a finite-dimensional complex normed space is +Levi pseudoconvex: the Levi form of every local defining function is positive semidefinite on +the complex tangent space at every boundary point. -/ +theorem IsDomainOfHolomorphy.isLeviPseudoconvex [FiniteDimensional ℂ E] {U : Set E} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : IsLeviPseudoconvex U := by + let L := (Module.finBasis ℂ E).equivFunL + exact IsLeviPseudoconvex.of_image_equiv L + ((hU.image_equiv L).isLeviPseudoconvex_fin (L.isOpenMap U ho)) + +end Transport + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Peak.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Peak.lean new file mode 100644 index 0000000000..7a5f08c530 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviConvexity/Peak.lean @@ -0,0 +1,498 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.FDeriv.Bilinear +public import Mathlib.Analysis.Calculus.FDeriv.Pow +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Independence +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviConvexity.Necessity + +/-! +# Peak functions at strictly Levi convex boundary points + +A boundary point `p` of an open set `U` is strictly Levi pseudoconvex if the Levi form of a +local defining function is positive definite on the complex tangent space. Adding a multiple of +the square of the defining function makes the Levi form positive definite on the whole space at +`p`, by a compactness argument on the unit sphere. The Levi polynomial of the modified defining +function `\tilde ρ` is the holomorphic quadratic function `F(z) = ∂\tilde ρ(p)(z - p) + Q(z - +p)`, where `Q` is the complex quadratic part of the real Hessian; the second-order Taylor +expansion gives `Re F(z) = \tilde ρ(z) - Lev \tilde ρ(p, z - p) + o(‖z - p‖²)`, so `Re F < 0` on +the domain near `p`, except at `p` where `F` vanishes. The reciprocal `1 / F` is then +holomorphic on the domain near `p` and unbounded at `p`: a local holomorphic blow-up function. +Exponentiating `F` gives a normalized local peak function with value one at `p` and modulus less +than one elsewhere on the closed side. + +References: [Range][Range1986] (1986), Chapter II, Lemma 2.13, Proposition 2.16 and Theorem +2.15; [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 4. + +## Main definitions + +* `IsStrictlyLeviPseudoconvexAt`: The strict Levi condition at a boundary point: the Levi form of + every local defining function is positive definite on the complex tangent space. +* `leviBilinear`: The complex bilinear part of a real bilinear form on a complex space. + +## Main results + +* `exists_leviForm_add_normSq_ge`: **Positive definiteness after modification.** If the Levi form is + positive definite on the complex tangent space at `p`, then adding a large multiple of the squared + modulus of the complex-linear part of the derivative makes it positive definite on the whole + space. +* `IsLocalDefiningFunction.exists_holomorphic_support`: **Levi polynomial as a peak function + ([Range][Range1986], Proposition 2.16).** At a boundary point with positive definite Levi form on + the complex tangent space there is an entire holomorphic function `F` vanishing at `p` whose real + part is negative at all nearby points where the defining function is nonpositive, except at `p`. +* `IsLocalDefiningFunction.exists_peak`: **Normalized local peak function.** Exponentiating a + holomorphic supporting function has value one at the boundary point and modulus strictly less than + one at every other nearby point on the closed side of the defining function. +* `IsLocalDefiningFunction.exists_tendsto_norm_atTop`: **Local holomorphic blow-up.** At a strictly + Levi convex boundary point of an open set there is a holomorphic function on the set near the + point whose modulus tends to infinity at the point. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +section StrictDefinition + +/-- The strict Levi condition at a boundary point: the Levi form of every local defining function is +positive definite on the complex tangent space. -/ +@[expose] def IsStrictlyLeviPseudoconvexAt (U : Set E) (p : E) : Prop := + ∀ (ρ : E → ℝ) (V : Set E), IsLocalDefiningFunction U p ρ V → + ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w + +/-- The strict Levi condition can be checked on one defining function. -/ +theorem isStrictlyLeviPseudoconvexAt_iff_of_defining {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + (h : IsLocalDefiningFunction U p ρ V) : + IsStrictlyLeviPseudoconvexAt U p ↔ ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w := + by + constructor + · intro hL w hw hw0 + exact hL ρ V h w hw hw0 + · intro hL ρ' V' h' w hw hw0 + obtain ⟨c, hc, hlev⟩ := h'.exists_leviForm_eq h + have hw' : IsComplexTangent ρ p w := (h'.isComplexTangent_iff h w).mp hw + rw [hlev w hw'] + exact mul_pos hc (hL w hw' hw0) + +end StrictDefinition + +section Bilinear + +/-- The complex bilinear part of a real bilinear form on a complex space. -/ +def leviBilinear (B : E →L[ℝ] E →L[ℝ] ℝ) (q : E × E) : ℂ := + (((B q.1 q.2 - B (I • q.1) (I • q.2)) / 4 : ℝ) : ℂ) - + I / 4 * (((B q.1 (I • q.2) + B (I • q.1) q.2) : ℝ) : ℂ) + +/-- Multiplying the first argument by `I` multiplies the complex bilinear part by `I`. -/ +theorem leviBilinear_I_smul_left (B : E →L[ℝ] E →L[ℝ] ℝ) (k k' : E) : + leviBilinear B (I • k, k') = I * leviBilinear B (k, k') := by + simp only [leviBilinear, smul_smul, Complex.I_mul_I, neg_one_smul, map_neg, + neg_apply] + apply Complex.ext <;> simp <;> ring + +/-- Multiplying the second argument by `I` multiplies the complex bilinear part by `I`. -/ +theorem leviBilinear_I_smul_right (B : E →L[ℝ] E →L[ℝ] ℝ) (k k' : E) : + leviBilinear B (k, I • k') = I * leviBilinear B (k, k') := by + simp only [leviBilinear, smul_smul, Complex.I_mul_I, neg_one_smul, map_neg] + apply Complex.ext <;> simp <;> ring + +/-- The complex bilinear part is a bounded complex bilinear map. -/ +theorem isBoundedBilinearMap_leviBilinear (B : E →L[ℝ] E →L[ℝ] ℝ) : + IsBoundedBilinearMap ℂ (leviBilinear B) := by + have hre : ∀ (r : ℝ) (k k' : E), leviBilinear B (r • k, k') = (r : ℂ) * leviBilinear B (k, k') + := by + intro r k k' + have h1 : I • r • k = r • I • k := smul_comm I r k + simp only [leviBilinear, h1, map_smul] + apply Complex.ext <;> simp <;> ring + have hre' : ∀ (r : ℝ) (k k' : E), leviBilinear B (k, r • k') = (r : ℂ) * leviBilinear B (k, k') + := by + intro r k k' + have h1 : I • r • k' = r • I • k' := smul_comm I r k' + simp only [leviBilinear, h1, map_smul] + apply Complex.ext <;> simp <;> ring + refine ⟨fun k₁ k₂ k' => ?_, fun c k k' => ?_, fun k k₁' k₂' => ?_, fun c k k' => ?_, ?_⟩ + · simp only [leviBilinear, smul_add, map_add] + apply Complex.ext <;> simp <;> ring + · rw [Complex.smul_eq_re_smul_add_im_smul c k] + have h1 : leviBilinear B (c.re • k + c.im • I • k, k') = + leviBilinear B (c.re • k, k') + leviBilinear B (c.im • I • k, k') := by + simp only [leviBilinear, smul_add, map_add] + apply Complex.ext <;> simp <;> ring + rw [h1, hre, hre, leviBilinear_I_smul_left, smul_eq_mul] + conv_rhs => rw [← Complex.re_add_im c] + ring + · simp only [leviBilinear, smul_add, map_add] + apply Complex.ext <;> simp <;> ring + · rw [Complex.smul_eq_re_smul_add_im_smul c k'] + have h1 : leviBilinear B (k, c.re • k' + c.im • I • k') = + leviBilinear B (k, c.re • k') + leviBilinear B (k, c.im • I • k') := by + simp only [leviBilinear, smul_add, map_add] + apply Complex.ext <;> simp <;> ring + rw [h1, hre', hre', leviBilinear_I_smul_right, smul_eq_mul] + conv_rhs => rw [← Complex.re_add_im c] + ring + · refine ⟨‖B‖ + 1, by positivity, fun k k' => ?_⟩ + have hB : ∀ x y : E, |B x y| ≤ ‖B‖ * ‖x‖ * ‖y‖ := fun x y => by + have := B.le_opNorm₂ x y + rwa [Real.norm_eq_abs] at this + have hI : ∀ x : E, ‖I • x‖ = ‖x‖ := fun x => by rw [norm_smul, Complex.norm_I, one_mul] + have h1 : |B k k' - B (I • k) (I • k')| ≤ 2 * (‖B‖ * ‖k‖ * ‖k'‖) := by + calc |B k k' - B (I • k) (I • k')| ≤ |B k k'| + |B (I • k) (I • k')| := abs_sub _ _ + _ ≤ ‖B‖ * ‖k‖ * ‖k'‖ + ‖B‖ * ‖I • k‖ * ‖I • k'‖ := add_le_add (hB _ _) (hB _ _) + _ = 2 * (‖B‖ * ‖k‖ * ‖k'‖) := by rw [hI, hI]; ring + have h2 : |B k (I • k') + B (I • k) k'| ≤ 2 * (‖B‖ * ‖k‖ * ‖k'‖) := by + calc |B k (I • k') + B (I • k) k'| ≤ |B k (I • k')| + |B (I • k) k'| := abs_add_le _ _ + _ ≤ ‖B‖ * ‖k‖ * ‖I • k'‖ + ‖B‖ * ‖I • k‖ * ‖k'‖ := add_le_add (hB _ _) (hB _ _) + _ = 2 * (‖B‖ * ‖k‖ * ‖k'‖) := by rw [hI, hI]; ring + have hnn : 0 ≤ ‖B‖ * ‖k‖ * ‖k'‖ := by positivity + calc ‖leviBilinear B (k, k')‖ + ≤ ‖(((B k k' - B (I • k) (I • k')) / 4 : ℝ) : ℂ)‖ + + ‖I / 4 * (((B k (I • k') + B (I • k) k') : ℝ) : ℂ)‖ := norm_sub_le _ _ + _ = |B k k' - B (I • k) (I • k')| / 4 + |B k (I • k') + B (I • k) k'| / 4 := by + rw [Complex.norm_real, Real.norm_eq_abs, abs_div, abs_of_pos (by norm_num : (0:ℝ) < 4), + norm_mul, norm_div, Complex.norm_I, Complex.norm_real, Real.norm_eq_abs] + norm_num + ring + _ ≤ 2 * (‖B‖ * ‖k‖ * ‖k'‖) / 4 + 2 * (‖B‖ * ‖k‖ * ‖k'‖) / 4 := by gcongr + _ = ‖B‖ * ‖k‖ * ‖k'‖ := by ring + _ ≤ (‖B‖ + 1) * ‖k‖ * ‖k'‖ := by gcongr; linarith + +/-- On the diagonal, the complex bilinear part of a symmetric form is the complex quadratic +coefficient of `LeviConvexity.Necessity`. -/ +theorem leviBilinear_self (B : E →L[ℝ] E →L[ℝ] ℝ) {k : E} (hsymm : B k (I • k) = B (I • k) k) : + leviBilinear B (k, k) = leviQuadratic B k := by + simp only [leviBilinear, leviQuadratic, hsymm] + apply Complex.ext + · simp + · simp + ring + +end Bilinear + +section Modification + +variable {ρ : E → ℝ} {p : E} + +/-- The Levi form of `ρ + A ρ ^ 2` at a zero of `ρ` adds `A / 2` times the squared modulus of the +complex-linear part of the derivative. -/ +theorem leviForm_add_mul_sq (hρ : ContDiffAt ℝ 2 ρ p) (hρ0 : ρ p = 0) (A : ℝ) (w : E) : + leviForm (fun z => ρ z + A * ρ z ^ 2) p w = + leviForm ρ p w + A / 2 * ‖complexPart (fderiv ℝ ρ p) w‖ ^ 2 := by + have hev : ∀ᶠ y in 𝓝 p, HasFDerivAt ρ (fderiv ℝ ρ y) y := by + filter_upwards [hρ.eventually (by simp)] with y hy + exact (hy.differentiableAt (by norm_num)).hasFDerivAt + have hD2 : HasFDerivAt (fderiv ℝ ρ) (fderiv ℝ (fderiv ℝ ρ) p) p := + ((hρ.fderiv_right (m := 1) (by norm_num)).differentiableAt (by norm_num)).hasFDerivAt + -- first derivative of the modified function + have hD1 : (fun y => fderiv ℝ (fun z => ρ z + A * ρ z ^ 2) y) =ᶠ[𝓝 p] + fun y => fderiv ℝ ρ y + (A * (2 * ρ y)) • fderiv ℝ ρ y := by + filter_upwards [hev] with y hy + have h := hy.add ((hy.pow 2).const_mul A) + refine h.fderiv.trans ?_ + ext v + simp + ring + -- second derivative at `p` + have hℓ : HasFDerivAt ρ (fderiv ℝ ρ p) p := (hρ.differentiableAt (by norm_num)).hasFDerivAt + have hc : HasFDerivAt (fun y => A * (2 * ρ y)) ((A * 2) • fderiv ℝ ρ p) p := by + have h := (hℓ.const_mul (2 : ℝ)).const_mul A + convert h using 1 + ext v + simp + ring + have hsm := hc.smul hD2 + have hsum : HasFDerivAt (fun y => fderiv ℝ ρ y + (A * (2 * ρ y)) • fderiv ℝ ρ y) _ p := + hD2.add hsm + rw [leviForm_eq_fderiv, leviForm_eq_fderiv, hD1.fderiv_eq, hsum.fderiv] + have hn : ‖complexPart (fderiv ℝ ρ p) w‖ ^ 2 = + fderiv ℝ ρ p w ^ 2 + fderiv ℝ ρ p (I • w) ^ 2 := by + rw [Complex.sq_norm, Complex.normSq_apply] + simp [complexPart_apply] + ring + rw [hn] + simp [hρ0, add_apply, smul_apply, smul_eq_mul] + ring + +end Modification + +section Compactness + +variable {ρ : E → ℝ} {p : E} + +/-- The Levi form is homogeneous of degree two under real scaling. -/ +theorem leviForm_smul_real (f : E → ℝ) (p : E) (t : ℝ) (w : E) : + leviForm f p (t • w) = t ^ 2 * leviForm f p w := by + have h1 : I • t • w = t • I • w := smul_comm I t w + simp only [leviForm_eq_fderiv, h1, map_smul, smul_apply, smul_eq_mul] + ring + +/-- The Levi form is continuous in the direction. -/ +theorem continuous_leviForm (f : E → ℝ) (p : E) : Continuous fun w => leviForm f p w := by + simp only [leviForm_eq_fderiv] + have hB := (fderiv ℝ (fderiv ℝ f) p).isBoundedBilinearMap.continuous + fun_prop + +/-- Real scaling of the complex-linear part. -/ +theorem complexPart_real_smul (ℓ : E →L[ℝ] ℝ) (r : ℝ) (w : E) : + complexPart ℓ (r • w) = (r : ℂ) * complexPart ℓ w := by + rw [← Complex.coe_smul, map_smul, smul_eq_mul] + +/-- A vector is complex tangent exactly when the complex-linear part of the derivative vanishes on +it. -/ +theorem isComplexTangent_iff_complexPart_eq_zero (w : E) : + IsComplexTangent ρ p w ↔ complexPart (fderiv ℝ ρ p) w = 0 := by + simp only [IsComplexTangent, complexPart_apply, Complex.ext_iff] + simp + +/-- **Positive definiteness after modification.** If the Levi form is positive definite on +the complex tangent space at `p`, then adding a large multiple of the squared modulus of the +complex-linear part of the derivative makes it positive definite on the whole space. -/ +theorem exists_leviForm_add_normSq_ge [FiniteDimensional ℂ E] + (hstrict : ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w) : + ∃ A : ℝ, 0 ≤ A ∧ ∃ c : ℝ, 0 < c ∧ ∀ w, + c * ‖w‖ ^ 2 ≤ leviForm ρ p w + A / 2 * ‖complexPart (fderiv ℝ ρ p) w‖ ^ 2 := by + set ℓ := fderiv ℝ ρ p with hℓ + by_contra hcon + push Not at hcon + -- a sequence of bad unit vectors + have hbad : ∀ n : ℕ, ∃ u : E, ‖u‖ = 1 ∧ + leviForm ρ p u + (n : ℝ) / 2 * ‖complexPart ℓ u‖ ^ 2 < 1 / ((n : ℝ) + 1) := by + intro n + obtain ⟨w, hw⟩ := hcon n (Nat.cast_nonneg n) (1 / ((n : ℝ) + 1)) (by positivity) + have hw0 : w ≠ 0 := by + rintro rfl + have h0 : leviForm ρ p 0 = 0 := by simp [leviForm_eq_fderiv] + have h1 : complexPart ℓ 0 = 0 := by simp [complexPart_apply] + rw [h0, h1] at hw + simp at hw + have hn0 : 0 < ‖w‖ := norm_pos_iff.mpr hw0 + refine ⟨‖w‖⁻¹ • w, by rw [norm_smul, norm_inv, norm_norm, inv_mul_cancel₀ hn0.ne'], ?_⟩ + rw [leviForm_smul_real, complexPart_real_smul, norm_mul, Complex.norm_real, norm_inv, norm_norm, + mul_pow] + have h2 : 0 < ‖w‖ ^ 2 := by positivity + have hinv : (‖w‖⁻¹) ^ 2 = (‖w‖ ^ 2)⁻¹ := by rw [inv_pow] + rw [hinv] + rw [← sub_pos] at hw ⊢ + have : (‖w‖ ^ 2)⁻¹ * (1 / ((n : ℝ) + 1) * ‖w‖ ^ 2 - + (leviForm ρ p w + (n : ℝ) / 2 * ‖complexPart ℓ w‖ ^ 2)) > 0 := by positivity + convert this using 1 + field_simp + choose u hu using hbad + have huS : ∀ n, u n ∈ sphere (0 : E) 1 := fun n => by simpa using (hu n).1 + -- bound on the Levi form over the unit sphere + obtain ⟨M, hM⟩ := (isCompact_sphere (0 : E) 1).exists_bound_of_continuousOn + (continuous_leviForm ρ p).continuousOn + have hM' : ∀ n, -M ≤ leviForm ρ p (u n) := fun n => by + have := hM _ (huS n) + rw [Real.norm_eq_abs] at this + linarith [neg_abs_le (leviForm ρ p (u n))] + -- the complex parts tend to zero + have hpart : ∀ n : ℕ, (n : ℝ) / 2 * ‖complexPart ℓ (u n)‖ ^ 2 ≤ M + 1 := fun n => by + have h1 := (hu n).2 + have h2 : (1 : ℝ) / ((n : ℝ) + 1) ≤ 1 := by + rw [div_le_one (by positivity)]; linarith [(Nat.cast_nonneg n : (0:ℝ) ≤ n)] + linarith [hM' n] + -- a convergent subsequence + obtain ⟨v, hvS, φ, hφ, hlim⟩ := (isCompact_sphere (0 : E) 1).tendsto_subseq huS + have hv0 : v ≠ 0 := by + rintro rfl + simp at hvS + -- the limit is complex tangent + have hcp : Tendsto (fun n => ‖complexPart ℓ (u (φ n))‖ ^ 2) atTop (𝓝 (‖complexPart ℓ v‖ ^ 2)) := + (((complexPart ℓ).continuous.norm.pow 2).continuousAt.tendsto.comp hlim) + have hφtop : Tendsto (fun n => (φ n : ℝ)) atTop atTop := + tendsto_natCast_atTop_atTop.comp hφ.tendsto_atTop + have hcp0 : ‖complexPart ℓ v‖ ^ 2 = 0 := by + apply le_antisymm _ (by positivity) + have hg : Tendsto (fun n => 2 * (M + 1) / (φ n : ℝ)) atTop (𝓝 0) := + (tendsto_const_div_atTop_nhds_zero_nat (2 * (M + 1))).comp hφ.tendsto_atTop + refine le_of_tendsto_of_tendsto hcp hg ?_ + filter_upwards [hφtop.eventually (eventually_gt_atTop (0 : ℝ))] with n hn + have h := hpart (φ n) + rw [le_div_iff₀ hn] + linarith + have hv_tan : IsComplexTangent ρ p v := by + rw [isComplexTangent_iff_complexPart_eq_zero] + have : ‖complexPart ℓ v‖ = 0 := pow_eq_zero_iff (two_ne_zero) |>.mp hcp0 + exact norm_eq_zero.mp this + -- the limit has nonpositive Levi form + have hlev : leviForm ρ p v ≤ 0 := by + have hl : Tendsto (fun n => leviForm ρ p (u (φ n))) atTop (𝓝 (leviForm ρ p v)) := + (continuous_leviForm ρ p).continuousAt.tendsto.comp hlim + have hg : Tendsto (fun n => 1 / ((φ n : ℝ) + 1)) atTop (𝓝 0) := + tendsto_one_div_add_atTop_nhds_zero_nat.comp hφ.tendsto_atTop + refine le_of_tendsto_of_tendsto hl hg (Filter.Eventually.of_forall fun n => ?_) + have := (hu (φ n)).2 + have hnn : 0 ≤ ((φ n : ℕ) : ℝ) / 2 * ‖complexPart ℓ (u (φ n))‖ ^ 2 := by positivity + linarith + exact absurd (hstrict v hv_tan hv0) (not_lt.mpr hlev) + +end Compactness + +section PeakFunction + +variable [FiniteDimensional ℂ E] {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + +/-- **Levi polynomial as a peak function ([Range][Range1986], Proposition 2.16).** At a boundary +point with +positive definite Levi form on the complex tangent space there is an entire holomorphic function +`F` vanishing at `p` whose real part is negative at all nearby points where the defining +function is nonpositive, except at `p`. -/ +theorem IsLocalDefiningFunction.exists_holomorphic_support (h : IsLocalDefiningFunction U p ρ V) + (hstrict : ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w) : + ∃ W ∈ 𝓝 p, ∃ F : E → ℂ, AnalyticOnNhd ℂ F univ ∧ F p = 0 ∧ + ∀ z ∈ W, z ≠ p → ρ z ≤ 0 → (F z).re < 0 := by + set ℓ := fderiv ℝ ρ p with hℓ + have hρc : ContDiffAt ℝ 2 ρ p := h.contDiffOn.contDiffAt (h.isOpen.mem_nhds h.mem) + obtain ⟨A, hA, c, hc, hpos⟩ := exists_leviForm_add_normSq_ge hstrict + -- the modified defining function + set σ : E → ℝ := fun z => ρ z + A * ρ z ^ 2 with hσ + have hσc : ContDiffAt ℝ 2 σ p := hρc.add (contDiffAt_const.mul (hρc.pow 2)) + have hσ0 : σ p = 0 := by simp [hσ, h.eq_zero] + have hσlev : ∀ w, c * ‖w‖ ^ 2 ≤ leviForm σ p w := fun w => by + rw [hσ, leviForm_add_mul_sq hρc h.eq_zero] + exact hpos w + have hd : HasFDerivAt ρ ℓ p := (hρc.differentiableAt (by norm_num)).hasFDerivAt + have hσℓ : fderiv ℝ σ p = ℓ := by + have := hd.add ((hd.pow 2).const_mul A) + refine this.fderiv.trans ?_ + ext v + simp [h.eq_zero] + set B := fderiv ℝ (fderiv ℝ σ) p with hB + have hev : ∀ᶠ y in 𝓝 p, HasFDerivAt σ (fderiv ℝ σ y) y := by + filter_upwards [hσc.eventually (by simp)] with y hy + exact (hy.differentiableAt (by norm_num)).hasFDerivAt + have hBd : HasFDerivAt (fderiv ℝ σ) B p := + ((hσc.fderiv_right (m := 1) (by norm_num)).differentiableAt (by norm_num)).hasFDerivAt + have hsymm : ∀ v v', B v v' = B v' v := second_derivative_symmetric_of_eventually hev hBd + -- the Levi polynomial + set F : E → ℂ := fun z => complexPart ℓ (z - p) + leviBilinear B (z - p, z - p) with hF + have hFd : Differentiable ℂ F := by + have h1 : Differentiable ℂ (complexPart ℓ) := fun x => + (complexPart ℓ).differentiableAt + have h2 : Differentiable ℂ (leviBilinear B) := fun q => + (isBoundedBilinearMap_leviBilinear B).differentiableAt q + have hsub : Differentiable ℂ (fun z : E => z - p) := differentiable_id.sub_const p + exact (h1.comp hsub).add (h2.comp (hsub.prodMk hsub)) + have hFan : AnalyticOnNhd ℂ F univ := hFd.analyticOnNhd_of_finiteDimensional + have hF0 : F p = 0 := by simp [hF, leviBilinear] + -- Taylor expansion of the modified defining function + obtain ⟨δ, hδ, htaylor⟩ := exists_taylor_bound hσc (ε := c / 2) (by positivity) + have hsmall : ∀ᶠ z in 𝓝 p, |ρ z| < 1 / (A + 1) := by + have hcont : ContinuousAt (fun z => |ρ z|) p := hρc.continuousAt.abs + exact hcont.eventually (eventually_lt_nhds (by + change |ρ p| < 1 / (A + 1) + rw [h.eq_zero, abs_zero] + positivity)) + refine ⟨ball p δ ∩ {z | |ρ z| < 1 / (A + 1)}, inter_mem (ball_mem_nhds p hδ) hsmall, F, hFan, + hF0, ?_⟩ + rintro z ⟨hzδ, hzρ⟩ hzp hρz + have hzρ' : |ρ z| < 1 / (A + 1) := hzρ + set k := z - p with hk + have hk0 : k ≠ 0 := sub_ne_zero.mpr hzp + have hkδ : ‖k‖ < δ := by rw [hk, ← dist_eq_norm]; exact mem_ball.mp hzδ + have ht := htaylor k hkδ + have hpk : p + k = z := by rw [hk]; abel + rw [hpk, hσ0, sub_zero, hσℓ] at ht + -- the real part of the Levi polynomial + have hlin : ℓ k = (complexPart ℓ k).re := by + have := apply_smul_eq_re_mul_complexPart ℓ 1 k + simpa using this + have hquad : (1 / 2 : ℝ) * B k k = leviForm σ p k + (leviQuadratic B k).re := by + have := bilinear_smul_smul_eq B (hsymm k (I • k)) 1 + simpa [leviForm_eq_fderiv, leviQuadratic] using this + have hFre : (F z).re = ℓ k + (leviQuadratic B k).re := by + simp only [hF, Complex.add_re] + rw [← hk, hlin, leviBilinear_self B (hsymm k (I • k))] + -- the modified function is nonpositive at `z` + have hσz : σ z ≤ 0 := by + have h1 : 0 < 1 + A * ρ z := by + have hlow := (abs_lt.mp hzρ').1 + have : A * (1 / (A + 1)) < 1 := by + rw [mul_one_div, div_lt_one (by positivity)] + linarith + nlinarith + have : σ z = (1 + A * ρ z) * ρ z := by simp only [hσ]; ring + rw [this] + exact mul_nonpos_of_nonneg_of_nonpos h1.le hρz + have hknorm : 0 < c / 2 * ‖k‖ ^ 2 := by positivity + have h1 := (abs_le.mp ht).1 + rw [hFre] + linarith [hσlev k] + +/-- **Normalized local peak function.** Exponentiating a holomorphic supporting function +has value one at the boundary point and modulus strictly less than one at every other nearby +point on the closed side of the defining function. -/ +theorem IsLocalDefiningFunction.exists_peak + (h : IsLocalDefiningFunction U p ρ V) + (hstrict : ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w) : + ∃ W ∈ 𝓝 p, ∃ f : E → ℂ, AnalyticOnNhd ℂ f univ ∧ f p = 1 ∧ + ∀ z ∈ W, z ≠ p → ρ z ≤ 0 → ‖f z‖ < 1 := by + obtain ⟨W, hW, F, hF, hFp, hneg⟩ := h.exists_holomorphic_support hstrict + refine ⟨W, hW, fun z => Complex.exp (F z), ?_, by simp [hFp], ?_⟩ + · exact fun z hz => (hF z hz).cexp + · intro z hz hzp hρ + rw [Complex.norm_exp, Real.exp_lt_one_iff] + exact hneg z hz hzp hρ + +/-- On the domain near a strictly Levi convex boundary point, the Levi polynomial has negative real +part. -/ +theorem IsLocalDefiningFunction.exists_holomorphic_support_of_mem (hU : IsOpen U) (hp : p ∈ + frontier U) + (h : IsLocalDefiningFunction U p ρ V) + (hstrict : ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w) : + ∃ W ∈ 𝓝 p, ∃ F : E → ℂ, AnalyticOnNhd ℂ F univ ∧ F p = 0 ∧ ∀ z ∈ W ∩ U, (F z).re < 0 := by + obtain ⟨W, hW, F, hFan, hF0, hneg⟩ := h.exists_holomorphic_support hstrict + refine ⟨W ∩ V, inter_mem hW (h.isOpen.mem_nhds h.mem), F, hFan, hF0, ?_⟩ + rintro z ⟨⟨hzW, hzV⟩, hzU⟩ + have hzp : z ≠ p := fun hzp => hU.notMem_of_mem_frontier hp (hzp ▸ hzU) + exact hneg z hzW hzp (h.neg_of_mem hzV hzU).le + +/-- **Local holomorphic blow-up.** At a strictly Levi convex boundary point of an open set there is +a +holomorphic function on the set near the point whose modulus tends to infinity at the point. -/ +theorem IsLocalDefiningFunction.exists_tendsto_norm_atTop (hU : IsOpen U) (hp : p ∈ frontier U) + (h : IsLocalDefiningFunction U p ρ V) + (hstrict : ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w) : + ∃ W ∈ 𝓝 p, ∃ f : E → ℂ, AnalyticOnNhd ℂ f (W ∩ U) ∧ + Tendsto (fun z => ‖f z‖) (𝓝[U] p) atTop := by + obtain ⟨W, hW, F, hFan, hF0, hneg⟩ := h.exists_holomorphic_support_of_mem hU hp hstrict + have hFne : ∀ z ∈ W ∩ U, F z ≠ 0 := fun z hz hzero => by + have := hneg z hz + rw [hzero, Complex.zero_re] at this + exact lt_irrefl _ this + refine ⟨W, hW, fun z => (F z)⁻¹, fun z hz => (hFan z (mem_univ z)).inv (hFne z hz), ?_⟩ + have hF : Tendsto (fun z => ‖F z‖) (𝓝[U] p) (𝓝[>] 0) := by + rw [tendsto_nhdsWithin_iff] + constructor + · have := ((hFan p (mem_univ p)).continuousAt.norm).tendsto + rw [hF0, norm_zero] at this + exact this.mono_left nhdsWithin_le_nhds + · filter_upwards [nhdsWithin_le_nhds hW, self_mem_nhdsWithin] with z hzW hzU + exact norm_pos_iff.mpr (hFne z ⟨hzW, hzU⟩) + have := tendsto_inv_nhdsGT_zero.comp hF + simpa [Function.comp_def, norm_inv] using this + +end PeakFunction + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviForm.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviForm.lean new file mode 100644 index 0000000000..5e148bfeb6 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviForm.lean @@ -0,0 +1,149 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Plurisubharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.SmoothCriterion + +/-! +# The Levi form + +The Levi form of a real `C²` function on a complex normed space, at a point `a` in a direction +`w`, is defined here in coordinate-free form as one quarter of the sum of the real Hessian +evaluated on `(w, w)` and on `(I • w, I • w)`. On `ℂⁿ` this is the classical Hermitian form `∑ +∂²f/∂z_ν∂\bar z_μ w_ν \bar w_μ`; the definition avoids Wirtinger derivatives. + +The Levi form in direction `w` is one quarter of the Laplacian of the slice `t ↦ f (a + t • w)` +at `t = 0`. Together with the Laplacian criterion for subharmonicity this gives the `C²` +criterion: a `C²` function on an open set is plurisubharmonic exactly when its Levi form is +positive semidefinite at every point. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 2 ("The Levi +Form", Theorem 2.8); [Hörmander][Hormander1973] (1973), Theorem 2.6.2; [Range][Range1986] +(1986), Chapter II, Section 2.6. + +## Main definitions + +* `leviForm`: The Levi form of a real function at `a` in direction `w`: one quarter of the sum of + the real Hessian evaluated on `(w, w)` and on `(I • w, I • w)`. + +## Main results + +* `PlurisubharmonicOn.leviForm_nonneg`: **Necessity.** The Levi form of a `C²` plurisubharmonic + function is positive semidefinite. +* `plurisubharmonicOn_of_leviForm_nonneg`: **Sufficiency.** A `C²` function on an open set with + positive semidefinite Levi form is plurisubharmonic. +* `plurisubharmonicOn_iff_leviForm_nonneg`: **The `C²` criterion for plurisubharmonicity.** A `C²` + function on an open set is plurisubharmonic exactly when its Levi form is positive semidefinite + everywhere. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology Laplacian + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- The Levi form of a real function at `a` in direction `w`: one quarter of the sum of the real +Hessian evaluated on `(w, w)` and on `(I • w, I • w)`. -/ +@[expose] def leviForm (f : E → ℝ) (a w : E) : ℝ := + (iteratedFDeriv ℝ 2 f a ![w, w] + iteratedFDeriv ℝ 2 f a ![I • w, I • w]) / 4 + +/-- The Levi form in terms of the second Fréchet derivative. -/ +theorem leviForm_eq_fderiv (f : E → ℝ) (a w : E) : + leviForm f a w = (fderiv ℝ (fderiv ℝ f) a w w + fderiv ℝ (fderiv ℝ f) a (I • w) (I • w)) / 4 + := by + simp [leviForm, iteratedFDeriv_two_apply] + +variable {f : E → ℝ} {U : Set E} + +/-- The second derivative of a complex-line slice of a `C²` function is the second derivative of the +function evaluated on the direction vectors. -/ +theorem fderiv_fderiv_slice {a w : E} {t₀ : ℂ} (hf : ContDiffAt ℝ 2 f (a + t₀ • w)) (s s' : ℂ) : + fderiv ℝ (fderiv ℝ (fun t : ℂ => f (a + t • w))) t₀ s s' = + fderiv ℝ (fderiv ℝ f) (a + t₀ • w) (s • w) (s' • w) := by + set φ : ℂ → E := fun t => a + ((ContinuousLinearMap.id ℝ ℂ).smulRight w) t with hφdef + have hφ : ∀ t, HasFDerivAt φ ((ContinuousLinearMap.id ℝ ℂ).smulRight w) t := fun t => + ((ContinuousLinearMap.id ℝ ℂ).smulRight w).hasFDerivAt.const_add a + have hφc : Continuous φ := ((ContinuousLinearMap.id ℝ ℂ).smulRight w).continuous.const_add a + have hev : ∀ᶠ t in 𝓝 t₀, ContDiffAt ℝ 2 f (φ t) := + hφc.continuousAt.eventually (hf.eventually (by simp)) + have hg : (fun t => fderiv ℝ (f ∘ φ) t) =ᶠ[𝓝 t₀] + fun t => (fderiv ℝ f (φ t)).comp ((ContinuousLinearMap.id ℝ ℂ).smulRight w) := by + filter_upwards [hev] with t ht + exact ((ht.differentiableAt (by norm_num)).hasFDerivAt.comp t (hφ t)).fderiv + have hD2 : HasFDerivAt (fderiv ℝ f) (fderiv ℝ (fderiv ℝ f) (φ t₀)) (φ t₀) := + ((hf.fderiv_right (m := 1) (by norm_num)).differentiableAt (by norm_num)).hasFDerivAt + have hcomp : HasFDerivAt (fun t => fderiv ℝ f (φ t)) + ((fderiv ℝ (fderiv ℝ f) (φ t₀)).comp ((ContinuousLinearMap.id ℝ ℂ).smulRight w)) t₀ + := hD2.comp t₀ (hφ t₀) + have hfin := hcomp.clm_comp (hasFDerivAt_const ((ContinuousLinearMap.id ℝ ℂ).smulRight w) t₀) + have hgφ : (fun t : ℂ => f (a + t • w)) = f ∘ φ := rfl + rw [hgφ, hg.fderiv_eq, hfin.fderiv] + simp [ContinuousLinearMap.compL_apply] + rfl + +/-- The first derivative of a complex-line slice of a differentiable function. -/ +theorem fderiv_slice {a w : E} {t₀ : ℂ} (hf : DifferentiableAt ℝ f (a + t₀ • w)) : + fderiv ℝ (fun t : ℂ => f (a + t • w)) t₀ = (fderiv ℝ f (a + t₀ • w)).comp + ((ContinuousLinearMap.id ℝ ℂ).smulRight w) := by + have hφ : HasFDerivAt (fun t : ℂ => a + ((ContinuousLinearMap.id ℝ ℂ).smulRight w) t) + ((ContinuousLinearMap.id ℝ ℂ).smulRight w) t₀ := + ((ContinuousLinearMap.id ℝ ℂ).smulRight w).hasFDerivAt.const_add a + exact (hf.hasFDerivAt.comp t₀ hφ).fderiv + +/-- The Laplacian of a complex-line slice is four times the Levi form in that direction. -/ +theorem laplacian_slice {a w : E} {t₀ : ℂ} (hf : ContDiffAt ℝ 2 f (a + t₀ • w)) : + Δ (fun t : ℂ => f (a + t • w)) t₀ = 4 * leviForm f (a + t₀ • w) w := by + rw [laplacian_eq_fderiv_fderiv, fderiv_fderiv_slice hf, fderiv_fderiv_slice hf, + leviForm_eq_fderiv, one_smul] + ring + +/-- **Necessity.** The Levi form of a `C²` plurisubharmonic function is positive semidefinite. -/ +theorem PlurisubharmonicOn.leviForm_nonneg (hU : IsOpen U) (hf : ContDiffOn ℝ 2 f U) + (hpsh : PlurisubharmonicOn f U) {a : E} (ha : a ∈ U) (w : E) : 0 ≤ leviForm f a w := by + have ha' : a + (0 : ℂ) • w ∈ U := by simpa using ha + have hc : ContDiffAt ℝ 2 (fun t : ℂ => f (a + t • w)) 0 := + (hf.contDiffAt (hU.mem_nhds ha')).comp 0 + (by fun_prop : ContDiff ℝ 2 fun t : ℂ => a + t • w).contDiffAt + have := (hpsh.hasSubmeanAt_slice ha w).laplacian_nonneg hc + rw [laplacian_slice (hf.contDiffAt (hU.mem_nhds ha'))] at this + simp only [zero_smul, add_zero] at this + linarith + +/-- **Sufficiency.** A `C²` function on an open set with positive semidefinite Levi form is +plurisubharmonic. -/ +theorem plurisubharmonicOn_of_leviForm_nonneg (hU : IsOpen U) (hf : ContDiffOn ℝ 2 f U) + (h : ∀ a ∈ U, ∀ w : E, 0 ≤ leviForm f a w) : PlurisubharmonicOn f U := by + refine ⟨hf.continuousOn.upperSemicontinuousOn, fun a ha w => ?_⟩ + apply subharmonicOn_of_laplacian_nonneg + (hU.preimage (by fun_prop : Continuous fun t : ℂ => a + t • w)) + · exact hf.comp (by fun_prop : ContDiff ℝ 2 fun t : ℂ => a + t • w).contDiffOn fun _ ht => ht + · intro t ht + rw [laplacian_slice (hf.contDiffAt (hU.mem_nhds ht))] + exact mul_nonneg (by norm_num) (h _ ht w) + +/-- **The `C²` criterion for plurisubharmonicity.** A `C²` function on an open set is +plurisubharmonic exactly when its Levi form is positive semidefinite everywhere. -/ +theorem plurisubharmonicOn_iff_leviForm_nonneg (hU : IsOpen U) (hf : ContDiffOn ℝ 2 f U) : + PlurisubharmonicOn f U ↔ ∀ a ∈ U, ∀ w : E, 0 ≤ leviForm f a w := + ⟨fun hpsh _ ha w => hpsh.leviForm_nonneg hU hf ha w, + fun h => plurisubharmonicOn_of_leviForm_nonneg hU hf h⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviForm/Holomorphic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviForm/Holomorphic.lean new file mode 100644 index 0000000000..393f5b2cca --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LeviForm/Holomorphic.lean @@ -0,0 +1,123 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.ContDiff.Operations +public import Mathlib.Analysis.Calculus.ContDiff.RestrictScalars +public import Mathlib.Analysis.Calculus.FDeriv.RestrictScalars +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LeviForm + +/-! +# The Levi form under holomorphic maps + +The Levi form transforms under a holomorphic map `Φ` by the chain rule `Lev (g ∘ Φ) (a, w) = Lev +g (Φ a, Φ'(a) w)`: the second derivative of `Φ` contributes `Dg (D²Φ (w, w) + D²Φ (I • w, I • +w))`, which vanishes because the second derivative of a holomorphic map is complex bilinear. +Consequently `C²` plurisubharmonic functions compose with holomorphic maps to `C²` +plurisubharmonic functions. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 2, Example 4 +after the definition of the Levi form; [Hörmander][Hormander1973] (1973), Theorem 2.6.4 (smooth +case). + +## Main results + +* `leviForm_comp_analytic`: **Chain rule for the Levi form.** For a `C²` function `g` and a + holomorphic map `Φ`, `Lev (g ∘ Φ) (a, w) = Lev g (Φ a, Φ'(a) w)`. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- The real second derivative of a holomorphic map is complex bilinear: it changes sign when both +arguments are multiplied by `I`. -/ +theorem fderiv_fderiv_smul_I_smul_I {Φ : E → F} {a : E} (hΦ : AnalyticAt ℂ Φ a) (s t : E) : + fderiv ℝ (fderiv ℝ Φ) a (I • s) (I • t) = -fderiv ℝ (fderiv ℝ Φ) a s t := by + have hc : ContDiffAt ℂ 2 Φ a := hΦ.contDiffAt + have hr := hc.restrictScalars_iteratedFDeriv (𝕜 := ℝ) (n := 2) + have h1 : fderiv ℝ (fderiv ℝ Φ) a (I • s) (I • t) = iteratedFDeriv ℝ 2 Φ a ![I • s, I • t] := by + rw [iteratedFDeriv_two_apply]; rfl + have h2 : fderiv ℝ (fderiv ℝ Φ) a s t = iteratedFDeriv ℝ 2 Φ a ![s, t] := by + rw [iteratedFDeriv_two_apply]; rfl + have hv : (![I • s, I • t] : Fin 2 → E) = fun i => I • (![s, t] : Fin 2 → E) i := by + funext i; fin_cases i <;> rfl + rw [h1, h2, ← hr, hv] + change (iteratedFDeriv ℂ 2 Φ a) (fun i => I • (![s, t] : Fin 2 → E) i) = + -(iteratedFDeriv ℂ 2 Φ a) ![s, t] + rw [ContinuousMultilinearMap.map_smul_univ] + simp + +/-- **Chain rule for the Levi form.** For a `C²` function `g` and a holomorphic map `Φ`, +`Lev (g ∘ Φ) (a, w) = Lev g (Φ a, Φ'(a) w)`. -/ +theorem leviForm_comp_analytic {g : F → ℝ} {Φ : E → F} {a : E} (hg : ContDiffAt ℝ 2 g (Φ a)) + (hΦ : AnalyticAt ℂ Φ a) (w : E) : + leviForm (g ∘ Φ) a w = leviForm g (Φ a) (fderiv ℂ Φ a w) := by + have hΦc : ContDiffAt ℝ 2 Φ a := (hΦ.contDiffAt (n := 2)).restrict_scalars ℝ + -- first derivatives near `a` + have hΦev : ∀ᶠ x in 𝓝 a, HasFDerivAt Φ (fderiv ℝ Φ x) x := by + filter_upwards [hΦc.eventually (by simp)] with x hx + exact (hx.differentiableAt (by norm_num)).hasFDerivAt + have hgev : ∀ᶠ x in 𝓝 a, HasFDerivAt g (fderiv ℝ g (Φ x)) (Φ x) := by + have hcont : ContinuousAt Φ a := hΦc.continuousAt + filter_upwards [hcont.eventually (hg.eventually (by simp))] with x hx + exact (hx.differentiableAt (by norm_num)).hasFDerivAt + have hD1 : (fun x => fderiv ℝ (g ∘ Φ) x) =ᶠ[𝓝 a] + fun x => (fderiv ℝ g (Φ x)).comp (fderiv ℝ Φ x) := by + filter_upwards [hΦev, hgev] with x hx1 hx2 + exact (hx2.comp x hx1).fderiv + -- second derivatives + have hD2Φ : HasFDerivAt (fderiv ℝ Φ) (fderiv ℝ (fderiv ℝ Φ) a) a := + ((hΦc.fderiv_right (m := 1) (by norm_num)).differentiableAt (by norm_num)).hasFDerivAt + have hD2g : HasFDerivAt (fderiv ℝ g) (fderiv ℝ (fderiv ℝ g) (Φ a)) (Φ a) := + ((hg.fderiv_right (m := 1) (by norm_num)).differentiableAt (by norm_num)).hasFDerivAt + have hΦa : HasFDerivAt Φ (fderiv ℝ Φ a) a := hΦc.differentiableAt (by norm_num) |>.hasFDerivAt + have hcomp : HasFDerivAt (fun x => fderiv ℝ g (Φ x)) + ((fderiv ℝ (fderiv ℝ g) (Φ a)).comp (fderiv ℝ Φ a)) a := hD2g.comp a hΦa + have hfin := hcomp.clm_comp hD2Φ + have hD2 : ∀ s t : E, fderiv ℝ (fderiv ℝ (g ∘ Φ)) a s t = + fderiv ℝ g (Φ a) (fderiv ℝ (fderiv ℝ Φ) a s t) + + fderiv ℝ (fderiv ℝ g) (Φ a) (fderiv ℝ Φ a s) (fderiv ℝ Φ a t) := by + intro s t + rw [hD1.fderiv_eq, hfin.fderiv] + simp [ContinuousLinearMap.compL_apply] + -- complex linearity of the first derivative + have hlin : fderiv ℝ Φ a (I • w) = I • fderiv ℂ Φ a w := by + rw [hΦ.differentiableAt.fderiv_restrictScalars (𝕜 := ℝ), + ContinuousLinearMap.coe_restrictScalars', + map_smul] + have hlin' : fderiv ℝ Φ a w = fderiv ℂ Φ a w := by + rw [hΦ.differentiableAt.fderiv_restrictScalars (𝕜 := ℝ), + ContinuousLinearMap.coe_restrictScalars'] + rw [leviForm_eq_fderiv, leviForm_eq_fderiv, hD2, hD2, fderiv_fderiv_smul_I_smul_I hΦ, map_neg, + hlin, hlin'] + ring + +/-- `C²` plurisubharmonic functions compose with holomorphic maps. -/ +theorem PlurisubharmonicOn.comp_analyticOnNhd {g : F → ℝ} {V : Set F} (hV : IsOpen V) + (hgc : ContDiffOn ℝ 2 g V) (hg : PlurisubharmonicOn g V) {Φ : E → F} {U : Set E} + (hU : IsOpen U) (hΦ : AnalyticOnNhd ℂ Φ U) (hmaps : MapsTo Φ U V) : + PlurisubharmonicOn (g ∘ Φ) U := by + have hΦc : ContDiffOn ℝ 2 Φ U := (hΦ.contDiffOn hU.uniqueDiffOn (n := 2)).restrict_scalars ℝ + refine plurisubharmonicOn_of_leviForm_nonneg hU (hgc.comp hΦc hmaps) fun a ha w => ?_ + rw [leviForm_comp_analytic (hgc.contDiffAt (hV.mem_nhds (hmaps ha))) (hΦ a ha)] + exact hg.leviForm_nonneg hV hgc (hmaps ha) _ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LocallyBounded.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LocallyBounded.lean new file mode 100644 index 0000000000..fc84a25e3e --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LocallyBounded.lean @@ -0,0 +1,161 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.MeanValue +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyEstimates + +/-! +# Locally bounded separate holomorphy + +Coordinate Cauchy estimates give joint local Lipschitz bounds for locally bounded, separately +holomorphic functions. This supplies the continuity hypothesis of Osgood's theorem and the +equicontinuity estimate used in Montel's theorem. + +## Main results + +`exists_lipschitzOnWith_of_separately_analytic_locally_bounded` converts a local bound on a +separately holomorphic map into a joint local Lipschitz bound, hence into joint continuity. +`analyticOnNhd_of_separately_analytic_locally_bounded` is the corresponding analyticity +statement, using Osgood after that continuity. +-/ + +public section + +open Complex Filter Function Metric Set +open scoped NNReal Topology + +namespace SeveralComplexVariables + +variable {ι F : Type*} [Fintype ι] [DecidableEq ι] [NormedAddCommGroup F] [NormedSpace ℂ F] + +omit [NormedSpace ℂ F] in +/-- Coordinate variation bounds telescope to a joint bound on a product set. This also includes the +empty product, where every function is constant. -/ +theorem norm_sub_le_sum_of_update {s : ι → Set ℂ} {f : (ι → ℂ) → F} {C : ℝ} + (hf : ∀ z ∈ Set.pi univ s, ∀ i, ∀ w ∈ s i, + ‖f (update z i w) - f z‖ ≤ C * ‖w - z i‖) + {x y : ι → ℂ} (hx : x ∈ Set.pi univ s) (hy : y ∈ Set.pi univ s) : + ‖f y - f x‖ ≤ ∑ i, C * ‖y i - x i‖ := by + have hmem (t : Finset ι) : (fun i => if i ∈ t then y i else x i) ∈ Set.pi univ s := by + intro i hi + dsimp only + split_ifs <;> [exact hy i hi; exact hx i hi] + have hstep (t : Finset ι) : + ‖f (fun i => if i ∈ t then y i else x i) - f x‖ ≤ ∑ i ∈ t, C * ‖y i - x i‖ := by + induction t using Finset.induction_on with + | empty => simp + | @insert i t hi ih => + have heq : (fun j => if j ∈ insert i t then y j else x j) = + update (fun j => if j ∈ t then y j else x j) i (y i) := by + funext j + by_cases hji : j = i <;> simp [hji] + rw [heq, Finset.sum_insert hi] + refine (norm_sub_le_norm_sub_add_norm_sub _ (f (fun j => if j ∈ t then y j else x j)) _).trans + (add_le_add ?_ ih) + simpa [hi] using hf _ (hmem t) i (y i) (hy i (mem_univ i)) + simpa using hstep Finset.univ + +/-- Updating a coordinate within its disc preserves a closed sup-norm ball. -/ +theorem update_mem_closedBall_of_mem {c z : ι → ℂ} {r : ℝ} (hr : 0 ≤ r) + (hz : z ∈ closedBall c r) (i : ι) {w : ℂ} (hw : w ∈ closedBall (c i) r) : + update z i w ∈ closedBall c r := by + rw [mem_closedBall, dist_pi_le_iff hr] at hz ⊢ + intro j + by_cases hji : j = i + · simpa [hji] using hw + · simpa [hji] using hz j + +/-- A bounded separately holomorphic map is jointly Lipschitz on a smaller polydisc. The constant is +explicit and uniform over families with the same bound. -/ +theorem norm_sub_le_of_separately_analytic_bounded {f : (ι → ℂ) → F} + {c : ι → ℂ} {r M : ℝ} (hr : 0 < r) + (hf : ∀ z ∈ closedBall c (2 * r), ∀ i, + AnalyticAt ℂ (fun w => f (update z i w)) (z i)) + (hM : ∀ z ∈ closedBall c (2 * r), ‖f z‖ ≤ M) + {x y : ι → ℂ} (hx : x ∈ closedBall c r) (hy : y ∈ closedBall c r) : + ‖f y - f x‖ ≤ (Fintype.card ι : ℝ) * (M / r) * ‖y - x‖ := by + have hM0 : 0 ≤ M := (norm_nonneg (f c)).trans (hM c (mem_closedBall_self (by positivity))) + have hsmall : closedBall c r ⊆ closedBall c (2 * r) := closedBall_subset_closedBall (by linarith) + have hdiff (z : ι → ℂ) (i : ι) (w : ℂ) (hw : update z i w ∈ closedBall c (2 * r)) : + DifferentiableAt ℂ (fun v => f (update z i v)) w := by + simpa only [update_idem, update_self] using (hf _ hw i).differentiableAt + have hcoord (z : ι → ℂ) (hz : z ∈ closedBall c r) (i : ι) (w : ℂ) + (hw : w ∈ closedBall (c i) r) : + ‖f (update z i w) - f z‖ ≤ (M / r) * ‖w - z i‖ := by + have hder (v : ℂ) (hv : v ∈ closedBall (c i) r) : + ‖deriv (fun a => f (update z i a)) v‖ ≤ M / r := by + have hp := update_mem_closedBall_of_mem hr.le hz i hv + have hball : closedBall (update z i v) r ⊆ closedBall c (2 * r) := + closedBall_subset_closedBall' (by linarith [mem_closedBall.mp hp]) + have hslice := norm_partialDeriv_le_of_slice (f := f) (z := update z i v) i hr + (fun a ha => (hdiff (update z i v) i a + (hball (update_mem_closedBall hr.le ha))).differentiableWithinAt) + (fun a ha => hM _ (hball (update_mem_closedBall hr.le (sphere_subset_closedBall ha)))) + simpa only [partialDeriv, update_idem, update_self] using hslice + have hzi : z i ∈ closedBall (c i) r := (dist_pi_le_iff hr.le).mp (mem_closedBall.mp hz) i + simpa only [update_eq_self] using + (convex_closedBall (c i) r).norm_image_sub_le_of_norm_deriv_le + (fun v hv => hdiff z i v (hsmall (update_mem_closedBall_of_mem hr.le hz i hv))) + hder hzi hw + have hprod : closedBall c r = Set.pi univ (fun i => closedBall (c i) r) := closedBall_pi c hr.le + have hsum := norm_sub_le_sum_of_update (C := M / r) + (fun z hz i w hw => hcoord z (hprod.symm ▸ hz) i w hw) (hprod ▸ hx) (hprod ▸ hy) + refine hsum.trans ?_ + calc + ∑ i, (M / r) * ‖y i - x i‖ ≤ ∑ i : ι, (M / r) * ‖y - x‖ := + Finset.sum_le_sum (fun i _ => mul_le_mul_of_nonneg_left (norm_le_pi_norm (y - x) i) + (div_nonneg hM0 hr.le)) + _ = _ := by simp [mul_assoc] + +/-- Local bounds and separate holomorphy give a Lipschitz neighborhood of each point. -/ +theorem exists_lipschitzOnWith_of_separately_analytic_locally_bounded + {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} (hU : IsOpen U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) + {c : ι → ℂ} (hc : c ∈ U) (hb : ∃ M : ℝ, ∀ᶠ z in 𝓝 c, ‖f z‖ ≤ M) : + ∃ r > 0, ∃ C : ℝ≥0, LipschitzOnWith C f (closedBall c r) := by + obtain ⟨M, hM⟩ := hb + obtain ⟨R, hR, hball⟩ := nhds_basis_closedBall.mem_iff.mp (inter_mem (hU.mem_nhds hc) hM) + have hM0 : 0 ≤ M := (norm_nonneg (f c)).trans + (hball (mem_closedBall_self hR.le)).2 + have hr : 0 < R / 2 := by positivity + have htwo : 2 * (R / 2) = R := by ring + have hfa : ∀ z ∈ closedBall c (2 * (R / 2)), ∀ i, + AnalyticAt ℂ (fun w => f (update z i w)) (z i) := by + intro z hz + exact hf z (hball (by simpa only [htwo] using hz)).1 + have hbound : ∀ z ∈ closedBall c (2 * (R / 2)), ‖f z‖ ≤ M := by + intro z hz + exact (hball (by simpa only [htwo] using hz)).2 + refine ⟨R / 2, hr, ⟨(Fintype.card ι : ℝ) * (M / (R / 2)), by positivity⟩, ?_⟩ + apply lipschitzOnWith_iff_norm_sub_le.mpr + intro x hx y hy + exact norm_sub_le_of_separately_analytic_bounded hr hfa hbound hy hx + +variable [CompleteSpace F] + +/-- **Locally bounded Osgood theorem.** Joint continuity need not be assumed when a +separately holomorphic map is locally bounded on its open domain. + +This is weaker than Hartogs' theorem `analyticOnNhd_of_separately_analytic`, which drops the +local boundedness hypothesis. It is a step in the proof of that theorem, applied after Baire's +theorem provides local bounds, and therefore cannot be derived from it. -/ +theorem analyticOnNhd_of_separately_analytic_locally_bounded + {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} (hU : IsOpen U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) + (hb : ∀ c ∈ U, ∃ M : ℝ, ∀ᶠ z in 𝓝 c, ‖f z‖ ≤ M) : AnalyticOnNhd ℂ f U := by + apply analyticOnNhd_pi_of_analyticOnNhd_update hU _ hf + apply continuousOn_of_forall_continuousAt + intro c hc + obtain ⟨r, hr, C, hC⟩ := exists_lipschitzOnWith_of_separately_analytic_locally_bounded + hU hf hc (hb c hc) + exact hC.continuousOn.continuousAt (closedBall_mem_nhds _ hr) + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LocallyUniform.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LocallyUniform.lean new file mode 100644 index 0000000000..7c651c3dae --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/LocallyUniform.lean @@ -0,0 +1,288 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.LocallyUniformLimit +public import Mathlib.Analysis.Normed.Group.FunctionSeries +public import Mathlib.Topology.Algebra.InfiniteSum.TsumUniformlyOn +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyEstimates +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives + +/-! +# Locally uniform limits of analytic maps in several variables + +This file proves the Weierstrass convergence theorem for finite-dimensional complex domains, its +normally summable series consequences, and locally uniform convergence of all mixed coordinate +and iterated Fréchet derivatives. The topological notion `TendstoLocallyUniformlyOn` is +Mathlib's. + +This is a temporary project home for material ultimately intended for a Mathlib location such as +`Mathlib.Analysis.Complex.SeveralVariables.LocallyUniform`. + +## Main results + +* `TendstoLocallyUniformlyOn.analyticOnNhd_pi` is the several-variable Weierstrass convergence + theorem for finite complex coordinate spaces. +* `HasSumLocallyUniformlyOn.analyticOnNhd_pi` is its series form. +* `TendstoLocallyUniformlyOn.partialDeriv` and + `TendstoLocallyUniformlyOn.iteratedPartialDeriv` give convergence of coordinate derivatives. +* `HasSumLocallyUniformlyOn.iteratedPartialDeriv` gives termwise differentiation of series. +* `TendstoLocallyUniformlyOn.analyticOnNhd_of_finiteDimensional` and + `TendstoLocallyUniformlyOn.iteratedFDeriv_of_finiteDimensional` are the coordinate-independent + formulations, with multilinear operator norm for the latter. + +Derivative convergence uses a one-variable Cauchy estimate on compact thickenings, followed by +finite sums, currying, and transport along a continuous linear choice of coordinates. +-/ + +public section + +open Filter Set + +variable {ι κ F : Type*} [Fintype ι] [DecidableEq ι] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +omit [DecidableEq ι] in +/-- **Weierstrass convergence theorem, finite-coordinate form.** A locally uniform limit of +analytic maps on an open subset of a finite complex coordinate space is analytic. -/ +theorem TendstoLocallyUniformlyOn.analyticOnNhd_pi + {U : Set (ι → ℂ)} {l : Filter κ} [l.NeBot] + {f : κ → (ι → ℂ) → F} {g : (ι → ℂ) → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) : + AnalyticOnNhd ℂ g U := by + classical + classical + have hg : ContinuousOn g U := + hlim.continuousOn (hf.frequently.mono fun _ hn => hn.continuousOn) + apply SeveralComplexVariables.analyticOnNhd_pi_of_analyticOnNhd_update hU hg + intro z hz i + let update : ℂ → (ι → ℂ) := fun w ↦ Function.update z i w + let V : Set ℂ := update ⁻¹' U + have hupdate : Continuous update := by + dsimp only [update] + fun_prop + have hupdate_diff : Differentiable ℂ update := + fun w => (hasDerivAt_update z i w).differentiableAt + have hV : IsOpen V := hU.preimage hupdate + have hmap : Set.MapsTo update V U := fun _ hw ↦ hw + have hlim' : TendstoLocallyUniformlyOn + (fun n ↦ f n ∘ update) (g ∘ update) l V := + hlim.comp update hmap hupdate.continuousOn + have hfdiff : ∀ᶠ n in l, DifferentiableOn ℂ (f n ∘ update) V := by + filter_upwards [hf] with n hn + intro w hw + exact (((hn.differentiableOn _ hw).differentiableAt + (hU.mem_nhds (hmap hw))).comp w hupdate_diff.differentiableAt).differentiableWithinAt + exact (hlim'.differentiableOn hfdiff hV).analyticAt + (hV.mem_nhds (show update (z i) ∈ U by simpa [update] using hz)) + +omit [DecidableEq ι] in +/-- A locally uniformly convergent sum of analytic maps on an open finite complex coordinate space +is analytic. -/ +theorem HasSumLocallyUniformlyOn.analyticOnNhd_pi + {U : Set (ι → ℂ)} {f : κ → (ι → ℂ) → F} {g : (ι → ℂ) → F} + (hsum : HasSumLocallyUniformlyOn f g U) + (hf : ∀ n, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) : + AnalyticOnNhd ℂ g U := by + classical + apply TendstoLocallyUniformlyOn.analyticOnNhd_pi hsum _ hU + filter_upwards with s + exact Finset.analyticOnNhd_fun_sum s fun n _ ↦ hf n + +omit [DecidableEq ι] in +/-- A series of analytic maps is analytic when its terms admit a summable uniform majorant on every +compact subset of the domain. -/ +theorem analyticOnNhd_tsum_of_summable_norm_on_compacts + {U : Set (ι → ℂ)} {f : κ → (ι → ℂ) → F} + (hU : IsOpen U) (hf : ∀ n, AnalyticOnNhd ℂ (f n) U) + (hmajorant : ∀ K ⊆ U, IsCompact K → ∃ M : κ → ℝ, + Summable M ∧ ∀ n x, x ∈ K → ‖f n x‖ ≤ M n) : + AnalyticOnNhd ℂ (fun x ↦ ∑' n, f n x) U := by + classical + have hs : SummableLocallyUniformlyOn f U := + SummableLocallyUniformlyOn_of_locally_bounded hU hmajorant + exact hs.hasSumLocallyUniformlyOn.analyticOnNhd_pi hf hU + +/-- Locally uniform convergence of holomorphic maps implies locally uniform convergence of each +coordinate derivative. The Cauchy estimate is applied on a compact thickening. -/ +theorem TendstoLocallyUniformlyOn.partialDeriv + {U : Set (ι → ℂ)} {l : Filter κ} [l.NeBot] + {f : κ → (ι → ℂ) → F} {g : (ι → ℂ) → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) (i : ι) : + TendstoLocallyUniformlyOn (fun n => SeveralComplexVariables.partialDeriv i (f n)) + (SeveralComplexVariables.partialDeriv i g) l U := by + have hg := hlim.analyticOnNhd_pi hf hU + rw [tendstoLocallyUniformlyOn_iff_forall_isCompact hU] + intro K hKU hK + obtain ⟨δ, hδ, hKδ⟩ := hK.exists_cthickening_subset_open hU hKU + have hc := (tendstoLocallyUniformlyOn_iff_forall_isCompact hU).mp hlim + (Metric.cthickening δ K) hKδ hK.cthickening + rw [Metric.tendstoUniformlyOn_iff] at hc ⊢ + intro ε hε + filter_upwards [hf, hc (ε * δ / 2) (by positivity)] with n hn hbound z hz + have hball : Metric.closedBall z δ ⊆ Metric.cthickening δ K := + Metric.closedBall_subset_cthickening hz δ + have hnorm := SeveralComplexVariables.norm_partialDeriv_le (hg.sub hn) i hδ + (hball.trans hKδ) (M := ε * δ / 2) (fun w hw => by + exact le_of_lt (by simpa [dist_eq_norm] using hbound w (hball hw))) + rw [SeveralComplexVariables.partialDeriv_sub (hg z (hKU hz)).differentiableAt + (hn z (hKU hz)).differentiableAt i] at hnorm + rw [dist_eq_norm] + exact hnorm.trans_lt ((div_lt_iff₀ hδ).mpr (by nlinarith [mul_pos hε hδ])) + +/-- All mixed coordinate derivatives converge locally uniformly on the original domain. -/ +theorem TendstoLocallyUniformlyOn.iteratedPartialDeriv + {U : Set (ι → ℂ)} {l : Filter κ} [l.NeBot] + {f : κ → (ι → ℂ) → F} {g : (ι → ℂ) → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) (is : List ι) : + TendstoLocallyUniformlyOn (fun n => SeveralComplexVariables.iteratedPartialDeriv is (f n)) + (SeveralComplexVariables.iteratedPartialDeriv is g) l U := by + induction is with + | nil => exact hlim + | cons i is ih => + exact ih.partialDeriv (hf.mono fun n hn => hn.iteratedPartialDeriv hU is) hU i + +omit [DecidableEq ι] in +/-- Locally uniform convergence of holomorphic maps gives locally uniform convergence of their +Fréchet derivatives in operator norm. -/ +theorem TendstoLocallyUniformlyOn.fderiv_pi + {U : Set (ι → ℂ)} {l : Filter κ} [l.NeBot] + {f : κ → (ι → ℂ) → F} {g : (ι → ℂ) → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) : + TendstoLocallyUniformlyOn (fun n => fderiv ℂ (f n)) (fderiv ℂ g) l U := by + classical + classical + let L (i : ι) : F →L[ℂ] ((ι → ℂ) →L[ℂ] F) := + ContinuousLinearMap.smulRightL ℂ (ι → ℂ) F (ContinuousLinearMap.proj i) + have hi (i : ι) := (L i).uniformContinuous.comp_tendstoLocallyUniformlyOn + (hlim.partialDeriv hf hU i) + have hs (s : Finset ι) : TendstoLocallyUniformlyOn + (fun n z => ∑ i ∈ s, L i (SeveralComplexVariables.partialDeriv i (f n) z)) + (fun z => ∑ i ∈ s, L i (SeveralComplexVariables.partialDeriv i g z)) l U := by + induction s using Finset.induction_on with + | empty => + simpa using (tendsto_const_nhds.tendstoUniformlyOn_const U).tendstoLocallyUniformlyOn + | @insert i s his ih => + simpa only [Finset.sum_insert his, Function.comp_def] using (hi i).fun_add ih + have heq {a : (ι → ℂ) → F} {z : ι → ℂ} (ha : DifferentiableAt ℂ a z) : + (∑ i, L i (SeveralComplexVariables.partialDeriv i a z)) = fderiv ℂ a z := by + ext v + simpa [L] using (SeveralComplexVariables.fderiv_eq_sum_partialDeriv ha v).symm + have h := (hs Finset.univ).congr_inseparable (hf.mono fun n hn z hz => + Inseparable.of_eq (heq (hn z hz).differentiableAt)) + exact h.congr_right fun z hz => heq ((hlim.analyticOnNhd_pi hf hU) z hz).differentiableAt + +omit [DecidableEq ι] in +/-- All iterated Fréchet derivatives converge locally uniformly in multilinear operator norm. -/ +theorem TendstoLocallyUniformlyOn.iteratedFDeriv_pi + {U : Set (ι → ℂ)} {l : Filter κ} [l.NeBot] + {f : κ → (ι → ℂ) → F} {g : (ι → ℂ) → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) (k : ℕ) : + TendstoLocallyUniformlyOn (fun n => iteratedFDeriv ℂ k (f n)) + (iteratedFDeriv ℂ k g) l U := by + classical + induction k with + | zero => + simpa only [iteratedFDeriv_zero_eq_comp] using + (continuousMultilinearCurryFin0 ℂ (ι → ℂ) + F).symm.isometry.uniformContinuous.comp_tendstoLocallyUniformlyOn hlim + | succ k ih => + have hd := ih.fderiv_pi (hf.mono fun n hn => hn.iteratedFDeriv_of_isOpen hU k) hU + simpa only [iteratedFDeriv_succ_eq_comp_left] using + (continuousMultilinearCurryLeftEquiv ℂ (fun _ : Fin (k + 1) => ι → ℂ) + F).symm.isometry.uniformContinuous.comp_tendstoLocallyUniformlyOn hd + +/-- A locally uniformly convergent holomorphic series may be differentiated term by term any finite +number of times, with locally uniform convergence of the differentiated series. -/ +theorem HasSumLocallyUniformlyOn.iteratedPartialDeriv + {U : Set (ι → ℂ)} {f : κ → (ι → ℂ) → F} {g : (ι → ℂ) → F} + (hsum : HasSumLocallyUniformlyOn f g U) + (hf : ∀ n, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) (is : List ι) : + HasSumLocallyUniformlyOn (fun n => SeveralComplexVariables.iteratedPartialDeriv is (f n)) + (SeveralComplexVariables.iteratedPartialDeriv is g) U := by + have h := TendstoLocallyUniformlyOn.iteratedPartialDeriv hsum + (Eventually.of_forall fun t => Finset.analyticOnNhd_fun_sum t fun n _ => hf n) hU is + exact h.congr_inseparable (Eventually.of_forall fun t z hz => Inseparable.of_eq + (SeveralComplexVariables.iteratedPartialDeriv_finset_sum t (fun n _ => hf n) hU is hz)) + +section FiniteDimensional + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + +/-- The Weierstrass convergence theorem on any finite-dimensional complex normed domain. -/ +theorem TendstoLocallyUniformlyOn.analyticOnNhd_of_finiteDimensional + {U : Set E} {l : Filter κ} [l.NeBot] {f : κ → E → F} {g : E → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) : + AnalyticOnNhd ℂ g U := by + let e := (Module.finBasis ℂ E).equivFunL + have hc := hlim.comp e.symm (fun _ hx => hx) e.symm.continuous.continuousOn + have ha := hc.analyticOnNhd_pi (hf.mono fun n hn => + hn.comp (e.symm.toContinuousLinearMap.analyticOnNhd _) (fun _ hx => hx)) + (hU.preimage e.symm.continuous) + intro x hx + have hmem : e x ∈ e.symm ⁻¹' U := by simpa using hx + simpa [Function.comp_def] using + (ha (e x) hmem).comp_of_eq (e.toContinuousLinearMap.analyticAt x) rfl + +/-- Locally uniform convergence of the Fréchet derivatives, without a choice of coordinates in the +statement. The target carries the operator norm. -/ +theorem TendstoLocallyUniformlyOn.fderiv_of_finiteDimensional + {U : Set E} {l : Filter κ} [l.NeBot] {f : κ → E → F} {g : E → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) : + TendstoLocallyUniformlyOn (fun n => fderiv ℂ (f n)) (fderiv ℂ g) l U := by + let e := (Module.finBasis ℂ E).equivFunL + have hc := hlim.comp e.symm (fun _ hx => hx) e.symm.continuous.continuousOn + have hd := hc.fderiv_pi (hf.mono fun n hn => + hn.comp (e.symm.toContinuousLinearMap.analyticOnNhd _) (fun _ hx => hx)) + (hU.preimage e.symm.continuous) + let L := (ContinuousLinearMap.compL ℂ E (Fin (Module.finrank ℂ E) → ℂ) F).flip + e.toContinuousLinearMap + have H := (L.uniformContinuous.comp_tendstoLocallyUniformlyOn hd).comp e + (fun x hx => show e x ∈ e.symm ⁻¹' U by simpa using hx) e.continuous.continuousOn + have heq {a : E → F} {x : E} (ha : DifferentiableAt ℂ a x) : + L (fderiv ℂ (a ∘ e.symm) (e x)) = fderiv ℂ a x := by + have ha' : DifferentiableAt ℂ a (e.symm (e x)) := by simpa using ha + rw [fderiv_comp _ ha' e.symm.differentiableAt, e.symm.fderiv] + ext v + simp [L] + have H' := H.congr_inseparable (hf.mono fun n hn x hx => + Inseparable.of_eq (heq (hn x hx).differentiableAt)) + exact H'.congr_right fun x hx => heq + ((hlim.analyticOnNhd_of_finiteDimensional hf hU) x hx).differentiableAt + +/-- All iterated Fréchet derivatives converge locally uniformly on a finite-dimensional complex +domain, in multilinear operator norm. -/ +theorem TendstoLocallyUniformlyOn.iteratedFDeriv_of_finiteDimensional + {U : Set E} {l : Filter κ} [l.NeBot] {f : κ → E → F} {g : E → F} + (hlim : TendstoLocallyUniformlyOn f g l U) + (hf : ∀ᶠ n in l, AnalyticOnNhd ℂ (f n) U) (hU : IsOpen U) (k : ℕ) : + TendstoLocallyUniformlyOn (fun n => iteratedFDeriv ℂ k (f n)) + (iteratedFDeriv ℂ k g) l U := by + induction k with + | zero => + simpa only [iteratedFDeriv_zero_eq_comp] using + (continuousMultilinearCurryFin0 ℂ E + F).symm.isometry.uniformContinuous.comp_tendstoLocallyUniformlyOn hlim + | succ k ih => + have hd := ih.fderiv_of_finiteDimensional + (hf.mono fun n hn => hn.iteratedFDeriv_of_isOpen hU k) hU + simpa only [iteratedFDeriv_succ_eq_comp_left] using + (continuousMultilinearCurryLeftEquiv ℂ (fun _ : Fin (k + 1) => E) + F).symm.isometry.uniformContinuous.comp_tendstoLocallyUniformlyOn hd + +end FiniteDimensional + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/MaximumModulus.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/MaximumModulus.lean new file mode 100644 index 0000000000..9437f2c4ec --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/MaximumModulus.lean @@ -0,0 +1,70 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.AbsMax +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple + +/-! +# The maximum modulus principle in several variables + +If the modulus of a scalar holomorphic function on an open, preconnected set has a local maximum +at an interior point, then the function is constant on the set. This is +[Fritzsche–Grauert][FritzscheGrauert2002] (2002), I.4.11, p. 22. A local maximum suffices; a +maximum over the whole domain is not required. The proof combines Mathlib's local maximum +modulus principle with the holomorphic identity theorem. + +The source is any finite-dimensional complex normed space, including `ι → ℂ` for any finite +index type (also empty). The supporting norm theorem permits strictly convex complex Banach +targets. Strict convexity cannot be dropped for constancy of the map: on the unit disc, `z ↦ (1, +z)` is nonconstant but has constant supremum norm. + +## Main results + +* `eqOn_const_of_holomorphic_of_isLocalMax_norm`: **Maximum modulus principle + ([Fritzsche–Grauert][FritzscheGrauert2002] I.4.11).** A holomorphic map into a strictly convex + complex Banach space, in particular a scalar holomorphic function, is constant on an open, + preconnected domain if its norm has a local maximum at an interior point. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +-/ + +public section + +open Set Filter Function +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + +/-- **Maximum modulus principle ([Fritzsche–Grauert][FritzscheGrauert2002] I.4.11).** A holomorphic +map into a strictly convex complex Banach space, in particular a scalar holomorphic function, is +constant on an open, preconnected domain if its norm has a local maximum at an interior point. -/ +theorem eqOn_const_of_holomorphic_of_isLocalMax_norm + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + [StrictConvexSpace ℝ F] {U : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) + {f : E → F} (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) + (hmax : IsLocalMax (norm ∘ f) a) : EqOn f (const E (f a)) U := + hf.eqOn_of_preconnected_of_eventuallyEq hU hconn (differentiableOn_const (f a)) ha + (Complex.eventually_eq_of_isLocalMax_norm + (hf.eventually_differentiableAt (hU.mem_nhds ha)) hmax) + +/-- The maximum principle with the local maximum expressed relative to the domain. Since the point +is interior, this agrees with the ambient local-maximum formulation. -/ +theorem eqOn_const_of_holomorphic_of_isLocalMaxOn_norm + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + [StrictConvexSpace ℝ F] {U : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) + {f : E → F} (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) + (hmax : IsLocalMaxOn (norm ∘ f) U a) : EqOn f (const E (f a)) U := + eqOn_const_of_holomorphic_of_isLocalMax_norm hU hconn hf ha (hmax.isLocalMax (hU.mem_nhds ha)) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Montel.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Montel.lean new file mode 100644 index 0000000000..42d89f712e --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Montel.lean @@ -0,0 +1,245 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Schwarz +public import Mathlib.Topology.MetricSpace.Equicontinuity +public import Mathlib.Topology.UniformSpace.Ascoli +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.FunctionSpace +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyBounded + +/-! +# Montel's and Vitali's theorems + +A family of holomorphic maps which is bounded uniformly on each compact subset of its domain is +equicontinuous. For finite-dimensional targets it has compact closure in the compact-open +topology. Compactness is supplied by Mathlib's Arzelà–Ascoli theorem. For uniformly bounded +sequences, a subsequence theorem is also provided on arbitrary finite-dimensional complex source +spaces. Vitali convergence follows from compactness and the identity theorem: pointwise +convergence on a nonempty open subset determines every cluster limit uniquely. + +## Main results + +`equicontinuous_of_holomorphic_bounded_on_compacts` is equicontinuity of a family bounded on compact +sets. `isCompact_closure_of_holomorphic_bounded_on_compacts` is Montel's theorem for +finite-dimensional targets. `exists_tendstoLocallyUniformlyOn_of_forall_exists_tendsto` is Vitali +convergence from pointwise convergence on a nonempty open subset. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public section + +open Complex Filter Function Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +omit [CompleteSpace F] in +/-- Compact-local bounds on a holomorphic family give equicontinuity. Banach targets are allowed +here; finite dimensionality is needed only for compactness in Montel's theorem. -/ +theorem equicontinuous_of_holomorphic_bounded_on_compacts + {U : TopologicalSpace.Opens E} {S : Set (HolomorphicMap U F)} + (hb : ∀ K ⊆ (U : Set E), IsCompact K → ∃ M : ℝ, + ∀ f ∈ S, ∀ z ∈ K, ‖openExtension U f.val z‖ ≤ M) : + Equicontinuous (fun f : S => (f.val.val : U → F)) := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + intro c + rw [Metric.equicontinuousAt_iff] + intro ε hε + obtain ⟨R, hR, hRU⟩ := nhds_basis_closedBall.mem_iff.mp (U.isOpen.mem_nhds c.property) + obtain ⟨M, hM⟩ := hb (closedBall (c : E) R) hRU (isCompact_closedBall _ _) + let C : ℝ := 2 * max M 0 / R + have hC : 0 ≤ C := div_nonneg (by positivity) hR.le + refine ⟨min R (ε / (C + 1)), lt_min hR (div_pos hε (by positivity)), ?_⟩ + intro w hw f + have hwr : dist (w : E) c < R := (lt_min_iff.mp hw).1 + have hwe : dist (w : E) c < ε / (C + 1) := (lt_min_iff.mp hw).2 + have hmaps : MapsTo (openExtension U f.val.val) (ball (c : E) R) + (closedBall (openExtension U f.val.val c) (2 * max M 0)) := by + intro z hz + rw [mem_closedBall, dist_eq_norm] + calc + ‖openExtension U f.val.val z - openExtension U f.val.val c‖ ≤ + ‖openExtension U f.val.val z‖ + ‖openExtension U f.val.val c‖ := norm_sub_le _ _ + _ ≤ max M 0 + max M 0 := add_le_add + ((hM f.val f.property z (ball_subset_closedBall hz)).trans (le_max_left _ _)) + ((hM f.val f.property c (mem_closedBall_self hR.le)).trans (le_max_left _ _)) + _ = 2 * max M 0 := by ring + have hn := dist_le_div_mul_dist_of_mapsTo_ball + (f.val.property.differentiableOn.mono (ball_subset_closedBall.trans hRU)) hmaps hwr + simp only [openExtension_coe] at hn + have hlt : (C + 1) * dist (w : E) c < ε := by + nlinarith [(lt_div_iff₀ (by positivity : 0 < C + 1)).mp hwe] + rw [dist_comm] + change dist (f.val.val w) (f.val.val c) < ε + change dist (f.val.val w) (f.val.val c) ≤ C * dist (w : E) c at hn + nlinarith [show 0 ≤ dist (w : E) (c : E) from dist_nonneg] + +/-- **Montel's theorem.** A compact-locally bounded family of holomorphic maps into a +finite-dimensional complex normed space has compact closure in the compact-open topology. -/ +theorem isCompact_closure_of_holomorphic_bounded_on_compacts + [FiniteDimensional ℂ F] {U : TopologicalSpace.Opens E} + {S : Set (HolomorphicMap U F)} + (hb : ∀ K ⊆ (U : Set E), IsCompact K → ∃ M : ℝ, + ∀ f ∈ S, ∀ z ∈ K, ‖openExtension U f.val z‖ ≤ M) : IsCompact (closure S) := by + let := FiniteDimensional.proper ℂ F + let := UniformOnFun.t2Space_of_covering (β := F) + (𝔖 := {K : Set U | IsCompact K}) (by + apply eq_univ_iff_forall.mpr + intro z + exact mem_sUnion_of_mem (mem_singleton z) isCompact_singleton) + have he : Topology.IsClosedEmbedding + (UniformOnFun.ofFun {K : Set U | IsCompact K} ∘ + (fun f : HolomorphicMap U F => (f.val : U → F))) := by + exact (ContinuousMap.isUniformEmbedding_toUniformOnFunIsCompact.comp + isUniformEmbedding_subtype_val).isClosedEmbedding + apply ArzelaAscoli.isCompact_closure_of_isClosedEmbedding (fun K hK => hK) he + · intro K hK + exact (equicontinuous_of_holomorphic_bounded_on_compacts hb).equicontinuousOn K + · intro K hK z hz + obtain ⟨M, hM⟩ := hb {(z : E)} (singleton_subset_iff.mpr z.property) isCompact_singleton + refine ⟨closedBall (0 : F) (max M 0), isCompact_closedBall _ _, ?_⟩ + intro f hf + have h := (hM f hf z (mem_singleton _)).trans (le_max_left M 0) + simpa using h + +/-- **Vitali's theorem ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.4.24)** in the compact-open +function space. +A locally bounded sequence converging pointwise on a nonempty open subset of a +preconnected domain converges in the whole holomorphic-map space. -/ +theorem exists_tendsto_of_holomorphic_bounded_on_compacts + [FiniteDimensional ℂ F] {U : TopologicalSpace.Opens E} + (hconn : IsPreconnected (U : Set E)) (f : ℕ → HolomorphicMap U F) + (hb : ∀ K ⊆ (U : Set E), IsCompact K → ∃ M : ℝ, + ∀ n, ∀ z ∈ K, ‖openExtension U (f n).val z‖ ≤ M) + {V : Set E} (hV : IsOpen V) (hne : V.Nonempty) (hVU : V ⊆ U) + (hp : ∀ z ∈ V, ∃ y : F, + Tendsto (fun n => openExtension U (f n).val z) atTop (𝓝 y)) : + ∃ g : HolomorphicMap U F, Tendsto f atTop (𝓝 g) := by + have hc : IsCompact (closure (range f)) := + isCompact_closure_of_holomorphic_bounded_on_compacts (by + intro K hKU hK + obtain ⟨M, hM⟩ := hb K hKU hK + exact ⟨M, by rintro _ ⟨n, rfl⟩; exact hM n⟩) + have hm : ∀ᶠ n in atTop, f n ∈ closure (range f) := + .of_forall fun n => subset_closure (mem_range_self n) + obtain ⟨g, _, hg⟩ := hc.exists_mapClusterPt_of_frequently hm.frequently + refine ⟨g, hc.tendsto_nhds_of_unique_mapClusterPt hm ?_⟩ + intro q _ hq + have hvalue : ∀ (r : HolomorphicMap U F), MapClusterPt r atTop f → + ∀ z ∈ V, ∀ y : F, + Tendsto (fun n => openExtension U (f n).val z) atTop (𝓝 y) → + openExtension U r.val z = y := by + intro r hr z hz y hy + have he := hr.continuousAt_comp + (continuous_holomorphicMap_eval U ⟨z, hVU hz⟩).continuousAt + obtain ⟨φ, hφ, hlim⟩ := he.tendsto_subseq + have hy' : Tendsto (fun n => (f n).val ⟨z, hVU hz⟩) atTop (𝓝 y) := by + simpa only [openExtension_apply U _ (hVU hz)] using hy + simpa only [openExtension_apply U _ (hVU hz)] using + tendsto_nhds_unique hlim (hy'.comp hφ.tendsto_atTop) + have heq : EqOn (openExtension U q.val) (openExtension U g.val) U := + DifferentiableOn.eqOn_of_preconnected_of_eqOn U.isOpen hconn q.property.differentiableOn + g.property.differentiableOn hV hne hVU (by + intro z hz + obtain ⟨y, hy⟩ := hp z hz + exact (hvalue q hq z hz y hy).trans (hvalue g hg z hz y hy).symm) + apply Subtype.ext + apply ContinuousMap.ext + intro z + simpa only [openExtension_coe] using heq z.property + +/-- **Vitali's theorem** for holomorphic functions on a finite-dimensional complex normed space. +The limit is holomorphic and convergence is locally uniform on the whole domain. +Finite-dimensional complex targets, including scalar-valued functions, are allowed. -/ +theorem exists_tendstoLocallyUniformlyOn_of_forall_exists_tendsto [FiniteDimensional ℂ F] + {D V : Set E} + (hD : IsOpen D) (hconn : IsPreconnected D) {f : ℕ → E → F} + (hf : ∀ n, DifferentiableOn ℂ (f n) D) + (hb : ∀ K ⊆ D, IsCompact K → ∃ M : ℝ, ∀ n, ∀ z ∈ K, ‖f n z‖ ≤ M) + (hV : IsOpen V) (hne : V.Nonempty) (hVD : V ⊆ D) + (hp : ∀ z ∈ V, ∃ y : F, Tendsto (fun n => f n z) atTop (𝓝 y)) : + ∃ g : E → F, DifferentiableOn ℂ g D ∧ + TendstoLocallyUniformlyOn f g atTop D := by + let U : TopologicalSpace.Opens E := ⟨D, hD⟩ + let s : ℕ → HolomorphicMap U F := fun n => + ⟨⟨fun z => f n z, (hf n).continuousOn.domRestrict⟩, + by + apply AnalyticOnNhd.congr hD ((hf n).analyticOnNhd_of_finiteDimensional hD) + intro z hz + simp [openExtension, U, hz] + rfl⟩ + have hs : ∀ n, ∀ z ∈ D, openExtension U (s n).val z = f n z := by + intro n z hz + exact openExtension_apply U _ hz + obtain ⟨g, hg⟩ := exists_tendsto_of_holomorphic_bounded_on_compacts hconn s + (by + intro K hKD hK + obtain ⟨M, hM⟩ := hb K hKD hK + refine ⟨M, fun n z hz => ?_⟩ + rw [hs n z (hKD hz)] + exact hM n z hz) hV hne hVD (by + intro z hz + simpa only [hs _ z (hVD hz)] using hp z hz) + refine ⟨openExtension U g.val, g.property.differentiableOn, ?_⟩ + exact (holomorphicMap_tendsto_iff.mp hg).congr + (fun n z hz => hs n z hz) + +/-- A uniformly bounded holomorphic sequence on a finite-dimensional complex space has a locally +uniformly convergent subsequence, with holomorphic limit. -/ +theorem exists_subseq_tendstoLocallyUniformlyOn_of_uniform_bound + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [FiniteDimensional ℂ F] {U : Set E} (hU : IsOpen U) {f : ℕ → E → F} + (hf : ∀ n, AnalyticOnNhd ℂ (f n) U) {M : ℝ} + (hM : ∀ n z, z ∈ U → ‖f n z‖ ≤ M) : + ∃ (g : E → F) (φ : ℕ → ℕ), StrictMono φ ∧ AnalyticOnNhd ℂ g U ∧ + TendstoLocallyUniformlyOn (fun n => f (φ n)) g atTop U := by + let e := (Module.finBasis ℂ E).equivFunL + let V : TopologicalSpace.Opens (Fin (Module.finrank ℂ E) → ℂ) := + ⟨e.symm ⁻¹' U, hU.preimage e.symm.continuous⟩ + let : LocallyCompactSpace V := V.isOpen.locallyCompactSpace + have hA (n) : AnalyticOnNhd ℂ (f n ∘ e.symm) V := + (hf n).comp (e.symm.toContinuousLinearMap.analyticOnNhd _) (fun _ hz => hz) + let G (n : ℕ) : HolomorphicMap V F := + ⟨⟨fun z => f n (e.symm z), (hA n).continuousOn.domRestrict⟩, + (hA n).congr V.isOpen (fun z hz => by rw [openExtension_apply V _ hz]; rfl)⟩ + have hc : IsCompact (closure (range G)) := + isCompact_closure_of_holomorphic_bounded_on_compacts (by + intro K hKV _ + refine ⟨M, ?_⟩ + rintro _ ⟨n, rfl⟩ z hz + rw [openExtension_apply V _ (hKV hz)] + exact hM n _ (hKV hz)) + have : (uniformity C(V, F)).IsCountablyGenerated := inferInstance + have : (uniformity (HolomorphicMap V F)).IsCountablyGenerated := + Filter.comap.isCountablyGenerated _ _ + have hm : ∀ᶠ n in atTop, G n ∈ closure (range G) := + .of_forall fun n => subset_closure (mem_range_self n) + obtain ⟨g, _, hg⟩ := hc.exists_mapClusterPt_of_frequently hm.frequently + obtain ⟨φ, hφ, hlim⟩ := hg.tendsto_subseq + let g' : E → F := fun z => openExtension V g.val (e z) + have hmaps : MapsTo e U V := fun z hz => by simpa [V] using hz + refine ⟨g', φ, hφ, g.property.comp (e.toContinuousLinearMap.analyticOnNhd U) hmaps, ?_⟩ + have hl := (holomorphicMap_tendsto_iff.mp hlim).comp e hmaps e.continuous.continuousOn + apply hl.congr + intro n z hz + simp only [Function.comp_apply, openExtension_apply V _ (hmaps hz), G] + change f (φ n) (e.symm (e z)) = f (φ n) z + rw [e.symm_apply_apply] + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Osgood.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Osgood.lean new file mode 100644 index 0000000000..f3ea1c8fdc --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Osgood.lean @@ -0,0 +1,116 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.LinearAlgebra.FiniteDimensional.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchySeries + +/-! +# Osgood's theorem in finite products + +Joint continuity and separate holomorphy imply joint analyticity on an open subset of a finite +complex coordinate space. The stronger Hartogs theorem without continuity is not proved here. +The polydisc Cauchy formula and its series construction live in the imported modules and remain +available through this file. + +## Main results + +`analyticOnNhd_pi_of_analyticOnNhd_update` is Osgood's theorem on an arbitrary finite coordinate +space `ι → ℂ`: continuity on an open set together with holomorphy in each coordinate separately +yields joint analyticity. +-/ + +public section + +open Complex Filter Function MeasureTheory Metric Set +open scoped ENNReal NNReal Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-- Osgood's theorem on `Fin d → ℂ`, before reindexing to an arbitrary finite coordinate type. -/ +private theorem analyticOnNhd_fin_of_analyticOnNhd_update {d : ℕ} + {U : Set (Fin d → ℂ)} {f : (Fin d → ℂ) → E} + (hU : IsOpen U) (hfc : ContinuousOn f U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + AnalyticOnNhd ℂ f U := by + intro c hc + obtain ⟨R, hR, hRU⟩ := nhds_basis_closedBall.mem_iff.mp (hU.mem_nhds hc) + have hP : closedPolydisc c (fun _ => R) ⊆ U := by + rw [closedPolydisc_eq_closedBall hR.le] + exact hRU + have hfcP : ContinuousOn f (closedPolydisc c (fun _ => R)) := hfc.mono hP + have hfaP : ∀ z ∈ closedPolydisc c (fun _ => R), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i) := fun z hz => hf z (hP hz) + have hPcpt : IsCompact (closedPolydisc c (fun _ => R)) := by + rw [closedPolydisc_eq_closedBall hR.le] + exact isCompact_closedBall _ _ + obtain ⟨M, hM⟩ := hPcpt.bddAbove_image hfcP.norm + exact (hasFPowerSeriesOnBall_polydiscCauchy hR hfcP hfaP + (fun z hz => hM (mem_image_of_mem _ hz))).analyticAt + +/-- **Osgood's theorem, finite-product form.** A jointly continuous function on an open subset of +a finite product of copies of `ℂ` is jointly analytic when all of its one-coordinate restrictions +are analytic. + +This is weaker than Hartogs' theorem `analyticOnNhd_of_separately_analytic`, which drops the +continuity hypothesis. It is the first step in the proof of that theorem, through the locally +bounded version `analyticOnNhd_of_separately_analytic_locally_bounded`, and therefore cannot be +derived from it. Continuity is present in every application preceding Hartogs' theorem in this +library. -/ +theorem analyticOnNhd_pi_of_analyticOnNhd_update + {ι : Type*} [Fintype ι] [DecidableEq ι] {U : Set (ι → ℂ)} {f : (ι → ℂ) → E} + (hU : IsOpen U) (hfc : ContinuousOn f U) + (hf : ∀ z ∈ U, ∀ i, + AnalyticAt ℂ (fun w => f (Function.update z i w)) (z i)) : + AnalyticOnNhd ℂ f U := by + let e : Fin (Fintype.card ι) ≃ ι := (Fintype.equivFin ι).symm + let L : (Fin (Fintype.card ι) → ℂ) ≃L[ℂ] (ι → ℂ) := + ContinuousLinearEquiv.piCongrLeft ℂ (fun _ : ι => ℂ) e + let V : Set (Fin (Fintype.card ι) → ℂ) := L ⁻¹' U + let g : (Fin (Fintype.card ι) → ℂ) → E := f ∘ L + have hV : IsOpen V := hU.preimage L.continuous + have hgc : ContinuousOn g V := + hfc.comp L.continuous.continuousOn (fun _ hz => hz) + have hL_apply (z : Fin (Fintype.card ι) → ℂ) + (j : Fin (Fintype.card ι)) : L z (e j) = z j := by + change (Equiv.piCongrLeft (fun _ : ι => ℂ) e) z (e j) = z j + exact Equiv.piCongrLeft_apply_apply (fun _ : ι => ℂ) e z j + have hL_update (z : Fin (Fintype.card ι) → ℂ) + (j : Fin (Fintype.card ι)) (w : ℂ) : + L (update z j w) = update (L z) (e j) w := by + funext i + obtain ⟨k, rfl⟩ := e.surjective i + by_cases hkj : k = j + · subst k + simp [hL_apply] + · have hek : e k ≠ e j := fun he => hkj (e.injective he) + simp [hkj, hek, hL_apply] + have hga : ∀ z ∈ V, ∀ j, + AnalyticAt ℂ (fun w => g (update z j w)) (z j) := by + intro z hz j + have h := hf (L z) hz (e j) + convert h using 1 + · funext w + simp only [g, Function.comp_apply] + rw [hL_update] + · exact (hL_apply z j).symm + have hg := analyticOnNhd_fin_of_analyticOnNhd_update hV hgc hga + intro z hz + have hzV : L.symm z ∈ V := by + change L (L.symm z) ∈ U + simpa + have hcomp : AnalyticAt ℂ (g ∘ ⇑L.symm.toContinuousLinearMap) z := + AnalyticAt.compContinuousLinearMap (u := L.symm.toContinuousLinearMap) + (hg (L.symm z) hzV) + simpa [g, Function.comp_def] using hcomp + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ParametricIntegral.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ParametricIntegral.lean new file mode 100644 index 0000000000..51548bbdb1 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ParametricIntegral.lean @@ -0,0 +1,181 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.ParametricIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity + +/-! +# Analytic dependence of integrals on several complex parameters + +This file combines Mathlib's dominated differentiation-under-the-integral API with +finite-dimensional complex analyticity from `SeveralComplexVariables.Analyticity`. A +compact-domain criterion derives the required domination from joint continuity of the pointwise +derivative. + +The parameter space in the analyticity criterion is an arbitrary finite-dimensional complex +normed space: the statement uses Fréchet derivatives and requires no coordinates. The compact +integral criteria below concern a single complex parameter and arbitrary compact integration +sets, not a particular integration geometry. This material is ultimately intended near +`Mathlib.Analysis.Calculus.ParametricIntegral`. + +## Main results + +`analyticOnNhd_integral_of_dominated_of_fderiv_le` packages the existing local dominated +Fréchet-derivative criterion at every point of an open finite-dimensional parameter domain. + +`hasDerivAt_integral_of_continuousOn_compact` identifies the derivative of a compact set +integral with the integral of its pointwise complex derivative. +`hasDerivAt_integral_smul_of_continuousOn_compact` allows a fixed scalar weight with Banach-valued +kernels; `hasDerivAt_integral_mul_of_continuousOn_compact` is its scalar specialization, including a +weight singular on the boundary. The general dominated Fréchet derivative identification is +already Mathlib's `hasFDerivAt_integral_of_dominated_of_fderiv_le`. The integral theorem names +remain in the root namespace, consistently with that API. +-/ + +public section + +open Filter MeasureTheory Set +open scoped Topology + +variable {α E : Type*} [MeasurableSpace α] + [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-- An integral on a finite-dimensional complex parameter space is analytic if, locally at every +parameter, its pointwise Fréchet derivatives have an integrable uniform bound. The hypotheses +are grouped pointwise so that the dominating function and neighborhood may depend on the base +parameter. -/ +theorem analyticOnNhd_integral_of_dominated_of_fderiv_le + {P : Type*} [NormedAddCommGroup P] [NormedSpace ℂ P] [FiniteDimensional ℂ P] + {μ : Measure α} {U : Set P} {F : P → α → E} + (hU : IsOpen U) + (hdom : ∀ x ∈ U, ∃ (s : Set P) (bound : α → ℝ) + (F' : P → α → P →L[ℂ] E), + s ∈ nhds x ∧ + (∀ᶠ y in nhds x, AEStronglyMeasurable (F y) μ) ∧ + Integrable (F x) μ ∧ AEStronglyMeasurable (F' x) μ ∧ + (∀ᵐ a ∂μ, ∀ y ∈ s, ‖F' y a‖ ≤ bound a) ∧ Integrable bound μ ∧ + (∀ᵐ a ∂μ, ∀ y ∈ s, HasFDerivAt (F · a) (F' y a) y)) : + AnalyticOnNhd ℂ (fun x ↦ ∫ a, F x a ∂μ) U := by + apply DifferentiableOn.analyticOnNhd_of_finiteDimensional _ hU + intro x hx + obtain ⟨s, bound, F', hs, hmeas, hint, hF'meas, hbound, hboundInt, hdiff⟩ := hdom x hx + exact (hasFDerivAt_integral_of_dominated_of_fderiv_le hs hmeas hint hF'meas + hbound hboundInt hdiff).differentiableAt.differentiableWithinAt + +omit [CompleteSpace E] in +/-- Differentiation under an integral over a compact set when the integrand and its pointwise +complex derivative are jointly continuous. Compactness supplies domination. -/ +theorem hasDerivAt_integral_of_continuousOn_compact + [TopologicalSpace α] [BorelSpace α] [T2Space α] + {μ : Measure α} [IsLocallyFiniteMeasure μ] {K : Set α} (hK : IsCompact K) + {U : Set ℂ} (hU : IsOpen U) {x : ℂ} (hx : x ∈ U) + {F F' : ℂ → α → E} + (hF : ContinuousOn (fun p : ℂ × α => F p.1 p.2) (U ×ˢ K)) + (hF' : ContinuousOn (fun p : ℂ × α => F' p.1 p.2) (U ×ˢ K)) + (hd : ∀ z ∈ U, ∀ a ∈ K, HasDerivAt (fun w => F w a) (F' z a) z) : + HasDerivAt (fun z => ∫ a in K, F z a ∂μ) (∫ a in K, F' x a ∂μ) x := by + obtain ⟨r, hr, hball⟩ := Metric.nhds_basis_closedBall.mem_iff.mp (hU.mem_nhds hx) + have hc : IsCompact (Metric.closedBall x r ×ˢ K) := (isCompact_closedBall _ _).prod hK + have hcont := hF'.mono (Set.prod_mono hball Subset.rfl) + obtain ⟨M, hM⟩ := hc.bddAbove_image hcont.norm + have hslice {z : ℂ} (hz : z ∈ U) : ContinuousOn (F z) K := + hF.comp (continuous_const.prodMk continuous_id).continuousOn (fun a ha => ⟨hz, ha⟩) + have hslice' {z : ℂ} (hz : z ∈ U) : ContinuousOn (F' z) K := + hF'.comp (continuous_const.prodMk continuous_id).continuousOn (fun a ha => ⟨hz, ha⟩) + apply (hasDerivAt_integral_of_dominated_loc_of_deriv_le + (μ := μ.restrict K) (F := F) (F' := F') (bound := fun _ => M) + (Metric.closedBall_mem_nhds x hr) ?_ ((hslice hx).integrableOn_compact hK) + ((hslice' hx).integrableOn_compact hK).aestronglyMeasurable ?_ + (integrableOn_const hK.measure_ne_top) ?_).2 + · filter_upwards [hU.eventually_mem hx] with z hz + exact ((hslice hz).integrableOn_compact hK).aestronglyMeasurable + · filter_upwards [ae_restrict_mem hK.measurableSet] with a ha + intro z hz + exact hM (mem_image_of_mem (fun p : ℂ × α => ‖F' p.1 p.2‖) + (show (z, a) ∈ Metric.closedBall x r ×ˢ K from ⟨hz, ha⟩)) + · filter_upwards [ae_restrict_mem hK.measurableSet] with a ha + intro z hz + exact hd z (hball hz) a ha + +omit [CompleteSpace E] in +/-- An integrable scalar weight times a continuous Banach-valued function on a compact set is +integrable. Compactness gives both boundedness and a separable image, so no countability +assumption on either ambient space is required. -/ +theorem MeasureTheory.IntegrableOn.smul_continuousOn_of_isCompact + [TopologicalSpace α] [BorelSpace α] [T2Space α] + {μ : Measure α} {K : Set α} {g : α → ℂ} {H : α → E} + (hg : IntegrableOn g K μ) (hH : ContinuousOn H K) (hK : IsCompact K) : + IntegrableOn (fun t => g t • H t) K μ := by + obtain ⟨M, hM⟩ := hK.bddAbove_image hH.norm + apply (hg.norm.mul_const M).mono' + (hg.aestronglyMeasurable.smul (hH.aestronglyMeasurable_of_isCompact hK hK.measurableSet)) + filter_upwards [ae_restrict_mem hK.measurableSet] with t ht + change ‖g t • H t‖ ≤ ‖g t‖ * M + rw [norm_smul] + exact mul_le_mul_of_nonneg_left (hM ⟨t, ht, rfl⟩) (norm_nonneg _) + +omit [CompleteSpace E] in +/-- A fixed integrable scalar weight can be included in compact-domain differentiation. Only the +kernel and its derivative must be jointly continuous; the weight may be singular on the boundary +of the integration domain. -/ +theorem hasDerivAt_integral_smul_of_continuousOn_compact + [TopologicalSpace α] [BorelSpace α] [T2Space α] + {μ : Measure α} {K : Set α} (hK : IsCompact K) + {g : α → ℂ} (hg : IntegrableOn g K μ) + {U : Set ℂ} (hU : IsOpen U) {x : ℂ} (hx : x ∈ U) + {F F' : ℂ → α → E} + (hF : ContinuousOn (fun p : ℂ × α => F p.1 p.2) (U ×ˢ K)) + (hF' : ContinuousOn (fun p : ℂ × α => F' p.1 p.2) (U ×ˢ K)) + (hd : ∀ z ∈ U, ∀ a ∈ K, HasDerivAt (fun w => F w a) (F' z a) z) : + HasDerivAt (fun z => ∫ a in K, g a • F z a ∂μ) + (∫ a in K, g a • F' x a ∂μ) x := by + obtain ⟨r, hr, hball⟩ := Metric.nhds_basis_closedBall.mem_iff.mp (hU.mem_nhds hx) + have hc : IsCompact (Metric.closedBall x r ×ˢ K) := (isCompact_closedBall _ _).prod hK + obtain ⟨M, hM⟩ := hc.bddAbove_image + (hF'.mono (Set.prod_mono hball Subset.rfl)).norm + have hslice {z : ℂ} (hz : z ∈ U) : ContinuousOn (F z) K := + hF.comp (continuous_const.prodMk continuous_id).continuousOn (fun a ha => ⟨hz, ha⟩) + have hslice' {z : ℂ} (hz : z ∈ U) : ContinuousOn (F' z) K := + hF'.comp (continuous_const.prodMk continuous_id).continuousOn (fun a ha => ⟨hz, ha⟩) + apply (hasDerivAt_integral_of_dominated_loc_of_deriv_le + (μ := μ.restrict K) (F := fun z a => g a • F z a) + (F' := fun z a => g a • F' z a) (bound := fun a => ‖g a‖ * M) + (Metric.closedBall_mem_nhds x hr) ?_ (hg.smul_continuousOn_of_isCompact (hslice hx) hK) + (hg.smul_continuousOn_of_isCompact (hslice' hx) hK).aestronglyMeasurable ?_ + (hg.norm.mul_const M) ?_).2 + · filter_upwards [hU.eventually_mem hx] with z hz + exact (hg.smul_continuousOn_of_isCompact (hslice hz) hK).aestronglyMeasurable + · filter_upwards [ae_restrict_mem hK.measurableSet] with a ha + intro z hz + rw [norm_smul] + exact mul_le_mul_of_nonneg_left + (hM (mem_image_of_mem (fun p : ℂ × α => ‖F' p.1 p.2‖) + (show (z, a) ∈ Metric.closedBall x r ×ˢ K from ⟨hz, ha⟩))) (norm_nonneg _) + · filter_upwards [ae_restrict_mem hK.measurableSet] with a ha + intro z hz + exact (hd z (hball hz) a ha).const_smul (g a) + +/-- A fixed integrable scalar weight can be included in compact-domain differentiation. Only the +kernel and its derivative must be jointly continuous; the weight may be singular on the boundary +of the integration domain. -/ +theorem hasDerivAt_integral_mul_of_continuousOn_compact + [TopologicalSpace α] [BorelSpace α] [T2Space α] + {μ : Measure α} {K : Set α} (hK : IsCompact K) + {g : α → ℂ} (hg : IntegrableOn g K μ) + {U : Set ℂ} (hU : IsOpen U) {x : ℂ} (hx : x ∈ U) + {F F' : ℂ → α → ℂ} + (hF : ContinuousOn (fun p : ℂ × α => F p.1 p.2) (U ×ˢ K)) + (hF' : ContinuousOn (fun p : ℂ × α => F' p.1 p.2) (U ×ˢ K)) + (hd : ∀ z ∈ U, ∀ a ∈ K, HasDerivAt (fun w => F w a) (F' z a) z) : + HasDerivAt (fun z => ∫ a in K, g a * F z a ∂μ) + (∫ a in K, g a * F' x a ∂μ) x := by + simpa only [smul_eq_mul] using + hasDerivAt_integral_smul_of_continuousOn_compact hK hg hU hx hF hF' hd + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Plurisubharmonic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Plurisubharmonic.lean new file mode 100644 index 0000000000..2fbff1f135 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Plurisubharmonic.lean @@ -0,0 +1,255 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Module.Convex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic + +/-! +# Plurisubharmonic functions + +A real function on an open subset of a complex normed space is plurisubharmonic if it is upper +semicontinuous and its restriction to every complex line is subharmonic, in the local submean +sense of `Subharmonic`. This file proves closure under sums, nonnegative multiples, maxima and +complex affine substitutions, shows that continuous convex functions are plurisubharmonic, and +gives the holomorphic examples: real parts, positive powers of norms, and logarithms of +nonvanishing moduli of holomorphic functions. + +Only real-valued functions are considered. The characterization of `C²` plurisubharmonic +functions through the Levi form is proved in `LeviForm`. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 2; +[Hörmander][Hormander1973] (1973), Definition 2.6.1; [Range][Range1986] (1986), Chapter II, +Section 5. + +## Main definitions + +* `PlurisubharmonicOn`: A real function is plurisubharmonic on a set if it is upper semicontinuous + there and its restriction to every complex line is subharmonic on the corresponding parameter set. + +## Main results + +* `PlurisubharmonicOn.add`: Sums of plurisubharmonic functions are plurisubharmonic. +* `PlurisubharmonicOn.sup`: The pointwise maximum of two plurisubharmonic functions is + plurisubharmonic. +* `PlurisubharmonicOn.comp_affine`: Plurisubharmonicity is preserved by complex affine + substitutions. +* `ConvexOn.plurisubharmonicOn`: A continuous convex function on an open set is plurisubharmonic. +* `plurisubharmonicOn_norm`: The norm is plurisubharmonic. +* `AnalyticOnNhd.plurisubharmonicOn_re`: Real parts of holomorphic functions are plurisubharmonic. +* `AnalyticOnNhd.plurisubharmonicOn_norm_rpow`: Positive powers of the norm of a holomorphic map are + plurisubharmonic. +* `AnalyticOnNhd.plurisubharmonicOn_log_norm`: The logarithm of the modulus of a nonvanishing + holomorphic function is plurisubharmonic. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public section + +open Filter Metric Set Real +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- A real function is plurisubharmonic on a set if it is upper semicontinuous there and its +restriction to every complex line is subharmonic on the corresponding parameter set. -/ +@[expose] def PlurisubharmonicOn (f : E → ℝ) (U : Set E) : Prop := + UpperSemicontinuousOn f U ∧ + ∀ a ∈ U, ∀ w : E, SubharmonicOn (fun t : ℂ => f (a + t • w)) {t | a + t • w ∈ U} + +variable {f g : E → ℝ} {U V : Set E} + +/-- A plurisubharmonic function is upper semicontinuous. -/ +theorem PlurisubharmonicOn.upperSemicontinuousOn (h : PlurisubharmonicOn f U) : + UpperSemicontinuousOn f U := h.1 + +/-- Complex-line slices of a plurisubharmonic function are subharmonic. -/ +theorem PlurisubharmonicOn.slice (h : PlurisubharmonicOn f U) {a : E} (ha : a ∈ U) (w : E) : + SubharmonicOn (fun t : ℂ => f (a + t • w)) {t | a + t • w ∈ U} := h.2 a ha w + +/-- The local submean property of the slice through a point of the domain. -/ +theorem PlurisubharmonicOn.hasSubmeanAt_slice (h : PlurisubharmonicOn f U) {a : E} (ha : a ∈ U) + (w : E) : HasSubmeanAt (fun t : ℂ => f (a + t • w)) 0 := + (h.slice ha w).hasSubmeanAt (by simpa using ha) + +/-- Plurisubharmonicity restricts to subsets. -/ +theorem PlurisubharmonicOn.mono (h : PlurisubharmonicOn f U) (hV : V ⊆ U) : + PlurisubharmonicOn f V := + ⟨h.1.mono hV, fun a ha w => (h.2 a (hV ha) w).mono fun _ ht => hV ht⟩ + +/-- The slice of an upper semicontinuous function is upper semicontinuous. -/ +theorem upperSemicontinuousOn_slice (h : UpperSemicontinuousOn f U) (a w : E) : + UpperSemicontinuousOn (fun t : ℂ => f (a + t • w)) {t | a + t • w ∈ U} := + h.comp (by fun_prop : Continuous fun t : ℂ => a + t • w).continuousOn fun _ ht => ht + +/-- Translating the parameter of a function with the local submean property. -/ +theorem HasSubmeanAt.comp_add_right {u : ℂ → ℝ} {t₀ : ℂ} + (h : HasSubmeanAt (fun t => u (t + t₀)) 0) : HasSubmeanAt u t₀ := by + filter_upwards [h] with r ⟨hint, hle⟩ + have hmap : ∀ θ : ℝ, circleMap 0 r θ + t₀ = circleMap t₀ r θ := fun θ => by + simp [circleMap, add_comm] + refine ⟨?_, ?_⟩ + · rw [circleIntegrable_def] at hint ⊢ + simpa only [hmap] using hint + · simpa only [zero_add, circleAverage_map_add_const] using hle + +/-- Plurisubharmonicity follows from upper semicontinuity and the local submean property of the +slices through each point of the domain. -/ +theorem plurisubharmonicOn_of_hasSubmeanAt (husc : UpperSemicontinuousOn f U) + (h : ∀ a ∈ U, ∀ w : E, HasSubmeanAt (fun t : ℂ => f (a + t • w)) 0) : + PlurisubharmonicOn f U := by + refine ⟨husc, fun a ha w => ⟨upperSemicontinuousOn_slice husc a w, fun t₀ ht₀ => ?_⟩⟩ + apply HasSubmeanAt.comp_add_right + have := h (a + t₀ • w) ht₀ w + convert this using 2 with t + simp only [add_smul, add_assoc, add_comm (t • w) (t₀ • w)] + +section Algebra + +/-- Constants are plurisubharmonic. -/ +theorem plurisubharmonicOn_const (c : ℝ) (U : Set E) : PlurisubharmonicOn (fun _ => c) U := + ⟨continuousOn_const.upperSemicontinuousOn, fun _ _ _ => subharmonicOn_const c _⟩ + +/-- Sums of plurisubharmonic functions are plurisubharmonic. -/ +theorem PlurisubharmonicOn.add (hf : PlurisubharmonicOn f U) (hg : PlurisubharmonicOn g U) : + PlurisubharmonicOn (fun z => f z + g z) U := + ⟨hf.1.add hg.1, fun a ha w => (hf.2 a ha w).add (hg.2 a ha w)⟩ + +/-- Nonnegative multiples of plurisubharmonic functions are plurisubharmonic. -/ +theorem PlurisubharmonicOn.const_mul {c : ℝ} (hc : 0 ≤ c) (hf : PlurisubharmonicOn f U) : + PlurisubharmonicOn (fun z => c * f z) U := + ⟨(hf.1.const_mul hc), fun a ha w => (hf.2 a ha w).const_mul hc⟩ + +/-- The pointwise maximum of two plurisubharmonic functions is plurisubharmonic. -/ +theorem PlurisubharmonicOn.sup (hf : PlurisubharmonicOn f U) (hg : PlurisubharmonicOn g U) : + PlurisubharmonicOn (fun z => max (f z) (g z)) U := + ⟨hf.1.sup hg.1, fun a ha w => (hf.2 a ha w).sup (hg.2 a ha w)⟩ + +/-- Plurisubharmonicity is preserved by complex affine substitutions. -/ +theorem PlurisubharmonicOn.comp_affine {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + (hf : PlurisubharmonicOn f U) (L : F →L[ℂ] E) (b : E) : + PlurisubharmonicOn (fun z => f (b + L z)) {z | b + L z ∈ U} := by + refine ⟨hf.1.comp (by fun_prop) fun _ hz => hz, fun a ha w => ?_⟩ + have := hf.2 (b + L a) ha (L w) + convert this using 2 with t <;> simp [map_add, map_smul, add_assoc] + +end Algebra + +section Convex + +/-- A continuous function that is convex on an open set of `ℂ` is subharmonic there. -/ +theorem _root_.ConvexOn.subharmonicOn {u : ℂ → ℝ} {W : Set ℂ} (hW : IsOpen W) + (hu : ConvexOn ℝ W u) (hc : ContinuousOn u W) : SubharmonicOn u W := by + refine ⟨hc.upperSemicontinuousOn, fun a ha => ?_⟩ + obtain ⟨ρ, hρ, hball⟩ := Metric.mem_nhds_iff.mp (hW.mem_nhds ha) + refine hasSubmeanAt_of_forall_lt hρ fun r hr hrρ => ?_ + have hsub : closedBall a r ⊆ W := (closedBall_subset_ball hrρ).trans hball + have hint : CircleIntegrable u a r := + (hc.mono (sphere_subset_closedBall.trans hsub)).circleIntegrable hr.le + have hrefl : ∀ t ∈ sphere a r, 2 * a - t ∈ sphere a r := by + intro t ht + rw [mem_sphere, dist_eq_norm] at ht ⊢ + rw [← ht, ← norm_neg] + congr 1 + ring + have hint' : CircleIntegrable (fun t => u (2 * a - t)) a r := by + refine ContinuousOn.circleIntegrable hr.le ?_ + exact (hc.mono (sphere_subset_closedBall.trans hsub)).comp (by fun_prop) fun t ht => + hrefl t (by simpa [abs_of_pos hr] using ht) + refine ⟨hint, ?_⟩ + have hmid : ∀ t ∈ sphere a r, u a ≤ (1 / 2 : ℝ) • u t + (1 / 2 : ℝ) • u (2 * a - t) := by + intro t ht + have h1 : t ∈ W := hsub (sphere_subset_closedBall ht) + have h2 : 2 * a - t ∈ W := hsub (sphere_subset_closedBall (hrefl t ht)) + have := hu.2 h1 h2 (by norm_num : (0 : ℝ) ≤ 1 / 2) (by norm_num : (0 : ℝ) ≤ 1 / 2) (by norm_num) + convert this using 2 + simp only [Complex.real_smul] + push_cast + ring + have hi₁ : CircleIntegrable (fun t => (1 / 2 : ℝ) • u t) a r := hint.const_smul + have hi₂ : CircleIntegrable (fun t => (1 / 2 : ℝ) • u (2 * a - t)) a r := hint'.const_smul + have hle := circleAverage_mono (circleIntegrable_const (u a) a r) (hi₁.add hi₂) + (fun t ht => hmid t (by simpa [abs_of_pos hr] using ht)) + rw [circleAverage_const, circleAverage_add hi₁ hi₂, circleAverage_fun_smul, + circleAverage_fun_smul, Real.circleAverage_reflect] at hle + simp only [smul_eq_mul] at hle + linarith + +/-- A real convex combination of two points of a complex line, in line coordinates. -/ +private theorem line_combo (a w : E) (s t : ℂ) {α β : ℝ} (hαβ : α + β = 1) : + a + (α • s + β • t) • w = α • (a + s • w) + β • (a + t • w) := by + have ha : a = α • a + β • a := by rw [← add_smul, hαβ, one_smul] + conv_lhs => rw [ha] + simp only [smul_add, add_smul, Complex.real_smul, mul_smul, Complex.coe_smul] + abel + +/-- A continuous convex function on an open set is plurisubharmonic. -/ +theorem _root_.ConvexOn.plurisubharmonicOn (hU : IsOpen U) (hf : ConvexOn ℝ U f) + (hc : ContinuousOn f U) : PlurisubharmonicOn f U := by + refine ⟨hc.upperSemicontinuousOn, fun a ha w => ?_⟩ + apply ConvexOn.subharmonicOn (hU.preimage (by fun_prop : Continuous fun t : ℂ => a + t • w)) + · refine ⟨fun s hs t ht α β hα hβ hαβ => ?_, fun s hs t ht α β hα hβ hαβ => ?_⟩ + · change a + (α • s + β • t) • w ∈ U + rw [line_combo a w s t hαβ] + exact hf.1 hs ht hα hβ hαβ + · have := hf.2 hs ht hα hβ hαβ + simpa only [line_combo a w s t hαβ] using this + · exact hc.comp (by fun_prop : Continuous fun t : ℂ => a + t • w).continuousOn fun _ ht => ht + +/-- The norm is plurisubharmonic. -/ +theorem plurisubharmonicOn_norm : PlurisubharmonicOn (fun z : E => ‖z‖) univ := + ConvexOn.plurisubharmonicOn isOpen_univ (convexOn_norm convex_univ) + continuous_norm.continuousOn + +end Convex + +section Holomorphic + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- The slice of a holomorphic map along a complex line is holomorphic. -/ +theorem analyticOnNhd_slice {h : E → F} (hh : AnalyticOnNhd ℂ h U) (a w : E) : + AnalyticOnNhd ℂ (fun t : ℂ => h (a + t • w)) {t | a + t • w ∈ U} := fun _ ht => + (hh _ ht).comp_of_eq (analyticAt_const.add (analyticAt_id.smul analyticAt_const)) rfl + +/-- Real parts of holomorphic functions are plurisubharmonic. -/ +theorem _root_.AnalyticOnNhd.plurisubharmonicOn_re {h : E → ℂ} (hh : AnalyticOnNhd ℂ h U) : + PlurisubharmonicOn (fun z => (h z).re) U := + ⟨(Complex.continuous_re.comp_continuousOn hh.continuousOn).upperSemicontinuousOn, + fun a _ w => AnalyticOnNhd.subharmonicOn_re (analyticOnNhd_slice hh a w)⟩ + +/-- Positive powers of the norm of a holomorphic map are plurisubharmonic. -/ +theorem _root_.AnalyticOnNhd.plurisubharmonicOn_norm_rpow (hU : IsOpen U) {h : E → F} {p : ℝ} + (hp : 0 < p) (hh : AnalyticOnNhd ℂ h U) : PlurisubharmonicOn (fun z => ‖h z‖ ^ p) U := + ⟨(hh.continuousOn.norm.rpow_const fun _ _ => Or.inr hp.le).upperSemicontinuousOn, + fun a _ w => AnalyticOnNhd.subharmonicOn_norm_rpow + (hU.preimage (by fun_prop : Continuous fun t : ℂ => a + t • w)) hp + (analyticOnNhd_slice hh a w)⟩ + +/-- The logarithm of the modulus of a nonvanishing holomorphic function is plurisubharmonic. -/ +theorem _root_.AnalyticOnNhd.plurisubharmonicOn_log_norm (hU : IsOpen U) {h : E → ℂ} + (hh : AnalyticOnNhd ℂ h U) (hne : ∀ z ∈ U, h z ≠ 0) : + PlurisubharmonicOn (fun z => Real.log ‖h z‖) U := + ⟨(ContinuousOn.log hh.continuousOn.norm fun z hz => + norm_ne_zero_iff.mpr (hne z hz)).upperSemicontinuousOn, + fun a _ w => AnalyticOnNhd.subharmonicOn_log_norm + (hU.preimage (by fun_prop : Continuous fun t : ℂ => a + t • w)) + (analyticOnNhd_slice hh a w) fun _ ht => hne _ ht⟩ + +end Holomorphic + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polydisc.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polydisc.lean new file mode 100644 index 0000000000..b5299517d1 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polydisc.lean @@ -0,0 +1,232 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.CauchyIntegral +public import Mathlib.MeasureTheory.Integral.TorusIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt + +/-! +# Polydiscs and distinguished boundaries + +Geometry for the polydisc Cauchy formula. Equal-radius polydiscs use the supremum norm; these +are not Euclidean balls. Origin-centred open and closed polydiscs are complete Reinhardt sets. +Containment of the closed polydisc determined by each point's moduli characterizes the complete +Reinhardt property. + +## Notation + +`polydisc c r` and `closedPolydisc c r` are products of coordinate balls of radii `r i`. The +definitions and their elementary topology allow any family of pseudo-metric spaces as factors; the +Reinhardt and torus statements are specific to `ℂ`. The equal-radius case `r = fun _ => R` coincides +with the sup-norm ball; see `polydisc_const_eq_ball` and `closedPolydisc_eq_closedBall`. The +distinguished boundary is parametrized by `torusMap`. + +## Main results + +`isCompleteReinhardt_iff_closedPolydisc_subset` characterizes complete Reinhardt sets. +`polydisc_const_eq_ball` identifies equal positive radii with the open sup-norm ball. +`closure_polydisc` identifies the closure of a positive-radius open polydisc with the +corresponding closed polydisc. +-/ + +public section + +open Complex Filter Function MeasureTheory Metric Set +open scoped ENNReal NNReal Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-! +### Closed polydiscs +-/ + +/-- An open polydisc with a separate radius in each coordinate: the product of the open balls +`ball (c i) (r i)`. The factors may be any pseudo-metric spaces; the several-complex-variables +theory uses `X i = ℂ`. -/ +@[expose] def polydisc {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + (c : ∀ i, X i) (r : ι → ℝ) : Set (∀ i, X i) := + Set.pi univ fun i => ball (c i) (r i) + +/-- A closed polydisc with a separate radius in each coordinate: the product of the closed balls +`closedBall (c i) (r i)`. -/ +@[expose] def closedPolydisc {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + (c : ∀ i, X i) (r : ι → ℝ) : Set (∀ i, X i) := + Set.pi univ fun i => closedBall (c i) (r i) + +/-- Membership in a polydisc is a coordinatewise strict distance bound. -/ +@[simp] lemma mem_polydisc {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + {c z : ∀ i, X i} {r : ι → ℝ} : + z ∈ polydisc c r ↔ ∀ i, dist (z i) (c i) < r i := by + simp [polydisc, mem_ball] + +/-- Membership in a closed polydisc is a coordinatewise non-strict distance bound. -/ +@[simp] lemma mem_closedPolydisc {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + {c z : ∀ i, X i} {r : ι → ℝ} : + z ∈ closedPolydisc c r ↔ ∀ i, dist (z i) (c i) ≤ r i := by + simp [closedPolydisc, mem_closedBall] + +/-- Every origin-centred open polydisc is complete Reinhardt, even with nonpositive radii. -/ +theorem isCompleteReinhardt_polydisc {ι : Type*} (r : ι → ℝ) : + IsCompleteReinhardt (polydisc (0 : ι → ℂ) r) := by + intro z hz w hw + simp only [mem_polydisc, Pi.zero_apply, dist_zero_right] at hz ⊢ + exact fun i => (hw i).trans_lt (hz i) + +/-- Every origin-centred closed polydisc is complete Reinhardt, including degenerate ones. -/ +theorem isCompleteReinhardt_closedPolydisc {ι : Type*} (r : ι → ℝ) : + IsCompleteReinhardt (closedPolydisc (0 : ι → ℂ) r) := by + intro z hz w hw + simp only [mem_closedPolydisc, Pi.zero_apply, dist_zero_right] at hz ⊢ + exact fun i => (hw i).trans (hz i) + +/-- Completeness means containing the closed polydisc determined by each point's moduli. -/ +theorem isCompleteReinhardt_iff_closedPolydisc_subset {ι : Type*} + {U : Set (ι → ℂ)} : + IsCompleteReinhardt U ↔ + ∀ z ∈ U, closedPolydisc 0 (fun i => ‖z i‖) ⊆ U := by + simp only [IsCompleteReinhardt, Set.subset_def, mem_closedPolydisc, + Pi.zero_apply, dist_zero_right] + +/-- An origin-centred open polydisc has independent coordinate rotation symmetry. -/ +theorem isReinhardt_polydisc {ι : Type*} (r : ι → ℝ) : + IsReinhardt (polydisc (0 : ι → ℂ) r) := + (isCompleteReinhardt_polydisc r).isReinhardt + +/-- An origin-centred closed polydisc has independent coordinate rotation symmetry. -/ +theorem isReinhardt_closedPolydisc {ι : Type*} (r : ι → ℝ) : + IsReinhardt (closedPolydisc (0 : ι → ℂ) r) := + (isCompleteReinhardt_closedPolydisc r).isReinhardt + +/-- Open origin-centred polydiscs are logarithmically convex, with arbitrary real radii. -/ +theorem isLogarithmicallyConvex_polydisc {ι : Type*} (r : ι → ℝ) : + IsLogarithmicallyConvex (polydisc (0 : ι → ℂ) r) := by + intro x hx y hy a b ha hb hab + simp only [logarithmicImage, Set.mem_ofPred_eq, mem_polydisc, + Pi.zero_apply, dist_zero_right] at hx hy ⊢ + intro i + have h := (convexOn_exp.convex_lt (r i)) + ⟨Set.mem_univ _, by simpa using hx i⟩ ⟨Set.mem_univ _, by simpa using hy i⟩ ha hb hab + simpa only [Pi.add_apply, Pi.smul_apply, smul_eq_mul, + Complex.norm_of_nonneg (Real.exp_nonneg _)] using h.2 + +/-- Closed origin-centred polydiscs are logarithmically convex, including degenerate ones. -/ +theorem isLogarithmicallyConvex_closedPolydisc {ι : Type*} (r : ι → ℝ) : + IsLogarithmicallyConvex (closedPolydisc (0 : ι → ℂ) r) := by + intro x hx y hy a b ha hb hab + simp only [logarithmicImage, Set.mem_ofPred_eq, mem_closedPolydisc, + Pi.zero_apply, dist_zero_right] at hx hy ⊢ + intro i + have h := (convexOn_exp.convex_le (r i)) + ⟨Set.mem_univ _, by simpa using hx i⟩ ⟨Set.mem_univ _, by simpa using hy i⟩ ha hb hab + simpa only [Pi.add_apply, Pi.smul_apply, smul_eq_mul, + Complex.norm_of_nonneg (Real.exp_nonneg _)] using h.2 + +/-- A finite-dimensional polydisc is open. -/ +theorem isOpen_polydisc {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + [Finite ι] (c : ∀ i, X i) (r : ι → ℝ) : + IsOpen (polydisc c r) := by + change IsOpen (Set.pi univ fun i => ball (c i) (r i)) + exact isOpen_set_pi finite_univ (fun _ _ => isOpen_ball) + +/-- A closed polydisc in a product of proper spaces is compact, by the product compactness +theorem. -/ +theorem isCompact_closedPolydisc {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + [∀ i, ProperSpace (X i)] (c : ∀ i, X i) (r : ι → ℝ) : + IsCompact (closedPolydisc c r) := + isCompact_univ_pi fun i => isCompact_closedBall (c i) (r i) + +/-- The closure of a positive-radius polydisc is the corresponding closed polydisc. -/ +theorem closure_polydisc {ι : Type*} (c : ι → ℂ) {r : ι → ℝ} + (hr : ∀ i, 0 < r i) : + closure (polydisc c r) = closedPolydisc c r := by + simp only [polydisc, closedPolydisc, closure_pi_set, + closure_ball _ (ne_of_gt (hr _))] + +/-- In finite coordinates, equal positive radii give the open ball for the supremum norm. -/ +theorem polydisc_const_eq_ball {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + [Fintype ι] (c : ∀ i, X i) {R : ℝ} (hR : 0 < R) : polydisc c (fun _ => R) = ball c R := + (ball_pi c hR).symm + +/-- Enlarging every radius enlarges the polydisc. -/ +theorem polydisc_mono {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + (c : ∀ i, X i) {r s : ι → ℝ} (hrs : ∀ i, r i ≤ s i) : polydisc c r ⊆ polydisc c s := by + intro z hz + exact mem_polydisc.mpr fun i => (mem_polydisc.mp hz i).trans_le (hrs i) + +/-- Strictly smaller closed coordinate discs lie in the larger open polydisc. -/ +theorem closedPolydisc_subset_polydisc {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + (c : ∀ i, X i) {r s : ι → ℝ} (hrs : ∀ i, r i < s i) : + closedPolydisc c r ⊆ polydisc c s := by + intro z hz + exact mem_polydisc.mpr fun i => (mem_closedPolydisc.mp hz i).trans_lt (hrs i) + +/-- The torus parametrization with separate coordinate radii is continuous. -/ +theorem continuous_torusMap {n : ℕ} (c : Fin n → ℂ) (r : Fin n → ℝ) : + Continuous (torusMap c r) := by + apply continuous_pi + intro i + simp only [torusMap] + fun_prop + +/-- Each torus coordinate has the prescribed nonnegative radius. -/ +theorem norm_torusMap_sub {n : ℕ} {c : Fin n → ℂ} {r : Fin n → ℝ} + (hr : ∀ i, 0 ≤ r i) (θ : Fin n → ℝ) (i : Fin n) : + ‖torusMap c r θ i - c i‖ = r i := by + simp [torusMap, abs_of_nonneg (hr i)] + +/-- A torus with nonnegative radii belongs to its closed polydisc. -/ +theorem torusMap_mem_closedPolydisc {n : ℕ} {c : Fin n → ℂ} {r : Fin n → ℝ} + (hr : ∀ i, 0 ≤ r i) (θ : Fin n → ℝ) : + torusMap c r θ ∈ closedPolydisc c r := by + exact mem_closedPolydisc.mpr fun i => by + rw [dist_eq_norm, norm_torusMap_sub hr] + +/-- A Cauchy kernel has no pole on a coordinate circle when evaluated inside the polydisc. -/ +theorem torusMap_apply_ne_of_norm_sub_lt {n : ℕ} {c w : Fin n → ℂ} + {r : Fin n → ℝ} {θ : Fin n → ℝ} {i : Fin n} + (hr : ∀ i, 0 < r i) (hw : ‖w i - c i‖ < r i) : torusMap c r θ i ≠ w i := by + intro h + have H := norm_torusMap_sub (c := c) (fun j => (hr j).le) θ i + rw [h] at H + exact hw.ne H + +/-- Membership of a coordinate and the tail gives membership of the full polydisc. -/ +theorem cons_mem_closedPolydisc {n : ℕ} {c : Fin (n + 1) → ℂ} + {r : Fin (n + 1) → ℝ} {x : ℂ} {y : Fin n → ℂ} + (hx : x ∈ closedBall (c 0) (r 0)) + (hy : y ∈ closedPolydisc (c ∘ Fin.succ) (r ∘ Fin.succ)) : + Fin.cons x y ∈ closedPolydisc c r := by + intro i _ + refine Fin.cases ?_ ?_ i + · simpa using hx + · intro j + simpa using hy j (mem_univ _) + +/-- An equal-radius closed polydisc is the closed ball for the supremum norm. -/ +theorem closedPolydisc_eq_closedBall {ι : Type*} {X : ι → Type*} [∀ i, PseudoMetricSpace (X i)] + [Fintype ι] {c : ∀ i, X i} {R : ℝ} (hR : 0 ≤ R) : + closedPolydisc c (fun _ => R) = closedBall c R := + (closedBall_pi c hR).symm + +/-- The standard equal-radius torus parametrization is continuous. -/ +theorem continuous_torusMap_const {n : ℕ} (c : Fin n → ℂ) (R : ℝ) : + Continuous (torusMap c (fun _ => R)) := + continuous_pi fun i => by + simp only [torusMap] + fun_prop + +/-- No natural-number power of `2 * π * I` vanishes. -/ +theorem _root_.Complex.two_pi_I_pow_ne_zero (n : ℕ) : ((2 * π * I : ℂ) ^ n) ≠ 0 := + pow_ne_zero _ two_pi_I_ne_zero + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolydiscMeanValue.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolydiscMeanValue.lean new file mode 100644 index 0000000000..a866b0a28e --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolydiscMeanValue.lean @@ -0,0 +1,186 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.MeanValue +public import Mathlib.MeasureTheory.Constructions.Pi +public import Mathlib.MeasureTheory.Integral.Prod +public import Mathlib.MeasureTheory.Measure.Haar.InnerProductSpace +public import Mathlib.MeasureTheory.Measure.Lebesgue.Complex +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyIntegral + +/-! +# Torus and volume mean values on polydiscs + +The fixed-radius torus average of a holomorphic function equals its value at the center, for +every valid radius. This is the plain Bochner-integral average, with no residual Jacobian +factor: the complex contour normalization in `torusIntegral` cancels exactly at the center. +Averaging common complex rotations and applying Fubini also gives the volume mean-value formula +on equal-radius polydiscs. This formula supports the local `Lp` estimate on holomorphic function +spaces. Arbitrary finite coordinate types, including the empty type, are allowed in the volume +formula. + +## Main results + +* `torusAverage_eq_center`: At the center of a polydisc, the fixed-radius torus average is a plain + Bochner-integral average of the function over the angle cube, with no Jacobian residue. +* `integral_closedBall_zero_eq_volume_smul`: Averaging a holomorphic function over an equal-radius + polydisc centered at zero returns its center value times the volume. +* `integral_closedBall_eq_volume_smul`: The volume mean-value formula on an equal-radius polydisc + with arbitrary center. +-/ + +public section + +open Complex Filter Function MeasureTheory Metric Set +open scoped ENNReal NNReal Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-- At the center of a polydisc, the fixed-radius torus average is a plain Bochner-integral average +of the function over the angle cube, with no Jacobian residue. -/ +theorem torusAverage_eq_center {d : ℕ} {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} {R : Fin d → ℝ} + (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) : + ∫ θ in Set.Icc (0 : Fin d → ℝ) (fun _ => 2 * π), f (torusMap c R θ) = + (2 * π : ℂ) ^ d • f c := by + have hw : ∀ i, ‖c i - c i‖ < R i := fun i => by simpa using hR i + have hkey := two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul hR hw hfc hfa + rw [torusIntegral] at hkey + have hkernel : Set.EqOn + (fun θ : Fin d → ℝ => (∏ i, (R i : ℂ) * Complex.exp ((θ i : ℂ) * I) * I) • + ((∏ i, (torusMap c R θ i - c i)⁻¹) • f (torusMap c R θ))) + (fun θ : Fin d → ℝ => (I : ℂ) ^ d • f (torusMap c R θ)) + (Set.Icc (0 : Fin d → ℝ) fun _ => 2 * π) := by + intro θ _ + simp only + rw [smul_smul] + congr 1 + rw [← Finset.prod_mul_distrib] + rw [show (I : ℂ) ^ d = ∏ _i : Fin d, I by simp] + apply Finset.prod_congr rfl + intro i _ + have hRi : (R i : ℂ) ≠ 0 := Complex.ofReal_ne_zero.mpr (hR i).ne' + have hzc : torusMap c R θ i - c i = R i * Complex.exp ((θ i : ℂ) * I) := by + simp [torusMap] + rw [hzc] + have hexp : Complex.exp ((θ i : ℂ) * I) ≠ 0 := Complex.exp_ne_zero _ + field_simp + rw [MeasureTheory.setIntegral_congr_fun measurableSet_Icc hkernel, + MeasureTheory.integral_smul] at hkey + have hI : ((2 * π * I : ℂ) ^ d)⁻¹ • ((I : ℂ) ^ d • + ∫ θ in Set.Icc (0 : Fin d → ℝ) fun _ => 2 * π, f (torusMap c R θ)) = f c := hkey + have hIpow : ((2 * π * I : ℂ) ^ d)⁻¹ * (I : ℂ) ^ d = ((2 * π : ℂ) ^ d)⁻¹ := by + rw [mul_pow] + field_simp + rw [smul_smul, hIpow] at hI + have h2π : ((2 * π : ℂ) ^ d) ≠ 0 := by + apply pow_ne_zero + exact_mod_cast (by positivity : (2 * π : ℝ) ≠ 0) + have := congrArg (fun x => (2 * π : ℂ) ^ d • x) hI + simpa [smul_smul, h2π] using this + +omit [CompleteSpace E] in +/-- A common unit complex rotation preserves integration over a centered polydisc. -/ +private theorem integral_closedBall_smul {ι : Type*} [Fintype ι] + (f : (ι → ℂ) → E) (r : ℝ) {w : ℂ} (hw : ‖w‖ = 1) : + ∫ z in closedBall (0 : ι → ℂ) r, f (w • z) = + ∫ z in closedBall (0 : ι → ℂ) r, f z := by + have hw0 : w ≠ 0 := by intro h; simp [h] at hw + let e : ℂ ≃ₗᵢ[ℝ] ℂ := + { (LinearEquiv.smulOfNeZero ℂ ℂ w hw0).restrictScalars ℝ with + norm_map' := fun z => by simp [LinearEquiv.smulOfNeZero_apply, hw] } + let ePi := MeasurableEquiv.piCongrRight (fun _ : ι => e.toMeasurableEquiv) + have hm : MeasurePreserving (fun z : ι → ℂ => w • z) volume volume := + volume_preserving_pi (fun _ : ι => e.measurePreserving) + have hpre : (fun z : ι → ℂ => w • z) ⁻¹' closedBall 0 r = closedBall 0 r := by + ext z + simp [mem_closedBall, dist_zero_right, norm_smul, hw] + simpa only [hpre] using + hm.setIntegral_preimage_emb ePi.measurableEmbedding f (closedBall 0 r) + +/-- Averaging a holomorphic function over an equal-radius polydisc centered at zero returns its +center value times the volume. The proof averages common complex rotations and uses Fubini; it +also applies when the coordinate type is empty. -/ +theorem integral_closedBall_zero_eq_volume_smul {ι : Type*} [Fintype ι] + {f : (ι → ℂ) → E} {r : ℝ} + (hf : AnalyticOnNhd ℂ f (closedBall 0 r)) : + ∫ z in closedBall (0 : ι → ℂ) r, f z = + volume.real (closedBall (0 : ι → ℂ) r) • f 0 := by + let B := closedBall (0 : ι → ℂ) r + let T := Icc (0 : ℝ) (2 * π) + let H := fun (z : ι → ℂ) (θ : ℝ) => f (circleMap 0 1 θ • z) + have hrot (θ : ℝ) : ‖circleMap 0 1 θ‖ = 1 := by simp + have hmap : MapsTo (fun p : (ι → ℂ) × ℝ => circleMap 0 1 p.2 • p.1) (B ×ˢ T) B := by + intro p hp + simpa only [B, mem_closedBall, dist_zero_right, norm_smul, hrot, one_mul] using hp.1 + have hcont : ContinuousOn (Function.uncurry H) (B ×ˢ T) := + hf.continuousOn.comp (by fun_prop) hmap + have hint : Integrable (Function.uncurry H) + ((volume.restrict B).prod (volume.restrict T)) := by + rw [Measure.prod_restrict, ← Measure.volume_eq_prod] + exact hcont.integrableOn_compact ((isCompact_closedBall _ _).prod isCompact_Icc) + have hmean (z : ι → ℂ) (hz : z ∈ B) : + ∫ θ in T, H z θ = (2 * π) • f 0 := by + have hline : DifferentiableOn ℂ (fun w : ℂ => f (w • z)) (closedBall 0 1) := by + intro w hw + have hwz : w • z ∈ closedBall (0 : ι → ℂ) r := by + rw [mem_closedBall, dist_zero_right, norm_smul] + exact (mul_le_mul_of_nonneg_right (mem_closedBall_zero_iff.mp hw) (norm_nonneg z)).trans + (by simpa [B] using hz) + have hmap : AnalyticAt ℂ (fun t : ℂ => t • z) w := + analyticAt_id.smul analyticAt_const + exact ((hf _ hwz).comp_of_eq hmap rfl).differentiableWithinAt + have hline' : DifferentiableOn ℂ (fun w : ℂ => f (w • z)) + (closure (ball 0 |(1 : ℝ)|)) := by + simpa only [abs_one, closure_ball _ one_ne_zero] using hline + have h := hline'.diffContOnCl.circleAverage + simp only [Real.circleAverage, zero_smul] at h + rw [intervalIntegral.integral_of_le Real.two_pi_pos.le, ← integral_Icc_eq_integral_Ioc] at h + have he := congrArg (fun v : E => (2 * π) • v) h + simpa only [smul_smul, mul_inv_cancel₀ Real.two_pi_pos.ne', one_smul] using he + have hswap := integral_integral_swap hint + have hleft : (∫ z in B, ∫ θ in T, H z θ) = + (2 * π) • (volume.real B • f 0) := by + rw [setIntegral_congr_fun measurableSet_closedBall hmean, integral_const] + simp only [Measure.real, Measure.restrict_apply_univ] + exact smul_comm _ _ _ + have hright : (∫ θ in T, ∫ z in B, H z θ) = + (2 * π) • (∫ z in B, f z) := by + simp_rw [H, B, integral_closedBall_smul f r (hrot _)] + simp [T, integral_const, Real.volume_Icc, Measure.real, ENNReal.toReal_ofReal Real.pi_pos.le] + rw [hleft, hright] at hswap + exact (smul_right_injective E Real.two_pi_pos.ne' hswap).symm + +/-- The volume mean-value formula on an equal-radius polydisc with arbitrary center. The norm on the +finite coordinate space is the supremum norm. -/ +theorem integral_closedBall_eq_volume_smul {ι : Type*} [Fintype ι] + {f : (ι → ℂ) → E} {c : ι → ℂ} {r : ℝ} + (hf : AnalyticOnNhd ℂ f (closedBall c r)) : + ∫ z in closedBall c r, f z = volume.real (closedBall c r) • f c := by + have hpre : (fun z : ι → ℂ => c + z) ⁻¹' closedBall c r = closedBall 0 r := by + ext z + simp [mem_closedBall, dist_eq_norm] + have hvol : volume (closedBall (0 : ι → ℂ) r) = volume (closedBall c r) := by + rw [← hpre] + exact measure_preimage_add volume c _ + have hm := (measurePreserving_add_left (volume : Measure (ι → ℂ)) c).setIntegral_preimage_emb + (Homeomorph.addLeft c).isClosedEmbedding.measurableEmbedding f (closedBall c r) + rw [hpre] at hm + have htrans : AnalyticOnNhd ℂ (fun z => f (c + z)) (closedBall (0 : ι → ℂ) r) := by + intro z hz + have hcz : c + z ∈ closedBall c r := by simpa [mem_closedBall, dist_eq_norm] using hz + exact (hf _ hcz).comp (analyticAt_const.add analyticAt_id) + rw [← hm, integral_closedBall_zero_eq_volume_smul htrans, Measure.real, hvol, add_zero] + rfl + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolydiscTaylor.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolydiscTaylor.lean new file mode 100644 index 0000000000..62c7df94b9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolydiscTaylor.lean @@ -0,0 +1,334 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.RingTheory.MvPowerSeries.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyCoefficients +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform + +/-! +# Taylor expansions on polydiscs with separate radii + +The multi-index Cauchy series converges throughout its open polydisc, not merely on the largest +inscribed equal-radius ball. Convergence is uniform on smaller closed polydiscs and locally +uniform on the full open polydisc, also after mixed differentiation. Explicit geometric-tail +estimates control the remainder after any finite set of multi-indices. Scalar Taylor +coefficients also define an element of Mathlib's `MvPowerSeries`. + +## Main definitions + +* `holomorphicTaylorSeries`: The Taylor series of a Banach-valued function as a Mathlib multivariate + formal power series: the normalized mixed derivatives at the center. + +## Main results + +* `hasSum_polydiscTaylor`: The full multi-index Taylor expansion on a polydisc with separate radii. +* `hasSumLocallyUniformlyOn_polydiscTaylor`: The multi-index Taylor expansion converges locally + uniformly throughout its polydisc. +* `norm_polydiscTaylor_remainder_le`: A uniform remainder bound for any finite Taylor polynomial. +* `hasSumLocallyUniformlyOn_iteratedPartialDeriv_polydiscTaylor`: Any mixed derivative of the + separate-radius Taylor expansion is obtained by termwise differentiation, with locally uniform + convergence on the full open polydisc. +-/ + +public noncomputable section + +open Complex Filter Function MeasureTheory Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {d : ℕ} {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + +/-- The Taylor series of a Banach-valued function as a Mathlib multivariate formal power series: the +normalized mixed derivatives at the center. -/ +@[expose] def holomorphicTaylorSeries (f : (Fin d → ℂ) → E) (c : Fin d → ℂ) : MvPowerSeries + (Fin d) E := + fun m => (∏ i, (m i).factorial : ℂ)⁻¹ • multiIndexDeriv m f c + +/-- Formal Taylor coefficients coincide with the integral Cauchy coefficients. -/ +theorem coeff_holomorphicTaylorSeries {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} + {R : Fin d → ℝ} (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) (m : Fin d →₀ ℕ) : + holomorphicTaylorSeries f c m = polydiscCauchyCoeffWithRadii f c R m := by + exact (polydiscCauchyCoeffWithRadii_eq_multiIndexDeriv hR hfc hfa m).symm + +/-- The ungrouped multi-index geometric expansion of the Cauchy kernel. -/ +theorem hasSum_multiIndex_cauchyKernel {z c h : Fin d → ℂ} + (hz : ∀ i, z i ≠ c i) (hh : ∀ i, ‖h i‖ < ‖z i - c i‖) : + HasSum (fun m : Fin d → ℕ => (∏ i, h i ^ m i) * cauchyKernel m c z) + (∏ i, (z i - (c + h) i)⁻¹) := by + have hx : ∀ i, ‖h i / (z i - c i)‖ < 1 := by + intro i + rw [norm_div, div_lt_one (norm_pos_iff.mpr (sub_ne_zero.mpr (hz i)))] + exact hh i + have hs := (hasSum_pi_geometric (fun i => h i / (z i - c i)) hx).mul_right + (∏ i, (z i - c i)⁻¹) + have hterm (m : Fin d → ℕ) : (∏ i, h i ^ m i) * cauchyKernel m c z = + (∏ i, (h i / (z i - c i)) ^ m i) * ∏ i, (z i - c i)⁻¹ := by + rw [cauchyKernel, ← Finset.prod_mul_distrib, ← Finset.prod_mul_distrib] + apply Finset.prod_congr rfl + intro i hi + rw [pow_succ, div_pow, inv_pow] + field_simp [sub_ne_zero.mpr (hz i)] + have hconst : (∏ i, (z i - (c + h) i)⁻¹) = + (∏ i, (1 - h i / (z i - c i))⁻¹) * ∏ i, (z i - c i)⁻¹ := by + rw [← Finset.prod_mul_distrib] + apply Finset.prod_congr rfl + intro i hi + have hzi : z i - c i ≠ 0 := sub_ne_zero.mpr (hz i) + have hzih : z i - (c + h) i ≠ 0 := by + intro heq + have he : z i - c i = h i := by + have H := sub_eq_zero.mp heq + simp only [Pi.add_apply] at H + linear_combination H + exact (hh i).ne (congrArg norm he.symm) + simp only [Pi.add_apply] + field_simp [hzi, hzih] + ring + simpa only [hterm, hconst] using hs + +omit [CompleteSpace E] in +/-- Every higher Cauchy kernel times a continuous function is integrable on its contour. -/ +theorem torusIntegrable_cauchyKernel_multi {f : (Fin d → ℂ) → E} + {c w : Fin d → ℂ} {R : Fin d → ℝ} (hR : ∀ i, 0 < R i) + (hw : w ∈ polydisc c R) + (hfc : ContinuousOn f (closedPolydisc c R)) (m : Fin d → ℕ) : + TorusIntegrable (fun z => cauchyKernel m w z • f z) c R := by + have hfθ : ContinuousOn (fun θ => f (torusMap c R θ)) + (Icc (0 : Fin d → ℝ) (fun _ => 2 * π)) := + hfc.comp (continuous_torusMap c R).continuousOn + (fun θ _ => torusMap_mem_closedPolydisc (fun i => (hR i).le) θ) + have hk : ContinuousOn (fun θ => cauchyKernel m w (torusMap c R θ)) + (Icc (0 : Fin d → ℝ) (fun _ => 2 * π)) := by + apply continuousOn_finsetProd + intro i hi + apply ContinuousOn.pow + refine (((continuous_apply i).comp (continuous_torusMap c R)).continuousOn.sub + continuousOn_const).inv₀ (fun θ hθ => ?_) + exact sub_ne_zero.mpr (torusMap_apply_ne_of_norm_sub_lt hR + (by simpa [dist_eq_norm] using mem_polydisc.mp hw i)) + exact (hk.smul hfθ).integrableOn_compact isCompact_Icc + +omit [CompleteSpace E] in +/-- Bound for the Cauchy–Taylor integrand on the distinguished boundary. -/ +private theorem norm_cauchyTaylor_integrand_le {f : (Fin d → ℂ) → E} + {c h : Fin d → ℂ} {R : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) + (m : Fin d → ℕ) (θ : Fin d → ℝ) : + ‖(∏ i, h i ^ m i) • cauchyKernel m c (torusMap c R θ) • f (torusMap c R θ)‖ ≤ + (M * ∏ i, (R i)⁻¹) * ∏ i, (‖h i‖ / R i) ^ m i := by + calc + _ = (∏ i, ‖h i‖ ^ m i) * (∏ i, (R i)⁻¹ ^ (m i + 1)) * ‖f (torusMap c R θ)‖ := by + simp only [norm_smul, cauchyKernel, norm_prod, norm_pow, norm_inv, + norm_torusMap_sub (fun i => (hR i).le), mul_assoc] + _ ≤ (∏ i, ‖h i‖ ^ m i) * (∏ i, (R i)⁻¹ ^ (m i + 1)) * M := + mul_le_mul_of_nonneg_left + (hM _ (torusMap_mem_closedPolydisc (fun i => (hR i).le) θ)) + (mul_nonneg (Finset.prod_nonneg fun i _ => pow_nonneg (norm_nonneg _) _) + (Finset.prod_nonneg fun i _ => pow_nonneg (inv_nonneg.mpr (hR i).le) _)) + _ = _ := by + simp only [div_eq_mul_inv, mul_pow, pow_succ, Finset.prod_mul_distrib] + ring + +/-- The full multi-index Taylor expansion on a polydisc with separate radii. The sum is indexed by +all multi-indices, and therefore does not depend on a summation order. -/ +theorem hasSum_polydiscTaylor {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} + {R : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) (hh : ∀ i, ‖h i‖ < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) : + HasSum (fun m : Fin d → ℕ => (∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m) + (f (c + h)) := by + let T (m : Fin d → ℕ) (z : Fin d → ℂ) := (∏ i, h i ^ m i) • cauchyKernel m c z • f z + let a (m : Fin d → ℕ) := (M * ∏ i, (R i)⁻¹) * ∏ i, (‖h i‖ / R i) ^ m i + have hq : ∀ i, ‖‖h i‖ / R i‖ < 1 := by + intro i + rw [Real.norm_eq_abs, abs_of_nonneg (div_nonneg (norm_nonneg _) (hR i).le), div_lt_one (hR i)] + exact hh i + have ha : Summable a := (hasSum_pi_geometric (fun i => ‖h i‖ / R i) hq).summable.mul_left _ + have hc : c ∈ polydisc c R := mem_polydisc.mpr (by simpa using hR) + have hTi (m : Fin d → ℕ) : TorusIntegrable (T m) c R := + (torusIntegrable_cauchyKernel_multi hR hc hfc m).smul (∏ i, h i ^ m i) + have hs := hasSum_torusIntegral_of_uniform (g := fun z => (∏ i, (z i - (c + h) i)⁻¹) • f z) + ha hTi (fun m θ => norm_cauchyTaylor_integrand_le hR hM m θ) (fun θ => by + have hz : ∀ i, torusMap c R θ i ≠ c i := by + intro i hi + have H := norm_torusMap_sub (c := c) (fun i => (hR i).le) θ i + rw [hi, sub_self, norm_zero] at H + exact (hR i).ne' H.symm + have H := hasSum_multiIndex_cauchyKernel (h := h) hz (fun i => by + rw [norm_torusMap_sub (fun i => (hR i).le)]; exact hh i) + simpa only [T, smul_smul, smul_eq_mul] using H.smul_const (f (torusMap c R θ))) + have hn := hs.const_smul (((2 * π * I : ℂ) ^ d)⁻¹) + have hterm (m : Fin d → ℕ) : (∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m = + (((2 * π * I : ℂ) ^ d)⁻¹) • torusIntegral (T m) c R := by + dsimp only [polydiscCauchyCoeffWithRadii, polydiscCauchyTransform, T] + rw [torusIntegral_smul] + exact smul_comm _ _ _ + rw [two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul hR (fun i => by simpa using hh i) hfc + hfa] at hn + simpa only [hterm] using hn + +omit [CompleteSpace E] in +/-- A summable geometric majorant for individual Taylor terms on a smaller closed polydisc. -/ +theorem norm_polydiscTaylor_term_le {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} + {R s : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) (hM0 : 0 ≤ M) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) + (hh : ∀ i, ‖h i‖ ≤ s i) (m : Fin d → ℕ) : + ‖(∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m‖ ≤ + M * ∏ i, (s i / R i) ^ m i := by + calc + _ ≤ (∏ i, ‖h i‖ ^ m i) * (M * ∏ i, (R i)⁻¹ ^ m i) := by + rw [norm_smul, norm_prod] + simp only [norm_pow] + exact mul_le_mul_of_nonneg_left (norm_polydiscCauchyCoeffWithRadii_le hR hM m) + (Finset.prod_nonneg fun i _ => pow_nonneg (norm_nonneg _) _) + _ = M * ∏ i, (‖h i‖ / R i) ^ m i := by + simp only [div_eq_mul_inv, mul_pow, Finset.prod_mul_distrib] + ring + _ ≤ _ := by + apply mul_le_mul_of_nonneg_left _ hM0 + apply Finset.prod_le_prod₀ + · intro i hi + exact pow_nonneg (div_nonneg (norm_nonneg _) (hR i).le) _ + · intro i hi + exact pow_le_pow_left₀ (div_nonneg (norm_nonneg _) (hR i).le) + (div_le_div_of_nonneg_right (hh i) (hR i).le) _ + +/-- Uniform convergence of the Taylor series on every strictly smaller closed polydisc. -/ +theorem hasSumUniformlyOn_polydiscTaylor {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} + {R s : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) + (hs : ∀ i, 0 ≤ s i) (hsR : ∀ i, s i < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) : + HasSumUniformlyOn + (fun (m : Fin d → ℕ) h => (∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m) + (fun h => f (c + h)) (closedPolydisc 0 s) := by + have hM0 : 0 ≤ M := (norm_nonneg (f c)).trans + (hM c (mem_closedPolydisc.mpr (by simpa using fun i => (hR i).le))) + have hq : ∀ i, ‖s i / R i‖ < 1 := by + intro i + rw [Real.norm_eq_abs, abs_of_nonneg (div_nonneg (hs i) (hR i).le), div_lt_one (hR i)] + exact hsR i + have ha := (hasSum_pi_geometric (fun i => s i / R i) hq).summable.mul_left M + apply hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + refine (tendstoUniformlyOn_tsum ha (fun m h hh => + norm_polydiscTaylor_term_le hR hM0 hM + (fun i => by simpa using mem_closedPolydisc.mp hh i) m)).congr_right ?_ + intro h hh + exact (hasSum_polydiscTaylor hR (fun i => + (show ‖h i‖ ≤ s i by simpa using mem_closedPolydisc.mp hh i).trans_lt (hsR i)) + hfc hfa hM).tsum_eq + +/-- The multi-index Taylor expansion converges locally uniformly throughout its polydisc. -/ +theorem hasSumLocallyUniformlyOn_polydiscTaylor {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} + {R : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) : + HasSumLocallyUniformlyOn + (fun (m : Fin d → ℕ) h => (∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m) + (fun h => f (c + h)) (polydisc 0 R) := by + apply hasSumLocallyUniformlyOn_of_of_forall_exists_nhds + intro h hh + let s (i : Fin d) := (‖h i‖ + R i) / 2 + have hhR (i) : ‖h i‖ < R i := by simpa using mem_polydisc.mp hh i + have hs (i) : 0 ≤ s i := by dsimp [s]; linarith [norm_nonneg (h i), hR i] + have hsR (i) : s i < R i := by dsimp [s]; linarith [hhR i] + have hhs : h ∈ polydisc 0 s := mem_polydisc.mpr (by + intro i; simp only [Pi.zero_apply, dist_zero_right]; dsimp [s]; linarith [hhR i]) + refine ⟨closedPolydisc 0 s, ?_, + hasSumUniformlyOn_polydiscTaylor hR hs hsR hfc hfa hM⟩ + apply mem_nhdsWithin_of_mem_nhds + exact Filter.mem_of_superset ((isOpen_polydisc 0 s).mem_nhds hhs) + (fun z hz => mem_closedPolydisc.mpr (fun i => + (mem_polydisc.mp hz i).le)) + +/-- A uniform remainder bound for any finite Taylor polynomial. The right-hand side is the tail of +an explicitly summable product of geometric series. -/ +theorem norm_polydiscTaylor_remainder_le {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} + {R s : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) + (hs : ∀ i, 0 ≤ s i) (hsR : ∀ i, s i < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) + (hh : ∀ i, ‖h i‖ ≤ s i) (t : Finset (Fin d → ℕ)) : + ‖f (c + h) - ∑ m ∈ t, (∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m‖ ≤ + ∑' m : {m : Fin d → ℕ // m ∉ t}, M * ∏ i, (s i / R i) ^ m.val i := by + have hM0 : 0 ≤ M := (norm_nonneg (f c)).trans + (hM c (mem_closedPolydisc.mpr (by simpa using fun i => (hR i).le))) + have hq : ∀ i, ‖s i / R i‖ < 1 := by + intro i + rw [Real.norm_eq_abs, abs_of_nonneg (div_nonneg (hs i) (hR i).le), div_lt_one (hR i)] + exact hsR i + have ha := (hasSum_pi_geometric (fun i => s i / R i) hq).summable.mul_left M + have hn := Summable.of_nonneg_of_le + (fun m => norm_nonneg ((∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m)) + (norm_polydiscTaylor_term_le hR hM0 hM hh) ha + rw [← (hasSum_polydiscTaylor hR (fun i => (hh i).trans_lt (hsR i)) hfc hfa hM).tsum_eq, + ← hn.of_norm.sum_add_tsum_subtype_compl t, add_sub_cancel_left] + exact (norm_tsum_le_tsum_norm (hn.subtype _)).trans + ((hn.subtype _).tsum_le_tsum (fun m => norm_polydiscTaylor_term_le hR hM0 hM hh m.val) + (ha.subtype _)) + +/-- The geometric-tail bound written without an infinite sum: a finite polynomial is subtracted from +the product of the geometric sums. -/ +theorem norm_polydiscTaylor_remainder_le_prod {f : (Fin d → ℂ) → E} {c h : Fin d → ℂ} + {R s : Fin d → ℝ} {M : ℝ} (hR : ∀ i, 0 < R i) + (hs : ∀ i, 0 ≤ s i) (hsR : ∀ i, s i < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) + (hh : ∀ i, ‖h i‖ ≤ s i) (t : Finset (Fin d → ℕ)) : + ‖f (c + h) - ∑ m ∈ t, (∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m‖ ≤ + M * ((∏ i, (1 - s i / R i)⁻¹) - ∑ m ∈ t, ∏ i, (s i / R i) ^ m i) := by + have hq : ∀ i, ‖s i / R i‖ < 1 := by + intro i + rw [Real.norm_eq_abs, abs_of_nonneg (div_nonneg (hs i) (hR i).le), div_lt_one (hR i)] + exact hsR i + have ha := (hasSum_pi_geometric (fun i => s i / R i) hq).mul_left M + have ht := ha.summable.sum_add_tsum_subtype_compl t + rw [ha.tsum_eq, ← Finset.mul_sum] at ht + have heq : (∑' m : {m : Fin d → ℕ // m ∉ t}, M * ∏ i, (s i / R i) ^ m.val i) = + M * ((∏ i, (1 - s i / R i)⁻¹) - ∑ m ∈ t, ∏ i, (s i / R i) ^ m i) := by + linarith + exact (norm_polydiscTaylor_remainder_le hR hs hsR hfc hfa hM hh t).trans_eq heq + +/-- Any mixed derivative of the separate-radius Taylor expansion is obtained by termwise +differentiation, with locally uniform convergence on the full open polydisc. -/ +theorem hasSumLocallyUniformlyOn_iteratedPartialDeriv_polydiscTaylor + {f : (Fin d → ℂ) → E} {c : Fin d → ℂ} {R : Fin d → ℝ} {M : ℝ} + (hR : ∀ i, 0 < R i) (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun v => f (update z i v)) (z i)) + (hM : ∀ z ∈ closedPolydisc c R, ‖f z‖ ≤ M) (is : List (Fin d)) : + HasSumLocallyUniformlyOn + (fun m : Fin d → ℕ => iteratedPartialDeriv is + (fun h => (∏ i, h i ^ m i) • polydiscCauchyCoeffWithRadii f c R m)) + (iteratedPartialDeriv is (fun h => f (c + h))) (polydisc 0 R) := by + apply (hasSumLocallyUniformlyOn_polydiscTaylor hR hfc hfa hM).iteratedPartialDeriv + _ (isOpen_polydisc 0 R) is + intro m z hz + apply AnalyticAt.smul + · exact Finset.analyticAt_fun_prod Finset.univ (fun i _ => + ((ContinuousLinearMap.proj i : (Fin d → ℂ) →L[ℂ] ℂ).analyticAt z).pow (m i)) + · exact analyticAt_const + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polynomial.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polynomial.lean new file mode 100644 index 0000000000..c4bf674854 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polynomial.lean @@ -0,0 +1,12 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polynomial.OfFn + +/-! Supporting modules for Classical several complex variables. -/ + diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polynomial/OfFn.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polynomial/OfFn.lean new file mode 100644 index 0000000000..43014ef0bc --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Polynomial/OfFn.lean @@ -0,0 +1,72 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Algebra.Polynomial.Monic +public import Mathlib.Algebra.Polynomial.OfFn + +/-! +# Reconstruction of polynomials from finite coefficient vectors + +The notation `R[X]` denotes `Polynomial R`. Mathlib's linear map `Polynomial.ofFn n` builds +an `R[X]` from `n` coefficients. Adding `X ^ n` gives a monic polynomial; its monicity follows +from `Polynomial.monic_X_pow_add` and `Polynomial.ofFn_degree_lt`. + +## Main results + +* `Polynomial.ofFn_toFn_eq_of_degree_lt`: Reconstruction below a degree bound, including the + zero polynomial and the empty coefficient vector. +* `Polynomial.Monic.eq_X_pow_add_ofFn`: Reconstruction of a monic polynomial from its leading + term and its lower coefficients. +* `Polynomial.coeff_X_pow_add_ofFn_of_lt`: The lower coefficients of the monic construction. +* `Polynomial.natDegree_X_pow_add_ofFn`: Its natural degree over a nontrivial semiring. + +These algebraic facts require no topology and apply to arbitrary semirings. +-/ + +public section + +namespace Polynomial + +variable {R : Type*} [Semiring R] [DecidableEq R] + +/-- A polynomial of degree below `n` is recovered from its first `n` coefficients, including +when `n = 0` and the polynomial is zero. -/ +theorem ofFn_toFn_eq_of_degree_lt {n : ℕ} {p : R[X]} (hp : p.degree < (n : WithBot ℕ)) : + ofFn n (toFn n p) = p := by + ext i + by_cases hi : i < n + · simp [hi, toFn] + · rw [ofFn_coeff_eq_zero_of_ge _ (Nat.le_of_not_gt hi)] + exact (coeff_eq_zero_of_degree_lt (hp.trans_le (by exact_mod_cast Nat.le_of_not_gt hi))).symm + +/-- A monic polynomial is its leading power of `X` plus the polynomial of its lower +coefficient vector. -/ +theorem Monic.eq_X_pow_add_ofFn {p : R[X]} (hp : p.Monic) : + p = X ^ p.natDegree + ofFn p.natDegree (toFn p.natDegree p) := by + rw [ofFn_eq_sum_monomial] + simp only [toFn, LinearMap.pi_apply, lcoeff_apply, ← C_mul_X_pow_eq_monomial] + rw [Fin.sum_univ_eq_sum_range (fun i => C (p.coeff i) * X ^ i) p.natDegree] + exact hp.as_sum + +/-- Adding the leading monomial leaves every prescribed lower coefficient unchanged. -/ +theorem coeff_X_pow_add_ofFn_of_lt {n i : ℕ} (v : Fin n → R) (hi : i < n) : + (X ^ n + ofFn n v).coeff i = v ⟨i, hi⟩ := by + simp [coeff_add, coeff_X_pow, hi.ne, ofFn_coeff_eq_val_of_lt v hi] + +/-- Over a nontrivial semiring, adding `X ^ n` to a polynomial with `n` prescribed lower +coefficients gives natural degree `n`. -/ +theorem natDegree_X_pow_add_ofFn [Nontrivial R] {n : ℕ} (v : Fin n → R) : + (X ^ n + ofFn n v).natDegree = n := by + apply natDegree_eq_of_degree_eq_some + have hlt : (ofFn n v).degree < (X ^ n : R[X]).degree := by + rw [degree_X_pow] + exact ofFn_degree_lt v + rw [degree_add_eq_left_of_degree_lt hlt, degree_X_pow] + +end Polynomial + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolynomialDerivatives.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolynomialDerivatives.lean new file mode 100644 index 0000000000..c0510afb06 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PolynomialDerivatives.lean @@ -0,0 +1,53 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Algebra.MvPolynomial.PDeriv +public import Mathlib.Analysis.Analytic.Polynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives + +/-! +# Formal and analytic coordinate derivatives of complex polynomials + +The formal partial derivatives of a multivariate polynomial agree with the analytic coordinate +derivatives of its evaluation. No finiteness assumption on the variable type is needed for the +one-variable slice identity. + +## Main results + +`hasDerivAt_eval_update` identifies `pderiv i p` with the derivative of the `i`-th coordinate +slice of `eval`. `partialDeriv_eval` is the corresponding statement for the several-variable +coordinate derivative `partialDeriv`. +-/ + +public noncomputable section +namespace MvPolynomial +variable {ι : Type*} + +/-- Formal partial differentiation agrees with differentiating a coordinate slice. No finiteness +assumption on the variable type is needed. -/ +theorem hasDerivAt_eval_update [DecidableEq ι] (p : MvPolynomial ι ℂ) (z : ι → ℂ) (i : ι) (x : ℂ) : + HasDerivAt (fun w => p.eval (Function.update z i w)) + ((pderiv i p).eval (Function.update z i x)) x := by + induction p using MvPolynomial.induction_on with + | C c => simpa using hasDerivAt_const x c + | add p q hp hq => simpa using! hp.add hq + | mul_X p j hp => + by_cases h : j = i + · subst j + simpa [pderiv_mul, mul_comm, add_comm] using! hp.mul (hasDerivAt_id x) + · simpa [pderiv_mul, h, Ne.symm h, mul_comm] using! hp.mul (hasDerivAt_const x (z j)) + +/-- Coordinate differentiation of a polynomial is evaluation of its formal derivative. -/ +theorem partialDeriv_eval [Finite ι] [DecidableEq ι] (p : MvPolynomial ι ℂ) (z : ι → ℂ) (i : ι) : + SeveralComplexVariables.partialDeriv i (fun w => p.eval w) z = (pderiv i p).eval z := by + classical + let := Fintype.ofFinite ι + simpa [SeveralComplexVariables.partialDeriv] using (p.hasDerivAt_eval_update z i (z i)).deriv + +end MvPolynomial + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence.lean new file mode 100644 index 0000000000..1a8a219abc --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence.lean @@ -0,0 +1,127 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CartanThullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.HolomorphicConvexity + +/-! +# Characterization of power-series convergence domains + +An open complete logarithmically convex Reinhardt domain is holomorphically convex, by monomial +separation. Cartan–Thullen supplies a function with precisely that domain of existence. Its +Taylor series at zero has the prescribed convergence domain. + +## Main results + +`exists_powerSeriesConvergenceDomain_eq` realizes every nonempty open complete logarithmically +convex Reinhardt set as a scalar power-series convergence domain. +`isLogarithmicallyConvex_iff_exists_powerSeriesConvergenceDomain` is the corresponding +characterization among open complete Reinhardt sets. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +-/ + +public noncomputable section + +open Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {ι : Type*} [Fintype ι] + +/-- Changing coordinate labels transports the convergence domain of a coefficient family. -/ +theorem powerSeriesConvergenceDomain_domCongr {κ : Type*} [Fintype κ] + (e : ι ≃ κ) (c : MvPowerSeries κ ℂ) : + powerSeriesConvergenceDomain (fun m => c (Finsupp.domCongr e m)) = + (Homeomorph.piCongrLeft (Y := fun _ : κ => ℂ) e) ⁻¹' powerSeriesConvergenceDomain c := by + let H := Homeomorph.piCongrLeft (Y := fun _ : κ => ℂ) e + have he : powerSeriesAbsConvergenceSet (fun m => c (Finsupp.domCongr e m)) = + H ⁻¹' powerSeriesAbsConvergenceSet c := by + ext z + change Summable (fun m : ι →₀ ℕ => ‖c (Finsupp.domCongr e m)‖ * ∏ i, ‖z i‖ ^ m i) ↔ + Summable (fun m : κ →₀ ℕ => ‖c m‖ * ∏ i, ‖H z i‖ ^ m i) + rw [← (Finsupp.domCongr e).toEquiv.summable_iff] + apply summable_congr + intro m + congr 1 + rw [← e.prod_comp] + simp [H, Homeomorph.piCongrLeft, Equiv.piCongrLeft, Finsupp.domCongr_apply, + Finsupp.equivMapDomain_apply] + change interior (powerSeriesAbsConvergenceSet _) = H ⁻¹' interior (powerSeriesAbsConvergenceSet c) + rw [he, H.preimage_interior] + +/-- On finite ordered coordinates, the Taylor series of a nonextendable function realizes an open +complete logarithmically convex Reinhardt domain. -/ +private theorem exists_powerSeriesConvergenceDomain_eq_fin {n : ℕ} {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hne : U.Nonempty) (hc : IsCompleteReinhardt U) + (hl : IsLogarithmicallyConvex U) : + ∃ c : MvPowerSeries (Fin n) ℂ, powerSeriesConvergenceDomain c = U := by + obtain ⟨f, hf⟩ := (isHolomorphicallyConvex_of_completeReinhardt ho hc + hl).exists_domainOfExistence ho + obtain ⟨hUD, he⟩ + := IsCompleteReinhardt.subset_convergenceDomain_and_eqOn_powerSeriesSum ho hc hf.1 + refine ⟨taylorCoefficientsAtZero f, Subset.antisymm ?_ hUD⟩ + exact hf.2 _ U (isOpen_powerSeriesConvergenceDomain _) + ((isCompleteReinhardt_powerSeriesConvergenceDomain _).isConnected (hne.mono hUD)) + ho hne Subset.rfl hUD ⟨_, analyticOnNhd_powerSeriesSum _, he⟩ + +/-- **Hartogs' characterization, existence direction** ([Boas][Boas2013] §2.2, Theorem 1). +Every nonempty open complete logarithmically convex Reinhardt set is exactly the convergence +domain of a scalar power series. Monomial separation and Cartan–Thullen give a +nonextendable function whose Taylor series realizes the domain. -/ +theorem exists_powerSeriesConvergenceDomain_eq {U : Set (ι → ℂ)} (hU : IsOpen U) + (hne : U.Nonempty) (hc : IsCompleteReinhardt U) (hl : IsLogarithmicallyConvex U) : + ∃ c : MvPowerSeries ι ℂ, powerSeriesConvergenceDomain c = U := by + let e := Fintype.equivFin ι + let H : (Fin (Fintype.card ι) → ℂ) ≃ₜ (ι → ℂ) := + { toFun := fun z i => z (e i) + invFun := fun z j => z (e.symm j) + left_inv := fun z => by ext j; simp + right_inv := fun z => by ext i; simp + continuous_toFun := continuous_pi fun i => continuous_apply (e i) + continuous_invFun := continuous_pi fun j => continuous_apply (e.symm j) } + let V := H ⁻¹' U + have hoV : IsOpen V := hU.preimage H.continuous + have hnV : V.Nonempty := by + obtain ⟨z, hz⟩ := hne + exact ⟨H.symm z, by simpa only [V, mem_preimage, H.apply_symm_apply] using hz⟩ + have hcV : IsCompleteReinhardt V := by + intro z hz w hw + change (fun i => w (e i)) ∈ U + exact hc (show (fun i => z (e i)) ∈ U from hz) (fun i => hw (e i)) + have hlV : IsLogarithmicallyConvex V := by + intro x hx y hy a b ha hb hab + exact hl (x := fun i => x (e i)) hx (y := fun i => y (e i)) hy ha hb hab + obtain ⟨c, hD⟩ := exists_powerSeriesConvergenceDomain_eq_fin hoV hnV hcV hlV + refine ⟨fun m => c (Finsupp.domCongr e m), ?_⟩ + rw [powerSeriesConvergenceDomain_domCongr, hD] + ext z + change H ((Homeomorph.piCongrLeft (Y := fun _ : Fin (Fintype.card ι) => ℂ) e) z) ∈ U ↔ z ∈ U + have he : H ((Homeomorph.piCongrLeft (Y := fun _ : Fin (Fintype.card ι) => ℂ) e) z) = z := by + ext i + exact Equiv.piCongrLeft_apply_apply (fun _ : Fin (Fintype.card ι) => ℂ) e z i + rw [he] + +/-- **Hartogs' characterization of power-series convergence domains.** For a nonempty +open complete Reinhardt set, logarithmic convexity is exactly the existence condition. -/ +theorem isLogarithmicallyConvex_iff_exists_powerSeriesConvergenceDomain + {U : Set (ι → ℂ)} (hU : IsOpen U) (hne : U.Nonempty) (hc : IsCompleteReinhardt U) : + IsLogarithmicallyConvex U ↔ + ∃ c : MvPowerSeries ι ℂ, powerSeriesConvergenceDomain c = U := by + constructor + · exact exists_powerSeriesConvergenceDomain_eq hU hne hc + · rintro ⟨c, rfl⟩ + exact isLogarithmicallyConvex_powerSeriesConvergenceDomain c + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence/Analytic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence/Analytic.lean new file mode 100644 index 0000000000..aba1f1f98c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence/Analytic.lean @@ -0,0 +1,148 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Hull + +/-! +# Analytic sums on power-series convergence domains + +Arbitrary Banach-valued coefficient families converge locally uniformly on the interior of their +absolute-convergence set, and their sum is analytic there. Absolute-convergence sets are +geometrically convex in moduli even at zero coordinates and boundary points. Reference: +[Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), Theorem 2.4.2. + +## Main results + +`powerSeriesSum` is the sum of a Banach-valued power series on its convergence domain. +`hasSumLocallyUniformlyOn_powerSeries` is locally uniform convergence there. +`analyticOnNhd_powerSeriesSum` is analyticity of the sum. +`hasGeometricallyConvexModuli_powerSeriesConvergenceDomain` is geometric convexity of the moduli, +including zero coordinates. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Set Filter +open scoped NNReal Topology BigOperators + +namespace SeveralComplexVariables + +variable {ι F : Type*} [Fintype ι] [NormedAddCommGroup F] + +/-- Nonnegative monomials commute with weighted geometric interpolation, including zeros. -/ +theorem prod_geometricCombination_pow (r s : ι → ℝ≥0) (m : ι →₀ ℕ) (a b : ℝ) : + (∏ i, geometricCombination a b r s i ^ m i) = + (∏ i, r i ^ m i) ^ a * (∏ i, s i ^ m i) ^ b := by + simp only [geometricCombination, mul_pow, Finset.prod_mul_distrib] + congr 1 + · rw [← NNReal.finsetProd_rpow] + apply Finset.prod_congr rfl + intro i _ + rw [← NNReal.rpow_mul_natCast, mul_comm, NNReal.rpow_natCast_mul] + · rw [← NNReal.finsetProd_rpow] + apply Finset.prod_congr rfl + intro i _ + rw [← NNReal.rpow_mul_natCast, mul_comm, NNReal.rpow_natCast_mul] + +/-- Weighted arithmetic–geometric mean bounds a coefficient times an interpolated monomial. -/ +theorem geometric_monomial_le (k : ℝ≥0) (r s : ι → ℝ≥0) (m : ι →₀ ℕ) + {a b : ℝ} (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1) : + (k : ℝ) * (∏ i, (geometricCombination a b r s i : ℝ) ^ m i) ≤ + a * ((k : ℝ) * ∏ i, (r i : ℝ) ^ m i) + + b * ((k : ℝ) * ∏ i, (s i : ℝ) ^ m i) := by + have he : k * (∏ i, geometricCombination a b r s i ^ m i) = + (k * ∏ i, r i ^ m i) ^ a * (k * ∏ i, s i ^ m i) ^ b := by + rw [prod_geometricCombination_pow, NNReal.mul_rpow, NNReal.mul_rpow] + have hk : k ^ a * k ^ b = k := by + rw [← NNReal.rpow_add_of_nonneg k ha hb, hab, NNReal.rpow_one] + calc + _ = (k ^ a * k ^ b) * ((∏ i, r i ^ m i) ^ a * (∏ i, s i ^ m i) ^ b) := by rw [hk] + _ = _ := by ring + have h := NNReal.geom_mean_le_arith_mean2_weighted ⟨a, ha⟩ ⟨b, hb⟩ + (k * ∏ i, r i ^ m i) (k * ∏ i, s i ^ m i) (by ext; exact hab) + change (k * ∏ i, r i ^ m i) ^ a * (k * ∏ i, s i ^ m i) ^ b ≤ _ at h + rw [← he] at h + exact_mod_cast h + +/-- The absolute-convergence set has geometrically convex moduli, including boundary points and +points on coordinate hyperplanes. No completeness of the coefficient space is needed. -/ +theorem hasGeometricallyConvexModuli_powerSeriesAbsConvergenceSet (c : MvPowerSeries ι F) : + HasGeometricallyConvexModuli (powerSeriesAbsConvergenceSet c) := by + rintro r ⟨z, hz, rfl⟩ s ⟨w, hw, rfl⟩ a b ha hb hab + apply (isCompleteReinhardt_powerSeriesAbsConvergenceSet c).isReinhardt.mem_modulusTrace_iff.mpr + change Summable (fun m : ι →₀ ℕ => ‖c m‖ * + ∏ i, ‖(geometricCombination a b (fun i => ‖z i‖₊) (fun i => ‖w i‖₊) i : ℂ)‖ ^ m i) + apply ((hz.mul_left a).add (hw.mul_left b)).of_nonneg_of_le (fun _ => by positivity) + intro m + simpa only [Complex.norm_of_nonneg (NNReal.coe_nonneg _), coe_nnnorm] using + geometric_monomial_le ‖c m‖₊ (fun i => ‖z i‖₊) (fun i => ‖w i‖₊) m ha hb hab + +/-- The convergence domain satisfies the zero-inclusive logarithmic convexity property. -/ +theorem hasGeometricallyConvexModuli_powerSeriesConvergenceDomain (c : MvPowerSeries ι F) : + HasGeometricallyConvexModuli (powerSeriesConvergenceDomain c) := + (isLogarithmicallyConvex_powerSeriesConvergenceDomain c).hasGeometricallyConvexModuli + (isOpen_powerSeriesConvergenceDomain c) (isCompleteReinhardt_powerSeriesConvergenceDomain c) + +variable [NormedSpace ℂ F] [CompleteSpace F] + +/-- The sum of a coefficient power series; its analytic domain is treated separately. -/ +@[expose] def powerSeriesSum (c : MvPowerSeries ι F) (z : ι → ℂ) : F := + ∑' m : ι →₀ ℕ, (∏ i, z i ^ m i) • c m + +/-- An arbitrary coefficient series converges locally uniformly on its convergence domain. -/ +theorem hasSumLocallyUniformlyOn_powerSeries (c : MvPowerSeries ι F) : + HasSumLocallyUniformlyOn (fun (m : ι →₀ ℕ) z => (∏ i, z i ^ m i) • c m) + (powerSeriesSum c) (powerSeriesConvergenceDomain c) := by + apply hasSumLocallyUniformlyOn_of_of_forall_exists_nhds + intro z hz + obtain ⟨r, hr, hzr⟩ := (isReinhardt_powerSeriesConvergenceDomain c).exists_strict_modulus_majorant + (isOpen_powerSeriesConvergenceDomain c) hz + let W : Set (ι → ℂ) := {w | ∀ i, ‖w i‖ < (r i : ℝ)} + have hW : IsOpen W := by + simpa only [W, ofPred_forall] using + (isOpen_iInter_of_finite fun i => isOpen_lt (continuous_apply i).norm + (continuous_const (y := (r i : ℝ)))) + refine ⟨W, nhdsWithin_le_nhds (hW.mem_nhds (fun i => hzr i)), ?_⟩ + apply hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + apply tendstoUniformlyOn_tsum (powerSeriesConvergenceDomain_subset c hr) + intro m w hw + simp only [norm_smul, norm_prod, norm_pow] + rw [mul_comm] + apply mul_le_mul_of_nonneg_left _ (norm_nonneg _) + apply Finset.prod_le_prod₀ (fun _ _ => by positivity) + intro i _ + apply pow_le_pow_left₀ (norm_nonneg _) _ + simpa only [Complex.norm_of_nonneg (NNReal.coe_nonneg _)] using (hw i).le + +/-- Compact subsets of the convergence domain have uniform convergence of finite subsums. -/ +theorem hasSumUniformlyOn_powerSeries (c : MvPowerSeries ι F) + {K : Set (ι → ℂ)} (hK : IsCompact K) (hKD : K ⊆ powerSeriesConvergenceDomain c) : + HasSumUniformlyOn (fun (m : ι →₀ ℕ) z => (∏ i, z i ^ m i) • c m) + (powerSeriesSum c) K := + hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + ((tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK).mp + ((hasSumLocallyUniformlyOn_powerSeries c).mono hKD)) + +/-- The sum of an arbitrary Banach-valued power series is analytic on its convergence domain. -/ +theorem analyticOnNhd_powerSeriesSum (c : MvPowerSeries ι F) : + AnalyticOnNhd ℂ (powerSeriesSum c) (powerSeriesConvergenceDomain c) := by + classical + apply (hasSumLocallyUniformlyOn_powerSeries c).analyticOnNhd_pi _ + (isOpen_powerSeriesConvergenceDomain c) + intro m z _ + exact (Finset.analyticAt_fun_prod Finset.univ (fun i _ => + ((ContinuousLinearMap.proj (R := ℂ) i).analyticAt z).pow (m i))).smul analyticAt_const + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence/Basic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence/Basic.lean new file mode 100644 index 0000000000..0ecefe7e49 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/PowerSeriesConvergence/Basic.lean @@ -0,0 +1,192 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Normed.Group.InfiniteSum +public import Mathlib.RingTheory.MvPowerSeries.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt + +/-! +# Domains of absolute convergence of multivariable power series + +For coefficients indexed by Mathlib's finitely supported multi-indices, the absolute convergence +set records summability of the norms of the individual monomial terms. Its interior is the +convergence domain, following [Boas][Boas2013] (2013), Sections 2.1--2.2. Boundary convergence +is deliberately not included in the definition of the domain. + +The absolute-convergence set and its interior are complete Reinhardt and logarithmically convex. +The proofs apply to normed-group-valued coefficients; a complex Banach target is needed only to +deduce summability of the actual vector-valued terms. Convexity follows by comparing terms at +logarithmic interpolates with arithmetic averages, using convexity of exp. + +The existence converse is proved in `SeveralComplexVariables.PowerSeriesConvergence`. Empty +coordinate index types are included; nonemptiness is required of a prescribed domain, but a +general series may have empty convergence domain. + +## Main definitions + +* `powerSeriesAbsConvergenceSet`: The absolute-convergence set of a power series centred at zero. +* `powerSeriesConvergenceDomain`: The convergence domain is the interior of the absolute-convergence + set. + +## Main results + +* `isOpen_powerSeriesConvergenceDomain`: A power-series convergence domain is open by definition, + and may be empty. +* `isCompleteReinhardt_powerSeriesConvergenceDomain`: The convergence domain is complete Reinhardt, + including at coordinate hyperplanes. +* `isLogarithmicallyConvex_powerSeriesConvergenceDomain`: The interior of the absolute-convergence + set is logarithmically convex. +* `isPathConnected_powerSeriesConvergenceDomain`: A nonempty convergence domain is path connected. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +-/ + +public noncomputable section + +open Set +open scoped BigOperators + +namespace SeveralComplexVariables + +variable {ι E : Type*} [Fintype ι] [NormedAddCommGroup E] + +/-- The absolute-convergence set of a power series centred at zero. The product records the norm of +the monomial, so no scalar action or completeness of the coefficient space is needed. -/ +@[expose] def powerSeriesAbsConvergenceSet (c : MvPowerSeries ι E) : Set (ι → ℂ) := + {z | Summable (fun m : ι →₀ ℕ => ‖c m‖ * ∏ i, ‖z i‖ ^ m i)} + +/-- The convergence domain is the interior of the absolute-convergence set. -/ +@[expose] def powerSeriesConvergenceDomain (c : MvPowerSeries ι E) : Set (ι → ℂ) := + interior (powerSeriesAbsConvergenceSet c) + +/-- For complex normed coefficients the defining summability condition is exactly absolute +convergence of the vector-valued monomial terms. -/ +theorem mem_powerSeriesAbsConvergenceSet_iff [NormedSpace ℂ E] + {c : MvPowerSeries ι E} {z : ι → ℂ} : + z ∈ powerSeriesAbsConvergenceSet c ↔ + Summable (fun m : ι →₀ ℕ => ‖(∏ i, z i ^ m i) • c m‖) := by + simp [powerSeriesAbsConvergenceSet, norm_smul, norm_prod, norm_pow, mul_comm] + +/-- Every formal series converges absolutely at zero, since only its constant term survives. This +does not assert that its convergence domain is nonempty. -/ +theorem zero_mem_powerSeriesAbsConvergenceSet (c : MvPowerSeries ι E) : + 0 ∈ powerSeriesAbsConvergenceSet c := by + classical + apply summable_of_ne_finset_zero (s := {0}) + intro m hm + have hm0 : m ≠ 0 := by simpa using hm + obtain ⟨i, hi⟩ := Finsupp.ne_iff.mp hm0 + have hterm : ‖(0 : ι → ℂ) i‖ ^ m i = 0 := by + simpa using (zero_pow hi : (0 : ℝ) ^ m i = 0) + rw [Finset.prod_eq_zero (Finset.mem_univ i) hterm, mul_zero] + +/-- A power-series convergence domain is open by definition, and may be empty. -/ +theorem isOpen_powerSeriesConvergenceDomain (c : MvPowerSeries ι E) : + IsOpen (powerSeriesConvergenceDomain c) := isOpen_interior + +/-- Membership of the convergence domain implies absolute convergence. -/ +theorem powerSeriesConvergenceDomain_subset (c : MvPowerSeries ι E) : + powerSeriesConvergenceDomain c ⊆ powerSeriesAbsConvergenceSet c := interior_subset + +/-- Decreasing coordinate moduli preserves absolute convergence. -/ +theorem isCompleteReinhardt_powerSeriesAbsConvergenceSet (c : MvPowerSeries ι E) : + IsCompleteReinhardt (powerSeriesAbsConvergenceSet c) := by + intro z hz w hw + apply hz.of_nonneg_of_le + · intro m + positivity + · intro m + apply mul_le_mul_of_nonneg_left _ (norm_nonneg _) + exact Finset.prod_le_prod₀ (fun i _ => by positivity) + (fun i _ => pow_le_pow_left₀ (norm_nonneg _) (hw i) _) + +/-- The convergence domain is complete Reinhardt, including at coordinate hyperplanes. -/ +theorem isCompleteReinhardt_powerSeriesConvergenceDomain (c : MvPowerSeries ι E) : + IsCompleteReinhardt (powerSeriesConvergenceDomain c) := + (isCompleteReinhardt_powerSeriesAbsConvergenceSet c).interior + +/-- A power-series convergence domain has independent coordinate rotation symmetry. -/ +theorem isReinhardt_powerSeriesConvergenceDomain (c : MvPowerSeries ι E) : + IsReinhardt (powerSeriesConvergenceDomain c) := + (isCompleteReinhardt_powerSeriesConvergenceDomain c).isReinhardt + +/-- A nonempty convergence domain is path connected. -/ +theorem isPathConnected_powerSeriesConvergenceDomain (c : MvPowerSeries ι E) + (hne : (powerSeriesConvergenceDomain c).Nonempty) : + IsPathConnected (powerSeriesConvergenceDomain c) := + (isCompleteReinhardt_powerSeriesConvergenceDomain c).isPathConnected hne + +/-- In logarithmic coordinates the modulus of a monomial is an exponential of a linear form. -/ +theorem prod_norm_exp_pow (x : ι → ℝ) (m : ι →₀ ℕ) : + (∏ i, ‖(Real.exp (x i) : ℂ)‖ ^ m i) = Real.exp (∑ i, (m i : ℝ) * x i) := by + simp [Real.exp_sum, Real.exp_nat_mul] + +/-- Absolute convergence has a convex logarithmic image, by termwise convexity of exp and comparison +of nonnegative series. -/ +theorem isLogarithmicallyConvex_powerSeriesAbsConvergenceSet (c : MvPowerSeries ι E) : + IsLogarithmicallyConvex (powerSeriesAbsConvergenceSet c) := by + intro x hx y hy a b ha hb hab + change Summable (fun m : ι →₀ ℕ => + ‖c m‖ * ∏ i, ‖(Real.exp ((a • x + b • y) i) : ℂ)‖ ^ m i) + have hx' : Summable (fun m : ι →₀ ℕ => ‖c m‖ * Real.exp (∑ i, (m i : ℝ) * x i)) := by + simpa only [logarithmicImage, mem_ofPred_eq, powerSeriesAbsConvergenceSet, + prod_norm_exp_pow] using hx + have hy' : Summable (fun m : ι →₀ ℕ => ‖c m‖ * Real.exp (∑ i, (m i : ℝ) * y i)) := by + simpa only [logarithmicImage, mem_ofPred_eq, powerSeriesAbsConvergenceSet, + prod_norm_exp_pow] using hy + apply ((hx'.mul_left a).add (hy'.mul_left b)).of_nonneg_of_le + · intro m + positivity + · intro m + rw [prod_norm_exp_pow] + have heq : (∑ i, (m i : ℝ) * (a • x + b • y) i) = + a * (∑ i, (m i : ℝ) * x i) + b * (∑ i, (m i : ℝ) * y i) := by + simp only [Pi.add_apply, Pi.smul_apply, smul_eq_mul, mul_add, + Finset.sum_add_distrib, Finset.mul_sum] + congr 1 <;> apply Finset.sum_congr rfl <;> intros <;> ring + rw [heq] + have h := mul_le_mul_of_nonneg_left + (convexOn_exp.2 (mem_univ (∑ i, (m i : ℝ) * x i)) + (mem_univ (∑ i, (m i : ℝ) * y i)) ha hb hab) (norm_nonneg (c m)) + simpa only [smul_eq_mul, mul_add, mul_left_comm] using h + +/-- The interior of the absolute-convergence set is logarithmically convex. -/ +theorem isLogarithmicallyConvex_powerSeriesConvergenceDomain (c : MvPowerSeries ι E) : + IsLogarithmicallyConvex (powerSeriesConvergenceDomain c) := + (isLogarithmicallyConvex_powerSeriesAbsConvergenceSet c).interior + (isCompleteReinhardt_powerSeriesAbsConvergenceSet c) + +/-- Absolute convergence implies summability of the vector-valued monomial terms in a complex Banach +space. -/ +theorem summable_powerSeriesTerms [NormedSpace ℂ E] [CompleteSpace E] + {c : MvPowerSeries ι E} {z : ι → ℂ} (hz : z ∈ powerSeriesAbsConvergenceSet c) : + Summable (fun m : ι →₀ ℕ => (∏ i, z i ^ m i) • c m) := by + apply hz.of_norm_bounded + intro m + simp [norm_smul, norm_prod, norm_pow, mul_comm] + +/-- The zero series has the whole coordinate space as its convergence domain. -/ +@[simp] theorem powerSeriesConvergenceDomain_zero : + powerSeriesConvergenceDomain (0 : MvPowerSeries ι E) = univ := by + have hz (m : ι →₀ ℕ) : (0 : MvPowerSeries ι E) m = 0 := rfl + simp [powerSeriesConvergenceDomain, powerSeriesAbsConvergenceSet, hz] + +/-- With no coordinates, every series has the whole singleton coordinate space as its convergence +domain. -/ +theorem powerSeriesConvergenceDomain_of_isEmpty [IsEmpty ι] (c : MvPowerSeries ι E) : + powerSeriesConvergenceDomain c = univ := by + have h : powerSeriesAbsConvergenceSet c = univ := by + apply Set.eq_univ_of_forall + intro z + exact Summable.of_finite + simp [powerSeriesConvergenceDomain, h] + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Pseudoconvexity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Pseudoconvexity.lean new file mode 100644 index 0000000000..432660cd95 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Pseudoconvexity.lean @@ -0,0 +1,656 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.AbsMax +public import Mathlib.Topology.Connected.LocallyPathConnected +public import Mathlib.Topology.Order.ProjIcc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Plurisubharmonic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.Majorant + +/-! +# Pseudoconvexity + +This file relates domains of holomorphy to plurisubharmonic functions and to two geometric +convexity notions. + +* **Boundary distance.** On a domain of holomorphy in `Fin n → ℂ`, the negative logarithm of +the supremum-norm distance to the complement is plurisubharmonic. The proof is +[Hörmander][Hormander1973]'s: a +harmonic polynomial majorant of `-log δ` on a circle in a complex line gives, through the +weighted hull-radius bound of Thullen's lemma, the same bound at the center. +* **Pseudoconvexity.** An open set is pseudoconvex if it carries a continuous + plurisubharmonic exhaustion function. Domains of holomorphy are pseudoconvex. +* **Continuity principle.** Along a continuous family of affine analytic discs whose boundary + circles stay in a pseudoconvex set and whose initial disc lies in the set, every disc lies in + the set. This is the Kontinuitätssatz for affine discs, proved by the maximum principle for + plurisubharmonic functions on discs. +* **Hartogs convexity.** In a product `E × ℂ`, a set satisfying the continuity principle + contains the filled cylinder of every Hartogs cylinder it contains. +* **Kontinuitätssatz.** On a domain of holomorphy in a finite-dimensional complex normed space, the +continuity principle +holds for continuous families of holomorphic discs, not only affine ones: every point of a +holomorphic disc lies in the holomorphic hull of the boundary circle, and Thullen's radius +bound keeps the discs at a fixed distance from the complement. + +The boundary-distance result uses the supremum norm on `Fin n → ℂ`. For the whole space, +`Metric.infDist` of the empty complement and `Real.log 0` are both zero, so the function in +that theorem is identically zero. This is a real-valued convention; `boundaryEDistance` instead +takes the value `∞` for an empty complement. Pseudoconvexity and the holomorphic continuity +principle are transported to arbitrary finite-dimensional complex normed spaces; this transport +does not identify their boundary-distance functions. + +The converse implications, from pseudoconvexity back to the domain-of-holomorphy property, form +the Levi problem and are outside the present scope. + +References: [Hörmander][Hormander1973] (1973), Theorems 2.5.4, 2.6.5 and 2.6.7; +[Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Sections 1 and 3; +[Range][Range1986] (1986), Chapter II, Sections 2 and 5. + +## Main definitions + +* `IsPseudoconvex`: An open set is pseudoconvex if it carries a continuous plurisubharmonic + exhaustion function: one whose sublevel sets inside the set are compact. +* `SatisfiesContinuityPrinciple`: **Continuity principle for affine analytic discs.** Along a + continuous family of affine analytic discs whose boundary circles stay in the set and whose + initial disc lies in the set, every disc of the family lies in the set. +* `SatisfiesHolomorphicContinuityPrinciple`: **Continuity principle for holomorphic discs + (Kontinuitätssatz).** Along a continuous family of holomorphic discs whose boundary circles stay + in the set and whose initial disc lies in the set, every disc of the family lies in the set. +* `IsHartogsConvex`: **Hartogs convexity** for cylinder figures: whenever a Hartogs cylinder over an + open preconnected base, with disc fibers over a nonempty open part of the base, lies in the set, + so does the filled cylinder. + +## Main results + +* `IsDomainOfHolomorphy.plurisubharmonicOn_neg_log_infDist`: **Plurisubharmonicity of the boundary + distance ([Hörmander][Hormander1973] 2.6.5).** On a domain of holomorphy in `Fin n → ℂ`, the + negative logarithm of the distance to the complement is plurisubharmonic. +* `IsDomainOfHolomorphy.isPseudoconvex_fin`: **Domains of holomorphy in coordinates are + pseudoconvex.** The exhaustion is the maximum of the negative logarithm of the boundary distance + and the norm. +* `IsPseudoconvex.satisfiesContinuityPrinciple`: **Pseudoconvex sets satisfy the continuity + principle ([Fritzsche–Grauert][FritzscheGrauert2002] II.3.1).** +* `IsDomainOfHolomorphy.satisfiesHolomorphicContinuityPrinciple_fin`: **Domains of holomorphy in + coordinates satisfy the continuity principle for holomorphic discs.** The coordinate-free version + is `IsDomainOfHolomorphy.satisfiesHolomorphicContinuityPrinciple`. +* `IsDomainOfHolomorphy.isPseudoconvex`: **Domains of holomorphy are pseudoconvex.** The exhaustion + is transported from the coordinate version `IsDomainOfHolomorphy.isPseudoconvex_fin`. +* `IsDomainOfHolomorphy.satisfiesHolomorphicContinuityPrinciple`: **Domains of holomorphy satisfy + the continuity principle for holomorphic discs.** +* `SatisfiesContinuityPrinciple.isHartogsConvex`: **The continuity principle implies Hartogs + convexity ([Fritzsche–Grauert][FritzscheGrauert2002] II.1.5).** The disc fibers are slid along a + path in the base from the part carrying full discs. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +-/ + +public section + +open Complex Filter Metric Set Real +open scoped Topology + +namespace SeveralComplexVariables + +/-- Clamp a real parameter to the unit interval. -/ +private noncomputable def clampIcc01 (t : ℝ) : ℝ := Set.projIcc 0 1 zero_le_one t + +/-- Clamping to `[0, 1]` is continuous. -/ +private theorem continuous_clampIcc01 : Continuous clampIcc01 := continuous_subtype_val.comp + continuous_projIcc + +/-- The clamp of any real lies in `[0, 1]`. -/ +private theorem clampIcc01_mem_Icc (t : ℝ) : clampIcc01 t ∈ Icc (0 : ℝ) 1 := + (Set.projIcc 0 1 zero_le_one t).property + +/-- Clamping is the identity on `[0, 1]`. -/ +private theorem clampIcc01_eq_of_mem_Icc {t : ℝ} (ht : t ∈ Icc (0 : ℝ) 1) : clampIcc01 t = t + := congrArg + Subtype.val (Set.projIcc_of_mem zero_le_one ht) + +/-- Clamping is idempotent. -/ +private theorem clampIcc01_idem (t : ℝ) : clampIcc01 (clampIcc01 t) = clampIcc01 t := + clampIcc01_eq_of_mem_Icc (clampIcc01_mem_Icc t) + +section BoundaryDistance + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Points of a closed disc in a complex line lie in the holomorphic hull of its boundary circle, by +the maximum modulus principle. -/ +theorem mem_holomorphicHull_of_mem_disc {U : Set E} {a w : E} {r : ℝ} (hr : 0 < r) + (hdisc : ∀ t ∈ closedBall (0 : ℂ) r, a + t • w ∈ U) {t : ℂ} (ht : t ∈ closedBall (0 : ℂ) r) : + a + t • w ∈ holomorphicHull U ((fun t : ℂ => a + t • w) '' sphere 0 r) := by + refine ⟨hdisc t ht, fun f hf M hM => ?_⟩ + have hg : DiffContOnCl ℂ (fun t : ℂ => f (a + t • w)) (ball 0 r) := by + apply DifferentiableOn.diffContOnCl + rw [closure_ball 0 hr.ne'] + exact fun s hs => ((hf _ (hdisc s hs)).comp_of_eq + (analyticAt_const.add (analyticAt_id.smul analyticAt_const)) + rfl).differentiableAt.differentiableWithinAt + have hbd : ∀ s ∈ frontier (ball (0 : ℂ) r), ‖f (a + s • w)‖ ≤ M := by + intro s hs + rw [frontier_ball 0 hr.ne'] at hs + exact hM _ ⟨s, hs, rfl⟩ + have := Complex.norm_le_of_forall_mem_frontier_norm_le isBounded_ball hg hbd + (z := t) (by rw [closure_ball 0 hr.ne']; exact ht) + exact this + +/-- Every point of a closed holomorphic disc lies in the holomorphic hull of the boundary circle, by +the maximum modulus principle. -/ +theorem mem_holomorphicHull_of_analytic_disc {U : Set E} {φ : ℂ → E} {r : ℝ} (hr : 0 < r) + (hφ : AnalyticOnNhd ℂ φ (closedBall 0 r)) (hdisc : ∀ t ∈ closedBall (0 : ℂ) r, φ t ∈ U) + {t : ℂ} (ht : t ∈ closedBall (0 : ℂ) r) : φ t ∈ holomorphicHull U (φ '' sphere 0 r) := by + refine ⟨hdisc t ht, fun f hf M hM => ?_⟩ + have hg : DiffContOnCl ℂ (fun t : ℂ => f (φ t)) (ball 0 r) := by + apply DifferentiableOn.diffContOnCl + rw [closure_ball 0 hr.ne'] + exact fun s hs => ((hf _ (hdisc s hs)).comp_of_eq (hφ s hs) + rfl).differentiableAt.differentiableWithinAt + have hbd : ∀ s ∈ frontier (ball (0 : ℂ) r), ‖f (φ s)‖ ≤ M := by + intro s hs + rw [frontier_ball 0 hr.ne'] at hs + exact hM _ ⟨s, hs, rfl⟩ + exact Complex.norm_le_of_forall_mem_frontier_norm_le isBounded_ball hg hbd + (z := t) (by rw [closure_ball 0 hr.ne']; exact ht) + +variable {n : ℕ} + +/-- **Plurisubharmonicity of the boundary distance ([Hörmander][Hormander1973] 2.6.5).** On a domain +of holomorphy in `Fin n → ℂ`, the negative logarithm of the supremum-norm distance to the +complement is plurisubharmonic. When the complement is empty, this function is zero by the +conventions `Metric.infDist_empty` and `Real.log_zero`. -/ +theorem IsDomainOfHolomorphy.plurisubharmonicOn_neg_log_infDist {U : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : + PlurisubharmonicOn (fun z => -Real.log (infDist z Uᶜ)) U := by + rcases eq_empty_or_nonempty Uᶜ with hc | hc + · simp only [hc, infDist_empty, Real.log_zero, neg_zero] + exact plurisubharmonicOn_const 0 U + have hpos : ∀ z ∈ U, 0 < infDist z Uᶜ := fun z hz => + (infDist_pos_iff_notMem_closure hc).mp (by rwa [ho.isClosed_compl.closure_eq, notMem_compl_iff]) + have hcont : ContinuousOn (fun z => -Real.log (infDist z Uᶜ)) U := + ((continuous_infDist_pt Uᶜ).continuousOn.log fun z hz => (hpos z hz).ne').neg + refine plurisubharmonicOn_of_hasSubmeanAt hcont.upperSemicontinuousOn fun a ha w => ?_ + -- the constant slice + by_cases hw : w = 0 + · simp only [hw, smul_zero, add_zero] + exact hasSubmeanAt_const _ 0 + obtain ⟨i, hi⟩ := Function.ne_iff.mp hw + have hline : Continuous fun t : ℂ => a + t • w := by fun_prop + obtain ⟨ρ, hρ, hball⟩ := Metric.mem_nhds_iff.mp (hline.continuousAt.preimage_mem_nhds (by + change U ∈ 𝓝 ((fun t : ℂ => a + t • w) 0) + simp only [zero_smul, add_zero] + exact ho.mem_nhds ha)) + refine hasSubmeanAt_of_forall_lt hρ fun r hr hrρ => ?_ + have hdisc : ∀ t ∈ closedBall (0 : ℂ) r, a + t • w ∈ U := fun t ht => + hball (closedBall_subset_ball hrρ ht) + have hslice_cont : ContinuousOn (fun t : ℂ => -Real.log (infDist (a + t • w) Uᶜ)) (sphere 0 r) := + hcont.comp hline.continuousOn fun t ht => hdisc t (sphere_subset_closedBall ht) + refine ⟨hslice_cont.circleIntegrable hr.le, ?_⟩ + refine le_circleAverage_of_forall_polynomial_majorant hr hslice_cont fun Q hQ => ?_ + simp only [zero_smul, add_zero] + -- the entire function realizing the polynomial majorant along the line + set F : (Fin n → ℂ) → ℂ := fun z => Q.eval ((z i - a i) / w i / r) with hF + have hFline : ∀ t : ℂ, F (a + t • w) = Q.eval ((t - 0) / r) := fun t => by + simp only [hF, Pi.add_apply, Pi.smul_apply, smul_eq_mul, add_sub_cancel_left, sub_zero] + rw [mul_div_cancel_right₀ _ hi] + set q : (Fin n → ℂ) → ℂ := fun z => Complex.exp (-F z) with hq + have hqan : AnalyticOnNhd ℂ q U := by + have hd : Differentiable ℂ q := by + apply Complex.differentiable_exp.comp + apply Differentiable.neg + exact Q.differentiable.comp (by fun_prop) + exact hd.analyticOnNhd_of_finiteDimensional.mono (subset_univ U) + have hqnorm : ∀ z, ‖q z‖ = Real.exp (-(F z).re) := fun z => by + simp [hq, Complex.norm_exp] + set K := (fun t : ℂ => a + t • w) '' sphere 0 r with hK + have hKc : IsCompact K := (isCompact_sphere 0 r).image hline + have hKU : K ⊆ U := by + rintro _ ⟨t, ht, rfl⟩ + exact hdisc t (sphere_subset_closedBall ht) + have hrad : ∀ z ∈ K, ball z ‖q z‖ ⊆ U := by + rintro _ ⟨t, ht, rfl⟩ + have h1 := hQ t ht + rw [← hFline t] at h1 + change ball (a + t • w) ‖q (a + t • w)‖ ⊆ U + rw [hqnorm] + have hδ : 0 < infDist (a + t • w) Uᶜ := hpos _ (hdisc t (sphere_subset_closedBall ht)) + have h2 : Real.exp (-(F (a + t • w)).re) ≤ infDist (a + t • w) Uᶜ := by + rw [← Real.le_log_iff_exp_le hδ] + linarith + apply (ball_subset_ball h2).trans + simpa using (ball_infDist_subset_compl (x := a + t • w) (s := Uᶜ)) + have hhull := hU.holomorphic_radius_bound ho hKc hKU hqan hrad a + (by simpa using mem_holomorphicHull_of_mem_disc hr hdisc (mem_closedBall_self hr.le)) + -- the radius bound at the center gives the distance bound + have hδa : 0 < infDist a Uᶜ := hpos a ha + have hle : ‖q a‖ ≤ infDist a Uᶜ := by + by_contra hlt + push Not at hlt + obtain ⟨y, hy, hdy⟩ := (infDist_lt_iff hc).mp hlt + exact hy (hhull (by rwa [mem_ball, dist_comm])) + rw [hqnorm, ← Real.le_log_iff_exp_le hδa] at hle + have hFa : F a = Q.eval 0 := by + have := hFline 0 + simpa using this + rw [hFa] at hle + linarith + +end BoundaryDistance + +section Pseudoconvex + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- An open set is pseudoconvex if it carries a continuous plurisubharmonic exhaustion function: one +whose sublevel sets inside the set are compact. -/ +@[expose] def IsPseudoconvex (U : Set E) : Prop := + IsOpen U ∧ ∃ φ : E → ℝ, ContinuousOn φ U ∧ PlurisubharmonicOn φ U ∧ + ∀ c : ℝ, IsCompact {z ∈ U | φ z ≤ c} + +/-- A pseudoconvex set is open. -/ +theorem IsPseudoconvex.isOpen {U : Set E} (h : IsPseudoconvex U) : IsOpen U := h.1 + +variable {n : ℕ} + +/-- **Domains of holomorphy in coordinates are pseudoconvex.** The exhaustion is the maximum +of the negative logarithm of the boundary distance and the norm. The coordinate-free version +is `IsDomainOfHolomorphy.isPseudoconvex`. -/ +theorem IsDomainOfHolomorphy.isPseudoconvex_fin {U : Set (Fin n → ℂ)} (hU : IsDomainOfHolomorphy U) + (ho : IsOpen U) : IsPseudoconvex U := by + refine ⟨ho, ?_⟩ + rcases eq_empty_or_nonempty Uᶜ with hc | hc + · have hU' : U = univ := compl_empty_iff.mp hc + refine ⟨fun z => ‖z‖, continuous_norm.continuousOn, plurisubharmonicOn_norm.mono (subset_univ + U), + fun c => ?_⟩ + convert isCompact_closedBall (0 : Fin n → ℂ) c using 1 + ext z + simp [hU'] + have hpos : ∀ z ∈ U, 0 < infDist z Uᶜ := fun z hz => + (infDist_pos_iff_notMem_closure hc).mp (by rwa [ho.isClosed_compl.closure_eq, notMem_compl_iff]) + refine ⟨fun z => max (-Real.log (infDist z Uᶜ)) ‖z‖, ?_, ?_, fun c => ?_⟩ + · exact (((continuous_infDist_pt Uᶜ).continuousOn.log fun z hz => (hpos z hz).ne').neg).sup + continuous_norm.continuousOn + · exact (hU.plurisubharmonicOn_neg_log_infDist ho).sup (plurisubharmonicOn_norm.mono + (subset_univ U)) + · have heq : {z ∈ U | max (-Real.log (infDist z Uᶜ)) ‖z‖ ≤ c} = + {z | Real.exp (-c) ≤ infDist z Uᶜ} ∩ closedBall 0 c := by + ext z + simp only [mem_ofPred_eq, mem_inter_iff, mem_closedBall, dist_zero_right, max_le_iff] + constructor + · rintro ⟨hz, h1, h2⟩ + refine ⟨?_, h2⟩ + rw [← Real.le_log_iff_exp_le (hpos z hz)] + linarith + · rintro ⟨h1, h2⟩ + have hδ : 0 < infDist z Uᶜ := (Real.exp_pos _).trans_le h1 + have hz : z ∈ U := by + by_contra hz + rw [infDist_zero_of_mem hz] at hδ + exact lt_irrefl _ hδ + refine ⟨hz, ?_, h2⟩ + rw [← Real.le_log_iff_exp_le hδ] at h1 + linarith + rw [heq] + refine isCompact_of_isClosed_isBounded ((isClosed_le continuous_const + (continuous_infDist_pt Uᶜ)).inter isClosed_closedBall) ?_ + exact isBounded_closedBall.subset inter_subset_right + +/-- **Continuity principle for affine analytic discs.** Along a continuous family of affine +analytic discs whose boundary circles stay in the set and whose initial disc lies in the set, +every disc of the family lies in the set. -/ +@[expose] def SatisfiesContinuityPrinciple (U : Set E) : Prop := + ∀ a b : ℝ → E, Continuous a → Continuous b → + (∀ t ∈ Icc (0 : ℝ) 1, ∀ ζ ∈ sphere (0 : ℂ) 1, a t + ζ • b t ∈ U) → + (∀ ζ ∈ closedBall (0 : ℂ) 1, a 0 + ζ • b 0 ∈ U) → + ∀ t ∈ Icc (0 : ℝ) 1, ∀ ζ ∈ closedBall (0 : ℂ) 1, a t + ζ • b t ∈ U + +/-- **Pseudoconvex sets satisfy the continuity principle ([Fritzsche–Grauert][FritzscheGrauert2002] +II.3.1).** -/ +theorem IsPseudoconvex.satisfiesContinuityPrinciple {U : Set E} (h : IsPseudoconvex U) : + SatisfiesContinuityPrinciple U := by + obtain ⟨hU, φ, hφc, hφpsh, hφex⟩ := h + intro a b ha hb hbd h0 + set p := clampIcc01 + have hpc : Continuous p := continuous_clampIcc01 + have hpI : ∀ t, p t ∈ Icc (0 : ℝ) 1 := clampIcc01_mem_Icc + have hpid : ∀ t ∈ Icc (0 : ℝ) 1, p t = t := fun t ht => clampIcc01_eq_of_mem_Icc ht + have hpp : ∀ t, p (p t) = p t := clampIcc01_idem + set Φ : ℝ × ℂ → E := fun q => a (p q.1) + q.2 • b (p q.1) with hΦ + have hΦc : Continuous Φ := by fun_prop + -- the compact set of boundary points and initial disc points + set K₀ := Φ '' (Icc (0 : ℝ) 1 ×ˢ sphere (0 : ℂ) 1) ∪ Φ '' ({0} ×ˢ closedBall (0 : ℂ) 1) with hK₀ + have hK₀c : IsCompact K₀ := + ((isCompact_Icc.prod (isCompact_sphere _ _)).image hΦc).union + ((isCompact_singleton.prod (isCompact_closedBall _ _)).image hΦc) + have hK₀U : K₀ ⊆ U := by + rintro _ (⟨⟨t, ζ⟩, ⟨ht, hζ⟩, rfl⟩ | ⟨⟨t, ζ⟩, ⟨ht, hζ⟩, rfl⟩) + · simp only [hΦ, hpid t ht] + exact hbd t ht ζ hζ + · simp only [mem_singleton_iff] at ht + simp only [hΦ, ht, hpid 0 (left_mem_Icc.mpr zero_le_one)] + exact h0 ζ hζ + obtain ⟨C, hC⟩ := hK₀c.exists_bound_of_continuousOn (hφc.mono hK₀U) + have hCle : ∀ z ∈ K₀, φ z ≤ C := fun z hz => (le_abs_self _).trans (by simpa using hC z hz) + set L := {z ∈ U | φ z ≤ C} with hL + have hLc : IsCompact L := hφex C + have hLU : L ⊆ U := fun z hz => hz.1 + -- the parameters whose disc lies in `U` + set W := {t : ℝ | ∀ ζ ∈ closedBall (0 : ℂ) 1, Φ (t, ζ) ∈ U} with hW + have hdisc : ∀ t ∈ W, ∀ ζ ∈ closedBall (0 : ℂ) 1, Φ (t, ζ) ∈ L := by + intro t ht ζ hζ + have hat : a (p t) ∈ U := by simpa [hΦ] using ht 0 (mem_closedBall_self zero_le_one) + have hsl : SubharmonicOn (fun ζ : ℂ => φ (a (p t) + ζ • b (p t))) (ball 0 1) := + (hφpsh.slice hat (b (p t))).mono fun ζ hζ => ht ζ (ball_subset_closedBall hζ) + have husc : UpperSemicontinuousOn (fun ζ : ℂ => φ (a (p t) + ζ • b (p t))) (closedBall 0 1) := + (hφc.comp (by fun_prop : Continuous fun ζ : ℂ => a (p t) + ζ • b (p t)).continuousOn + fun ζ hζ => ht ζ hζ).upperSemicontinuousOn + have hbdy : ∀ ζ ∈ sphere (0 : ℂ) 1, φ (a (p t) + ζ • b (p t)) ≤ C := by + intro ζ hζ + apply hCle + refine Or.inl ⟨(p t, ζ), ⟨hpI t, hζ⟩, ?_⟩ + simp only [hΦ, hpp] + exact ⟨ht ζ hζ, hsl.le_of_le_sphere zero_lt_one husc hbdy ζ hζ⟩ + have hWo : IsOpen W := by + rw [isOpen_iff_mem_nhds] + intro t ht + have := (isCompact_closedBall (0 : ℂ) 1).eventually_forall_of_forall_eventually + (x₀ := t) (P := fun t ζ => Φ (t, ζ) ∈ U) fun ζ hζ => + hΦc.continuousAt.preimage_mem_nhds (hU.mem_nhds (ht ζ hζ)) + exact this + have hWcl : IsClosed W := by + rw [← closure_subset_iff_isClosed] + intro t ht ζ hζ + have hne : NeBot (𝓝[W] t) := mem_closure_iff_nhdsWithin_neBot.mp ht + have htend : Tendsto (fun t' => Φ (t', ζ)) (𝓝[W] t) (𝓝 (Φ (t, ζ))) := + ((hΦc.comp (continuous_id.prodMk continuous_const)).tendsto t).mono_left nhdsWithin_le_nhds + have hmem : Φ (t, ζ) ∈ closure L := + mem_closure_of_tendsto htend (eventually_nhdsWithin_of_forall fun t' ht' => hdisc t' ht' ζ hζ) + rw [hLc.isClosed.closure_eq] at hmem + exact hLU hmem + have hW0 : (0 : ℝ) ∈ W := by + intro ζ hζ + simp only [hΦ, hpid 0 (left_mem_Icc.mpr zero_le_one)] + exact h0 ζ hζ + have hWuniv : W = univ := IsClopen.eq_univ (⟨hWcl, hWo⟩ : IsClopen W) ⟨0, hW0⟩ + intro t ht ζ hζ + have := (hWuniv ▸ mem_univ t : t ∈ W) ζ hζ + simpa [hΦ, hpid t ht] using this + +end Pseudoconvex + + +section HolomorphicContinuity + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- **Continuity principle for holomorphic discs (Kontinuitätssatz).** Along a continuous +family of holomorphic discs whose boundary circles stay in the set and whose initial disc lies +in the set, every disc of the family lies in the set. -/ +@[expose] def SatisfiesHolomorphicContinuityPrinciple (U : Set E) : Prop := + ∀ φ : ℝ → ℂ → E, Continuous (fun q : ℝ × ℂ => φ q.1 q.2) → + (∀ t ∈ Icc (0 : ℝ) 1, AnalyticOnNhd ℂ (φ t) (closedBall 0 1)) → + (∀ t ∈ Icc (0 : ℝ) 1, ∀ ζ ∈ sphere (0 : ℂ) 1, φ t ζ ∈ U) → + (∀ ζ ∈ closedBall (0 : ℂ) 1, φ 0 ζ ∈ U) → + ∀ t ∈ Icc (0 : ℝ) 1, ∀ ζ ∈ closedBall (0 : ℂ) 1, φ t ζ ∈ U + +/-- The holomorphic continuity principle contains the affine one. -/ +theorem SatisfiesHolomorphicContinuityPrinciple.satisfiesContinuityPrinciple {U : Set E} + (h : SatisfiesHolomorphicContinuityPrinciple U) : SatisfiesContinuityPrinciple U := by + intro a b ha hb hbd h0 + exact h (fun t ζ => a t + ζ • b t) (by fun_prop) + (fun t _ ζ _ => analyticAt_const.add (analyticAt_id.smul analyticAt_const)) hbd h0 + +variable {n : ℕ} + +/-- **Domains of holomorphy in coordinates satisfy the continuity principle for holomorphic +discs.** The coordinate-free version is +`IsDomainOfHolomorphy.satisfiesHolomorphicContinuityPrinciple`. -/ +theorem IsDomainOfHolomorphy.satisfiesHolomorphicContinuityPrinciple_fin {U : Set (Fin n → ℂ)} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : SatisfiesHolomorphicContinuityPrinciple U := by + intro φ hφc hφan hbd h0 + rcases eq_empty_or_nonempty Uᶜ with hc | hc + · have hU' : U = univ := compl_empty_iff.mp hc + intro t _ ζ _ + rw [hU'] + exact mem_univ _ + set p := clampIcc01 + have hpc : Continuous p := continuous_clampIcc01 + have hpI : ∀ t, p t ∈ Icc (0 : ℝ) 1 := clampIcc01_mem_Icc + have hpid : ∀ t ∈ Icc (0 : ℝ) 1, p t = t := fun t ht => clampIcc01_eq_of_mem_Icc ht + have hpp : ∀ t, p (p t) = p t := clampIcc01_idem + set Φ : ℝ × ℂ → Fin n → ℂ := fun q => φ (p q.1) q.2 with hΦ + have hΦc : Continuous Φ := hφc.comp ((hpc.comp continuous_fst).prodMk continuous_snd) + -- the compact set of boundary points and initial disc points + set K₀ := Φ '' (Icc (0 : ℝ) 1 ×ˢ sphere (0 : ℂ) 1) ∪ Φ '' ({0} ×ˢ closedBall (0 : ℂ) 1) with hK₀ + have hK₀c : IsCompact K₀ := + ((isCompact_Icc.prod (isCompact_sphere _ _)).image hΦc).union + ((isCompact_singleton.prod (isCompact_closedBall _ _)).image hΦc) + have hK₀U : K₀ ⊆ U := by + rintro _ (⟨⟨t, ζ⟩, ⟨ht, hζ⟩, rfl⟩ | ⟨⟨t, ζ⟩, ⟨ht, hζ⟩, rfl⟩) + · simp only [hΦ, hpid t ht] + exact hbd t ht ζ hζ + · simp only [mem_singleton_iff] at ht + simp only [hΦ, ht, hpid 0 (left_mem_Icc.mpr zero_le_one)] + exact h0 ζ hζ + have hK₀ne : K₀.Nonempty := + ⟨Φ (0, 1), Or.inl ⟨(0, 1), ⟨left_mem_Icc.mpr zero_le_one, by simp⟩, rfl⟩⟩ + -- the minimal boundary distance over that compact set + obtain ⟨z₀, hz₀K, hz₀min⟩ := + hK₀c.exists_isMinOn hK₀ne (continuous_infDist_pt Uᶜ).continuousOn + set m := infDist z₀ Uᶜ with hm + have hm0 : 0 < m := (infDist_pos_iff_notMem_closure hc).mp (by + rw [ho.isClosed_compl.closure_eq] + exact notMem_compl_iff.mpr (hK₀U hz₀K)) + have hmK : ∀ z ∈ K₀, m ≤ infDist z Uᶜ := fun z hz => hz₀min hz + have hmC : ‖(m : ℂ)‖ = m := by rw [Complex.norm_real, Real.norm_eq_abs, abs_of_pos hm0] + set L := {z : Fin n → ℂ | m ≤ infDist z Uᶜ} with hL + have hLc : IsClosed L := isClosed_le continuous_const (continuous_infDist_pt _) + have hLU : L ⊆ U := fun z hz => by + by_contra hzU + have : infDist z Uᶜ = 0 := infDist_zero_of_mem hzU + have hz' : m ≤ infDist z Uᶜ := hz + linarith + -- the parameters whose disc lies in `U` + set W := {t : ℝ | ∀ ζ ∈ closedBall (0 : ℂ) 1, Φ (t, ζ) ∈ U} with hW + have hdisc : ∀ t ∈ W, ∀ ζ ∈ closedBall (0 : ℂ) 1, Φ (t, ζ) ∈ L := by + intro t ht ζ hζ + have han : AnalyticOnNhd ℂ (φ (p t)) (closedBall 0 1) := hφan (p t) (hpI t) + have hdU : ∀ ζ ∈ closedBall (0 : ℂ) 1, φ (p t) ζ ∈ U := fun ζ hζ => ht ζ hζ + have hhull := mem_holomorphicHull_of_analytic_disc zero_lt_one han hdU hζ + have hKt : (φ (p t)) '' sphere 0 1 ⊆ K₀ := by + rintro _ ⟨ζ', hζ', rfl⟩ + exact Or.inl ⟨(p t, ζ'), ⟨hpI t, hζ'⟩, by simp only [hΦ, hpp]⟩ + have hKtc : IsCompact ((φ (p t)) '' sphere 0 1) := + (isCompact_sphere _ _).image_of_continuousOn (han.continuousOn.mono sphere_subset_closedBall) + have hrad := hU.holomorphic_radius_bound ho hKtc (hKt.trans hK₀U) (q := fun _ => (m : ℂ)) + analyticOnNhd_const (fun z hz => by + rw [hmC] + exact (ball_subset_ball (hmK z (hKt hz))).trans + (by simpa using ball_infDist_subset_compl (x := z) (s := Uᶜ))) _ hhull + rw [hmC] at hrad + change m ≤ infDist (φ (p t) ζ) Uᶜ + by_contra hlt + push Not at hlt + obtain ⟨y, hy, hdy⟩ := (infDist_lt_iff hc).mp hlt + exact hy (hrad (by rwa [mem_ball, dist_comm])) + have hWo : IsOpen W := by + rw [isOpen_iff_mem_nhds] + intro t ht + have := (isCompact_closedBall (0 : ℂ) 1).eventually_forall_of_forall_eventually + (x₀ := t) (P := fun t ζ => Φ (t, ζ) ∈ U) fun ζ hζ => + hΦc.continuousAt.preimage_mem_nhds (ho.mem_nhds (ht ζ hζ)) + exact this + have hWcl : IsClosed W := by + rw [← closure_subset_iff_isClosed] + intro t ht ζ hζ + have hne : NeBot (𝓝[W] t) := mem_closure_iff_nhdsWithin_neBot.mp ht + have htend : Tendsto (fun t' => Φ (t', ζ)) (𝓝[W] t) (𝓝 (Φ (t, ζ))) := + ((hΦc.comp (continuous_id.prodMk continuous_const)).tendsto t).mono_left nhdsWithin_le_nhds + have hmem : Φ (t, ζ) ∈ closure L := + mem_closure_of_tendsto htend (eventually_nhdsWithin_of_forall fun t' ht' => hdisc t' ht' ζ hζ) + rw [hLc.closure_eq] at hmem + exact hLU hmem + have hW0 : (0 : ℝ) ∈ W := by + intro ζ hζ + simp only [hΦ, hpid 0 (left_mem_Icc.mpr zero_le_one)] + exact h0 ζ hζ + have hWuniv : W = univ := IsClopen.eq_univ (⟨hWcl, hWo⟩ : IsClopen W) ⟨0, hW0⟩ + intro t ht ζ hζ + have := (hWuniv ▸ mem_univ t : t ∈ W) ζ hζ + simpa [hΦ, hpid t ht] using this + +end HolomorphicContinuity + +section Transport + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- Pseudoconvexity pulls back along a continuous linear equivalence. -/ +theorem IsPseudoconvex.of_image_equiv {U : Set E} (L : E ≃L[ℂ] F) + (h : IsPseudoconvex (L '' U)) : IsPseudoconvex U := by + obtain ⟨ho, φ, hφc, hφp, hφk⟩ := h + have hU : IsOpen U := by + have : U = L ⁻¹' (L '' U) := (L.injective.preimage_image U).symm + rw [this] + exact ho.preimage L.continuous + refine ⟨hU, fun z => φ (L z), hφc.comp L.continuous.continuousOn (mapsTo_image L U), ?_, + fun c => ?_⟩ + · have := hφp.comp_affine (L : E →L[ℂ] F) 0 + simp only [zero_add, ContinuousLinearEquiv.coe_coe] at this + exact this.mono fun z hz => mem_image_of_mem L hz + · have heq : {z ∈ U | φ (L z) ≤ c} = L.symm '' {w ∈ L '' U | φ w ≤ c} := by + ext z + constructor + · rintro ⟨hz, hc⟩ + exact ⟨L z, ⟨mem_image_of_mem L hz, hc⟩, L.symm_apply_apply z⟩ + · rintro ⟨w, ⟨hw, hc⟩, rfl⟩ + refine ⟨?_, by simpa using hc⟩ + obtain ⟨z, hz, rfl⟩ := hw + simpa using hz + rw [heq] + exact (hφk c).image L.symm.continuous + +/-- The holomorphic continuity principle pulls back along a continuous linear equivalence. -/ +theorem SatisfiesHolomorphicContinuityPrinciple.of_image_equiv {U : Set E} (L : E ≃L[ℂ] F) + (h : SatisfiesHolomorphicContinuityPrinciple (L '' U)) : + SatisfiesHolomorphicContinuityPrinciple U := by + intro φ hφc hφa hbd h0 t ht ζ hζ + have := h (fun t ζ => L (φ t ζ)) (L.continuous.comp hφc) + (fun t ht => (L.toContinuousLinearMap.analyticOnNhd univ).comp (hφa t ht) (mapsTo_univ _ _)) + (fun t ht ζ hζ => mem_image_of_mem L (hbd t ht ζ hζ)) + (fun ζ hζ => mem_image_of_mem L (h0 ζ hζ)) t ht ζ hζ + exact L.injective.mem_set_image.mp this + +variable [FiniteDimensional ℂ E] + +/-- **Domains of holomorphy are pseudoconvex.** The exhaustion is transported from the +coordinate version `IsDomainOfHolomorphy.isPseudoconvex_fin`. -/ +theorem IsDomainOfHolomorphy.isPseudoconvex {U : Set E} (hU : IsDomainOfHolomorphy U) + (ho : IsOpen U) : IsPseudoconvex U := by + let L := (Module.finBasis ℂ E).equivFunL + exact IsPseudoconvex.of_image_equiv L ((hU.image_equiv L).isPseudoconvex_fin (L.isOpenMap U ho)) + +/-- **Domains of holomorphy satisfy the continuity principle for holomorphic discs.** -/ +theorem IsDomainOfHolomorphy.satisfiesHolomorphicContinuityPrinciple {U : Set E} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : SatisfiesHolomorphicContinuityPrinciple U := by + let L := (Module.finBasis ℂ E).equivFunL + exact SatisfiesHolomorphicContinuityPrinciple.of_image_equiv L + ((hU.image_equiv L).satisfiesHolomorphicContinuityPrinciple_fin (L.isOpenMap U ho)) + +/-- Domains of holomorphy satisfy the affine continuity principle. -/ +theorem IsDomainOfHolomorphy.satisfiesContinuityPrinciple {U : Set E} + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) : SatisfiesContinuityPrinciple U := + (hU.satisfiesHolomorphicContinuityPrinciple ho).satisfiesContinuityPrinciple + +end Transport + +section Hartogs + +variable {E' : Type*} [NormedAddCommGroup E'] [NormedSpace ℂ E'] + +/-- **Hartogs convexity** for cylinder figures: whenever a Hartogs cylinder over an open +preconnected base, with disc fibers over a nonempty open part of the base, lies in the set, so +does the filled cylinder. -/ +@[expose] def IsHartogsConvex (U : Set (E' × ℂ)) : Prop := + ∀ (D D₀ : Set E') (ρ R : ℝ), IsOpen D → IsPreconnected D → IsOpen D₀ → D₀.Nonempty → + D₀ ⊆ D → 0 ≤ ρ → ρ < R → hartogsCylinder D D₀ ρ R ⊆ U → D ×ˢ ball 0 R ⊆ U + +/-- **The continuity principle implies Hartogs convexity ([Fritzsche–Grauert][FritzscheGrauert2002] +II.1.5).** The disc +fibers are slid along a path in the base from the part carrying full discs. -/ +theorem SatisfiesContinuityPrinciple.isHartogsConvex {U : Set (E' × ℂ)} + (h : SatisfiesContinuityPrinciple U) : IsHartogsConvex U := by + intro D D₀ ρ R hD hDc hD₀ hne hsub hρ hρR hcyl + rintro ⟨w, ζ₀⟩ ⟨hw, hζ₀⟩ + obtain ⟨w₀, hw₀⟩ := hne + have hζ₀' : ‖ζ₀‖ < R := mem_ball_zero_iff.mp hζ₀ + obtain ⟨R', hR'₁, hR'₂⟩ := exists_between (max_lt hρR hζ₀') + have hρR' : ρ < R' := (le_max_left _ _).trans_lt hR'₁ + have hζR' : ‖ζ₀‖ < R' := (le_max_right _ _).trans_lt hR'₁ + have hR'pos : 0 < R' := hρ.trans_lt hρR' + have hpath : JoinedIn D w₀ w := + (hD.isConnected_iff_isPathConnected.mp ⟨⟨w, hw⟩, hDc⟩).joinedIn w₀ (hsub hw₀) w hw + set γ := hpath.somePath with hγ + have hγD : ∀ t, γ.extend t ∈ D := fun t => by + have : γ.extend t ∈ range γ := by + rw [← Path.extend_range] + exact mem_range_self t + obtain ⟨s, hs⟩ := this + rw [← hs] + exact hpath.somePath_mem s + set a : ℝ → E' × ℂ := fun t => (γ.extend t, (0 : ℂ)) with ha + set b : ℝ → E' × ℂ := fun _ => ((0 : E'), (R' : ℂ)) with hb + have hpt : ∀ (t : ℝ) (ζ : ℂ), a t + ζ • b t = (γ.extend t, ζ * R') := fun t ζ => by + simp [ha, hb] + have hac : Continuous a := (γ.continuous_extend).prodMk continuous_const + have hbc : Continuous b := continuous_const + have hbd : ∀ t ∈ Icc (0 : ℝ) 1, ∀ ζ ∈ sphere (0 : ℂ) 1, a t + ζ • b t ∈ U := by + intro t _ ζ hζ + rw [hpt] + apply hcyl + have hζn : ‖ζ * R'‖ = R' := by + rw [norm_mul, mem_sphere_zero_iff_norm.mp hζ, one_mul, Complex.norm_real, + Real.norm_eq_abs, abs_of_pos hR'pos] + refine Or.inl ⟨hγD t, ?_, ?_⟩ + · rw [mem_ball_zero_iff, hζn]; exact hR'₂ + · rw [mem_closedBall_zero_iff, hζn]; exact not_le.mpr hρR' + have h0 : ∀ ζ ∈ closedBall (0 : ℂ) 1, a 0 + ζ • b 0 ∈ U := by + intro ζ hζ + rw [hpt] + apply hcyl + refine Or.inr ⟨by rw [Path.extend_zero]; exact hw₀, ?_⟩ + rw [mem_ball_zero_iff, norm_mul, Complex.norm_real, Real.norm_eq_abs, abs_of_pos hR'pos] + calc ‖ζ‖ * R' ≤ 1 * R' := + mul_le_mul_of_nonneg_right (mem_closedBall_zero_iff.mp hζ) hR'pos.le + _ < R := by linarith + have hfin := h a b hac hbc hbd h0 1 (right_mem_Icc.mpr zero_le_one) (ζ₀ / R') (by + rw [mem_closedBall_zero_iff, norm_div, Complex.norm_real, Real.norm_eq_abs, + abs_of_pos hR'pos, div_le_one hR'pos] + exact hζR'.le) + rw [hpt, Path.extend_one, div_mul_cancel₀ _ (by exact_mod_cast hR'pos.ne')] at hfin + exact hfin + +/-- Pseudoconvex sets in a product with `ℂ` are Hartogs convex. -/ +theorem IsPseudoconvex.isHartogsConvex {U : Set (E' × ℂ)} (h : IsPseudoconvex U) : + IsHartogsConvex U := + h.satisfiesContinuityPrinciple.isHartogsConvex + +end Hartogs + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RealUniqueness.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RealUniqueness.lean new file mode 100644 index 0000000000..61ec4d15c9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RealUniqueness.lean @@ -0,0 +1,129 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.IsolatedZeros +public import Mathlib.Analysis.Complex.CauchyIntegral + +import Mathlib.Analysis.SpecificLimits.Basic + +/-! +# Analytic uniqueness from positive real parameters + +This file records uniqueness principles for holomorphic functions whose values are known only on +the positive real locus. They are useful for transporting certain identities proved using real +probability measures to their complex analytic continuations. + +## Main results + +`AnalyticOnNhd.eqOn_of_eventuallyEq_ofReal` is one-variable uniqueness from agreement on a real +germ, on a connected continuation domain. `AnalyticOnNhd.eq_of_eqOn_posReal` is uniqueness of +entire functions of one variable from the positive reals. `AnalyticOnNhd.eq_of_eqOn_posReal_pi` +is the corresponding statement for entire functions of finitely many variables. All three +results allow values in any complex normed space; completeness of the target is not needed. +-/ + +open Complex Set Filter +open scoped Topology + +public noncomputable section RealUniqueness + +variable {H : Type*} [NormedAddCommGroup H] [NormedSpace ℂ H] + +/-- Local one-variable uniqueness from agreement on a real germ. This is the form useful when the +functions are only analytic on a connected continuation domain rather than entire. -/ +theorem AnalyticOnNhd.eqOn_of_eventuallyEq_ofReal {U : Set ℂ} {F G : ℂ → H} + {x₀ : ℝ} (hF : AnalyticOnNhd ℂ F U) (hG : AnalyticOnNhd ℂ G U) + (hU : IsPreconnected U) (hx₀ : (x₀ : ℂ) ∈ U) + (hEq : ∀ᶠ x : ℝ in 𝓝 x₀, F (x : ℂ) = G (x : ℂ)) : Set.EqOn F G U := by + let wR : ℕ → ℝ := fun n ↦ x₀ + (n + 1 : ℝ)⁻¹ + let w : ℕ → ℂ := fun n ↦ (wR n : ℂ) + have hwR : Tendsto wR atTop (𝓝 x₀) := by + simpa [wR] using tendsto_const_nhds.add + (tendsto_one_div_add_atTop_nhds_zero_nat (𝕜 := ℝ)) + have hw : Tendsto w atTop (𝓝 (x₀ : ℂ)) := by + exact Complex.continuous_ofReal.continuousAt.tendsto.comp hwR + have hwne : ∀ n, w n ≠ (x₀ : ℂ) := by + intro n h + have hr : x₀ + (n + 1 : ℝ)⁻¹ = x₀ := Complex.ofReal_injective h + have : (0 : ℝ) < (n + 1 : ℝ)⁻¹ := by positivity + linarith + have hwithin : Tendsto w atTop (𝓝[≠] (x₀ : ℂ)) := + tendsto_nhdsWithin_iff.mpr ⟨hw, Eventually.of_forall hwne⟩ + have hagree : ∀ᶠ n : ℕ in atTop, F (w n) = G (w n) := by + filter_upwards [hwR.eventually hEq] with n hn + exact hn + exact hF.eqOn_of_preconnected_of_frequently_eq hG hU hx₀ + (hwithin.frequently hagree.frequently) + +/-- Two entire functions of one complex variable which agree at every positive real number agree +everywhere. -/ +theorem AnalyticOnNhd.eq_of_eqOn_posReal {F G : ℂ → H} + (hF : AnalyticOnNhd ℂ F univ) (hG : AnalyticOnNhd ℂ G univ) + (hEq : ∀ x : ℝ, 0 < x → F (x : ℂ) = G (x : ℂ)) : F = G := by + have hEq' : ∀ᶠ x : ℝ in 𝓝 1, F (x : ℂ) = G (x : ℂ) := by + filter_upwards [eventually_gt_nhds (show (0 : ℝ) < 1 by norm_num)] with x hx + exact hEq x hx + have h := hF.eqOn_of_eventuallyEq_ofReal hG isPreconnected_univ (Set.mem_univ _) hEq' + exact funext fun z => h (Set.mem_univ z) + +/-- Two entire functions of finitely many complex variables which agree on all vectors of strictly +positive real parameters agree everywhere. No complex-open agreement hypothesis is needed. -/ +theorem AnalyticOnNhd.eq_of_eqOn_posReal_pi {ι : Type*} [Fintype ι] + {F G : (ι → ℂ) → H} (hF : AnalyticOnNhd ℂ F univ) + (hG : AnalyticOnNhd ℂ G univ) + (hEq : ∀ b : ι → ℝ, (∀ i, 0 < b i) → + F (fun i ↦ (b i : ℂ)) = G (fun i ↦ (b i : ℂ))) : F = G := by + classical + have hstep : ∀ s : Finset ι, ∀ b : ι → ℂ, + (∀ i, i ∉ s → ∃ x : ℝ, 0 < x ∧ b i = (x : ℂ)) → F b = G b := by + intro s + induction s using Finset.induction with + | empty => + intro b hb + choose r hr hbr using fun i ↦ hb i (by simp) + have hb_eq : b = fun i ↦ (r i : ℂ) := by + funext i + exact hbr i + rw [hb_eq] + exact hEq r hr + | @insert a s ha ih => + intro b hb + let L : ℂ → (ι → ℂ) := fun w ↦ Function.update b a w + have hL : AnalyticOnNhd ℂ L univ := by + intro w _ + apply AnalyticAt.pi + intro i + by_cases hia : i = a + · subst i + have heq : (fun x : ℂ ↦ L x a) = id := by + funext x + simp [L] + rw [heq] + exact analyticAt_id + · simpa [L, hia] using + (analyticAt_const : AnalyticAt ℂ (fun _ : ℂ ↦ b i) w) + have hslices : (fun w ↦ F (L w)) = (fun w ↦ G (L w)) := by + apply AnalyticOnNhd.eq_of_eqOn_posReal + · intro w _ + exact (hF (L w) (mem_univ _)).comp_of_eq (hL w (mem_univ _)) rfl + · intro w _ + exact (hG (L w) (mem_univ _)).comp_of_eq (hL w (mem_univ _)) rfl + · intro x hx + apply ih + intro i his + by_cases hia : i = a + · subst i + exact ⟨x, hx, by simp [L]⟩ + · simpa [L, hia] using hb i (by simp [his, hia]) + have := congrFun hslices (b a) + simpa [L] using this + funext b + exact hstep Finset.univ b (by simp) + +end RealUniqueness + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reindex.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reindex.lean new file mode 100644 index 0000000000..c9974ed3da --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reindex.lean @@ -0,0 +1,90 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Derivatives + +/-! +# Reindexing finite complex coordinate spaces + +Coordinate derivatives commute with renaming coordinates. The polydisc Cauchy formula is +transported along any enumeration of a finite index type; its value is independent of that +enumeration whenever the Cauchy hypotheses hold. + +## Main results + +`partialDeriv_reindex` and `iteratedPartialDeriv_reindex` transport coordinate derivatives along a +renaming of coordinates. `two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul_reindex` transports +the polydisc Cauchy formula along any enumeration of a finite index type. +-/ + +public section + +open Complex Function MeasureTheory Set +open scoped Real + +namespace SeveralComplexVariables + +variable {ι κ F : Type*} [Fintype ι] [DecidableEq ι] [Fintype κ] [DecidableEq κ] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +omit [Fintype ι] [Fintype κ] in +/-- Renaming coordinates renames a coordinate derivative by the inverse equivalence. -/ +theorem partialDeriv_reindex (e : κ ≃ ι) (f : (κ → ℂ) → F) (z : ι → ℂ) (i : ι) : + partialDeriv i (fun w => f (w ∘ e)) z = partialDeriv (e.symm i) f (z ∘ e) := by + change deriv (fun w => f (update z i w ∘ e)) (z i) = + deriv (fun w => f (update (z ∘ e) (e.symm i) w)) ((z ∘ e) (e.symm i)) + simp only [update_comp_equiv, comp_apply, e.apply_symm_apply] + +omit [Fintype ι] [Fintype κ] in +/-- All iterated coordinate derivatives are natural under coordinate reindexing. -/ +theorem iteratedPartialDeriv_reindex (e : κ ≃ ι) (f : (κ → ℂ) → F) (is : List ι) + (z : ι → ℂ) : + iteratedPartialDeriv is (fun w => f (w ∘ e)) z = + iteratedPartialDeriv (is.map e.symm) f (z ∘ e) := by + induction is generalizing z with + | nil => rfl + | cons i is ih => + simp only [iteratedPartialDeriv, List.map_cons] + rw [show iteratedPartialDeriv is (fun w => f (w ∘ e)) = + fun w => iteratedPartialDeriv (is.map e.symm) f (w ∘ e) by funext w; exact ih w] + exact partialDeriv_reindex e _ z i + +variable [CompleteSpace F] + +omit [Fintype ι] in +/-- Cauchy's polydisc formula for an arbitrary finite index type, integrated using any enumeration +by `Fin n`. No nonemptiness or positive-dimension hypothesis is needed. -/ +theorem two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul_reindex {n : ℕ} (e : Fin n ≃ ι) + {f : (ι → ℂ) → F} {c w : ι → ℂ} {R : ι → ℝ} + (hR : ∀ i, 0 < R i) (hw : ∀ i, ‖w i - c i‖ < R i) + (hfc : ContinuousOn f (closedPolydisc c R)) + (hfa : ∀ z ∈ closedPolydisc c R, ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) : + ((2 * π * I : ℂ) ^ n)⁻¹ • torusIntegral + (fun z => (∏ i, (z i - w (e i))⁻¹) • f (z ∘ e.symm)) (c ∘ e) (R ∘ e) = f w := by + have hm : MapsTo (fun z => z ∘ e.symm) + (closedPolydisc (c ∘ e) (R ∘ e)) (closedPolydisc c R) := by + intro z hz j hj + simpa only [comp_apply, e.apply_symm_apply] using hz (e.symm j) (mem_univ _) + have hc := hfc.comp (continuous_pi (fun j => continuous_apply (e.symm j))).continuousOn hm + have ha : ∀ z ∈ closedPolydisc (c ∘ e) (R ∘ e), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x ∘ e.symm)) (z i) := by + intro z hz i + simpa only [update_comp_equiv, Equiv.symm_symm, comp_apply, e.symm_apply_apply] using + hfa (z ∘ e.symm) (hm hz) (e i) + have hew : (w ∘ e) ∘ e.symm = w := by funext j; simp + simpa only [comp_apply, hew] using + two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul (f := fun z => f (z ∘ e.symm)) + (c := c ∘ e) (w := w ∘ e) (R := R ∘ e) (fun i => hR (e i)) + (fun i => hw (e i)) hc ha + +end SeveralComplexVariables + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt.lean new file mode 100644 index 0000000000..633d852e55 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt.lean @@ -0,0 +1,295 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.Analysis.Convex.PathConnected +public import Mathlib.Analysis.Convex.SpecificFunctions.Basic +public import Mathlib.Analysis.Convex.Topology + +/-! +# Reinhardt sets + +`IsReinhardt` expresses invariance under independent rotations of the complex coordinates. +`IsCompleteReinhardt` additionally permits independent shrinking of their moduli. Both are +properties of sets: openness, connectedness and nonemptiness are separate hypotheses. +Completeness here is unrelated to metric completeness. A nonempty complete Reinhardt set +contains the origin and is path connected, without an openness assumption. + +`logarithmicImage` is the inverse image of a set under coordinatewise real exponentiation, +viewed in complex coordinates. `IsLogarithmicallyConvex` asks for this real set to be convex. +For complete Reinhardt sets, logarithmic image commutes with taking the interior; both +completeness and logarithmic convexity are preserved by taking interiors. + +The centre is the origin in the specified coordinates. To express the property about `a`, apply +the predicate to `{z | a + z ∈ U}`. Arbitrary complex linear changes of coordinates need not +preserve either property. These definitions and results also allow empty coordinate types; no +finiteness assumption is needed for the basic geometry in the product topology. + +References: [Korevaar–Wiegerinck][KorevaarWiegerinck2017], Definitions 2.3.2 and 2.3.4; +[Lebl][Lebl2026], Section 1.2; [Boas][Boas2013] (2013), Sections 2.1--2.2. Polydisc examples are +provided in `SeveralComplexVariables.Polydisc`. + +## Main definitions + +* `IsReinhardt`: A set is Reinhardt if membership is preserved by independent coordinate rotations. +* `IsCompleteReinhardt`: A set is complete Reinhardt if membership is preserved by decreasing + coordinate moduli. +* `logarithmicImage`: The logarithmic image uses the positive real slice, avoiding logarithms at + zero. +* `IsLogarithmicallyConvex`: Logarithmic convexity means convexity of the logarithmic image. + +## Main results + +* `IsCompleteReinhardt.isReinhardt`: Every complete Reinhardt set is Reinhardt. +* `IsCompleteReinhardt.isPathConnected`: Every nonempty complete Reinhardt set is path connected in + the product topology. +* `IsCompleteReinhardt.interior`: The interior of a complete Reinhardt set is complete Reinhardt. +* `IsCompleteReinhardt.logarithmicImage_interior`: For complete Reinhardt sets, logarithmic image + commutes with taking the interior. +* `IsLogarithmicallyConvex.interior`: The interior of a complete logarithmically convex Reinhardt + set is logarithmically convex. +* `isOpen_logarithmicImage`: The logarithmic image of an open set is open. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +* [J. Lebl, *Tasty Bits of Several Complex Variables: A Whirlwind Tour of the Subject*][Lebl2026] +-/ + +public noncomputable section + +open Filter Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {ι : Type*} {U V : Set (ι → ℂ)} + +/-- A set is Reinhardt if membership is preserved by independent coordinate rotations. The centre is +zero; openness, connectedness and nonemptiness are not required. -/ +@[expose] def IsReinhardt (U : Set (ι → ℂ)) : Prop := + ∀ ⦃z⦄, z ∈ U → ∀ ⦃w⦄, (∀ i, ‖w i‖ = ‖z i‖) → w ∈ U + +/-- A set is complete Reinhardt if membership is preserved by decreasing coordinate moduli. This +includes rotations and allows zero coordinates; no topological hypotheses are imposed. -/ +@[expose] def IsCompleteReinhardt (U : Set (ι → ℂ)) : Prop := + ∀ ⦃z⦄, z ∈ U → ∀ ⦃w⦄, (∀ i, ‖w i‖ ≤ ‖z i‖) → w ∈ U + +/-- The empty set is Reinhardt. -/ +@[simp] theorem isReinhardt_empty : IsReinhardt (∅ : Set (ι → ℂ)) := + fun _ hz => hz.elim + +/-- The whole coordinate space is Reinhardt. -/ +@[simp] theorem isReinhardt_univ : IsReinhardt (univ : Set (ι → ℂ)) := + fun _ _ _ _ => mem_univ _ + +/-- The empty set is complete Reinhardt. -/ +@[simp] theorem isCompleteReinhardt_empty : IsCompleteReinhardt (∅ : Set (ι → ℂ)) := + fun _ hz => hz.elim + +/-- The whole coordinate space is complete Reinhardt. -/ +@[simp] theorem isCompleteReinhardt_univ : IsCompleteReinhardt (univ : Set (ι → ℂ)) := + fun _ _ _ _ => mem_univ _ + +/-- Every complete Reinhardt set is Reinhardt. -/ +theorem IsCompleteReinhardt.isReinhardt (hU : IsCompleteReinhardt U) : IsReinhardt U := + fun _ hz _ hw => hU hz (fun i => (hw i).le) + +/-- With no coordinates, every set is complete Reinhardt. -/ +theorem isCompleteReinhardt_of_isEmpty [IsEmpty ι] (U : Set (ι → ℂ)) : + IsCompleteReinhardt U := by + intro z hz w _ + simpa only [Subsingleton.elim w z] using hz + +/-- Intersections preserve Reinhardt symmetry. -/ +theorem IsReinhardt.inter (hU : IsReinhardt U) (hV : IsReinhardt V) : + IsReinhardt (U ∩ V) := + fun _ hz _ hw => ⟨hU hz.1 hw, hV hz.2 hw⟩ + +/-- Unions preserve Reinhardt symmetry, without any connectedness requirement. -/ +theorem IsReinhardt.union (hU : IsReinhardt U) (hV : IsReinhardt V) : + IsReinhardt (U ∪ V) := + fun _ hz _ hw => hz.elim (fun h => Or.inl (hU h hw)) (fun h => Or.inr (hV h hw)) + +/-- Arbitrary unions of Reinhardt sets are Reinhardt. -/ +theorem isReinhardt_iUnion {κ : Sort*} {S : κ → Set (ι → ℂ)} + (hS : ∀ k, IsReinhardt (S k)) : IsReinhardt (⋃ k, S k) := by + intro z hz w hw + obtain ⟨k, hk⟩ := mem_iUnion.mp hz + exact mem_iUnion.mpr ⟨k, hS k hk hw⟩ + +/-- Intersections preserve the complete Reinhardt property. -/ +theorem IsCompleteReinhardt.inter (hU : IsCompleteReinhardt U) + (hV : IsCompleteReinhardt V) : IsCompleteReinhardt (U ∩ V) := + fun _ hz _ hw => ⟨hU hz.1 hw, hV hz.2 hw⟩ + +/-- Unions preserve the complete Reinhardt property. -/ +theorem IsCompleteReinhardt.union (hU : IsCompleteReinhardt U) + (hV : IsCompleteReinhardt V) : IsCompleteReinhardt (U ∪ V) := + fun _ hz _ hw => hz.elim (fun h => Or.inl (hU h hw)) (fun h => Or.inr (hV h hw)) + +/-- Arbitrary unions of complete Reinhardt sets are complete Reinhardt. -/ +theorem isCompleteReinhardt_iUnion {κ : Sort*} {S : κ → Set (ι → ℂ)} + (hS : ∀ k, IsCompleteReinhardt (S k)) : IsCompleteReinhardt (⋃ k, S k) := by + intro z hz w hw + obtain ⟨k, hk⟩ := mem_iUnion.mp hz + exact mem_iUnion.mpr ⟨k, hS k hk hw⟩ + +/-- Multiplying each coordinate by a complex number of modulus one preserves a Reinhardt set. -/ +theorem IsReinhardt.mul_mem (hU : IsReinhardt U) {z : ι → ℂ} (hz : z ∈ U) + {a : ι → ℂ} (ha : ∀ i, ‖a i‖ = 1) : (fun i => a i * z i) ∈ U := + hU hz (fun i => by simp [ha i]) + +/-- Independent complex contractions preserve a complete Reinhardt set. -/ +theorem IsCompleteReinhardt.mul_mem (hU : IsCompleteReinhardt U) {z : ι → ℂ} + (hz : z ∈ U) {a : ι → ℂ} (ha : ∀ i, ‖a i‖ ≤ 1) : (fun i => a i * z i) ∈ U := by + apply hU hz + intro i + rw [norm_mul] + exact mul_le_of_le_one_left (norm_nonneg _) (ha i) + +/-- A nonempty complete Reinhardt set contains the origin. -/ +theorem IsCompleteReinhardt.zero_mem (hU : IsCompleteReinhardt U) (hne : U.Nonempty) : + 0 ∈ U := by + obtain ⟨z, hz⟩ := hne + exact hU hz (fun i => by simp) + +/-- A complete Reinhardt set is star-convex about the origin, including when it is empty. -/ +theorem IsCompleteReinhardt.starConvex (hU : IsCompleteReinhardt U) : + StarConvex ℝ (0 : ι → ℂ) U := by + intro z hz a b ha hb hab + simp only [smul_zero, zero_add] + apply hU hz + intro i + change ‖b • z i‖ ≤ ‖z i‖ + rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg hb] + exact mul_le_of_le_one_left (norm_nonneg _) (by linarith) + +/-- Every nonempty complete Reinhardt set is path connected in the product topology. -/ +theorem IsCompleteReinhardt.isPathConnected (hU : IsCompleteReinhardt U) + (hne : U.Nonempty) : IsPathConnected U := + hU.starConvex.isPathConnected (hU.zero_mem hne) + +/-- Every nonempty complete Reinhardt set is connected. -/ +theorem IsCompleteReinhardt.isConnected (hU : IsCompleteReinhardt U) + (hne : U.Nonempty) : IsConnected U := + (hU.isPathConnected hne).isConnected + +/-- Complete Reinhardt sets are preconnected; this statement also covers the empty set. -/ +theorem IsCompleteReinhardt.isPreconnected (hU : IsCompleteReinhardt U) : + IsPreconnected U := by + rcases U.eq_empty_or_nonempty with rfl | hne + · exact isPreconnected_empty + · exact (hU.isConnected hne).isPreconnected + +/-- The logarithmic image uses the positive real slice, avoiding logarithms at zero. For a Reinhardt +set this is its usual image under coordinatewise log modulus. -/ +@[expose] def logarithmicImage (U : Set (ι → ℂ)) : Set (ι → ℝ) := + {x | (fun i => (Real.exp (x i) : ℂ)) ∈ U} + +/-- Logarithmic convexity means convexity of the logarithmic image. Reinhardt symmetry, +completeness, openness and nonemptiness remain separate hypotheses. -/ +@[expose] def IsLogarithmicallyConvex (U : Set (ι → ℂ)) : Prop := + Convex ℝ (logarithmicImage U) + +/-- Membership of the logarithmic image is membership of the exponential coordinate vector. -/ +@[simp] theorem mem_logarithmicImage {x : ι → ℝ} : + x ∈ logarithmicImage U ↔ (fun i => (Real.exp (x i) : ℂ)) ∈ U := Iff.rfl + +/-- The empty set is logarithmically convex. -/ +@[simp] theorem isLogarithmicallyConvex_empty : + IsLogarithmicallyConvex (∅ : Set (ι → ℂ)) := convex_empty + +/-- The whole coordinate space is logarithmically convex. -/ +@[simp] theorem isLogarithmicallyConvex_univ : + IsLogarithmicallyConvex (univ : Set (ι → ℂ)) := convex_univ + +/-- Intersections preserve logarithmic convexity. -/ +theorem IsLogarithmicallyConvex.inter (hU : IsLogarithmicallyConvex U) + (hV : IsLogarithmicallyConvex V) : IsLogarithmicallyConvex (U ∩ V) := + Convex.inter hU hV + +/-- The logarithmic image of an open set is open. -/ +theorem isOpen_logarithmicImage (hU : IsOpen U) : IsOpen (logarithmicImage U) := + hU.preimage (continuous_pi fun i => Complex.continuous_ofReal.comp + (Real.continuous_exp.comp (continuous_apply i))) + +/-- The interior of a complete Reinhardt set is complete Reinhardt. The proof also handles points on +coordinate hyperplanes, where coordinate contractions need not be open maps. -/ +theorem IsCompleteReinhardt.interior (hU : IsCompleteReinhardt U) : + IsCompleteReinhardt (_root_.interior U) := by + classical + intro z hz w hw + let f : (ι → ℂ) → (ι → ℂ) := fun v i => + if z i = 0 then v i else (max ‖z i‖ ‖v i‖ / ‖z i‖) • z i + have hf : Continuous f := by + apply continuous_pi + intro i + dsimp [f] + split_ifs + · exact continuous_apply i + · exact ((continuous_const.max (continuous_apply i).norm).div_const _).smul continuous_const + have hfw : f w = z := by + ext i + dsimp [f] + split_ifs with hi + · have hwi : w i = 0 := norm_eq_zero.mp (le_antisymm + (by simpa [hi] using hw i) (norm_nonneg _)) + simp [hi, hwi] + · simp [max_eq_left (hw i), norm_ne_zero_iff.mpr hi] + have hnorm (v : ι → ℂ) (i : ι) : ‖v i‖ ≤ ‖f v i‖ := by + dsimp [f] + split_ifs with hi + · exact le_rfl + · rw [norm_mul, Complex.norm_real, Real.norm_eq_abs, abs_of_nonneg + (div_nonneg (le_max_of_le_left (norm_nonneg _)) (norm_nonneg _)), + div_mul_cancel₀ _ (norm_ne_zero_iff.mpr hi)] + exact le_max_right _ _ + apply mem_interior_iff_mem_nhds.mpr + have hn : ∀ᶠ v in 𝓝 w, f v ∈ _root_.interior U := + (hf.continuousAt : ContinuousAt f w) (by simpa [hfw] using isOpen_interior.mem_nhds hz) + filter_upwards [hn] with v hv + exact hU (interior_subset hv) (hnorm v) + +/-- For complete Reinhardt sets, logarithmic image commutes with taking the interior. -/ +theorem IsCompleteReinhardt.logarithmicImage_interior (hU : IsCompleteReinhardt U) : + logarithmicImage (_root_.interior U) = _root_.interior (logarithmicImage U) := by + apply Subset.antisymm + · exact (isOpen_logarithmicImage isOpen_interior).subset_interior_iff.mpr + (fun x hx => (interior_subset hx : (fun i => (Real.exp (x i) : ℂ)) ∈ U)) + · intro x hx + change (fun i => (Real.exp (x i) : ℂ)) ∈ _root_.interior U + let z : ι → ℂ := fun i => Real.exp (x i) + have hc : ContinuousAt (fun w : ι → ℂ => fun i => Real.log ‖w i‖) z := by + apply continuousAt_pi.mpr + intro i + apply (continuousAt_apply i z).norm.log + simp [z, Real.exp_ne_zero] + have heq : (fun i => Real.log ‖z i‖) = x := by + ext i + simp [z] + have hn : ∀ᶠ w in 𝓝 z, (fun i => Real.log ‖w i‖) ∈ logarithmicImage U := + hc (by simpa [heq] using mem_interior_iff_mem_nhds.mp hx) + apply mem_interior_iff_mem_nhds.mpr + filter_upwards [hn] with w hw + apply hU hw + intro i + by_cases hi : ‖w i‖ = 0 + · simp [hi] + · simp [Real.exp_log (lt_of_le_of_ne (norm_nonneg _) (Ne.symm hi))] + +/-- The interior of a complete logarithmically convex Reinhardt set is logarithmically convex. -/ +theorem IsLogarithmicallyConvex.interior (hU : IsLogarithmicallyConvex U) + (hc : IsCompleteReinhardt U) : IsLogarithmicallyConvex (_root_.interior U) := by + unfold IsLogarithmicallyConvex + rw [hc.logarithmicImage_interior] + exact (show Convex ℝ (logarithmicImage U) from hU).interior + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/Extension.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/Extension.lean new file mode 100644 index 0000000000..5eea353bc6 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/Extension.lean @@ -0,0 +1,279 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LaurentSeries +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscTaylor +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PowerSeriesConvergence.Analytic + +/-! +# Extension to Reinhardt hulls + +Power series extend analytic functions from complete Reinhardt domains. More generally, a +connected Reinhardt domain meeting every coordinate hyperplane has a power-series extension to +its geometric logarithmic hull, even if it does not contain the origin. The hull here includes +zero coordinates. This is extension between subsets of ℂⁿ; no abstract envelope or Riemann +domain is constructed. + +Laurent expansion gives power-series extension to logarithmic and complete Reinhardt hulls. The +geometric inclusion of the complete hull in the logarithmic hull for open Reinhardt sets +containing zero is proved independently of Laurent expansion. Analyticity of the extended sums +follows from the proved arbitrary-coefficient convergence theorem. References: +[Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), Corollary 2.4.3, Theorem 2.5.1, Corollary +2.5.2, and Theorem 2.8.2. + +## Main results + +`IsCompleteReinhardt.subset_convergenceDomain_and_eqOn_powerSeriesSum` is the Taylor series of a +holomorphic function on a complete Reinhardt domain. +`exists_extension_logarithmicReinhardtHull_of_zero_mem` and `exists_extension_completeReinhardtHull` +extend to the logarithmic and complete hulls. +`completeReinhardtHull_subset_logarithmicReinhardtHull` is the geometric inclusion when the set is +open and contains the origin. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology NNReal + +namespace SeveralComplexVariables + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Banach-valued normalized multivariate Taylor coefficients at the origin. -/ +@[expose] def taylorCoefficientsAtZero (f : (Fin n → ℂ) → F) : MvPowerSeries (Fin n) F := + fun m => (∏ i, (m i).factorial : ℂ)⁻¹ • multiIndexDeriv m f 0 + +omit [CompleteSpace F] in +private theorem summable_polydiscTaylor_terms {f : (Fin n → ℂ) → F} + (z : Fin n → ℂ) (r : Fin n → ℝ≥0) (M : ℝ) + (hr : ∀ i, (0 : ℝ) < r i) (hM0 : 0 ≤ M) + (hMb : ∀ y ∈ closedPolydisc 0 (fun i => (r i : ℝ)), ‖f y‖ ≤ M) + (hq : ∀ i, ‖‖z i‖ / (r i : ℝ)‖ < 1) : + Summable (fun m : Fin n → ℕ => + ‖(∏ i, z i ^ m i) • polydiscCauchyCoeffWithRadii f 0 (fun i => (r i : ℝ)) m‖) := + ((hasSum_pi_geometric (fun i => ‖z i‖ / (r i : ℝ)) hq).summable.mul_left M).of_nonneg_of_le + (fun _ => norm_nonneg _) (fun m => norm_polydiscTaylor_term_le hr hM0 hMb + (fun _ => le_rfl) m) + +private theorem summable_finsupp_equiv {a : (Fin n → ℕ) → ℝ} (h : Summable a) : + Summable (fun m : Fin n →₀ ℕ => a m) := + (Finsupp.equivFunOnFinite : (Fin n →₀ ℕ) ≃ (Fin n → ℕ)).summable_iff.mpr h + +omit [CompleteSpace F] in +omit [NormedSpace ℂ F] in +private theorem hasSum_finsupp_equiv {a : (Fin n → ℕ) → F} {x : F} (h : HasSum a x) : + HasSum (fun m : Fin n →₀ ℕ => a m) x := + (Finsupp.equivFunOnFinite : (Fin n →₀ ℕ) ≃ (Fin n → ℕ)).hasSum_iff.mpr h + +private theorem taylorCoefficientsAtZero_polydisc {f : (Fin n → ℂ) → F} + (z : Fin n → ℂ) (r : Fin n → ℝ≥0) (M : ℝ) + (hr : ∀ i, (0 : ℝ) < r i) (hzr : ∀ i, ‖z i‖ < r i) + (hfc : ContinuousOn f (closedPolydisc 0 (fun i => (r i : ℝ)))) + (hfa : ∀ y ∈ closedPolydisc 0 (fun i => (r i : ℝ)), ∀ i, + AnalyticAt ℂ (fun v => f (Function.update y i v)) (y i)) + (hMb : ∀ y ∈ closedPolydisc 0 (fun i => (r i : ℝ)), ‖f y‖ ≤ M) (hM0 : 0 ≤ M) : + Summable (fun m : Fin n →₀ ℕ => ‖(∏ i, z i ^ m i) • taylorCoefficientsAtZero f m‖) ∧ + HasSum (fun m : Fin n →₀ ℕ => (∏ i, z i ^ m i) • taylorCoefficientsAtZero f m) (f z) := by + classical + have he : ∀ m : Fin n →₀ ℕ, taylorCoefficientsAtZero f m = + polydiscCauchyCoeffWithRadii f 0 (fun i => (r i : ℝ)) m := + fun m => (polydiscCauchyCoeffWithRadii_eq_multiIndexDeriv hr hfc hfa m).symm + have hq : ∀ i, ‖‖z i‖ / (r i : ℝ)‖ < 1 := by + intro i + rw [Real.norm_eq_abs, abs_of_nonneg (div_nonneg (norm_nonneg _) (hr i).le), div_lt_one (hr i)] + exact hzr i + have hnorm := summable_polydiscTaylor_terms z r M hr hM0 hMb hq + have hsum := hasSum_polydiscTaylor (f := f) (c := 0) (h := z) hr (fun i => hzr i) hfc hfa hMb + constructor + · simp_rw [he] + exact summable_finsupp_equiv hnorm + · simp_rw [he] + have hs : HasSum (fun m : Fin n → ℕ => + (∏ i, z i ^ m i) • polydiscCauchyCoeffWithRadii f 0 (fun i => (r i : ℝ)) m) (f z) := by + simpa only [zero_add] using hsum + exact hasSum_finsupp_equiv hs + +/-- On a complete Reinhardt open set, the Taylor series at zero represents the function, and the +entire set lies inside its absolute-convergence domain. The proof applies the existing polydisc +Taylor theorem and coefficient estimates. -/ +theorem IsCompleteReinhardt.subset_convergenceDomain_and_eqOn_powerSeriesSum {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsCompleteReinhardt U) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) : + U ⊆ powerSeriesConvergenceDomain (taylorCoefficientsAtZero f) ∧ + EqOn (powerSeriesSum (taylorCoefficientsAtZero f)) f U := by + classical + have hpoint : ∀ z ∈ U, + Summable (fun m : Fin n →₀ ℕ => ‖(∏ i, z i ^ m i) • taylorCoefficientsAtZero f m‖) ∧ + HasSum (fun m : Fin n →₀ ℕ => (∏ i, z i ^ m i) • taylorCoefficientsAtZero f m) (f z) := by + intro z hz + obtain ⟨r, hrU, hzr⟩ := hc.isReinhardt.exists_strict_modulus_majorant ho hz + have hr : ∀ i, (0 : ℝ) < r i := fun i => lt_of_le_of_lt (norm_nonneg _) (hzr i) + have hBU : closedPolydisc 0 (fun i => (r i : ℝ)) ⊆ U := by + intro y hy + apply hc hrU + intro i + simpa only [Complex.norm_of_nonneg (NNReal.coe_nonneg _), Pi.zero_apply, dist_zero_right] + using + (mem_closedPolydisc.mp hy i) + have hfc := hf.continuousOn.mono hBU + have hfa : ∀ y ∈ closedPolydisc 0 (fun i => (r i : ℝ)), ∀ i, + AnalyticAt ℂ (fun v => f (Function.update y i v)) (y i) := by + intro y hy i + have hd : Differentiable ℂ (fun v => Function.update y i v) := + fun v => (hasDerivAt_update y i v).differentiableAt + exact (hf y (hBU hy)).comp_of_eq (hd.analyticAt (y i)) (by simp) + obtain ⟨M, hM⟩ := (isCompact_closedPolydisc 0 (fun i => (r i : ℝ))).bddAbove_image + hfc.norm + have hMb : ∀ y ∈ closedPolydisc 0 (fun i => (r i : ℝ)), ‖f y‖ ≤ M := + fun y hy => hM ⟨y, hy, rfl⟩ + have hM0 : 0 ≤ M := (norm_nonneg (f 0)).trans + (hMb 0 (mem_closedPolydisc.mpr (fun i => by simpa only [Pi.zero_apply, dist_self] + using (hr i).le))) + exact taylorCoefficientsAtZero_polydisc z r M hr hzr hfc hfa hMb hM0 + refine ⟨ho.subset_interior_iff.mpr (fun z hz => ?_), fun z hz => (hpoint z hz).2.tsum_eq⟩ + exact mem_powerSeriesAbsConvergenceSet_iff.mpr (hpoint z hz).1 + +/-- **Extension from a complete Reinhardt domain to its logarithmic hull.** The explicit +extension is its Taylor sum. -/ +theorem analyticOnNhd_taylorSum_logarithmicReinhardtHull {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsCompleteReinhardt U) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) : + AnalyticOnNhd ℂ (powerSeriesSum (taylorCoefficientsAtZero f)) (logarithmicReinhardtHull U) ∧ + EqOn (powerSeriesSum (taylorCoefficientsAtZero f)) f U := by + obtain ⟨hD, he⟩ := IsCompleteReinhardt.subset_convergenceDomain_and_eqOn_powerSeriesSum ho hc hf + exact ⟨(analyticOnNhd_powerSeriesSum _).mono + (logarithmicReinhardtHull_min hD (isReinhardt_powerSeriesConvergenceDomain _) + (hasGeometricallyConvexModuli_powerSeriesConvergenceDomain _)), he⟩ + +/-- **Power-series extension from a Reinhardt domain meeting each coordinate hyperplane.** +The points on different hyperplanes need not coincide. The proof eliminates negative +Laurent coefficients and uses geometric convexity of the convergence domain; it depends +on the Laurent expansion theorem. -/ +theorem exists_powerSeries_extension_of_meets_coordinateHyperplanes + {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hc : IsConnected U) (hR : IsReinhardt U) + (hmeet : ∀ i, ∃ z ∈ U, z i = 0) {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) : + ∃ c : MvPowerSeries (Fin n) F, + logarithmicReinhardtHull U ⊆ powerSeriesConvergenceDomain c ∧ EqOn (powerSeriesSum c) f U := + by + classical + obtain ⟨z₀, hz₀⟩ := hc.nonempty + obtain ⟨r, hrU, hrz⟩ := hR.exists_strict_modulus_majorant ho hz₀ + have hr : ∀ i, (0 : ℝ) < r i := fun i => lt_of_le_of_lt (norm_nonneg _) (hrz i) + obtain ⟨hsum, hnorm, hneg, _, _⟩ := multivariableLaurent_expansion ho hc.isPreconnected hR hf hr + hrU + let e : (Fin n →₀ ℕ) → (Fin n → ℤ) := fun m i => (m i : ℤ) + have hinj : Function.Injective e := by + intro m k he + ext i + exact_mod_cast (show (m i : ℤ) = (k i : ℤ) from congrFun he i) + let c : MvPowerSeries (Fin n) F := fun m => multivariableLaurentCoeff f (fun i => (r i : ℝ)) (e m) + have hterm : ∀ m z, multivariableLaurentTerm (multivariableLaurentCoeff f (fun i => (r i : ℝ))) + (e m) z = (∏ i, z i ^ m i) • c m := by + intro m z + simp only [multivariableLaurentTerm, e, c, zpow_natCast] + have hzero : ∀ k, k ∉ Set.range e → multivariableLaurentCoeff f (fun i => (r i : ℝ)) k = 0 := by + intro k hk + by_cases hp : ∀ i, 0 ≤ k i + · exfalso + apply hk + refine ⟨Finsupp.equivFunOnFinite.symm (fun i => (k i).toNat), ?_⟩ + ext i + simp [e, Int.toNat_of_nonneg (hp i)] + · push Not at hp + obtain ⟨i, hi⟩ := hp + exact hneg k i (hmeet i) hi + have hA : U ⊆ powerSeriesAbsConvergenceSet c := by + intro z hz + apply mem_powerSeriesAbsConvergenceSet_iff.mpr + exact ((hnorm z hz).comp_injective hinj).congr (fun m => congrArg norm (hterm m z)) + refine ⟨c, logarithmicReinhardtHull_min (ho.subset_interior_iff.mpr hA) + (isReinhardt_powerSeriesConvergenceDomain c) + (hasGeometricallyConvexModuli_powerSeriesConvergenceDomain c), ?_⟩ + intro z hz + have hs := (hinj.hasSum_iff (fun k hk => by + simp only [multivariableLaurentTerm, hzero k hk, smul_zero])).mpr (hsum.hasSum hz) + exact (hs.congr_fun (fun m => (hterm m z).symm)).tsum_eq + +/-- Theorem 2.8.2: extension to the logarithmic hull when every coordinate hyperplane is met. +Depends on the Laurent expansion, and allows Banach-valued functions. -/ +theorem exists_extension_logarithmicReinhardtHull_of_meets_coordinateHyperplanes + {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hc : IsConnected U) (hR : IsReinhardt U) + (hmeet : ∀ i, ∃ z ∈ U, z i = 0) {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) : + ∃ g, AnalyticOnNhd ℂ g (logarithmicReinhardtHull U) ∧ EqOn g f U := by + obtain ⟨c, hD, he⟩ := exists_powerSeries_extension_of_meets_coordinateHyperplanes ho hc hR hmeet + hf + exact ⟨powerSeriesSum c, (analyticOnNhd_powerSeriesSum c).mono hD, he⟩ + +/-- Corollary 2.5.2: a connected Reinhardt domain containing zero admits extension to its +logarithmic hull. Depends on the Laurent expansion. -/ +theorem exists_extension_logarithmicReinhardtHull_of_zero_mem + {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hc : IsConnected U) (hR : IsReinhardt U) + (hzero : 0 ∈ U) {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) : + ∃ g, AnalyticOnNhd ℂ g (logarithmicReinhardtHull U) ∧ EqOn g f U := + exists_extension_logarithmicReinhardtHull_of_meets_coordinateHyperplanes ho hc hR + (fun _ => ⟨0, hzero, rfl⟩) hf + +/-- The geometric logarithmic hull of an open Reinhardt set containing zero contains its complete +Reinhardt hull. Interpolate a strict modulus majorant with radius vectors converging to zero; +the calculation also includes vanishing coordinates. -/ +theorem completeReinhardtHull_subset_logarithmicReinhardtHull + {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hR : IsReinhardt U) (hzero : 0 ∈ U) : + completeReinhardtHull U ⊆ logarithmicReinhardtHull U := by + rintro w ⟨z, hz, hw⟩ + obtain ⟨r, hrU, hzr⟩ := hR.exists_strict_modulus_majorant ho hz + have hwr (i : Fin n) : ‖w i‖₊ < r i := (show ‖w i‖₊ ≤ ‖z i‖₊ from hw i).trans_lt (hzr i) + have hr (i : Fin n) : 0 < r i := (show 0 ≤ ‖w i‖₊ from zero_le).trans_lt (hwr i) + let v (k : ℕ) : Fin n → ℝ≥0 := fun i => r i * (‖w i‖₊ / r i) ^ k + have hv : Tendsto (fun k i => (v k i : ℂ)) atTop (𝓝 0) := by + apply tendsto_pi_nhds.mpr + intro i + have hratio : ‖w i‖₊ / r i < 1 := (div_lt_one (hr i)).mpr (hwr i) + have h := (NNReal.tendsto_pow_atTop_nhds_zero_of_lt_one hratio).const_mul (r i) + have hreal := NNReal.tendsto_coe.mpr h + simpa only [mul_zero, NNReal.coe_zero, Complex.ofReal_zero, Function.comp_def, + v, Pi.zero_apply] using + Complex.continuous_ofReal.continuousAt.tendsto.comp hreal + obtain ⟨k, hk, hvU⟩ := ((eventually_ge_atTop 1).and (hv.eventually (ho.mem_nhds hzero))).exists + have hkpos : 0 < (k : ℝ) := by exact_mod_cast (show 0 < k by omega) + have hkle : 1 ≤ (k : ℝ) := by exact_mod_cast hk + have ha : 0 ≤ (k : ℝ)⁻¹ := (inv_pos.mpr hkpos).le + have hb : 0 ≤ 1 - (k : ℝ)⁻¹ := sub_nonneg.mpr (inv_le_one_of_one_le₀ hkle) + have hm := isGeometricallyConvex_geometricConvexHull (modulusTrace U) + (subset_geometricConvexHull _ (hR.mem_modulusTrace_iff.mpr hvU)) + (subset_geometricConvexHull _ (hR.mem_modulusTrace_iff.mpr hrU)) + ha hb (add_sub_cancel _ _) + have he : geometricCombination (k : ℝ)⁻¹ (1 - (k : ℝ)⁻¹) (v k) r = + fun i => ‖w i‖₊ := by + funext i + dsimp [geometricCombination, v] + rw [NNReal.mul_rpow, NNReal.pow_rpow_inv_natCast _ (by omega : k ≠ 0)] + calc + r i ^ (k : ℝ)⁻¹ * (‖w i‖₊ / r i) * r i ^ (1 - (k : ℝ)⁻¹) = + (r i ^ (k : ℝ)⁻¹ * r i ^ (1 - (k : ℝ)⁻¹)) * (‖w i‖₊ / r i) := by ring + _ = r i * (‖w i‖₊ / r i) := by + rw [← NNReal.rpow_add_of_nonneg _ ha hb, add_sub_cancel, NNReal.rpow_one] + _ = ‖w i‖₊ := mul_div_cancel₀ _ (hr i).ne' + change (fun i => ‖w i‖₊) ∈ geometricConvexHull (modulusTrace U) + exact he ▸ hm + +/-- Theorem 2.5.1: extension to the complete Reinhardt hull, obtained by restricting the +logarithmic-hull extension. Depends on the Laurent expansion. -/ +theorem exists_extension_completeReinhardtHull + {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hc : IsConnected U) (hR : IsReinhardt U) + (hzero : 0 ∈ U) {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) : + ∃ g, AnalyticOnNhd ℂ g (completeReinhardtHull U) ∧ EqOn g f U := by + obtain ⟨g, hg, he⟩ := exists_extension_logarithmicReinhardtHull_of_zero_mem ho hc hR hzero hf + exact ⟨g, hg.mono (completeReinhardtHull_subset_logarithmicReinhardtHull ho hR hzero), he⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/GeometricConvexity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/GeometricConvexity.lean new file mode 100644 index 0000000000..6597692b43 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/GeometricConvexity.lean @@ -0,0 +1,270 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.MeanInequalities +public import Mathlib.Analysis.Real.Sqrt +public import Mathlib.Topology.Homeomorph.Lemmas +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt + +/-! +# Geometric convexity including zero coordinates + +Geometric combinations of nonnegative radius vectors include coordinate hyperplanes. Weights are +nonnegative and sum to one, as in `Convex`. Mathlib's convention `0 ^ 0 = 1` gives the expected +endpoints. The old logarithmic-image predicate remains unchanged. Reinhardt symmetry, openness, +and completeness are separate assumptions. Positive geometric interpolation is an open map, +including on coordinate hyperplanes. Consequently, interiors preserve geometric convexity and +geometric convex hulls preserve openness. + +Reference: [Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), §2.2, Definition 2.2.3. + +## Main definitions + +* `geometricCombination`: Coordinatewise weighted geometric combination of nonnegative radii. +* `IsGeometricallyConvex`: Closure under geometric combinations, including zero coordinates and + endpoint weights. +* `geometricConvexHull`: The geometric convex hull, with zero coordinates included. +* `modulusTrace`: The modulus trace of a complex coordinate set, with values in nonnegative radii. +* `HasGeometricallyConvexModuli`: Logarithmic convexity including zero coordinates is geometric + convexity of the trace. + +## Main results + +* `isGeometricallyConvex_geometricConvexHull`: The geometric convex hull is geometrically convex. +* `geometricConvexHull_min`: Minimality of the geometric convex hull. +* `isOpenMap_geometricCombination`: Positive weighted geometric interpolation is an open map on + pairs of radius vectors. +* `IsGeometricallyConvex.interior`: The interior of a geometrically convex set of radii is + geometrically convex. +* `isOpen_geometricConvexHull`: The geometric convex hull of an open set of nonnegative radii is + open. +* `HasGeometricallyConvexModuli.isLogarithmicallyConvex`: Strong logarithmic convexity implies + convexity of the positive logarithmic image. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Set Filter +open scoped NNReal Topology + +namespace SeveralComplexVariables + +variable {ι : Type*} + +/-- Coordinatewise weighted geometric combination of nonnegative radii. -/ +@[expose] def geometricCombination (a b : ℝ) (r s : ι → ℝ≥0) : ι → ℝ≥0 := + fun i => r i ^ a * s i ^ b + +/-- Closure under geometric combinations, including zero coordinates and endpoint weights. -/ +@[expose] def IsGeometricallyConvex (S : Set (ι → ℝ≥0)) : Prop := + ∀ ⦃r⦄, r ∈ S → ∀ ⦃s⦄, s ∈ S → ∀ ⦃a b : ℝ⦄, + 0 ≤ a → 0 ≤ b → a + b = 1 → geometricCombination a b r s ∈ S + +/-- The left endpoint of geometric interpolation. -/ +@[simp] theorem geometricCombination_one_zero (r s : ι → ℝ≥0) : + geometricCombination 1 0 r s = r := by ext i; simp [geometricCombination] + +/-- The right endpoint of geometric interpolation. -/ +@[simp] theorem geometricCombination_zero_one (r s : ι → ℝ≥0) : + geometricCombination 0 1 r s = s := by ext i; simp [geometricCombination] + +/-- Interpolating a radius vector with itself fixes it, including its zero coordinates. -/ +theorem geometricCombination_self (r : ι → ℝ≥0) {a b : ℝ} + (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1) : geometricCombination a b r r = r := by + ext i + simp only [geometricCombination, ← NNReal.rpow_add_of_nonneg (r i) ha hb, hab, NNReal.rpow_one] + +/-- Positive interpolation weights preserve a zero from either input coordinate. -/ +theorem geometricCombination_eq_zero {r s : ι → ℝ≥0} {a b : ℝ} + (ha : 0 < a) (hb : 0 < b) {i : ι} (h : r i = 0 ∨ s i = 0) : + geometricCombination a b r s i = 0 := by + rcases h with h | h <;> simp [geometricCombination, h, ha.ne', hb.ne'] + +/-- A singleton of radii is geometrically convex, including when some radii are zero. -/ +theorem isGeometricallyConvex_singleton (r : ι → ℝ≥0) : IsGeometricallyConvex {r} := by + intro x hx y hy a b ha hb hab + rw [mem_singleton_iff] at hx hy ⊢ + rw [hx, hy] + exact geometricCombination_self r ha hb hab + +/-- The empty set is geometrically convex. -/ +@[simp] theorem isGeometricallyConvex_empty : IsGeometricallyConvex (∅ : Set (ι → ℝ≥0)) := + fun _ h => h.elim + +/-- The whole space of nonnegative radii is geometrically convex. -/ +@[simp] theorem isGeometricallyConvex_univ : IsGeometricallyConvex (univ : Set (ι → ℝ≥0)) := + fun _ _ _ _ _ _ _ _ _ => mem_univ _ + +/-- Arbitrary intersections preserve geometric convexity. -/ +theorem isGeometricallyConvex_sInter {A : Set (Set (ι → ℝ≥0))} + (hA : ∀ S ∈ A, IsGeometricallyConvex S) : IsGeometricallyConvex (⋂₀ A) := by + intro r hr s hs a b ha hb hab + exact mem_sInter.mpr fun S hS => hA S hS (mem_sInter.mp hr S hS) + (mem_sInter.mp hs S hS) ha hb hab + +/-- The geometric convex hull, with zero coordinates included. -/ +@[expose] def geometricConvexHull (S : Set (ι → ℝ≥0)) : Set (ι → ℝ≥0) := + ⋂₀ {T | S ⊆ T ∧ IsGeometricallyConvex T} + +/-- Every set is contained in its geometric convex hull. -/ +theorem subset_geometricConvexHull (S : Set (ι → ℝ≥0)) : S ⊆ geometricConvexHull S := + fun _ hr => mem_sInter.mpr fun _ hT => hT.1 hr + +/-- The geometric convex hull is geometrically convex. -/ +theorem isGeometricallyConvex_geometricConvexHull (S : Set (ι → ℝ≥0)) : + IsGeometricallyConvex (geometricConvexHull S) := + isGeometricallyConvex_sInter fun _ h => h.2 + +/-- Minimality of the geometric convex hull. -/ +theorem geometricConvexHull_min {S T : Set (ι → ℝ≥0)} (hST : S ⊆ T) + (hT : IsGeometricallyConvex T) : geometricConvexHull S ⊆ T := + fun _ h => mem_sInter.mp h T ⟨hST, hT⟩ + +/-- Taking the geometric convex hull is monotone. -/ +theorem geometricConvexHull_mono {S T : Set (ι → ℝ≥0)} (h : S ⊆ T) : + geometricConvexHull S ⊆ geometricConvexHull T := + geometricConvexHull_min (h.trans (subset_geometricConvexHull T)) + (isGeometricallyConvex_geometricConvexHull T) + +/-- A geometrically convex set equals its hull. -/ +theorem IsGeometricallyConvex.geometricConvexHull_eq {S : Set (ι → ℝ≥0)} + (h : IsGeometricallyConvex S) : geometricConvexHull S = S := + Subset.antisymm (geometricConvexHull_min Subset.rfl h) (subset_geometricConvexHull S) + +/-- Multiplication of nonnegative radii is open, including at the pair of zero radii. -/ +private theorem isOpenMap_nnreal_mul : IsOpenMap (fun p : ℝ≥0 × ℝ≥0 => p.1 * p.2) := by + intro S hS + rw [isOpen_iff_mem_nhds] + rintro _ ⟨⟨r, s⟩, hrs, rfl⟩ + by_cases hr : r = 0 + · subst r + by_cases hs : s = 0 + · subst s + have h : Tendsto (fun t : ℝ≥0 => (NNReal.sqrt t, NNReal.sqrt t)) + (𝓝 (0 * 0)) (𝓝 (0, 0)) := by + simpa using (NNReal.continuous_sqrt.prodMk NNReal.continuous_sqrt).tendsto 0 + filter_upwards [h.eventually (hS.mem_nhds hrs)] with t ht + exact ⟨(NNReal.sqrt t, NNReal.sqrt t), ht, NNReal.mul_self_sqrt t⟩ + · have h : Tendsto (fun t : ℝ≥0 => (t / s, s)) (𝓝 (0 * s)) (𝓝 (0, s)) := by + simpa using ((continuous_id.div_const s).prodMk continuous_const).tendsto 0 + filter_upwards [h.eventually (hS.mem_nhds hrs)] with t ht + exact ⟨(t / s, s), ht, div_mul_cancel₀ t hs⟩ + · have h : Tendsto (fun t : ℝ≥0 => (r, t / r)) (𝓝 (r * s)) (𝓝 (r, s)) := by + simpa [mul_div_cancel_left₀ s hr] using + (continuous_const.prodMk (continuous_id.div_const r)).tendsto (r * s) + filter_upwards [h.eventually (hS.mem_nhds hrs)] with t ht + exact ⟨(r, t / r), ht, mul_div_cancel₀ t hr⟩ + +/-- Positive weighted geometric interpolation is an open map on pairs of radius vectors. -/ +theorem isOpenMap_geometricCombination {a b : ℝ} (ha : 0 < a) (hb : 0 < b) : + IsOpenMap (fun p : (ι → ℝ≥0) × (ι → ℝ≥0) => geometricCombination a b p.1 p.2) := by + have hscalar : IsOpenMap (fun p : ℝ≥0 × ℝ≥0 => p.1 ^ a * p.2 ^ b) := + isOpenMap_nnreal_mul.comp + ((NNReal.orderIsoRpow a ha).toHomeomorph.isOpenMap.prodMap + (NNReal.orderIsoRpow b hb).toHomeomorph.isOpenMap) + have hsurj : Function.Surjective (fun p : ℝ≥0 × ℝ≥0 => p.1 ^ a * p.2 ^ b) := by + intro t + obtain ⟨r, hr⟩ := NNReal.rpow_left_surjective ha.ne' t + exact ⟨(r, 1), by simp [hr]⟩ + let e : ((ι → ℝ≥0) × (ι → ℝ≥0)) ≃ₜ (ι → ℝ≥0 × ℝ≥0) := + { toFun := fun p i => (p.1 i, p.2 i) + invFun := fun p => (fun i => (p i).1, fun i => (p i).2) + left_inv := fun _ => rfl + right_inv := fun _ => rfl + continuous_toFun := by fun_prop + continuous_invFun := by fun_prop } + exact (IsOpenMap.piMap (fun _ : ι => hscalar) (.of_forall fun _ => hsurj)).comp e.isOpenMap + +/-- The interior of a geometrically convex set of radii is geometrically convex. -/ +theorem IsGeometricallyConvex.interior {S : Set (ι → ℝ≥0)} + (hS : IsGeometricallyConvex S) : IsGeometricallyConvex (interior S) := by + intro r hr s hs a b ha hb hab + rcases ha.eq_or_lt with ha | ha + · have hb : b = 1 := by linarith + simpa [← ha, hb] using hs + rcases hb.eq_or_lt with hb | hb + · have ha : a = 1 := by linarith + simpa [ha, ← hb] using hr + let g := fun p : (ι → ℝ≥0) × (ι → ℝ≥0) => geometricCombination a b p.1 p.2 + have ho : IsOpen (g '' (_root_.interior S ×ˢ _root_.interior S)) := + isOpenMap_geometricCombination ha hb _ (isOpen_interior.prod isOpen_interior) + have hsub : g '' (_root_.interior S ×ˢ _root_.interior S) ⊆ S := by + rintro _ ⟨⟨x, y⟩, ⟨hx, hy⟩, rfl⟩ + exact hS (interior_subset hx) (interior_subset hy) ha.le hb.le hab + exact (ho.subset_interior_iff.mpr hsub) ⟨(r, s), ⟨hr, hs⟩, rfl⟩ + +/-- The geometric convex hull of an open set of nonnegative radii is open. -/ +theorem isOpen_geometricConvexHull {S : Set (ι → ℝ≥0)} (hS : IsOpen S) : + IsOpen (geometricConvexHull S) := + subset_interior_iff_isOpen.mp (geometricConvexHull_min + (hS.subset_interior_iff.mpr (subset_geometricConvexHull S)) + (isGeometricallyConvex_geometricConvexHull S).interior) + +/-- Taking a geometric convex hull twice has no further effect. -/ +@[simp] theorem geometricConvexHull_idem (S : Set (ι → ℝ≥0)) : + geometricConvexHull (geometricConvexHull S) = geometricConvexHull S := + (isGeometricallyConvex_geometricConvexHull S).geometricConvexHull_eq + +/-- The empty set has empty geometric convex hull. -/ +@[simp] theorem geometricConvexHull_empty : geometricConvexHull (∅ : Set (ι → ℝ≥0)) = ∅ := + isGeometricallyConvex_empty.geometricConvexHull_eq + +/-- A singleton is fixed by the geometric convex hull. -/ +@[simp] theorem geometricConvexHull_singleton (r : ι → ℝ≥0) : geometricConvexHull {r} = {r} := + (isGeometricallyConvex_singleton r).geometricConvexHull_eq + +/-- The modulus trace of a complex coordinate set, with values in nonnegative radii. -/ +@[expose] def modulusTrace (U : Set (ι → ℂ)) : Set (ι → ℝ≥0) := + (fun z i => ‖z i‖₊) '' U + +/-- Logarithmic convexity including zero coordinates is geometric convexity of the trace. This does +not impose Reinhardt symmetry, openness, or completeness. -/ +@[expose] def HasGeometricallyConvexModuli (U : Set (ι → ℂ)) : Prop := + IsGeometricallyConvex (modulusTrace U) + +/-- For a Reinhardt set, a radius vector belongs to the trace exactly when its positive real +representative belongs to the set. -/ +theorem IsReinhardt.mem_modulusTrace_iff {U : Set (ι → ℂ)} (hU : IsReinhardt U) + {r : ι → ℝ≥0} : r ∈ modulusTrace U ↔ (fun i => (r i : ℂ)) ∈ U := by + constructor + · rintro ⟨z, hz, rfl⟩ + exact hU hz (fun i => by simp) + · intro h + refine ⟨_, h, ?_⟩ + ext i + simp + +/-- Strong logarithmic convexity implies convexity of the positive logarithmic image. -/ +theorem HasGeometricallyConvexModuli.isLogarithmicallyConvex {U : Set (ι → ℂ)} + (h : HasGeometricallyConvexModuli U) (hU : IsReinhardt U) : IsLogarithmicallyConvex U := by + intro x hx y hy a b ha hb hab + let r : ι → ℝ≥0 := fun i => ⟨Real.exp (x i), (Real.exp_pos _).le⟩ + let s : ι → ℝ≥0 := fun i => ⟨Real.exp (y i), (Real.exp_pos _).le⟩ + have hr : r ∈ modulusTrace U := hU.mem_modulusTrace_iff.mpr hx + have hs : s ∈ modulusTrace U := hU.mem_modulusTrace_iff.mpr hy + have hm := hU.mem_modulusTrace_iff.mp (h hr hs ha hb hab) + have he : (fun i => (Real.exp ((a • x + b • y) i) : ℂ)) = + (fun i => (geometricCombination a b r s i : ℂ)) := by + ext i + apply congrArg Complex.ofReal + change Real.exp (a * x i + b * y i) = ((r i ^ a * s i ^ b : ℝ≥0) : ℝ) + rw [NNReal.coe_mul, NNReal.coe_rpow, NNReal.coe_rpow] + change Real.exp (a * x i + b * y i) = Real.exp (x i) ^ a * Real.exp (y i) ^ b + rw [← Real.exp_mul, ← Real.exp_mul, ← Real.exp_add] + congr 1 + ring + change (fun i => (Real.exp ((a • x + b • y) i) : ℂ)) ∈ U + rw [he] + exact hm + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/HolomorphicConvexity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/HolomorphicConvexity.lean new file mode 100644 index 0000000000..b8326aea5e --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/HolomorphicConvexity.lean @@ -0,0 +1,103 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.MonomialSeparation + +/-! +# Holomorphic convexity of complete Reinhardt domains + +An exterior point is separated from each compact subset by a monomial. The entire holomorphic +hull of the compact set therefore stays in the domain. Its compactness implies compactness of +the relative holomorphic hull. + +## Main results + +`exists_monomial_separator_of_isCompact` separates an exterior point from a compact subset by a +monomial. `isHolomorphicallyConvex_of_completeReinhardt` is holomorphic convexity of an open +complete logarithmically convex Reinhardt domain. +-/ + +public noncomputable section + +open Set +open scoped Topology NNReal + +namespace SeveralComplexVariables + +variable {ι : Type*} [Fintype ι] + +/-- A monomial separates a compact subset of an open complete logarithmically convex Reinhardt set +from any exterior point. -/ +theorem exists_monomial_separator_of_isCompact {U K : Set (ι → ℂ)} + (ho : IsOpen U) (hc : IsCompleteReinhardt U) (hl : IsLogarithmicallyConvex U) + (hK : IsCompact K) (hKU : K ⊆ U) {z : ι → ℂ} (hz : z ∉ U) : + ∃ (m : ι → ℕ) (M : ℝ), (∀ w ∈ K, ‖∏ i, w i ^ m i‖ ≤ M) ∧ + M < ‖∏ i, z i ^ m i‖ := by + rcases K.eq_empty_or_nonempty with rfl | hne + · exact ⟨0, 0, by simp, by simp⟩ + let R := {r : ι → ℝ≥0 | (fun i => (r i : ℂ)) ∈ U ∧ ∀ i, 0 < r i} + let P (r : R) := polydisc (0 : ι → ℂ) (fun i => (r.val i : ℝ)) + have hcover : K ⊆ ⋃ r : R, P r := by + intro w hw + obtain ⟨r, hrU, hr⟩ := hc.isReinhardt.exists_strict_modulus_majorant ho (hKU hw) + have hrpos (i) : 0 < r i := (show (0 : ℝ≥0) ≤ ‖w i‖₊ from zero_le).trans_lt (hr i) + apply mem_iUnion.mpr + refine ⟨⟨r, hrU, hrpos⟩, ?_⟩ + apply mem_polydisc.mpr + intro i + simpa only [dist_zero_right, Pi.zero_apply] using (show ‖w i‖ < (r i : ℝ) from hr i) + obtain ⟨s, hs⟩ := hK.elim_finite_subcover P (fun r => isOpen_polydisc _ _) hcover + have hsne : s.Nonempty := by + obtain ⟨w, hw⟩ := hne + obtain ⟨r, hr, _⟩ := mem_iUnion₂.mp (hs hw) + exact ⟨r, hr⟩ + let : Nonempty s := hsne.to_subtype + let r (j : s) (i : ι) : ℝ := j.val.val i + have hr (j : s) (i : ι) : 0 < r j i := j.val.property.2 i + obtain ⟨m, hm⟩ := exists_monomial_separator_of_finite_radii ho hc hl hr + (fun j => j.val.property.1) hz + obtain ⟨j, _, hj⟩ := Finset.exists_max_image (Finset.univ : Finset s) + (fun j => ∏ i, r j i ^ m i) Finset.univ_nonempty + refine ⟨m, ∏ i, r j i ^ m i, ?_, ?_⟩ + · intro w hw + obtain ⟨q, hq, hwq⟩ := mem_iUnion₂.mp (hs hw) + rw [norm_prod] + simp only [norm_pow] + apply le_trans _ (hj ⟨q, hq⟩ (Finset.mem_univ _)) + apply Finset.prod_le_prod₀ (fun i _ => pow_nonneg (norm_nonneg _) _) + intro i _ + apply pow_le_pow_left₀ (norm_nonneg _) + simpa only [Pi.zero_apply, dist_zero_right] using + (mem_polydisc.mp hwq i).le + · simpa only [norm_prod, norm_pow] using hm j + +/-- Open complete logarithmically convex Reinhardt sets are holomorphically convex. This includes +unbounded sets, the empty set, and empty coordinate types. -/ +theorem isHolomorphicallyConvex_of_completeReinhardt {U : Set (ι → ℂ)} + (ho : IsOpen U) (hc : IsCompleteReinhardt U) (hl : IsLogarithmicallyConvex U) : + IsHolomorphicallyConvex U := by + intro K hK hKU + have hC : IsCompact (holomorphicHull univ K) := + isHolomorphicallyConvex_univ K hK (subset_univ _) + have hCU : holomorphicHull univ K ⊆ U := by + intro z hz + by_contra hn + obtain ⟨m, M, hM, hMz⟩ := exists_monomial_separator_of_isCompact ho hc hl hK hKU hn + have hf : AnalyticOnNhd ℂ (fun w : ι → ℂ => ∏ i, w i ^ m i) univ := by + intro w _ + apply Finset.analyticAt_fun_prod + intro i _ + exact ((ContinuousLinearMap.proj (R := ℂ) i).analyticAt w).pow (m i) + exact (hz.2 _ hf M hM).not_gt hMz + exact isCompact_holomorphicHull_of_subset_compact hC hCU + (holomorphicHull_mono_ambient (subset_univ _)) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/Hull.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/Hull.lean new file mode 100644 index 0000000000..d49b5113fd --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/Hull.lean @@ -0,0 +1,248 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.MetricSpace.Pseudo.Pi +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.GeometricConvexity + +/-! +# Reinhardt hulls and comparison of logarithmic convexity conventions + +The complete Reinhardt hull allows coordinatewise shrinking. The logarithmic Reinhardt hull +closes the modulus trace under geometric interpolation, including zeros, and restores rotation +symmetry. Both are minimal hulls of sets; neither definition builds in openness. For open +complete Reinhardt sets in finite dimension, the two logarithmic convexity predicates agree. +References: [Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), §§2.2–2.5 and §2.8. + +## Main results + +`completeReinhardtHull` and `logarithmicReinhardtHull` are the two hulls. +`completeReinhardtHull_min` and `logarithmicReinhardtHull_min` are minimality. +`hasGeometricallyConvexModuli_iff` compares geometric and logarithmic convexity on open complete +Reinhardt sets. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Set Metric +open scoped NNReal Topology + +namespace SeveralComplexVariables + +variable {ι : Type*} {U V : Set (ι → ℂ)} + +/-- An open Reinhardt set contains a strictly larger positive modulus vector above each point. -/ +theorem IsReinhardt.exists_strict_modulus_majorant [Finite ι] + (hU : IsReinhardt U) (ho : IsOpen U) {z : ι → ℂ} (hz : z ∈ U) : + ∃ r : ι → ℝ≥0, (fun i => (r i : ℂ)) ∈ U ∧ ∀ i, ‖z i‖₊ < r i := by + classical + let := Fintype.ofFinite ι + have hz' : (fun i => (‖z i‖ : ℂ)) ∈ U := hU hz (fun i => by simp) + obtain ⟨δ, hδ, hball⟩ := Metric.isOpen_iff.mp ho _ hz' + let r : ι → ℝ≥0 := fun i => ‖z i‖₊ + ⟨δ / 2, by positivity⟩ + refine ⟨r, hball ?_, fun i => ?_⟩ + · rw [mem_ball, dist_pi_lt_iff hδ] + intro i + change dist ((‖z i‖ + δ / 2 : ℝ) : ℂ) (‖z i‖ : ℂ) < δ + rw [dist_eq_norm, ← Complex.ofReal_sub, Complex.norm_real, Real.norm_eq_abs] + simp only [add_sub_cancel_left, abs_of_pos (half_pos hδ)] + linarith + · change ‖z i‖₊ < ‖z i‖₊ + ⟨δ / 2, by positivity⟩ + exact lt_add_of_pos_right _ (by exact_mod_cast half_pos hδ) + +/-- Positive geometric combinations are controlled by convexity of the logarithmic image. -/ +theorem IsLogarithmicallyConvex.geometricCombination_mem {r s : ι → ℝ≥0} + (h : IsLogarithmicallyConvex U) (hr : (fun i => (r i : ℂ)) ∈ U) + (hs : (fun i => (s i : ℂ)) ∈ U) (hrp : ∀ i, 0 < r i) (hsp : ∀ i, 0 < s i) + {a b : ℝ} (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1) : + (fun i => (geometricCombination a b r s i : ℂ)) ∈ U := by + have hx : (fun i => Real.log (r i)) ∈ logarithmicImage U := by + simpa only [logarithmicImage, mem_ofPred_eq, Real.exp_log (show (0 : ℝ) < r _ from hrp _)] + using hr + have hy : (fun i => Real.log (s i)) ∈ logarithmicImage U := by + simpa only [logarithmicImage, mem_ofPred_eq, Real.exp_log (show (0 : ℝ) < s _ from hsp _)] + using hs + have hm := h hx hy ha hb hab + have he : (fun i => (Real.exp (a * Real.log (r i) + b * Real.log (s i)) : ℂ)) = + (fun i => (geometricCombination a b r s i : ℂ)) := by + ext i + apply congrArg Complex.ofReal + change Real.exp (a * Real.log (r i) + b * Real.log (s i)) = + ((r i ^ a * s i ^ b : ℝ≥0) : ℝ) + rw [NNReal.coe_mul, NNReal.coe_rpow, NNReal.coe_rpow, + Real.rpow_def_of_pos (show (0 : ℝ) < (r i : ℝ) from hrp i), + Real.rpow_def_of_pos (show (0 : ℝ) < (s i : ℝ) from hsp i), ← Real.exp_add] + congr 1 + ring + exact he ▸ hm + +/-- On open complete Reinhardt sets the logarithmic-image convention also controls zeros. -/ +theorem IsLogarithmicallyConvex.hasGeometricallyConvexModuli [Finite ι] + (h : IsLogarithmicallyConvex U) (ho : IsOpen U) (hc : IsCompleteReinhardt U) : + HasGeometricallyConvexModuli U := by + classical + let := Fintype.ofFinite ι + rintro r ⟨z, hz, rfl⟩ s ⟨w, hw, rfl⟩ a b ha hb hab + obtain ⟨r, hr, hzr⟩ := hc.isReinhardt.exists_strict_modulus_majorant ho hz + obtain ⟨s, hs, hws⟩ := hc.isReinhardt.exists_strict_modulus_majorant ho hw + apply hc.isReinhardt.mem_modulusTrace_iff.mpr + apply hc (h.geometricCombination_mem hr hs + (fun i => lt_of_le_of_lt (show (0 : ℝ≥0) ≤ _ from zero_le) (hzr i)) + (fun i => lt_of_le_of_lt (show (0 : ℝ≥0) ≤ _ from zero_le) (hws i)) ha hb hab) + intro i + simp only [Complex.norm_of_nonneg (NNReal.coe_nonneg _)] + exact_mod_cast mul_le_mul' (NNReal.rpow_le_rpow (hzr i).le ha) + (NNReal.rpow_le_rpow (hws i).le hb) + +/-- Equivalence of the two conventions on open complete Reinhardt sets. -/ +theorem hasGeometricallyConvexModuli_iff [Finite ι] (ho : IsOpen U) + (hc : IsCompleteReinhardt U) : + HasGeometricallyConvexModuli U ↔ IsLogarithmicallyConvex U := by + classical + let := Fintype.ofFinite ι + exact + ⟨fun h => h.isLogarithmicallyConvex hc.isReinhardt, + fun h => h.hasGeometricallyConvexModuli ho hc⟩ + +/-- Away from all coordinate hyperplanes, the two convexity conventions coincide without openness or +completeness assumptions. -/ +theorem hasGeometricallyConvexModuli_iff_of_nonzero (hR : IsReinhardt U) + (hne : ∀ z ∈ U, ∀ i, z i ≠ 0) : + HasGeometricallyConvexModuli U ↔ IsLogarithmicallyConvex U := by + refine ⟨fun h => h.isLogarithmicallyConvex hR, ?_⟩ + intro h r hr s hs a b ha hb hab + obtain ⟨z, hz, rfl⟩ := hr + obtain ⟨w, hw, rfl⟩ := hs + exact hR.mem_modulusTrace_iff.mpr (h.geometricCombination_mem + (hR.mem_modulusTrace_iff.mp ⟨z, hz, rfl⟩) + (hR.mem_modulusTrace_iff.mp ⟨w, hw, rfl⟩) + (fun i => nnnorm_pos.mpr (hne z hz i)) (fun i => nnnorm_pos.mpr (hne w hw i)) ha hb hab) + +/-- The smallest complete Reinhardt set containing a given set. -/ +@[expose] def completeReinhardtHull (U : Set (ι → ℂ)) : Set (ι → ℂ) := + {w | ∃ z ∈ U, ∀ i, ‖w i‖ ≤ ‖z i‖} + +/-- A set is contained in its complete Reinhardt hull. -/ +theorem subset_completeReinhardtHull : U ⊆ completeReinhardtHull U := + fun z hz => ⟨z, hz, fun _ => le_rfl⟩ + +/-- The complete Reinhardt hull is complete Reinhardt. -/ +theorem isCompleteReinhardt_completeReinhardtHull : IsCompleteReinhardt (completeReinhardtHull U) + := by + rintro z ⟨v, hv, hz⟩ w hw + exact ⟨v, hv, fun i => (hw i).trans (hz i)⟩ + +/-- Minimality of the complete Reinhardt hull. -/ +theorem completeReinhardtHull_min (hUV : U ⊆ V) (hV : IsCompleteReinhardt V) : + completeReinhardtHull U ⊆ V := by + rintro w ⟨z, hz, hw⟩ + exact hV (hUV hz) hw + +/-- Complete Reinhardt sets are fixed by their hull. -/ +theorem IsCompleteReinhardt.hull_eq (h : IsCompleteReinhardt U) : completeReinhardtHull U = U := + Subset.antisymm (completeReinhardtHull_min Subset.rfl h) subset_completeReinhardtHull + +/-- Completing an open Reinhardt set preserves openness. -/ +theorem isOpen_completeReinhardtHull [Finite ι] (ho : IsOpen U) (hR : IsReinhardt U) : + IsOpen (completeReinhardtHull U) := by + classical + let := Fintype.ofFinite ι + rw [isOpen_iff_mem_nhds] + rintro w ⟨z, hz, hwz⟩ + obtain ⟨r, hrU, hzr⟩ := hR.exists_strict_modulus_majorant ho hz + let W : Set (ι → ℂ) := {v | ∀ i, ‖v i‖ < (r i : ℝ)} + have hW : IsOpen W := by + simpa only [W, ofPred_forall] using + (isOpen_iInter_of_finite fun i => isOpen_lt (continuous_apply i).norm + (continuous_const (y := (r i : ℝ)))) + apply Filter.mem_of_superset (hW.mem_nhds (fun i => (hwz i).trans_lt (hzr i))) + intro v hv + exact ⟨_, hrU, fun i => by simpa only [Complex.norm_of_nonneg (NNReal.coe_nonneg _)] using (hv + i).le⟩ + +/-- The logarithmic Reinhardt hull uses geometric convexity including coordinate hyperplanes. -/ +@[expose] def logarithmicReinhardtHull (U : Set (ι → ℂ)) : Set (ι → ℂ) := + {z | (fun i => ‖z i‖₊) ∈ geometricConvexHull (modulusTrace U)} + +/-- A set is contained in its logarithmic Reinhardt hull. -/ +theorem subset_logarithmicReinhardtHull : U ⊆ logarithmicReinhardtHull U := + fun z hz => subset_geometricConvexHull _ ⟨z, hz, rfl⟩ + +/-- The logarithmic Reinhardt hull has coordinate rotation symmetry. -/ +theorem isReinhardt_logarithmicReinhardtHull : IsReinhardt (logarithmicReinhardtHull U) := by + intro z hz w hw + have he : (fun i => ‖w i‖₊) = (fun i => ‖z i‖₊) := funext fun i => Subtype.ext (hw i) + change (fun i => ‖w i‖₊) ∈ geometricConvexHull (modulusTrace U) + rw [he] + exact hz + +/-- The trace of the logarithmic Reinhardt hull is the geometric convex hull of the trace. -/ +theorem modulusTrace_logarithmicReinhardtHull : + modulusTrace (logarithmicReinhardtHull U) = geometricConvexHull (modulusTrace U) := by + ext r + constructor + · rintro ⟨z, hz, rfl⟩ + exact hz + · intro hr + refine ⟨fun i => (r i : ℂ), ?_, ?_⟩ + · simpa [logarithmicReinhardtHull] using hr + · ext i; simp + +/-- The logarithmic Reinhardt hull satisfies geometric convexity including zeros. -/ +theorem hasGeometricallyConvexModuli_logarithmicReinhardtHull : + HasGeometricallyConvexModuli (logarithmicReinhardtHull U) := by + rw [HasGeometricallyConvexModuli, modulusTrace_logarithmicReinhardtHull] + exact isGeometricallyConvex_geometricConvexHull _ + +/-- Minimality of the logarithmic Reinhardt hull among Reinhardt sets with convex moduli. -/ +theorem logarithmicReinhardtHull_min (hUV : U ⊆ V) (hV : IsReinhardt V) + (hg : HasGeometricallyConvexModuli V) : logarithmicReinhardtHull U ⊆ V := by + intro z hz + have hm : (fun i => ‖z i‖₊) ∈ modulusTrace V := + geometricConvexHull_min (image_mono hUV) hg hz + obtain ⟨w, hw, he⟩ := hm + exact hV hw (fun i => (congrArg (fun r : ι → ℝ≥0 => (r i : ℝ)) he).symm) + +/-- A Reinhardt set with geometrically convex moduli equals its logarithmic hull. -/ +theorem logarithmicReinhardtHull_eq (hU : IsReinhardt U) (hg : HasGeometricallyConvexModuli U) : + logarithmicReinhardtHull U = U := + Subset.antisymm (logarithmicReinhardtHull_min Subset.rfl hU hg) subset_logarithmicReinhardtHull + +/-- Openness of the geometric logarithmic hull in finite dimension, including zero coordinates. The +modulus trace of an open Reinhardt set is open, and so is its geometric convex hull. -/ +theorem isOpen_logarithmicReinhardtHull [Finite ι] (ho : IsOpen U) (hU : IsReinhardt U) : + IsOpen (logarithmicReinhardtHull U) := by + classical + let := Fintype.ofFinite ι + have htrace : modulusTrace U = + (fun r : ι → ℝ≥0 => fun i => (r i : ℂ)) ⁻¹' U := by + ext r + exact hU.mem_modulusTrace_iff + have hto : IsOpen (modulusTrace U) := by + rw [htrace] + apply ho.preimage + fun_prop + exact (isOpen_geometricConvexHull hto).preimage (by fun_prop) + +/-- The logarithmic Reinhardt hull is monotone. -/ +theorem logarithmicReinhardtHull_mono (hUV : U ⊆ V) : + logarithmicReinhardtHull U ⊆ logarithmicReinhardtHull V := + logarithmicReinhardtHull_min (hUV.trans subset_logarithmicReinhardtHull) + isReinhardt_logarithmicReinhardtHull hasGeometricallyConvexModuli_logarithmicReinhardtHull + +/-- Taking the logarithmic Reinhardt hull twice has no further effect. -/ +@[simp] theorem logarithmicReinhardtHull_idem : + logarithmicReinhardtHull (logarithmicReinhardtHull U) = logarithmicReinhardtHull U := + logarithmicReinhardtHull_eq isReinhardt_logarithmicReinhardtHull + hasGeometricallyConvexModuli_logarithmicReinhardtHull + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/MonomialSeparation.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/MonomialSeparation.lean new file mode 100644 index 0000000000..ddd9e00198 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/MonomialSeparation.lean @@ -0,0 +1,225 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.LocallyConvex.Separation +public import Mathlib.Analysis.SpecificLimits.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Hull + +/-! +# Monomial separation on complete logarithmically convex Reinhardt sets + +Logarithmic separation can be restricted to the nonzero coordinates of an exterior point. +Approximating the nonnegative separating weights by integer exponents then gives a monomial +separating that point from a compact subset of the domain. + +## Main results + +`exists_logarithmic_lift` produces a logarithmic lift of a modulus vector with some zero +coordinates. `exists_nat_weights` approximates nonnegative separating weights by integer +exponents. `exists_monomial_separator_of_finite_radii` is the resulting monomial separator. +-/ + +public noncomputable section + +open Set Filter +open scoped Topology NNReal + +namespace SeveralComplexVariables + +variable {ι : Type*} [Fintype ι] + +/-- Exponentiation on the coordinate face determined by the nonzero entries of `z`. -/ +private def faceExp (z : ι → ℂ) (t : ι → ℝ) : ι → ℂ := + fun i => if z i = 0 then 0 else (Real.exp (t i) : ℂ) + +omit [Fintype ι] in +/-- Exponentiation on a fixed coordinate face is continuous. -/ +private theorem continuous_faceExp (z : ι → ℂ) : Continuous (faceExp z) := by + classical + apply continuous_pi + intro i + by_cases hi : z i = 0 <;> simp only [faceExp, hi, ite_true, ite_false] + · exact continuous_const + · fun_prop + +omit [Fintype ι] in +/-- A face point in an open complete Reinhardt set has a positive lift with the same nonzero +coordinates. -/ +private theorem exists_logarithmic_lift [Finite ι] {U : Set (ι → ℂ)} (ho : IsOpen U) + (hc : IsCompleteReinhardt U) {z : ι → ℂ} {t : ι → ℝ} (ht : faceExp z t ∈ U) : + ∃ y ∈ logarithmicImage U, ∀ i, z i ≠ 0 → y i = t i := by + classical + let := Fintype.ofFinite ι + classical + obtain ⟨r, hrU, hr⟩ := hc.isReinhardt.exists_strict_modulus_majorant ho ht + have hrpos (i) : 0 < (r i : ℝ) := by + exact_mod_cast (show (0 : ℝ≥0) ≤ ‖faceExp z t i‖₊ from zero_le).trans_lt (hr i) + let y (i : ι) := if z i = 0 then Real.log (r i) else t i + refine ⟨y, hc hrU ?_, ?_⟩ + · intro i + by_cases hi : z i = 0 + · simp [y, hi, Real.exp_log (hrpos i)] + · have hri : ‖faceExp z t i‖ < (r i : ℝ) := by exact_mod_cast hr i + simpa [y, faceExp, hi, abs_of_pos (hrpos i)] using hri.le + · intro i hi + simp [y, hi] + +omit [Fintype ι] in +/-- Logarithmic coordinates on any coordinate face form an open convex lower set. -/ +private theorem convex_faceLog [Finite ι] {U : Set (ι → ℂ)} (ho : IsOpen U) + (hc : IsCompleteReinhardt U) (hl : IsLogarithmicallyConvex U) (z : ι → ℂ) : + Convex ℝ {t | faceExp z t ∈ U} := by + classical + let := Fintype.ofFinite ι + classical + intro x hx y hy a b ha hb hab + obtain ⟨x', hx', hxx⟩ := exists_logarithmic_lift ho hc hx + obtain ⟨y', hy', hyy⟩ := exists_logarithmic_lift ho hc hy + apply hc (hl hx' hy' ha hb hab) + intro i + by_cases hi : z i = 0 + · simp [faceExp, hi] + · simp [faceExp, hi, hxx i hi, hyy i hi] + +omit [Fintype ι] in +/-- The logarithmic face set is closed under decreasing coordinates. -/ +private theorem faceExp_mem_of_le {U : Set (ι → ℂ)} (hc : IsCompleteReinhardt U) + {z : ι → ℂ} {x y : ι → ℝ} (hx : faceExp z x ∈ U) (hy : y ≤ x) : + faceExp z y ∈ U := by + classical + apply hc hx + intro i + by_cases hi : z i = 0 + · simp [faceExp, hi] + · simpa [faceExp, hi] using Real.exp_le_exp.mpr (hy i) + +omit [Fintype ι] in +/-- A separating functional for a lower set has nonnegative coordinate weights. -/ +private theorem nonneg_separating_weights [DecidableEq ι] {S : Set (ι → ℝ)} + (hdown : ∀ x ∈ S, ∀ y, y ≤ x → y ∈ S) {x y : ι → ℝ} (hy : y ∈ S) + {l : (ι → ℝ) →L[ℝ] ℝ} (hl : ∀ t ∈ S, l t < l x) (i : ι) : + 0 ≤ l (Pi.single i 1) := by + classical + by_contra h + have hi : l (Pi.single i 1) < 0 := lt_of_not_ge h + let a := (l x - l y + 1) / (-l (Pi.single i 1)) + have ha : 0 ≤ a := le_of_lt (div_pos (by linarith [hl y hy]) (neg_pos.mpr hi)) + have ht := hl (y - a • Pi.single i 1) (hdown y hy _ (by + intro j + simp only [Pi.sub_apply, Pi.smul_apply, smul_eq_mul, sub_le_self_iff] + exact mul_nonneg ha (by simp [Pi.single_apply]; split_ifs <;> norm_num))) + rw [map_sub, map_smul, smul_eq_mul] at ht + have he : a * (-l (Pi.single i 1)) = l x - l y + 1 := + div_mul_cancel₀ _ (neg_ne_zero.mpr hi.ne) + nlinarith + +omit [Fintype ι] in +/-- Coordinates absent from a face have zero weight in any separating functional. -/ +private theorem separating_weight_zero [DecidableEq ι] {U : Set (ι → ℂ)} {z : ι → ℂ} + {x y : ι → ℝ} (hy : faceExp z y ∈ U) {l : (ι → ℝ) →L[ℝ] ℝ} + (hl : ∀ t, faceExp z t ∈ U → l t < l x) (i : ι) (hi : z i = 0) : + l (Pi.single i 1) = 0 := by + classical + by_contra hn + let a := (l x - l y + 1) / l (Pi.single i 1) + have he : faceExp z (y + a • Pi.single i 1) = faceExp z y := by + funext j + by_cases hj : j = i + · subst j; simp [faceExp, hi] + · simp [faceExp, Pi.single_eq_of_ne hj] + have ht := hl _ (he ▸ hy) + rw [map_add, map_smul, smul_eq_mul] at ht + have heq : a * l (Pi.single i 1) = l x - l y + 1 := div_mul_cancel₀ _ hn + linarith + +/-- A linear functional on a finite coordinate space is the sum of its coordinate weights. -/ +private theorem linear_functional_eq_sum [DecidableEq ι] (l : (ι → ℝ) →L[ℝ] ℝ) (t : ι → ℝ) : + l t = ∑ i, l (Pi.single i 1) * t i := by + rw [← Finset.univ_sum_single t, map_sum] + apply Finset.sum_congr rfl + intro i _ + have he : Pi.single i (t i) = t i • Pi.single i (1 : ℝ) := by + ext j + simp [Pi.single_apply, mul_ite] + rw [he, map_smul, smul_eq_mul, mul_comm, Finset.univ_sum_single] + +/-- Finitely many strict inequalities with nonnegative real weights persist for suitable nonnegative +integer weights. Zero weights remain zero. -/ +private theorem exists_nat_weights {κ : Type*} [Finite κ] {a x : ι → ℝ} + {y : κ → ι → ℝ} (ha : ∀ i, 0 ≤ a i) + (hxy : ∀ j, (∑ i, a i * y j i) < ∑ i, a i * x i) : + ∃ m : ι → ℕ, (∀ i, a i = 0 → m i = 0) ∧ + ∀ j, (∑ i, (m i : ℝ) * y j i) < ∑ i, (m i : ℝ) * x i := by + classical + let := Fintype.ofFinite κ + have hlim (j : κ) : Tendsto + (fun t : ℝ => ∑ i, ((⌊a i * t⌋₊ : ℝ) / t) * (x i - y j i)) atTop + (𝓝 (∑ i, a i * (x i - y j i))) := + tendsto_finsetSum _ (fun i _ => (tendsto_nat_floor_mul_div_atTop (ha i)).mul_const _) + have hpos (j : κ) : 0 < ∑ i, a i * (x i - y j i) := by + simpa only [mul_sub, Finset.sum_sub_distrib] using sub_pos.mpr (hxy j) + have hall : ∀ᶠ t : ℝ in atTop, ∀ j, 0 < ∑ i, ((⌊a i * t⌋₊ : ℝ) / t) * (x i - y j i) := + Filter.eventually_all.mpr (fun j => (hlim j).eventually (lt_mem_nhds (hpos j))) + obtain ⟨t, ht, h⟩ := (hall.and (eventually_gt_atTop (0 : ℝ))).exists + refine ⟨fun i => ⌊a i * t⌋₊, fun i hi => by simp [hi], ?_⟩ + intro j + have hj := ht j + simp only [div_mul_eq_mul_div, ← Finset.sum_div, mul_sub, Finset.sum_sub_distrib] at hj + exact (div_lt_div_iff_of_pos_right h).mp (sub_pos.mp hj) + +/-- A monomial separates an exterior point from finitely many positive radius vectors in an open +complete logarithmically convex Reinhardt set. -/ +theorem exists_monomial_separator_of_finite_radii {κ : Type*} [Finite κ] [Nonempty κ] + {U : Set (ι → ℂ)} (ho : IsOpen U) (hc : IsCompleteReinhardt U) + (hl : IsLogarithmicallyConvex U) {r : κ → ι → ℝ} + (hr : ∀ j i, 0 < r j i) (hrU : ∀ j, (fun i => (r j i : ℂ)) ∈ U) + {z : ι → ℂ} (hz : z ∉ U) : + ∃ m : ι → ℕ, ∀ j, (∏ i, r j i ^ m i) < ∏ i, ‖z i‖ ^ m i := by + classical + let := Fintype.ofFinite κ + classical + let x (i : ι) := Real.log ‖z i‖ + let y (j : κ) (i : ι) := Real.log (r j i) + have hx : faceExp z x ∉ U := by + intro hx + apply hz (hc.isReinhardt hx ?_) + intro i + by_cases hi : z i = 0 + · simp [faceExp, hi] + · simp [faceExp, hi, x, Real.exp_log (norm_pos_iff.mpr hi)] + have hy (j : κ) : faceExp z (y j) ∈ U := by + apply hc (hrU j) + intro i + by_cases hi : z i = 0 + · simp [faceExp, hi] + · simp [faceExp, hi, y, Real.exp_log (hr j i)] + obtain ⟨l, hsep⟩ := geometric_hahn_banach_open_point (convex_faceLog ho hc hl z) + (ho.preimage (continuous_faceExp z)) hx + let a (i : ι) := l (Pi.single i 1) + have ha (i : ι) : 0 ≤ a i := nonneg_separating_weights + (fun _ ht _ hle => faceExp_mem_of_le hc ht hle) (hy (Classical.arbitrary κ)) hsep i + have ha0 (i : ι) (hi : z i = 0) : a i = 0 := + separating_weight_zero (hy (Classical.arbitrary κ)) hsep i hi + obtain ⟨m, hm0, hm⟩ := exists_nat_weights ha (fun j => by + simpa only [linear_functional_eq_sum l (y j), linear_functional_eq_sum l x] using hsep _ (hy j)) + refine ⟨m, fun j => ?_⟩ + have hexp (v : ι → ℝ) (hv : ∀ i, 0 < v i) : + Real.exp (∑ i, (m i : ℝ) * Real.log (v i)) = ∏ i, v i ^ m i := by + simp [Real.exp_sum, Real.exp_nat_mul, Real.exp_log (hv _)] + have hzexp : Real.exp (∑ i, (m i : ℝ) * x i) = ∏ i, ‖z i‖ ^ m i := by + rw [Real.exp_sum] + apply Finset.prod_congr rfl + intro i _ + by_cases hi : z i = 0 + · simp [hm0 i (ha0 i hi)] + · simp [x, Real.exp_nat_mul, Real.exp_log (norm_pos_iff.mpr hi)] + rw [← hexp (r j) (hr j), ← hzexp] + exact Real.exp_lt_exp.mpr (hm j) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/PartialHull.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/PartialHull.lean new file mode 100644 index 0000000000..3f27f82a94 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Reinhardt/PartialHull.lean @@ -0,0 +1,319 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Extension + +/-! +# Completion in selected Reinhardt coordinates + +The selected coordinates can decrease in modulus; the others retain their moduli. On Reinhardt +sets this is precisely coordinate contraction without a coordinate ordering. The geometric hull +works for arbitrary index types, and its openness is proved. For finite coordinates, absolute +convergence and vanishing of the relevant negative Laurent coefficients give locally uniform +convergence and an analytic sum on the hull. These coefficient-series results are independent of +the Laurent expansion theorem; extension of arbitrary holomorphic functions is deduced from that +theorem. Reference: [Scheidemann][Scheidemann2005] (2005), Corollary 2.1.15. + +## Main results + +`IsCompleteReinhardtIn` is completeness in a selected set of coordinates. `partialReinhardtHull` +is the corresponding hull. `exists_extension_partialReinhardtHull` extends a holomorphic +function to that hull. `hasSumLocallyUniformlyOn_laurent_partialReinhardtHull` is locally +uniform convergence of the relevant Laurent terms. + +## References + +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {ι : Type*} {U V : Set (ι → ℂ)} {I : Set ι} + +/-- Reinhardt completeness restricted to a specified set of coordinates. -/ +@[expose] def IsCompleteReinhardtIn (I : Set ι) (U : Set (ι → ℂ)) : Prop := + ∀ ⦃z⦄, z ∈ U → ∀ ⦃w⦄, (∀ i, ‖w i‖ ≤ ‖z i‖) → + (∀ i ∉ I, ‖w i‖ = ‖z i‖) → w ∈ U + +/-- The hull formed by contracting selected moduli and preserving all other moduli. -/ +@[expose] def partialReinhardtHull (I : Set ι) (U : Set (ι → ℂ)) : Set (ι → ℂ) := + {w | ∃ z ∈ U, (∀ i, ‖w i‖ ≤ ‖z i‖) ∧ ∀ i ∉ I, ‖w i‖ = ‖z i‖} + +/-- The original set is contained in its partial hull. -/ +theorem subset_partialReinhardtHull : U ⊆ partialReinhardtHull I U := + fun z hz => ⟨z, hz, fun _ => le_rfl, fun _ _ => rfl⟩ + +/-- Partial completeness includes Reinhardt symmetry. -/ +theorem IsCompleteReinhardtIn.isReinhardt (h : IsCompleteReinhardtIn I U) : + IsReinhardt U := fun _ hz _ he => h hz (fun i => (he i).le) (fun i _ => he i) + +/-- The partial hull has the stated partial completeness property. -/ +theorem isCompleteReinhardtIn_partialReinhardtHull : + IsCompleteReinhardtIn I (partialReinhardtHull I U) := by + rintro z ⟨v, hv, hle, heq⟩ w hwl hwe + exact ⟨v, hv, fun i => (hwl i).trans (hle i), fun i hi => (hwe i hi).trans (heq i hi)⟩ + +/-- The partial hull is the smallest partially complete Reinhardt superset. -/ +theorem partialReinhardtHull_min (hUV : U ⊆ V) (hV : IsCompleteReinhardtIn I V) : + partialReinhardtHull I U ⊆ V := by + rintro w ⟨z, hz, hle, heq⟩ + exact hV (hUV hz) hle heq + +/-- Every partial hull retains independent coordinate rotations. -/ +theorem isReinhardt_partialReinhardtHull : IsReinhardt (partialReinhardtHull I U) := + isCompleteReinhardtIn_partialReinhardtHull.isReinhardt + +/-- Partial completion is monotone in the original set. -/ +theorem partialReinhardtHull_mono (hUV : U ⊆ V) : + partialReinhardtHull I U ⊆ partialReinhardtHull I V := + partialReinhardtHull_min (hUV.trans subset_partialReinhardtHull) + isCompleteReinhardtIn_partialReinhardtHull + +/-- Completing twice in the same coordinates has no further effect. -/ +theorem partialReinhardtHull_idem : + partialReinhardtHull I (partialReinhardtHull I U) = partialReinhardtHull I U := + Subset.antisymm (partialReinhardtHull_min Subset.rfl isCompleteReinhardtIn_partialReinhardtHull) + subset_partialReinhardtHull + +/-- Completion in all coordinates recovers the existing complete Reinhardt hull. -/ +theorem partialReinhardtHull_univ : partialReinhardtHull univ U = completeReinhardtHull U := by + ext z + simp [partialReinhardtHull, completeReinhardtHull] + +/-- With no selected coordinates, a Reinhardt set is unchanged. -/ +theorem partialReinhardtHull_empty (hU : IsReinhardt U) : partialReinhardtHull ∅ U = U := by + apply Subset.antisymm ?_ subset_partialReinhardtHull + rintro w ⟨z, hz, _, he⟩ + exact hU hz (fun i => he i (by simp)) + +/-- Partial hulls of open Reinhardt sets are open. A continuous modulus majorant supplies nearby +witnesses in the original open set. -/ +theorem isOpen_partialReinhardtHull [Finite ι] (ho : IsOpen U) (hR : IsReinhardt U) : + IsOpen (partialReinhardtHull I U) := by + classical + let := Fintype.ofFinite ι + classical + rw [isOpen_iff_mem_nhds] + rintro w ⟨z, hz, hle, heq⟩ + let v : (ι → ℂ) → (ι → ℂ) := fun x i => + if i ∈ I then (max ‖x i‖ ‖z i‖ : ℝ) else (‖x i‖ : ℝ) + have hv : Continuous v := by + apply continuous_pi + intro i + dsimp [v] + split_ifs <;> fun_prop + have hvw : v w ∈ U := by + apply hR hz + intro i + by_cases hi : i ∈ I + · simp [v, hi, max_eq_right (hle i)] + · simp [v, hi, heq i hi] + apply Filter.mem_of_superset (hv.continuousAt.preimage_mem_nhds (ho.mem_nhds hvw)) + intro x hx + refine ⟨v x, hx, ?_, ?_⟩ + · intro i + by_cases hi : i ∈ I + · simp [v, hi, abs_of_nonneg (le_trans (norm_nonneg _) (le_max_left _ _))] + · simp [v, hi] + · intro i hi + simp [v, hi] + +/-- A Laurent monomial is largest at the corner selected by its exponent signs. Summing over all +corners gives a bound independent of the signs. -/ +private theorem norm_laurentTerm_le_sum_corners {n : ℕ} {F : Type*} + [NormedAddCommGroup F] [NormedSpace ℂ F] (c : (Fin n → ℤ) → F) + (a b : Fin n → ℝ) (ha : ∀ i, 0 < a i) (hb : ∀ i, 0 < b i) + (m : Fin n → ℤ) (x : Fin n → ℂ) + (hupper : ∀ i, ‖x i‖ ≤ b i) + (hlower : c m ≠ 0 → ∀ i, m i < 0 → a i ≤ ‖x i‖) : + ‖multivariableLaurentTerm c m x‖ ≤ + ∑ s : Finset (Fin n), ‖multivariableLaurentTerm c m + (fun i => ((if i ∈ s then b i else a i) : ℂ))‖ := by + classical + by_cases hc : c m = 0 + · simp [multivariableLaurentTerm, hc] + let s := Finset.univ.filter (fun i => 0 ≤ m i) + have hcoord (i : Fin n) : ‖x i‖ ^ m i ≤ + ‖((if i ∈ s then b i else a i) : ℂ)‖ ^ m i := by + by_cases hi : 0 ≤ m i + · simpa [s, hi, abs_of_pos (hb i)] using + zpow_le_zpow_left₀ hi (norm_nonneg _) (hupper i) + · have hmi : m i < 0 := lt_of_not_ge hi + have hpow := zpow_le_zpow_left₀ (neg_nonneg.mpr hmi.le) (ha i).le (hlower hc i hmi) + have hinv := one_div_le_one_div_of_le (zpow_pos (ha i) (-m i)) hpow + simpa [s, hi, abs_of_pos (ha i), one_div, zpow_neg] using hinv + calc + ‖multivariableLaurentTerm c m x‖ ≤ ‖multivariableLaurentTerm c m + (fun i => ((if i ∈ s then b i else a i) : ℂ))‖ := by + simp only [multivariableLaurentTerm, norm_smul, norm_prod, norm_zpow] + exact mul_le_mul_of_nonneg_right + (Finset.prod_le_prod₀ (fun i _ => zpow_nonneg (norm_nonneg _) _) (fun i _ => hcoord i)) + (norm_nonneg _) + _ ≤ _ := Finset.single_le_sum + (f := fun t : Finset (Fin n) => ‖multivariableLaurentTerm c m + (fun i => ((if i ∈ t then b i else a i) : ℂ))‖) + (fun _ _ => norm_nonneg _) (Finset.mem_univ s) + +/-- Near a point of the partial hull, choose upper and lower radii whose finitely many corners lie +in the original domain. Lower bounds are needed only in coordinates where a nonzero Laurent +coefficient has negative exponent. -/ +private theorem exists_laurent_box_partialHull {n : ℕ} {I : Set (Fin n)} + {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hR : IsReinhardt U) + {F : Type*} [Zero F] (c : (Fin n → ℤ) → F) + (hzero : ∀ m i, (i ∈ I ∨ ∃ z ∈ U, z i = 0) → m i < 0 → c m = 0) + {w : Fin n → ℂ} (hw : w ∈ partialReinhardtHull I U) : + ∃ a b : Fin n → ℝ, (∀ i, 0 < a i) ∧ (∀ i, 0 < b i) ∧ + (∀ s : Finset (Fin n), (fun i => ((if i ∈ s then b i else a i) : ℂ)) ∈ U) ∧ + (∀ i, ‖w i‖ < b i) ∧ (∀ m, c m ≠ 0 → ∀ i, m i < 0 → a i < ‖w i‖) := by + classical + obtain ⟨z, hz, hwz, hweq⟩ := hw + let v (s : Finset (Fin n)) (t : ℝ) : Fin n → ℂ := fun i => + if z i = 0 then (t : ℂ) else ((1 + (if i ∈ s then t else -t)) * ‖z i‖ : ℝ) + have hv (s : Finset (Fin n)) : Continuous (v s) := by + apply continuous_pi + intro i + dsimp [v] + split_ifs <;> fun_prop + have hv0 (s : Finset (Fin n)) : v s 0 ∈ U := by + apply hR hz + intro i + by_cases hi : z i = 0 <;> simp [v, hi] + have hev : ∀ᶠ t in 𝓝 (0 : ℝ), ∀ s : Finset (Fin n), v s t ∈ U := + eventually_all.mpr fun s => (hv s).continuousAt.preimage_mem_nhds (ho.mem_nhds (hv0 s)) + obtain ⟨δ, hδ, hδv⟩ := Metric.eventually_nhds_iff.mp hev + let ε := min (δ / 2) (1 / 2) + have hε : 0 < ε := lt_min (half_pos hδ) (by norm_num) + have hεδ : ε < δ := (min_le_left _ _).trans_lt (half_lt_self hδ) + have hε1 : ε < 1 := (min_le_right _ _).trans_lt (by norm_num) + have hcorners := hδv (show dist ε 0 < δ by simpa [Real.dist_eq, abs_of_pos hε] using hεδ) + let a : Fin n → ℝ := fun i => if z i = 0 then ε else (1 - ε) * ‖z i‖ + let b : Fin n → ℝ := fun i => if z i = 0 then ε else (1 + ε) * ‖z i‖ + have ha (i : Fin n) : 0 < a i := by + dsimp [a] + split_ifs with hi + · exact hε + · exact mul_pos (sub_pos.mpr hε1) (norm_pos_iff.mpr hi) + have hb (i : Fin n) : ‖z i‖ < b i := by + dsimp [b] + split_ifs with hi + · simpa [hi] using hε + · nlinarith [norm_pos_iff.mpr hi] + refine ⟨a, b, ha, fun i => (norm_nonneg _).trans_lt (hb i), ?_, + fun i => (hwz i).trans_lt (hb i), ?_⟩ + · intro s + convert hcorners s using 1 + ext i + by_cases hi : z i = 0 <;> by_cases his : i ∈ s <;> simp [a, b, v, hi, his, sub_eq_add_neg] + · intro m hm i hmi + have hi : i ∉ I := fun hi => hm (hzero m i (Or.inl hi) hmi) + have hzi : z i ≠ 0 := fun hzi => hm (hzero m i (Or.inr ⟨z, hz, hzi⟩) hmi) + rw [hweq i hi] + dsimp [a] + rw [ite_eq_right hzi] + nlinarith [norm_pos_iff.mpr hzi] + +/-- An absolutely convergent Laurent series on an open Reinhardt set converges locally uniformly on +its partial hull when the relevant negative coefficients vanish. This convergence argument is +independent of Laurent expansion for functions. -/ +theorem hasSumLocallyUniformlyOn_laurent_partialReinhardtHull + {n : ℕ} {I : Set (Fin n)} {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hR : IsReinhardt U) + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + (c : (Fin n → ℤ) → F) + (hsum : ∀ z ∈ U, Summable (fun m => ‖multivariableLaurentTerm c m z‖)) + (hzero : ∀ m i, (i ∈ I ∨ ∃ z ∈ U, z i = 0) → m i < 0 → c m = 0) : + HasSumLocallyUniformlyOn (multivariableLaurentTerm c) + (fun z => ∑' m, multivariableLaurentTerm c m z) (partialReinhardtHull I U) := by + classical + apply hasSumLocallyUniformlyOn_of_of_forall_exists_nhds + intro w hw + obtain ⟨a, b, ha, hb, hcorners, hupper, hlower⟩ := + exists_laurent_box_partialHull ho hR c hzero hw + let W : Set (Fin n → ℂ) := {x | ∀ i, ‖x i‖ < b i ∧ (a i < ‖w i‖ → a i < ‖x i‖)} + have hW : IsOpen W := by + simp only [W, ofPred_forall, ofPred_and] + apply isOpen_iInter_of_finite + intro i + apply IsOpen.inter (isOpen_lt (continuous_apply i).norm continuous_const) + apply isOpen_iInter_of_finite + intro _ + exact isOpen_lt continuous_const (continuous_apply i).norm + have hwW : w ∈ W := fun i => ⟨hupper i, fun h => h⟩ + refine ⟨W, nhdsWithin_le_nhds (hW.mem_nhds hwW), ?_⟩ + apply hasSumUniformlyOn_iff_tendstoUniformlyOn.mpr + have hs : Summable (fun m => ∑ t : Finset (Fin n), + ‖multivariableLaurentTerm c m (fun i => ((if i ∈ t then b i else a i) : ℂ))‖) := + summable_sum (fun t _ => hsum _ (hcorners t)) + apply tendstoUniformlyOn_tsum hs + intro m x hx + exact norm_laurentTerm_le_sum_corners c a b ha hb m x + (fun i => (hx i).1.le) (fun hm i hmi => ((hx i).2 (hlower m hm i hmi)).le) + +/-- The Laurent sum is analytic on the partial hull. A term with a negative exponent is either +identically zero or has no coordinate singularity on the hull. -/ +theorem analyticOnNhd_laurentSum_partialReinhardtHull + {n : ℕ} {I : Set (Fin n)} {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hR : IsReinhardt U) + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + (c : (Fin n → ℤ) → F) + (hsum : ∀ z ∈ U, Summable (fun m => ‖multivariableLaurentTerm c m z‖)) + (hzero : ∀ m i, (i ∈ I ∨ ∃ z ∈ U, z i = 0) → m i < 0 → c m = 0) : + AnalyticOnNhd ℂ (fun z => ∑' m, multivariableLaurentTerm c m z) + (partialReinhardtHull I U) := by + apply (hasSumLocallyUniformlyOn_laurent_partialReinhardtHull ho hR c hsum hzero).analyticOnNhd_pi + _ (isOpen_partialReinhardtHull ho hR) + intro m w hw + change AnalyticAt ℂ (fun z => (∏ i, z i ^ m i) • c m) w + by_cases hm : c m = 0 + · simpa only [hm, smul_zero] using + (analyticAt_const : AnalyticAt ℂ (fun _ : Fin n → ℂ => (0 : F)) w) + apply AnalyticAt.smul _ analyticAt_const + apply Finset.analyticAt_fun_prod + intro i _ + by_cases hi : 0 ≤ m i + · exact ((ContinuousLinearMap.proj (R := ℂ) i).analyticAt w).zpow_nonneg hi + · apply ((ContinuousLinearMap.proj (R := ℂ) i).analyticAt w).zpow + intro hwi + change w i = 0 at hwi + have hmi : m i < 0 := lt_of_not_ge hi + by_cases hiI : i ∈ I + · exact hm (hzero m i (Or.inl hiI) hmi) + · obtain ⟨z, hz, _, hweq⟩ := hw + have hzi : z i = 0 := norm_eq_zero.mp (by simpa [hwi] using (hweq i hiI).symm) + exact hm (hzero m i (Or.inr ⟨z, hz, hzi⟩) hmi) + +/-- Extension in the coordinates whose zero hyperplanes meet the connected domain. The Laurent +expansion theorem supplies the coefficients and their vanishing; the series converges locally +uniformly and is analytic on the partial hull. This deduction depends on the Laurent expansion. +No common point on the hyperplanes is required. -/ +theorem exists_extension_partialReinhardtHull {n : ℕ} {I : Set (Fin n)} + {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hc : IsConnected U) (hR : IsReinhardt U) + (hmeet : ∀ i ∈ I, ∃ z ∈ U, z i = 0) + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f U) : + ∃ g, AnalyticOnNhd ℂ g (partialReinhardtHull I U) ∧ EqOn g f U := by + obtain ⟨z₀, hz₀⟩ := hc.nonempty + obtain ⟨r, hrU, hzr⟩ := hR.exists_strict_modulus_majorant ho hz₀ + have hr : ∀ i, (0 : ℝ) < r i := fun i => (norm_nonneg _).trans_lt (hzr i) + obtain ⟨hsum, hnorm, hneg, _, _⟩ := multivariableLaurent_expansion ho hc.isPreconnected hR hf hr + hrU + let c := multivariableLaurentCoeff f (fun i => (r i : ℝ)) + have hzero : ∀ m i, (i ∈ I ∨ ∃ z ∈ U, z i = 0) → m i < 0 → c m = 0 := by + intro m i hi hmi + exact hneg m i (hi.elim (hmeet i) id) hmi + exact ⟨fun z => ∑' m, multivariableLaurentTerm c m z, + analyticOnNhd_laurentSum_partialReinhardtHull ho hR c hnorm hzero, + fun z hz => (hsum.hasSum hz).tsum_eq⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity.lean new file mode 100644 index 0000000000..54ea33b703 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity.lean @@ -0,0 +1,179 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Gluing +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Local +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Basic + +/-! +# Removable singularities and Riemann extension + +A continuous function analytic away from a countable set is analytic everywhere on its open +domain. The proof applies the one-variable Cauchy theorem off countable sets to coordinate +slices, then uses Osgood. The exceptional set need not be closed or discrete. + +This supplies a proved continuous-removal step toward the classical Riemann extension theory in +[Scheidemann][Scheidemann2005] (2005), Section 4.2, and [Jakóbczak–Jarnicki][JakobczakJarnicki2021] +(2021), Section 2.1. The codomain is a complex Banach space. + +Locally bounded removal across a proper holomorphic zero set is proved by a local Cauchy +construction and gluing. It includes singular zero sets and does not require Weierstrass +preparation, division, or any algebraic regularity of the zero set. + +## Main results + +`analyticOnNhd_of_continuousOn_off_countable` (and `_pi`, `_finiteDimensional`) remove a countable +exceptional set from a continuous function. `exists_analyticOnNhd_extension_across_zeroSet` is +Riemann extension across a proper holomorphic zero set, for locally bounded Banach-valued maps. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [J. Lebl, *Tasty Bits of Several Complex Variables: A Whirlwind Tour of the Subject*][Lebl2026] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +* [T. Suwa, *Complex Analytic Geometry: From the Localization Viewpoint*][Suwa2024] +-/ + +public section + +open Filter Function Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- A continuous one-variable function analytic off a countable set is analytic on the whole open +domain, by Mathlib's Cauchy power-series theorem off countable sets. -/ +theorem analyticOnNhd_of_continuousOn_off_countable {U S : Set ℂ} {f : ℂ → F} + (hU : IsOpen U) (hS : S.Countable) (hc : ContinuousOn f U) + (hf : AnalyticOnNhd ℂ f (U \ S)) : AnalyticOnNhd ℂ f U := by + intro x hx + obtain ⟨r, hr, hball⟩ := nhds_basis_closedBall.mem_iff.mp (hU.mem_nhds hx) + exact (Complex.hasFPowerSeriesOnBall_of_differentiable_off_countable + (R := ⟨r, hr.le⟩) hS (hc.mono hball) + (fun z hz => (hf z ⟨hball (ball_subset_closedBall hz.1), hz.2⟩).differentiableAt) + hr).analyticAt + +/-- Continuous removal of a countable exceptional set in any finite complex coordinate space. Empty +coordinate types are allowed; no closedness of the exceptional set is required. -/ +theorem analyticOnNhd_of_continuousOn_off_countable_pi + {ι : Type*} [Fintype ι] {U S : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hU : IsOpen U) (hS : S.Countable) (hc : ContinuousOn f U) + (hf : AnalyticOnNhd ℂ f (U \ S)) : AnalyticOnNhd ℂ f U := by + classical + apply analyticOnNhd_pi_of_analyticOnNhd_update hU hc + intro z hz i + let L : ℂ → (ι → ℂ) := fun w => update z i w + have hL : Continuous L := by fun_prop + have hLd : Differentiable ℂ L := fun w => (hasDerivAt_update z i w).differentiableAt + have hslice : AnalyticOnNhd ℂ (f ∘ L) ((L ⁻¹' U) \ (L ⁻¹' S)) := by + intro w hw + exact (hf (L w) ⟨hw.1, hw.2⟩).comp (hLd.analyticAt w) + have hinj : Injective L := by + intro v w heq + simpa [L] using congrFun heq i + exact analyticOnNhd_of_continuousOn_off_countable (hU.preimage hL) + (hS.preimage hinj) (hc.comp hL.continuousOn (fun _ hw => hw)) hslice + (z i) (by simpa [L] using hz) + +/-- Continuous removal across a countable set in a finite-dimensional complex normed space. +Coordinates occur only in the proof. -/ +theorem analyticOnNhd_of_continuousOn_off_countable_of_finiteDimensional + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U S : Set E} {f : E → F} (hU : IsOpen U) (hS : S.Countable) + (hc : ContinuousOn f U) (hf : AnalyticOnNhd ℂ f (U \ S)) : + AnalyticOnNhd ℂ f U := by + let e := (Module.finBasis ℂ E).equivFunL + have ha : AnalyticOnNhd ℂ (f ∘ e.symm) (e.symm ⁻¹' U) := by + apply analyticOnNhd_of_continuousOn_off_countable_pi + (S := e.symm ⁻¹' S) (hU.preimage e.symm.continuous) + (hS.preimage e.symm.injective) + (hc.comp e.symm.continuous.continuousOn (fun _ hx => hx)) + intro z hz + exact (hf _ ⟨hz.1, hz.2⟩).comp (e.symm.toContinuousLinearMap.analyticAt z) + intro x hx + simpa [Function.comp_def] using + (ha (e x) (by simpa using hx)).comp (e.toContinuousLinearMap.analyticAt x) + +/-- Local Riemann extension at a point where the defining scalar germ is nonzero. A bound near this +point suffices; no connectedness assumption is needed. -/ +theorem exists_local_extension_across_zeroSet + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U : Set E} (hU : IsOpen U) {g : E → ℂ} (hg : AnalyticOnNhd ℂ g U) + {a : E} (ha : a ∈ U) (hne : ¬ g =ᶠ[𝓝 a] 0) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ g ⁻¹' {0})) + (hb : ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ (U \ g ⁻¹' {0}), ‖f z‖ ≤ C) : + ∃ (V : Set E) (f' : E → F), IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ + AnalyticOnNhd ℂ f' V ∧ EqOn f' f (V \ g ⁻¹' {0}) := by + obtain ⟨r, hr, C, hC⟩ := hb + obtain ⟨V, H, hV, haV, hVU, hH, he⟩ := exists_local_extension_zeroSet_of_bounded + (hU.inter isOpen_ball) (hg.mono inter_subset_left) ⟨ha, mem_ball_self hr⟩ hne + (hf.mono (by intro z hz; exact ⟨hz.1.1, hz.2⟩)) + (C := C) (by intro z hz; exact hC z ⟨hz.1.2, hz.1.1, hz.2⟩) + exact ⟨V, H, hV, haV, fun z hz => (hVU hz).1, hH, he⟩ + +/-- Riemann extension on an arbitrary open set: it is enough that the defining scalar function has a +nonzero germ at every point. No connectedness assumption is needed. -/ +theorem exists_analyticOnNhd_extension_across_zeroSet_of_nonzero_germs + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U : Set E} (hU : IsOpen U) {g : E → ℂ} (hg : AnalyticOnNhd ℂ g U) + (hne : ∀ a ∈ U, ¬ g =ᶠ[𝓝 a] 0) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ g ⁻¹' {0})) + (hb : ∀ a ∈ U, g a = 0 → ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ (U \ g ⁻¹' {0}), ‖f z‖ ≤ C) : + ∃ f' : E → F, AnalyticOnNhd ℂ f' U ∧ EqOn f' f (U \ g ⁻¹' {0}) := by + apply exists_analyticOnNhd_extension_of_local sdiff_subset + (subset_closure_nonzero_of_nonzero_germs hU hne) + intro a ha + by_cases hga : g a = 0 + · obtain ⟨V, H, hV, haV, hVU, hH, he⟩ := + exists_local_extension_across_zeroSet hU hg ha (hne a ha) hf (hb a ha hga) + exact ⟨V, H, hV, haV, hVU, hH, fun z hz => he ⟨hz.1, hz.2.2⟩⟩ + · refine ⟨U \ g ⁻¹' {0}, f, ?_, ⟨ha, hga⟩, sdiff_subset, hf, fun _ _ => rfl⟩ + exact hg.continuousOn.isOpen_inter_preimage hU isClosed_singleton.isOpen_compl + +omit [NormedSpace ℂ F] [CompleteSpace F] in +/-- Extensions across a scalar zero set are unique on the domain. The defining germs are assumed +nonzero locally, so the domain may have several connected components. -/ +theorem eqOn_of_extension_across_zeroSet + {E : Type*} [NormedAddCommGroup E] + {U : Set E} (hU : IsOpen U) {g : E → ℂ} (hne : ∀ a ∈ U, ¬ g =ᶠ[𝓝 a] 0) + {f f₁ f₂ : E → F} (h₁ : ContinuousOn f₁ U) (h₂ : ContinuousOn f₂ U) + (he₁ : EqOn f₁ f (U \ g ⁻¹' {0})) (he₂ : EqOn f₂ f (U \ g ⁻¹' {0})) : + EqOn f₁ f₂ U := + (he₁.trans he₂.symm).of_subset_closure h₁ h₂ sdiff_subset + (subset_closure_nonzero_of_nonzero_germs hU hne) + +/-- **Riemann extension across a holomorphic zero set.** A holomorphic function locally +bounded near the zero set of a nonzero scalar holomorphic function extends across that set. +See [Suwa][Suwa2024] Theorem 1.13, [Lebl][Lebl2026] Theorem 1.6.1, and +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] Theorem 2.1.6. +The proof uses one-variable removability and parameter-dependent Cauchy integration. + +The local bound controls only values outside the removed set. The given function may have +arbitrary values on that set. Extension uniqueness on `U` follows from the independently proved +density and continuous-uniqueness theorems in `ZeroSets.Basic`. -/ +theorem exists_analyticOnNhd_extension_across_zeroSet + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) + {g : E → ℂ} (hg : AnalyticOnNhd ℂ g U) (hne : ∃ z ∈ U, g z ≠ 0) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ g ⁻¹' {0})) + (hb : ∀ a ∈ U, g a = 0 → ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ (U \ g ⁻¹' {0}), ‖f z‖ ≤ C) : + ∃ f' : E → F, AnalyticOnNhd ℂ f' U ∧ EqOn f' f (U \ g ⁻¹' {0}) := by + apply exists_analyticOnNhd_extension_across_zeroSet_of_nonzero_germs hU hg ?_ hf hb + intro a ha hzero + obtain ⟨b, hbU, hgb⟩ := hne + exact hgb (hg.eqOn_zero_of_preconnected_of_eventuallyEq_zero hconn ha hzero hbU) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Cauchy.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Cauchy.lean new file mode 100644 index 0000000000..77027d52f1 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Cauchy.lean @@ -0,0 +1,54 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Integral.CircleIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ContourIntegral + +/-! +# Banach-valued holomorphic circle integrals + +A compact contour integral of a jointly analytic Banach-valued kernel is analytic in the +parameters. This is the parameter-dependent Cauchy integral used for Riemann extension. The +contour is fixed while its kernel may depend on all parameters. + +## Main results + +`analyticOnNhd_circleIntegral_kernel` is holomorphy of a circle integral of a jointly analytic +Banach-valued kernel. `analyticOnNhd_integral_smul_compact_kernel` is the compactly parametrized +form. +-/ + +public section + +open Complex MeasureTheory Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F α : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + [MeasurableSpace α] [TopologicalSpace α] [BorelSpace α] [T2Space α] + +omit [MeasurableSpace α] [TopologicalSpace α] [BorelSpace α] [T2Space α] in +/-- A Banach-valued jointly analytic kernel has an analytic circle integral. -/ +theorem analyticOnNhd_circleIntegral_kernel + {U : Set E} (hU : IsOpen U) {W : Set (E × ℂ)} + {H : E × ℂ → F} (hH : AnalyticOnNhd ℂ H W) + {c : ℂ} {R : ℝ} (hR : 0 ≤ R) + (hW : ∀ x ∈ U, ∀ t ∈ sphere c R, (x, t) ∈ W) : + AnalyticOnNhd ℂ (fun x => ∮ t in C(c, R), H (x, t)) U := by + have hg : ContinuousOn (fun t : ℝ => deriv (circleMap c R) t) (Icc 0 (2 * Real.pi)) := by + simp only [deriv_circleMap] + fun_prop + have h := analyticOnNhd_integral_smul_compact_kernel (μ := volume) isCompact_Icc + (hg.integrableOn_compact isCompact_Icc) (continuous_circleMap c R).continuousOn hU hH + (fun x hx t _ => hW x hx _ (circleMap_mem_sphere c hR t)) + simpa only [circleIntegral_def_Icc] using h + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/ExceptionalSet.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/ExceptionalSet.lean new file mode 100644 index 0000000000..83283ba5b9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/ExceptionalSet.lean @@ -0,0 +1,164 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity + +/-! +# Riemann extension across locally contained exceptional sets + +An exceptional set is locally contained in analytic zero sets if near each point of the open +domain it lies in the zero set of a nonzero scalar analytic germ. This is the condition called +“thin” in [Jakóbczak–Jarnicki][JakobczakJarnicki2021] §2.1. Closedness is a separate assumption, +expressed by openness of the complement within the open domain. Subsets and finite unions +satisfy the local containment condition. + +Locally bounded Banach-valued analytic functions extend uniquely across such sets. The proof +restricts to a locally containing zero set, applies Riemann extension, then recovers agreement +on the larger original domain by density and continuity. + +## Main results + +`LocallyContainedInAnalyticZeroSet` is the thinness predicate: near every point of the open domain, +the set lies in a proper scalar analytic zero set. +`exists_analyticOnNhd_extension_across_locallyContainedZeroSet` is Riemann extension across such a +set for locally bounded Banach-valued maps. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Near every point of `U`, the set `S` lies in the zero set of a nonzero scalar analytic germ. The +local neighborhoods imply openness of `U`; relative closedness of `S` and connectedness are not +imposed. -/ +@[expose] def LocallyContainedInAnalyticZeroSet (U S : Set E) : Prop := + ∀ a ∈ U, ∃ (V : Set E) (g : E → ℂ), IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ + AnalyticOnNhd ℂ g V ∧ (¬ g =ᶠ[𝓝 a] 0) ∧ V ∩ S ⊆ g ⁻¹' {0} + +/-- Local containment provides an open neighborhood inside the ambient domain at every point. -/ +theorem LocallyContainedInAnalyticZeroSet.isOpen {U S : Set E} + (h : LocallyContainedInAnalyticZeroSet U S) : IsOpen U := by + rw [isOpen_iff_mem_nhds] + intro a ha + obtain ⟨V, g, hV, haV, hVU, _⟩ := h a ha + exact Filter.mem_of_superset (hV.mem_nhds haV) hVU + +/-- A subset inherits local containment in analytic zero sets. -/ +theorem LocallyContainedInAnalyticZeroSet.mono {U S T : Set E} + (h : LocallyContainedInAnalyticZeroSet U S) (hTS : T ⊆ S) : + LocallyContainedInAnalyticZeroSet U T := by + intro a ha + obtain ⟨V, g, hV, haV, hVU, hg, hne, hS⟩ := h a ha + exact ⟨V, g, hV, haV, hVU, hg, hne, fun z hz => hS ⟨hz.1, hTS hz.2⟩⟩ + +/-- The empty set is locally contained in analytic zero sets on any open domain. -/ +theorem locallyContainedInAnalyticZeroSet_empty {U : Set E} (hU : IsOpen U) : + LocallyContainedInAnalyticZeroSet U ∅ := by + intro a ha + refine ⟨U, fun _ => 1, hU, ha, Subset.rfl, analyticOnNhd_const, ?_, by simp⟩ + intro h + have he := h.self_of_nhds + simp at he + +/-- The union of two locally contained exceptional sets is locally contained, using the product of +their local defining functions. -/ +theorem LocallyContainedInAnalyticZeroSet.union {U S T : Set E} + (hS : LocallyContainedInAnalyticZeroSet U S) (hT : LocallyContainedInAnalyticZeroSet U T) : + LocallyContainedInAnalyticZeroSet U (S ∪ T) := by + intro a ha + obtain ⟨V, g, hV, haV, hVU, hg, hgn, hSg⟩ := hS a ha + obtain ⟨W, k, hW, haW, _, hk, hkn, hTk⟩ := hT a ha + refine ⟨V ∩ W, fun z => g z * k z, hV.inter hW, ⟨haV, haW⟩, + fun z hz => hVU hz.1, (hg.mono inter_subset_left).mul (hk.mono inter_subset_right), ?_, ?_⟩ + · intro hzero + exact (eventuallyEq_zero_or_eventuallyEq_zero_of_mul (hg a haV) (hk a haW) hzero).elim hgn hkn + · rintro z ⟨⟨hzV, hzW⟩, hzS | hzT⟩ + · exact mul_eq_zero.mpr (Or.inl (hSg ⟨hzV, hzS⟩)) + · exact mul_eq_zero.mpr (Or.inr (hTk ⟨hzW, hzT⟩)) + +/-- A scalar zero set has the local containment property when all defining germs are nonzero. -/ +theorem locallyContainedInAnalyticZeroSet_zeroSet {U : Set E} (hU : IsOpen U) + {g : E → ℂ} (hg : AnalyticOnNhd ℂ g U) (hne : ∀ a ∈ U, ¬ g =ᶠ[𝓝 a] 0) : + LocallyContainedInAnalyticZeroSet U (g ⁻¹' {0}) := + fun a ha => ⟨U, g, hU, ha, Subset.rfl, hg, hne a ha, inter_subset_right⟩ + +/-- The complement of a locally contained exceptional set is dense in the domain. -/ +theorem LocallyContainedInAnalyticZeroSet.subset_closure {U S : Set E} + (h : LocallyContainedInAnalyticZeroSet U S) : U ⊆ closure (U \ S) := by + intro a ha + obtain ⟨V, g, hV, haV, hVU, _, hne, hS⟩ := h a ha + rw [Metric.mem_closure_iff] + intro r hr + by_contra! hnone + apply hne + filter_upwards [hV.mem_nhds haV, ball_mem_nhds a hr] with z hz hzr + by_cases hzs : z ∈ S + · exact hS ⟨hz, hzs⟩ + · exact False.elim (not_lt_of_ge (hnone z ⟨hVU hz, hzs⟩) + (by simpa [dist_comm] using hzr)) + +/-- Extensions across a locally contained exceptional set are unique on the domain, with no +assumptions on their values outside the domain. -/ +theorem LocallyContainedInAnalyticZeroSet.extension_unique + {F : Type*} [TopologicalSpace F] [T2Space F] {U S : Set E} + (h : LocallyContainedInAnalyticZeroSet U S) {f f₁ f₂ : E → F} + (h₁ : ContinuousOn f₁ U) (h₂ : ContinuousOn f₂ U) + (he₁ : EqOn f₁ f (U \ S)) (he₂ : EqOn f₂ f (U \ S)) : EqOn f₁ f₂ U := + (he₁.trans he₂.symm).of_subset_closure h₁ h₂ sdiff_subset h.subset_closure + +/-- **Riemann extension for locally contained exceptional sets.** Relative closedness +is expressed by `IsOpen (U \ S)`. Local bounds control values on the complement. +The domain may be disconnected and the target may be any complex Banach space. -/ +theorem exists_analyticOnNhd_extension_across_locallyContainedZeroSet + [FiniteDimensional ℂ E] {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + [CompleteSpace F] {U S : Set E} (hUS : IsOpen (U \ S)) + (hS : LocallyContainedInAnalyticZeroSet U S) {f : E → F} + (hf : AnalyticOnNhd ℂ f (U \ S)) + (hb : ∀ a ∈ U, ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ (U \ S), ‖f z‖ ≤ C) : + ∃ H : E → F, AnalyticOnNhd ℂ H U ∧ EqOn H f (U \ S) := by + apply exists_analyticOnNhd_extension_of_local sdiff_subset hS.subset_closure + intro a ha + obtain ⟨V, g, hV, haV, hVU, hg, hne, hSg⟩ := hS a ha + obtain ⟨r, hr, hBV⟩ := Metric.mem_nhds_iff.mp (hV.mem_nhds haV) + let B := ball a r + have hBU : B ⊆ U := hBV.trans hVU + have hgB : AnalyticOnNhd ℂ g B := hg.mono hBV + have hnB : ∃ b ∈ B, g b ≠ 0 := by + by_contra! h + exact hne (Filter.mem_of_superset (ball_mem_nhds a hr) (fun z hz => h z hz)) + have hcomp : B \ g ⁻¹' {0} ⊆ U \ S := by + intro z hz + exact ⟨hBU hz.1, fun hzs => hz.2 (hSg ⟨hBV hz.1, hzs⟩)⟩ + obtain ⟨H, hH, he⟩ := exists_analyticOnNhd_extension_across_zeroSet + isOpen_ball isPreconnected_ball hgB hnB (hf.mono hcomp) (by + intro b hbB _ + obtain ⟨s, hs, C, hC⟩ := hb b (hBU hbB) + exact ⟨s, hs, C, fun z hz => hC z ⟨hz.1, hcomp hz.2⟩⟩) + have hng : ∀ b ∈ B, ¬ g =ᶠ[𝓝 b] 0 := by + intro b hbB hz + obtain ⟨c, hcB, hgc⟩ := hnB + exact hgc (hgB.eqOn_zero_of_preconnected_of_eventuallyEq_zero isPreconnected_ball hbB hz hcB) + refine ⟨B, H, isOpen_ball, mem_ball_self hr, hBU, hH, ?_⟩ + apply eqOn_of_extension_across_zeroSet (g := g) (isOpen_ball.inter hUS) + (fun b hbO => hng b hbO.1) (hH.continuousOn.mono inter_subset_left) + (hf.continuousOn.mono inter_subset_right) + (fun z hz => he ⟨hz.1.1, hz.2⟩) (fun _ _ => rfl) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Geometry.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Geometry.lean new file mode 100644 index 0000000000..d1f5788aa2 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Geometry.lean @@ -0,0 +1,116 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.IsolatedZeros +public import Mathlib.Topology.Compactness.Compact +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Basic + +/-! +# Circles avoiding an analytic zero set + +A nonzero analytic germ admits a complex line on which it is not identically zero. A small +circle on that line avoids its zeros. Compactness then gives a fixed circle that continues to +avoid the zeros under small translations of its centre. A slightly larger closed disc remains in +the original open domain. No preparation or division theorem is used. + +## Main results + +`exists_nonzero_line_of_analyticAt` produces a complex line on which a nonzero germ is not +identically zero. `exists_translated_circle_avoiding_zeroSet` produces a circle that continues +to avoid the zeros under small translations of its centre. +-/ + +public section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- A nonzero analytic germ has a nonzero germ on some complex line through its centre. -/ +theorem exists_nonzero_line_of_analyticAt {g : E → ℂ} {a : E} + (hg : AnalyticAt ℂ g a) (hne : ¬ g =ᶠ[𝓝 a] 0) : + ∃ v : E, ¬ (fun w : ℂ => g (a + w • v)) =ᶠ[𝓝 0] 0 := by + by_cases hga : g a = 0 + · obtain ⟨r, hr, hgon⟩ := hg.exists_ball_analyticOnNhd + obtain ⟨b, hb, hgb⟩ : ∃ b ∈ ball a r, g b ≠ 0 := by + by_contra! h + exact hne (Filter.mem_of_superset (ball_mem_nhds a hr) (fun z hz => h z hz)) + let v := b - a + have hv : 0 < ‖v‖ := norm_pos_iff.mpr (sub_ne_zero.mpr (fun h => hgb (h ▸ hga))) + have hline : AnalyticOnNhd ℂ (fun w : ℂ => g (a + w • v)) (ball 0 (r / ‖v‖)) := by + intro w hw + have hm : a + w • v ∈ ball a r := by + rw [mem_ball, dist_eq_norm, add_sub_cancel_left, norm_smul] + exact (lt_div_iff₀ hv).mp (mem_ball_zero_iff.mp hw) + exact (hgon _ hm).comp_of_eq (analyticAt_const.add (analyticAt_id.smul analyticAt_const)) rfl + refine ⟨v, fun h => ?_⟩ + have he := hline.eqOn_zero_of_preconnected_of_eventuallyEq_zero + (convex_ball (0 : ℂ) (r / ‖v‖)).isPreconnected (mem_ball_self (div_pos hr hv)) h + have h1 : (1 : ℂ) ∈ ball 0 (r / ‖v‖) := by + rw [mem_ball_zero_iff, norm_one, lt_div_iff₀ hv, one_mul] + exact mem_ball_iff_norm.mp hb + exact hgb (by simpa [v] using he h1) + · exact ⟨0, fun h => hga (by simpa using h.self_of_nhds)⟩ + +/-- A fixed translated circle avoids the zero set for all nearby centres, while a larger closed disc +stays in the original domain. This also permits the zero direction when the defining function is +already nonzero at the centre. -/ +theorem exists_translated_circle_avoiding_zeroSet {U : Set E} (hU : IsOpen U) + {g : E → ℂ} (hg : AnalyticOnNhd ℂ g U) {a : E} (ha : a ∈ U) + (hne : ¬ g =ᶠ[𝓝 a] 0) : + ∃ (v : E) (r R : ℝ) (V : Set E), 0 < r ∧ r < R ∧ IsOpen V ∧ a ∈ V ∧ + (∀ z ∈ V, ∀ w ∈ closedBall (0 : ℂ) R, z + w • v ∈ U) ∧ + (∀ z ∈ V, ∀ w ∈ sphere (0 : ℂ) r, g (z + w • v) ≠ 0) := by + obtain ⟨v, hv⟩ := exists_nonzero_line_of_analyticAt (hg a ha) hne + have hal : AnalyticAt ℂ (fun w : ℂ => g (a + w • v)) 0 := + (hg a ha).comp_of_eq (analyticAt_const.add (analyticAt_id.smul analyticAt_const)) (by simp) + have he : ∀ᶠ w : ℂ in 𝓝 0, w ≠ 0 → g (a + w • v) ≠ 0 := + eventually_nhdsWithin_iff.mp (hal.eventually_eq_zero_or_eventually_ne_zero.resolve_left hv) + have ht : Tendsto (fun w : ℂ => a + w • v) (𝓝 0) (𝓝 a) := by + have hcont : Continuous (fun w : ℂ => a + w • v) := by fun_prop + simpa using hcont.tendsto (0 : ℂ) + obtain ⟨δ, hδ, hd⟩ := Metric.mem_nhds_iff.mp (inter_mem (ht (hU.mem_nhds ha)) he) + let r := δ / 4 + let R := δ / 2 + have hr : 0 < r := by dsimp [r]; positivity + have hrR : r < R := by dsimp [r, R]; linarith + have hRd : R < δ := by dsimp [R]; linarith + let A : E × ℂ → E := fun p => p.1 + p.2 • v + have hA : Continuous A := continuous_fst.add (continuous_snd.smul continuous_const) + obtain ⟨V₁, W₁, hV₁, _, ha₁, hW₁, hsub₁⟩ := generalized_tube_lemma + (isCompact_singleton (x := a)) (isCompact_closedBall (0 : ℂ) R) + (hU.preimage hA) (by + rintro ⟨z, w⟩ ⟨hz, hw⟩ + rcases hz with rfl + exact (hd (closedBall_subset_ball hRd hw)).1) + have hgood : IsOpen {z ∈ U | g z ≠ 0} := + hg.continuousOn.isOpen_inter_preimage hU isClosed_singleton.isOpen_compl + obtain ⟨V₂, W₂, hV₂, _, ha₂, hW₂, hsub₂⟩ := generalized_tube_lemma + (isCompact_singleton (x := a)) (isCompact_sphere (0 : ℂ) r) + (hgood.preimage hA) (by + rintro ⟨z, w⟩ ⟨hz, hw⟩ + rcases hz with rfl + have hwδ : w ∈ ball (0 : ℂ) δ := + mem_ball.mpr ((mem_sphere.mp hw).trans_lt (hrR.trans hRd)) + refine ⟨(hd hwδ).1, (hd hwδ).2 ?_⟩ + intro h + have heq := mem_sphere.mp hw + simp [h] at heq + linarith) + refine ⟨v, r, R, V₁ ∩ V₂, hr, hrR, hV₁.inter hV₂, + ⟨ha₁ (mem_singleton a), ha₂ (mem_singleton a)⟩, ?_, ?_⟩ + · intro z hz w hw + exact hsub₁ (a := (z, w)) ⟨hz.1, hW₁ hw⟩ + · intro z hz w hw + exact (hsub₂ (a := (z, w)) ⟨hz.2, hW₂ hw⟩).2 + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Gluing.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Gluing.lean new file mode 100644 index 0000000000..7a54bfe1d9 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Gluing.lean @@ -0,0 +1,79 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity + +/-! +# Gluing local analytic extensions from a dense subset + +Local continuous extensions of a function on a dense subset agree. The filter limit along that +subset therefore gives a single analytic extension on the whole domain. This elementary +construction uses no sheaf machinery and imposes no connectedness. + +## Main results + +`exists_analyticOnNhd_extension_of_local` glues local analytic extensions from a dense subset. +`subset_closure_nonzero_of_nonzero_germs` is density of the nonvanishing locus from nonzero +germs, without analyticity of a global function. +-/ + +public noncomputable section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +omit [NormedSpace ℂ E] in +/-- A function with nonzero germs everywhere on an open set has dense nonvanishing locus. This +topological statement needs no analyticity assumption. -/ +theorem subset_closure_nonzero_of_nonzero_germs {U : Set E} (hU : IsOpen U) + {g : E → ℂ} (hne : ∀ a ∈ U, ¬ g =ᶠ[𝓝 a] 0) : + U ⊆ closure (U \ g ⁻¹' {0}) := by + intro a ha + rw [Metric.mem_closure_iff] + intro r hr + by_contra! h + apply hne a ha + filter_upwards [hU.mem_nhds ha, ball_mem_nhds a hr] with z hz hzr + by_contra hgz + exact not_lt_of_ge (h z ⟨hz, hgz⟩) (by simpa [dist_comm] using hzr) + +/-- Local analytic extensions from a relatively dense subset glue to an extension on an open set. +Uniqueness is only asserted on that set, not outside it. -/ +theorem exists_analyticOnNhd_extension_of_local + {U S : Set E} {f : E → F} (hSU : S ⊆ U) (hdense : U ⊆ closure S) + (hloc : ∀ a ∈ U, ∃ (V : Set E) (H : E → F), IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ + AnalyticOnNhd ℂ H V ∧ EqOn H f (V ∩ S)) : + ∃ H : E → F, AnalyticOnNhd ℂ H U ∧ EqOn H f S := by + let H : E → F := fun a => limUnder (𝓝[S] a) f + have heq : ∀ (V : Set E) (G : E → F), IsOpen V → V ⊆ U → + AnalyticOnNhd ℂ G V → EqOn G f (V ∩ S) → EqOn H G V := by + intro V G hV hVU hG hGf a ha + have : (𝓝[S] a).NeBot := mem_closure_iff_nhdsWithin_neBot.mp (hdense (hVU ha)) + have he : G =ᶠ[𝓝[S] a] f := by + filter_upwards [nhdsWithin_le_nhds (hV.mem_nhds ha), self_mem_nhdsWithin] with z hz hzs + exact hGf ⟨hz, hzs⟩ + have ht : Tendsto f (𝓝[S] a) (𝓝 (G a)) := + ((hG a ha).continuousAt.tendsto.mono_left nhdsWithin_le_nhds).congr' he + exact ht.limUnder_eq + refine ⟨H, ?_, ?_⟩ + · intro a ha + obtain ⟨V, G, hV, haV, hVU, hG, hGf⟩ := hloc a ha + have he : H =ᶠ[𝓝 a] G := + Filter.mem_of_superset (hV.mem_nhds haV) (fun z hz => heq V G hV hVU hG hGf hz) + exact (analyticAt_congr he).mpr (hG a haV) + · intro a ha + obtain ⟨V, G, hV, haV, hVU, hG, hGf⟩ := hloc a (hSU ha) + exact (heq V G hV hVU hG hGf haV).trans (hGf ⟨haV, ha⟩) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Local.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Local.lean new file mode 100644 index 0000000000..6e184e06eb --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/Local.lean @@ -0,0 +1,105 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Geometry +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.OneVariable + +/-! +# Local Riemann extension in finite-dimensional complex spaces + +Translate a fixed small complex circle through nearby points and integrate the original function +along it. The circle avoids the defining zero set. One-variable removability identifies the +integral with the original function off the zero set; parameter-dependent integration proves +joint analyticity. The target is a complex Banach space, and no Weierstrass or Hartogs extension +theorem is used. + +## Main results + +`exists_local_extension_zeroSet_of_bounded` is local Riemann extension across a scalar zero set +for a locally bounded Banach-valued holomorphic map. +-/ + +public noncomputable section + +open Complex Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- A bounded analytic function off a scalar zero set admits a local analytic extension at every +point where the defining germ is nonzero. The neighborhood need not be connected. -/ +theorem exists_local_extension_zeroSet_of_bounded + {U : Set E} (hU : IsOpen U) {g : E → ℂ} (hg : AnalyticOnNhd ℂ g U) + {a : E} (ha : a ∈ U) (hne : ¬ g =ᶠ[𝓝 a] 0) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ g ⁻¹' {0})) + {C : ℝ} (hb : ∀ z ∈ U \ g ⁻¹' {0}, ‖f z‖ ≤ C) : + ∃ (V : Set E) (f' : E → F), IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ + AnalyticOnNhd ℂ f' V ∧ EqOn f' f (V \ g ⁻¹' {0}) := by + obtain ⟨v, r, R, V, hr, hrR, hV, haV, hdisc, hcircle⟩ := + exists_translated_circle_avoiding_zeroSet hU hg ha hne + have hR : 0 < R := hr.trans hrR + have hVU : V ⊆ U := by + intro z hz + simpa using hdisc z hz 0 (mem_closedBall_self hR.le) + let W : Set (E × ℂ) := {p | p.2 ≠ 0 ∧ p.1 + p.2 • v ∈ U ∧ g (p.1 + p.2 • v) ≠ 0} + let H : E × ℂ → F := fun p => p.2⁻¹ • f (p.1 + p.2 • v) + have hH : AnalyticOnNhd ℂ H W := by + intro p hp + have hA : AnalyticAt ℂ (fun q : E × ℂ => q.1 + q.2 • v) p := + analyticAt_fst.add (analyticAt_snd.smul analyticAt_const) + exact (analyticAt_snd.inv hp.1).smul ((hf _ hp.2).comp_of_eq hA rfl) + have hW : ∀ z ∈ V, ∀ t ∈ sphere (0 : ℂ) r, (z, t) ∈ W := by + intro z hz t ht + refine ⟨?_, hdisc z hz t (closedBall_subset_closedBall hrR.le (sphere_subset_closedBall ht)), + hcircle z hz t ht⟩ + change t ≠ 0 + intro h + have heq := mem_sphere.mp ht + simp [h] at heq + linarith + let f' : E → F := fun z => (2 * Real.pi * I : ℂ)⁻¹ • ∮ t in C(0, r), H (z, t) + have hfa : AnalyticOnNhd ℂ f' V := + (analyticOnNhd_circleIntegral_kernel hV hH hr.le hW).const_smul + refine ⟨V, f', hV, haV, hVU, hfa, ?_⟩ + intro z hz + have hsl : AnalyticOnNhd ℂ (fun t : ℂ => g (z + t • v)) (ball 0 R) := by + intro t ht + exact (hg _ (hdisc z hz.1 t (ball_subset_closedBall ht))).comp_of_eq + (analyticAt_const.add (analyticAt_id.smul analyticAt_const)) rfl + have hfs : AnalyticOnNhd ℂ (fun t : ℂ => f (z + t • v)) + (ball 0 R \ (fun t : ℂ => g (z + t • v)) ⁻¹' {0}) := by + intro t ht + exact (hf _ ⟨hdisc z hz.1 t (ball_subset_closedBall ht.1), ht.2⟩).comp_of_eq + (analyticAt_const.add (analyticAt_id.smul analyticAt_const)) rfl + have hsne : ∃ t ∈ ball (0 : ℂ) R, g (z + t • v) ≠ 0 := + ⟨0, mem_ball_self hR, by simpa using hz.2⟩ + obtain ⟨fsl, hfsl, heq⟩ := exists_analyticOnNhd_extension_zeroSet_oneVariable + isOpen_ball (convex_ball (0 : ℂ) R).isPreconnected hsl hsne hfs (by + intro t ht _ + refine ⟨1, zero_lt_one, C, ?_⟩ + intro w hw + exact hb _ ⟨hdisc z hz.1 w (ball_subset_closedBall hw.2.1), hw.2.2⟩) + have hcauchy := + Complex.two_pi_I_inv_smul_circleIntegral_sub_inv_smul_of_differentiable_on_off_countable + (f := fsl) countable_empty (mem_ball_self hr) + (hfsl.continuousOn.mono (closedBall_subset_ball hrR)) + (fun w hw => (hfsl w (ball_subset_ball hrR.le hw.1)).differentiableAt) + have hboundary : (∮ t in C(0, r), H (z, t)) = ∮ t in C(0, r), (t - 0)⁻¹ • fsl t := by + apply circleIntegral.integral_congr hr.le + intro t ht + have htR : t ∈ ball (0 : ℂ) R := closedBall_subset_ball hrR (sphere_subset_closedBall ht) + simp only [H, sub_zero, heq ⟨htR, hcircle z hz.1 t ht⟩] + exact (congrArg (fun q => (2 * Real.pi * I : ℂ)⁻¹ • q) hboundary).trans + (hcauchy.trans (by simpa using heq ⟨mem_ball_self hR, by simpa using hz.2⟩)) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/OneVariable.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/OneVariable.lean new file mode 100644 index 0000000000..796fde70b4 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/RemovableSingularity/OneVariable.lean @@ -0,0 +1,81 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.IsolatedZeros +public import Mathlib.Analysis.Complex.RemovableSingularity + +/-! +# One-variable extension across analytic zero sets + +Mathlib's Banach-valued isolated-singularity theorem applies at every zero of a nonzero scalar +analytic function. Redefining the function by its punctured limit at each zero gives one +extension on the whole open set. This is the slice theorem used in the several-variable Riemann +extension argument. + +## Main results + +`exists_analyticOnNhd_extension_zeroSet_oneVariable` extends a Banach-valued holomorphic +function across the zeros of a nonzero scalar analytic function of one variable. +-/ + +public noncomputable section + +open Filter Function Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- A bounded Banach-valued function analytic off the zeros of a nonzero one-variable analytic +function extends across all of those zeros. Bounds are needed only near zeros. -/ +theorem exists_analyticOnNhd_extension_zeroSet_oneVariable + {U : Set ℂ} (hU : IsOpen U) (hc : IsPreconnected U) + {g : ℂ → ℂ} (hg : AnalyticOnNhd ℂ g U) (hne : ∃ z ∈ U, g z ≠ 0) + {f : ℂ → F} (hf : AnalyticOnNhd ℂ f (U \ g ⁻¹' {0})) + (hb : ∀ a ∈ U, g a = 0 → ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ (U \ g ⁻¹' {0}), ‖f z‖ ≤ C) : + ∃ f' : ℂ → F, AnalyticOnNhd ℂ f' U ∧ EqOn f' f (U \ g ⁻¹' {0}) := by + classical + let f' : ℂ → F := fun z => if g z = 0 then limUnder (𝓝[≠] z) f else f z + refine ⟨f', ?_, fun z hz => by simp [f', show g z ≠ 0 from hz.2]⟩ + intro a ha + by_cases hga : g a = 0 + · have hnloc : ¬ g =ᶠ[𝓝 a] 0 := by + intro h + obtain ⟨b, hb, hgb⟩ := hne + exact hgb (hg.eqOn_zero_of_preconnected_of_eventuallyEq_zero hc ha h hb) + have hisol := ((hg a ha).eventually_eq_zero_or_eventually_ne_zero).resolve_left hnloc + obtain ⟨r, hr, C, hC⟩ := hb a ha hga + have he : ∀ᶠ z in 𝓝 a, z ≠ a → g z ≠ 0 := eventually_nhdsWithin_iff.mp hisol + obtain ⟨s, hs, hsa⟩ := Metric.mem_nhds_iff.mp + (inter_mem (hU.mem_nhds ha) (inter_mem (ball_mem_nhds a hr) he)) + have hdiff : DifferentiableOn ℂ f (ball a s \ {a}) := by + intro z hz + exact (hf z ⟨(hsa hz.1).1, (hsa hz.1).2.2 hz.2⟩).differentiableAt.differentiableWithinAt + have hbound : BddAbove ((norm ∘ f) '' (ball a s \ {a})) := by + refine ⟨C, ?_⟩ + rintro _ ⟨z, hz, rfl⟩ + exact hC z ⟨(hsa hz.1).2.1, (hsa hz.1).1, (hsa hz.1).2.2 hz.2⟩ + have hd := Complex.differentiableOn_update_limUnder_of_bddAbove + (ball_mem_nhds a hs) hdiff hbound + have han : AnalyticAt ℂ (update f a (limUnder (𝓝[≠] a) f)) a := + hd.analyticAt (ball_mem_nhds a hs) + apply (analyticAt_congr (g := update f a (limUnder (𝓝[≠] a) f)) ?_).mpr han + filter_upwards [he] with z hz + by_cases hza : z = a + · subst z + simp [f', hga] + · simp [f', hz hza, hza] + · have he : f' =ᶠ[𝓝 a] f := by + filter_upwards [(hg a ha).continuousAt.eventually_ne hga] with z hz + simp [f', hz] + exact (analyticAt_congr he).mpr (hf a ⟨ha, hga⟩) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Runge.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Runge.lean new file mode 100644 index 0000000000..6db956e137 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Runge.lean @@ -0,0 +1,382 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Algebra.MvPolynomial.Basic +public import Mathlib.Analysis.Analytic.Polynomial +public import Mathlib.Topology.Algebra.InfiniteSum.UniformOn +public import Mathlib.Topology.Algebra.MvPolynomial +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.CompactExhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.PolydiscTaylor + +/-! +# Runge pairs, Runge domains and polynomial hulls + +A pair of sets `U ⊆ V` is a Runge pair if every holomorphic function on `U` is a locally uniform +limit of holomorphic functions on `V`; an open subset of `ℂⁿ` is a Runge domain if every +holomorphic function on it is a locally uniform limit of polynomials. Both notions are stated +through approximation within `ε` on compact subsets, and for open sets this is shown equivalent +to convergence of a sequence locally uniformly. + +The polynomial hull of a compact set is the set of points where every polynomial is bounded by +its supremum on the set; it agrees with the hull relative to all entire functions, because +entire functions are locally uniform limits of their Taylor polynomials. Consequently a set is a +Runge domain exactly when it forms a Runge pair with the whole space. + +For a Runge domain `U`, the polynomial hull of a compact `K ⊆ U` meets `U` in the holomorphic +hull of `K` relative to `U`, and for a Runge domain of holomorphy this set is compact. These are +the elementary implications of the hull characterization of Runge domains +([Hörmander][Hormander1973], Theorem 2.7.3; [Jakóbczak–Jarnicki][JakobczakJarnicki2021], Theorem +4.3.3). The converse implications constitute the Oka–Weil theorem and are not included. + +References: [Hörmander][Hormander1973] (1973), Section 2.7; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Section 4.3; +[Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), Section 1.7. + +## Main definitions + +* `polynomialHull`: The polynomial hull of a set: the points at which every polynomial is bounded by + each of its bounds on the set. +* `IsPolynomiallyConvex`: A set is polynomially convex if it equals its polynomial hull. +* `IsRungePair`: A **Runge pair**: `U ⊆ V`, and every holomorphic function on `U` is approximated + within `ε` on every compact subset of `U` by a holomorphic function on `V`. +* `IsRungeDomain`: A **Runge domain** in `ℂⁿ`: every holomorphic function is approximated within `ε` + on every compact subset by a polynomial. + +## Main results + +* `exists_mvPolynomial_approx_of_entire`: **Entire functions are locally uniform limits of + polynomials.** On a compact set, an entire function is approximated within `ε` by a Taylor + polynomial. +* `polynomialHull_eq_holomorphicHull_univ`: **Polynomial and entire hulls agree** on compact sets, + since entire functions are locally uniform limits of polynomials. +* `IsRungeDomain.polynomialHull_inter`: **Hull identity for Runge domains.** For a Runge domain `U` + and a compact `K ⊆ U`, the polynomial hull of `K` meets `U` exactly in the holomorphic hull of `K` + relative to `U`. +* `IsRungePair.exists_seq_tendstoLocallyUniformlyOn`: **Sequence formulation.** For an open `U`, a + Runge pair provides, for each holomorphic function on `U`, a sequence of holomorphic functions on + `V` converging locally uniformly. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Filter Function Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +section Polynomials + +variable {n : ℕ} + +/-- A finite sum of monomials with complex coefficients, indexed by finitely supported +multi-indices, is the evaluation of a polynomial. -/ +theorem exists_mvPolynomial_eval_eq_sum (s : Finset (Fin n →₀ ℕ)) (c : (Fin n →₀ ℕ) → ℂ) : + ∃ P : MvPolynomial (Fin n) ℂ, ∀ z : Fin n → ℂ, + MvPolynomial.eval z P = ∑ m ∈ s, (∏ i, z i ^ m i) * c m := by + refine ⟨∑ m ∈ s, MvPolynomial.C (c m) * ∏ i, MvPolynomial.X i ^ (m i), fun z => ?_⟩ + simp only [map_sum, map_mul, MvPolynomial.eval_C, map_prod, map_pow, MvPolynomial.eval_X] + refine Finset.sum_congr rfl fun m _ => ?_ + ring + +/-- A finite sum of monomials with complex coefficients, indexed by functions `Fin n → ℕ`, is the +evaluation of a polynomial. -/ +theorem exists_mvPolynomial_eval_eq_sum' (s : Finset (Fin n → ℕ)) (c : (Fin n → ℕ) → ℂ) : + ∃ P : MvPolynomial (Fin n) ℂ, ∀ z : Fin n → ℂ, + MvPolynomial.eval z P = ∑ m ∈ s, (∏ i, z i ^ m i) * c m := by + refine ⟨∑ m ∈ s, MvPolynomial.C (c m) * ∏ i, MvPolynomial.X i ^ (m i), fun z => ?_⟩ + simp only [map_sum, map_mul, MvPolynomial.eval_C, map_prod, map_pow, MvPolynomial.eval_X] + refine Finset.sum_congr rfl fun m _ => ?_ + ring + +/-- **Entire functions are locally uniform limits of polynomials.** On a compact set, an entire +function is approximated within `ε` by a Taylor polynomial. -/ +theorem exists_mvPolynomial_approx_of_entire {g : (Fin n → ℂ) → ℂ} + (hg : AnalyticOnNhd ℂ g univ) {K : Set (Fin n → ℂ)} (hK : IsCompact K) {ε : ℝ} (hε : 0 < ε) : + ∃ P : MvPolynomial (Fin n) ℂ, ∀ z ∈ K, ‖g z - MvPolynomial.eval z P‖ < ε := by + obtain ⟨B, hB⟩ := hK.isBounded.subset_closedBall 0 + set R : Fin n → ℝ := fun _ => max B 0 + 1 with hRdef + have hR : ∀ i, 0 < R i := fun _ => by positivity + set s : Fin n → ℝ := fun _ => max B 0 with hsdef + have hs : ∀ i, 0 ≤ s i := fun _ => le_max_right _ _ + have hsR : ∀ i, s i < R i := fun _ => by simp [hsdef, hRdef] + have hKs : K ⊆ closedPolydisc 0 s := by + intro z hz + rw [mem_closedPolydisc] + intro i + have h1 : ‖z i‖ ≤ ‖z‖ := norm_le_pi_norm z i + have h2 : ‖z‖ ≤ B := mem_closedBall_zero_iff.mp (hB hz) + rw [Pi.zero_apply, dist_zero_right] + exact h1.trans (h2.trans (le_max_left _ _)) + have hcont : ContinuousOn g (closedPolydisc 0 R) := hg.continuousOn.mono (subset_univ _) + have hslice : ∀ z ∈ closedPolydisc 0 R, ∀ i, + AnalyticAt ℂ (fun v => g (update z i v)) (z i) := + fun z _ i => by convert hg.analyticAt_update (mem_univ z) i + obtain ⟨M, hM⟩ := (isCompact_closedPolydisc 0 R).exists_bound_of_continuousOn hcont + have hsum := hasSumUniformlyOn_polydiscTaylor hR hs hsR hcont hslice hM + rw [hasSumUniformlyOn_iff_tendstoUniformlyOn, Metric.tendstoUniformlyOn_iff] at hsum + obtain ⟨t, ht⟩ := (hsum ε hε).exists + obtain ⟨P, hP⟩ := exists_mvPolynomial_eval_eq_sum' t + (fun m => polydiscCauchyCoeffWithRadii g 0 R m) + refine ⟨P, fun z hz => ?_⟩ + have := ht z (hKs hz) + rw [dist_eq_norm, zero_add] at this + rw [hP z] + simpa only [smul_eq_mul] using this + +end Polynomials + +section Hull + +variable {n : ℕ} {σ : Type*} + +/-- The polynomial hull of a set: the points at which every polynomial is bounded by each of its +bounds on the set. The variables may be indexed by any type. -/ +@[expose] def polynomialHull (K : Set (σ → ℂ)) : Set (σ → ℂ) := + {z | ∀ P : MvPolynomial σ ℂ, ∀ M : ℝ, + (∀ w ∈ K, ‖MvPolynomial.eval w P‖ ≤ M) → ‖MvPolynomial.eval z P‖ ≤ M} + +/-- A set is polynomially convex if it equals its polynomial hull. -/ +@[expose] def IsPolynomiallyConvex (K : Set (σ → ℂ)) : Prop := polynomialHull K = K + +/-- A set lies in its polynomial hull. -/ +theorem subset_polynomialHull (K : Set (σ → ℂ)) : K ⊆ polynomialHull K := + fun z hz _ _ hM => hM z hz + +/-- The polynomial hull is monotone. -/ +theorem polynomialHull_mono {K L : Set (σ → ℂ)} (h : K ⊆ L) : + polynomialHull K ⊆ polynomialHull L := + fun _ hz P M hM => hz P M fun w hw => hM w (h hw) + +/-- The polynomial hull is closed. -/ +theorem isClosed_polynomialHull (K : Set (σ → ℂ)) : IsClosed (polynomialHull K) := by + have : polynomialHull K = ⋂ P : MvPolynomial σ ℂ, ⋂ M : ℝ, + ⋂ _ : (∀ w ∈ K, ‖MvPolynomial.eval w P‖ ≤ M), {z | ‖MvPolynomial.eval z P‖ ≤ M} := by + ext z + simp only [polynomialHull, mem_ofPred_eq, mem_iInter] + rw [this] + exact isClosed_iInter fun P => isClosed_iInter fun M => isClosed_iInter fun _ => + isClosed_le (P.continuous_eval).norm continuous_const + +/-- The polynomial hull of a bounded set is bounded, by the coordinate polynomials. -/ +theorem polynomialHull_subset_closedBall {K : Set (Fin n → ℂ)} {B : ℝ} (hB0 : 0 ≤ B) + (hK : K ⊆ closedBall 0 B) : polynomialHull K ⊆ closedBall 0 B := by + intro z hz + rw [mem_closedBall_zero_iff, pi_norm_le_iff_of_nonneg hB0] + intro i + have := hz (MvPolynomial.X i) B fun w hw => by + rw [MvPolynomial.eval_X] + exact (norm_le_pi_norm w i).trans (mem_closedBall_zero_iff.mp (hK hw)) + rwa [MvPolynomial.eval_X] at this + +/-- The polynomial hull of a compact set is compact. -/ +theorem isCompact_polynomialHull {K : Set (Fin n → ℂ)} (hK : IsCompact K) : + IsCompact (polynomialHull K) := by + obtain ⟨B, hB⟩ := hK.isBounded.subset_closedBall 0 + have hB' : K ⊆ closedBall 0 (max B 0) := + hB.trans (closedBall_subset_closedBall (le_max_left _ _)) + exact isCompact_of_isClosed_isBounded (isClosed_polynomialHull K) + (isBounded_closedBall.subset (polynomialHull_subset_closedBall (le_max_right _ _) hB')) + +/-- **Polynomial and entire hulls agree** on compact sets, since entire functions are locally +uniform limits of polynomials. -/ +theorem polynomialHull_eq_holomorphicHull_univ {K : Set (Fin n → ℂ)} (hK : IsCompact K) : + polynomialHull K = holomorphicHull univ K := by + ext z + constructor + · intro hz + refine ⟨mem_univ z, fun f hf M hM => ?_⟩ + refine le_of_forall_pos_le_add fun ε hε => ?_ + obtain ⟨P, hP⟩ := exists_mvPolynomial_approx_of_entire hf (hK.insert z) (half_pos hε) + have hPK : ∀ w ∈ K, ‖MvPolynomial.eval w P‖ ≤ M + ε / 2 := fun w hw => by + have h1 := hP w (mem_insert_of_mem z hw) + have h2 := hM w hw + calc ‖MvPolynomial.eval w P‖ = ‖f w - (f w - MvPolynomial.eval w P)‖ := by ring_nf + _ ≤ ‖f w‖ + ‖f w - MvPolynomial.eval w P‖ := norm_sub_le _ _ + _ ≤ M + ε / 2 := by linarith + have hz' := hz P (M + ε / 2) hPK + have h3 := hP z (mem_insert z K) + calc ‖f z‖ = ‖(f z - MvPolynomial.eval z P) + MvPolynomial.eval z P‖ := by ring_nf + _ ≤ ‖f z - MvPolynomial.eval z P‖ + ‖MvPolynomial.eval z P‖ := norm_add_le _ _ + _ ≤ M + ε := by linarith + · intro hz P M hM + exact hz.2 _ (AnalyticOnNhd.eval_mvPolynomial P) M hM + +/-- The polynomial hull is polynomially convex. -/ +theorem isPolynomiallyConvex_polynomialHull (K : Set (σ → ℂ)) : + IsPolynomiallyConvex (polynomialHull K) := by + refine Subset.antisymm (fun z hz P M hM => ?_) (subset_polynomialHull _) + exact hz P M fun w hw => hw P M hM + +end Hull + +section Runge + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- A **Runge pair**: `U ⊆ V`, and every holomorphic function on `U` is approximated within `ε` on +every compact subset of `U` by a holomorphic function on `V`. -/ +@[expose] def IsRungePair (U V : Set E) : Prop := + U ⊆ V ∧ ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → ∀ K : Set E, IsCompact K → K ⊆ U → ∀ ε > 0, + ∃ g : E → ℂ, AnalyticOnNhd ℂ g V ∧ ∀ z ∈ K, ‖f z - g z‖ < ε + +/-- A Runge pair is an inclusion. -/ +theorem IsRungePair.subset {U V : Set E} (h : IsRungePair U V) : U ⊆ V := h.1 + +/-- Every set forms a Runge pair with itself. -/ +theorem isRungePair_refl (U : Set E) : IsRungePair U U := + ⟨Subset.rfl, fun f hf _ _ _ ε hε => ⟨f, hf, fun _ _ => by simpa using hε⟩⟩ + +/-- Runge pairs are transitive. -/ +theorem IsRungePair.trans {U V W : Set E} (h₁ : IsRungePair U V) (h₂ : IsRungePair V W) : + IsRungePair U W := by + refine ⟨h₁.1.trans h₂.1, fun f hf K hK hKU ε hε => ?_⟩ + obtain ⟨g, hg, hfg⟩ := h₁.2 f hf K hK hKU (ε / 2) (half_pos hε) + obtain ⟨k, hk, hgk⟩ := h₂.2 g hg K hK (hKU.trans h₁.1) (ε / 2) (half_pos hε) + refine ⟨k, hk, fun z hz => ?_⟩ + calc ‖f z - k z‖ = ‖(f z - g z) + (g z - k z)‖ := by ring_nf + _ ≤ ‖f z - g z‖ + ‖g z - k z‖ := norm_add_le _ _ + _ < ε / 2 + ε / 2 := add_lt_add (hfg z hz) (hgk z hz) + _ = ε := add_halves ε + +/-- A **Runge domain** in `ℂ^ι`, for a finite index type `ι`: every holomorphic function is + approximated within `ε` on every +compact subset by a polynomial. Being a domain of holomorphy is not part of the definition. -/ +@[expose] def IsRungeDomain {ι : Type*} [Fintype ι] (U : Set (ι → ℂ)) : Prop := + ∀ f : (ι → ℂ) → ℂ, AnalyticOnNhd ℂ f U → ∀ K : Set (ι → ℂ), IsCompact K → K ⊆ U → + ∀ ε > 0, ∃ P : MvPolynomial ι ℂ, ∀ z ∈ K, ‖f z - MvPolynomial.eval z P‖ < ε + +variable {n : ℕ} + +/-- A set is a Runge domain exactly when it forms a Runge pair with the whole space. -/ +theorem isRungeDomain_iff_isRungePair_univ (U : Set (Fin n → ℂ)) : + IsRungeDomain U ↔ IsRungePair U univ := by + constructor + · intro h + refine ⟨subset_univ U, fun f hf K hK hKU ε hε => ?_⟩ + obtain ⟨P, hP⟩ := h f hf K hK hKU ε hε + exact ⟨fun z => MvPolynomial.eval z P, AnalyticOnNhd.eval_mvPolynomial P, hP⟩ + · intro h f hf K hK hKU ε hε + obtain ⟨g, hg, hfg⟩ := h.2 f hf K hK hKU (ε / 2) (half_pos hε) + obtain ⟨P, hP⟩ := exists_mvPolynomial_approx_of_entire hg hK (half_pos hε) + refine ⟨P, fun z hz => ?_⟩ + calc ‖f z - MvPolynomial.eval z P‖ = ‖(f z - g z) + (g z - MvPolynomial.eval z P)‖ := by ring_nf + _ ≤ ‖f z - g z‖ + ‖g z - MvPolynomial.eval z P‖ := norm_add_le _ _ + _ < ε / 2 + ε / 2 := add_lt_add (hfg z hz) (hP z hz) + _ = ε := add_halves ε + +/-- The whole space is a Runge domain. -/ +theorem isRungeDomain_univ : IsRungeDomain (univ : Set (Fin n → ℂ)) := + (isRungeDomain_iff_isRungePair_univ _).mpr (isRungePair_refl _) + +/-- **Hull identity for Runge domains.** For a Runge domain `U` and a compact `K ⊆ U`, the +polynomial hull of `K` meets `U` exactly in the holomorphic hull of `K` relative to `U`. -/ +theorem IsRungeDomain.polynomialHull_inter {U : Set (Fin n → ℂ)} (h : IsRungeDomain U) + {K : Set (Fin n → ℂ)} (hK : IsCompact K) (hKU : K ⊆ U) : + polynomialHull K ∩ U = holomorphicHull U K := by + ext z + constructor + · rintro ⟨hz, hzU⟩ + refine ⟨hzU, fun f hf M hM => ?_⟩ + refine le_of_forall_pos_le_add fun ε hε => ?_ + obtain ⟨P, hP⟩ := h f hf (insert z K) (hK.insert z) (insert_subset hzU hKU) (ε / 2) (half_pos + hε) + have hPK : ∀ w ∈ K, ‖MvPolynomial.eval w P‖ ≤ M + ε / 2 := fun w hw => by + have h1 := hP w (mem_insert_of_mem z hw) + have h2 := hM w hw + calc ‖MvPolynomial.eval w P‖ = ‖f w - (f w - MvPolynomial.eval w P)‖ := by ring_nf + _ ≤ ‖f w‖ + ‖f w - MvPolynomial.eval w P‖ := norm_sub_le _ _ + _ ≤ M + ε / 2 := by linarith + have hz' := hz P (M + ε / 2) hPK + have h3 := hP z (mem_insert z K) + calc ‖f z‖ = ‖(f z - MvPolynomial.eval z P) + MvPolynomial.eval z P‖ := by ring_nf + _ ≤ ‖f z - MvPolynomial.eval z P‖ + ‖MvPolynomial.eval z P‖ := norm_add_le _ _ + _ ≤ M + ε := by linarith + · intro hz + refine ⟨fun P M hM => hz.2 _ ((AnalyticOnNhd.eval_mvPolynomial P).mono (subset_univ U)) M hM, + hz.1⟩ + +/-- If the polynomial hull of every compact subset agrees with its holomorphic hull, then in +particular the intersection with `U` does. -/ +theorem polynomialHull_inter_eq_of_eq {U K : Set (Fin n → ℂ)} + (h : polynomialHull K = holomorphicHull U K) : + polynomialHull K ∩ U = holomorphicHull U K := by + rw [h] + exact inter_eq_left.mpr (holomorphicHull_subset U K) + +/-- For a Runge domain of holomorphy, the polynomial hull of a compact subset meets the domain in a +compact set. The converse implications are the Oka–Weil theorem. -/ +theorem IsRungeDomain.isCompact_polynomialHull_inter {U : Set (Fin n → ℂ)} (h : IsRungeDomain U) + (hU : IsDomainOfHolomorphy U) (ho : IsOpen U) {K : Set (Fin n → ℂ)} (hK : IsCompact K) + (hKU : K ⊆ U) : IsCompact (polynomialHull K ∩ U) := by + rw [h.polynomialHull_inter hK hKU] + exact hU.isHolomorphicallyConvex ho K hK hKU + +end Runge + +section Sequences + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Approximation on compact sets follows from locally uniform convergence of a sequence. -/ +theorem isRungePair_of_forall_exists_seq {U V : Set E} (hUV : U ⊆ V) + (h : ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → ∃ g : ℕ → E → ℂ, + (∀ k, AnalyticOnNhd ℂ (g k) V) ∧ TendstoLocallyUniformlyOn g f atTop U) : + IsRungePair U V := by + refine ⟨hUV, fun f hf K hK hKU ε hε => ?_⟩ + obtain ⟨g, hg, hlim⟩ := h f hf + have hu := (tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK).mp (hlim.mono hKU) + rw [Metric.tendstoUniformlyOn_iff] at hu + obtain ⟨k, hk⟩ := (hu ε hε).exists + exact ⟨g k, hg k, fun z hz => by rw [← dist_eq_norm]; exact hk z hz⟩ + +variable [ProperSpace E] + +/-- **Sequence formulation.** For an open `U`, a Runge pair provides, for each holomorphic +function on `U`, a sequence of holomorphic functions on `V` converging locally uniformly. -/ +theorem IsRungePair.exists_seq_tendstoLocallyUniformlyOn {U V : Set E} (hU : IsOpen U) + (h : IsRungePair U V) {f : E → ℂ} (hf : AnalyticOnNhd ℂ f U) : + ∃ g : ℕ → E → ℂ, (∀ k, AnalyticOnNhd ℂ (g k) V) ∧ TendstoLocallyUniformlyOn g f atTop U := by + obtain ⟨L, hLc, hLU, hLmono, hLex⟩ := hU.exists_compact_exhaustion + have hchoice : ∀ k : ℕ, ∃ g : E → ℂ, AnalyticOnNhd ℂ g V ∧ + ∀ z ∈ L k, ‖f z - g z‖ < 1 / ((k : ℝ) + 1) := + fun k => h.2 f hf (L k) (hLc k) (hLU k) _ (by positivity) + choose g hg using hchoice + refine ⟨g, fun k => (hg k).1, ?_⟩ + rw [tendstoLocallyUniformlyOn_iff_forall_isCompact hU] + intro K hKU hK + obtain ⟨k₀, hk₀⟩ := hLex K hK hKU + have hLmono' : ∀ k, k₀ ≤ k → L k₀ ⊆ L k := fun k hk => by + induction hk with + | refl => exact Subset.rfl + | step _ ih => exact ih.trans (hLmono _) + rw [Metric.tendstoUniformlyOn_iff] + intro ε hε + obtain ⟨N, hN⟩ := exists_nat_gt (1 / ε) + filter_upwards [eventually_ge_atTop (max k₀ N)] with k hk z hz + have hzk : z ∈ L k := hLmono' k ((le_max_left _ _).trans hk) (hk₀ hz) + have h1 := (hg k).2 z hzk + rw [dist_eq_norm] + refine h1.trans_le ?_ + have hkN : (N : ℝ) ≤ (k : ℝ) := by exact_mod_cast (le_max_right _ _).trans hk + rw [div_le_iff₀ (by positivity)] + rw [div_lt_iff₀ hε] at hN + nlinarith + +end Sequences + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Runge/Examples.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Runge/Examples.lean new file mode 100644 index 0000000000..ef5ba77bac --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Runge/Examples.lean @@ -0,0 +1,206 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Algebra.MvPolynomial.Monad +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CircularContinuation +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Reinhardt.Extension +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Runge + +/-! +# Examples of Runge domains + +Complete Reinhardt open sets in `ℂⁿ` are Runge domains, since holomorphic functions on them are +represented by their Taylor series at the origin, converging locally uniformly. More generally, +circular connected open sets containing the origin are Runge domains, since holomorphic +functions on them are locally uniform sums of their homogeneous expansions, whose terms are +polynomials. In particular polydiscs and balls centered at the origin, and the whole space, are +Runge domains. + +Runge domains are transported by holomorphic maps with polynomial inverses: if `U` is Runge, `Φ` +is holomorphic on `U` with values in `U'`, and `Ψ` is a polynomial map from `U'` into `U` with +`Φ ∘ Ψ = id` on `U'`, then `U'` is Runge. Translates and polynomial-automorphic images of Runge +domains are Runge ([Jakóbczak–Jarnicki][JakobczakJarnicki2021], Proposition 4.3.2). + +References: [Hörmander][Hormander1973] (1973), Section 2.7; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Section 4.3. + +## Main definitions + +* `mvPolynomialMap`: The polynomial map with components `G i`. + +## Main results + +* `IsCompleteReinhardt.isRungeDomain`: **Complete Reinhardt open sets are Runge domains** : + holomorphic functions are locally uniform sums of their Taylor series at the origin. +* `IsCircular.isRungeDomain`: **Circular connected open sets containing the origin are Runge + domains** : holomorphic functions are locally uniform sums of their homogeneous expansions, whose + terms are polynomials. +* `IsRungeDomain.transport`: **Transport of Runge domains.** If `U` is a Runge domain, `Φ` is + holomorphic on `U` with values in `U'`, and `Ψ` is a polynomial map from `U'` into `U` with `Φ ∘ Ψ + = id` on `U'`, then `U'` is a Runge domain. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Filter Function Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {n : ℕ} + +section Reinhardt + +/-- **Complete Reinhardt open sets are Runge domains**: holomorphic functions are locally uniform +sums of their Taylor series at the origin. -/ +theorem IsCompleteReinhardt.isRungeDomain {U : Set (Fin n → ℂ)} (ho : IsOpen U) + (hc : IsCompleteReinhardt U) : IsRungeDomain U := by + intro f hf K hK hKU ε hε + obtain ⟨hdom, heq⟩ + := IsCompleteReinhardt.subset_convergenceDomain_and_eqOn_powerSeriesSum ho hc hf + have hsum := hasSumUniformlyOn_powerSeries (taylorCoefficientsAtZero f) hK (hKU.trans hdom) + rw [hasSumUniformlyOn_iff_tendstoUniformlyOn, Metric.tendstoUniformlyOn_iff] at hsum + obtain ⟨t, ht⟩ := (hsum ε hε).exists + obtain ⟨P, hP⟩ := exists_mvPolynomial_eval_eq_sum t (fun m => taylorCoefficientsAtZero f m) + refine ⟨P, fun z hz => ?_⟩ + have := ht z hz + rw [dist_eq_norm, heq (hKU hz)] at this + rw [hP z] + simpa only [smul_eq_mul] using this + +/-- Polydiscs centered at the origin are Runge domains. -/ +theorem isRungeDomain_polydisc (r : Fin n → ℝ) : + IsRungeDomain (polydisc (0 : Fin n → ℂ) r) := + (isCompleteReinhardt_polydisc r).isRungeDomain (isOpen_polydisc 0 r) + +/-- Balls centered at the origin are Runge domains. -/ +theorem isRungeDomain_ball (r : ℝ) : IsRungeDomain (ball (0 : Fin n → ℂ) r) := by + refine IsCompleteReinhardt.isRungeDomain isOpen_ball fun z hz w hw => ?_ + rw [mem_ball_zero_iff] at hz ⊢ + refine lt_of_le_of_lt ?_ hz + rw [pi_norm_le_iff_of_nonneg (norm_nonneg z)] + exact fun i => (hw i).trans (norm_le_pi_norm z i) + +end Reinhardt + +section Circular + +/-- The restriction of a continuous multilinear map on `ℂⁿ` to the diagonal is a polynomial. -/ +theorem exists_mvPolynomial_eval_eq_multilinear_diagonal {k : ℕ} + (m : ContinuousMultilinearMap ℂ (fun _ : Fin k => (Fin n → ℂ)) ℂ) : + ∃ P : MvPolynomial (Fin n) ℂ, ∀ z, MvPolynomial.eval z P = m (fun _ => z) := by + refine ⟨∑ r : Fin k → Fin n, MvPolynomial.C (m fun j => Pi.single (r j) (1 : ℂ)) * + ∏ j, MvPolynomial.X (r j), fun z => ?_⟩ + have hz : (fun _ : Fin k => z) = fun _ => ∑ i : Fin n, z i • Pi.single i (1 : ℂ) := by + funext _ j + simp [Finset.sum_apply, Pi.single_apply] + rw [hz, ContinuousMultilinearMap.map_sum] + simp only [map_sum, map_mul, MvPolynomial.eval_C, map_prod, MvPolynomial.eval_X] + refine Finset.sum_congr rfl fun r _ => ?_ + rw [ContinuousMultilinearMap.map_smul_univ, smul_eq_mul, mul_comm] + +/-- Homogeneous terms of power series on `ℂⁿ` are polynomials. -/ +theorem exists_mvPolynomial_eval_eq_homogeneousTerm + (p : FormalMultilinearSeries ℂ (Fin n → ℂ) ℂ) (k : ℕ) : + ∃ P : MvPolynomial (Fin n) ℂ, ∀ z, MvPolynomial.eval z P = homogeneousTerm p k z := by + obtain ⟨P, hP⟩ := exists_mvPolynomial_eval_eq_multilinear_diagonal (p k) + exact ⟨P, fun z => by rw [hP, homogeneousTerm_apply]⟩ + +/-- **Circular connected open sets containing the origin are Runge domains**: holomorphic +functions are locally uniform sums of their homogeneous expansions, whose terms are +polynomials. -/ +theorem IsCircular.isRungeDomain {U : Set (Fin n → ℂ)} (ho : IsOpen U) (hc : IsPreconnected U) + (hrot : IsCircular U) (hzero : (0 : Fin n → ℂ) ∈ U) : IsRungeDomain U := by + intro f hf K hK hKU ε hε + obtain ⟨p, hp⟩ := hf 0 hzero + have hsum := + (IsCircular.hasSumLocallyUniformlyOn_homogeneousTerm_balancedHull ho hc hrot hzero hf hp).1 + rw [hasSumLocallyUniformlyOn_iff_tendstoLocallyUniformlyOn] at hsum + have hu := (tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK).mp (hsum.mono hKU) + rw [Metric.tendstoUniformlyOn_iff] at hu + obtain ⟨t, ht⟩ := (hu ε hε).exists + choose Q hQ using exists_mvPolynomial_eval_eq_homogeneousTerm p + refine ⟨∑ k ∈ t, Q k, fun z hz => ?_⟩ + have := ht z hz + rw [dist_eq_norm] at this + simpa only [map_sum, hQ] using this + +end Circular + +section Transport + +/-- The polynomial map with components `G i`. -/ +@[expose] def mvPolynomialMap (G : Fin n → MvPolynomial (Fin n) ℂ) (z : Fin n → ℂ) : Fin n → ℂ := + fun i => MvPolynomial.eval z (G i) + +/-- Polynomial maps are continuous. -/ +theorem continuous_mvPolynomialMap (G : Fin n → MvPolynomial (Fin n) ℂ) : + Continuous (mvPolynomialMap G) := + continuous_pi fun i => (G i).continuous_eval + +/-- Substitution of a polynomial map into a polynomial. -/ +theorem eval_bind₁_mvPolynomialMap (G : Fin n → MvPolynomial (Fin n) ℂ) + (P : MvPolynomial (Fin n) ℂ) (z : Fin n → ℂ) : + MvPolynomial.eval z (MvPolynomial.bind₁ G P) = MvPolynomial.eval (mvPolynomialMap G z) P := by + simp only [MvPolynomial.eval, MvPolynomial.eval₂Hom_bind₁] + rfl + +/-- **Transport of Runge domains.** If `U` is a Runge domain, `Φ` is holomorphic on `U` with +values in `U'`, and `Ψ` is a polynomial map from `U'` into `U` with `Φ ∘ Ψ = id` on `U'`, then +`U'` is a Runge domain. -/ +theorem IsRungeDomain.transport {U U' : Set (Fin n → ℂ)} (hU : IsRungeDomain U) + {Φ : (Fin n → ℂ) → (Fin n → ℂ)} (hΦ : AnalyticOnNhd ℂ Φ U) (hΦU : MapsTo Φ U U') + (G : Fin n → MvPolynomial (Fin n) ℂ) (hGU : MapsTo (mvPolynomialMap G) U' U) + (hinv : ∀ z ∈ U', Φ (mvPolynomialMap G z) = z) : IsRungeDomain U' := by + intro f hf K hK hKU ε hε + have hfΦ : AnalyticOnNhd ℂ (f ∘ Φ) U := hf.comp hΦ hΦU + have hK' : IsCompact (mvPolynomialMap G '' K) := hK.image (continuous_mvPolynomialMap G) + obtain ⟨P, hP⟩ := hU (f ∘ Φ) hfΦ _ hK' (image_subset_iff.mpr fun z hz => hGU (hKU hz)) ε hε + refine ⟨MvPolynomial.bind₁ G P, fun z hz => ?_⟩ + have := hP (mvPolynomialMap G z) (mem_image_of_mem _ hz) + rw [eval_bind₁_mvPolynomialMap] + simpa [comp_apply, hinv z (hKU hz)] using this + +/-- Runge domains are transported by polynomial automorphisms with polynomial inverses. -/ +theorem IsRungeDomain.image_mvPolynomialMap {U : Set (Fin n → ℂ)} (hU : IsRungeDomain U) + (F G : Fin n → MvPolynomial (Fin n) ℂ) + (hFG : ∀ z, mvPolynomialMap F (mvPolynomialMap G z) = z) + (hGF : ∀ z, mvPolynomialMap G (mvPolynomialMap F z) = z) : + IsRungeDomain (mvPolynomialMap F '' U) := by + refine hU.transport (Φ := mvPolynomialMap F) ?_ (mapsTo_image _ _) G ?_ fun z _ => hFG z + · exact fun z _ => by + apply analyticAt_pi_iff.mpr + intro i + exact AnalyticOnNhd.eval_mvPolynomial (F i) z (mem_univ z) + · rintro _ ⟨z, hz, rfl⟩ + rw [hGF] + exact hz + +/-- Translates of Runge domains are Runge domains. -/ +theorem IsRungeDomain.translate {U : Set (Fin n → ℂ)} (hU : IsRungeDomain U) (a : Fin n → ℂ) : + IsRungeDomain ((fun z => z + a) '' U) := by + have hF : (fun z : Fin n → ℂ => z + a) = + mvPolynomialMap (fun i => MvPolynomial.X i + MvPolynomial.C (a i)) := by + funext z i + simp [mvPolynomialMap] + rw [hF] + refine hU.image_mvPolynomialMap _ (fun i => MvPolynomial.X i - MvPolynomial.C (a i)) ?_ ?_ <;> + · intro z + funext i + simp [mvPolynomialMap] + +end Transport + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic.lean new file mode 100644 index 0000000000..3dff7cb10c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic.lean @@ -0,0 +1,274 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Baire +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.FiberExtension + +/-! +# Separate analyticity + +Hartogs' theorem asserts joint analyticity from analyticity of all coordinate slices, without +continuity or local boundedness assumptions. The versions with those extra hypotheses are proved +in `Osgood` and `LocallyBounded`. + +The proof is by induction on the number of coordinates. One coordinate is split off as a fiber +variable. Baire's theorem and the locally bounded Osgood theorem give joint analyticity on a +thin cylinder whose fiber disc is close to the given point. Hartogs' fiber extension lemma, +which rests on Hartogs' growth lemma for roots of the fiber Taylor coefficients, then gives a +local bound at the given point. The locally bounded Osgood theorem completes the induction step. + +References: [Boas][Boas2013] (2013), Section 2.7, Theorem 6; +[Hörmander][Hormander1973] (1973), Theorem 2.2.8; +[Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Theorem 1.5.1. + +## Main definitions + +* `optionSplit`: Splitting off the `none` coordinate of a finite coordinate space as the fiber + variable. + +## Main results + +* `analyticOnNhd_of_separately_analytic`: **Hartogs' separate-holomorphy theorem.** On an open + finite complex coordinate domain, analyticity of every coordinate slice implies joint analyticity, + with no continuity or local boundedness hypothesis. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Function Metric Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +section Split + +variable (κ : Type*) [Fintype κ] [DecidableEq κ] + +/-- Splitting off the `none` coordinate of a finite coordinate space as the fiber variable. The +remaining coordinates form the base. -/ +@[expose] def optionSplit : (Option κ → ℂ) ≃L[ℂ] (κ → ℂ) × ℂ := + ((LinearEquiv.piOptionEquivProd ℂ (M := fun _ : Option κ => ℂ)).trans + (LinearEquiv.prodComm ℂ ℂ (κ → ℂ))).toContinuousLinearEquiv + +variable {κ} + +omit [DecidableEq κ] in +/-- The splitting map records the base coordinates and the fiber coordinate. -/ +theorem optionSplit_apply (z : Option κ → ℂ) : + optionSplit κ z = (fun i => z (some i), z none) := rfl + +omit [DecidableEq κ] in +/-- The inverse splitting map reassembles a point from base and fiber coordinates. -/ +theorem optionSplit_symm_apply (z' : κ → ℂ) (w : ℂ) : + (optionSplit κ).symm (z', w) = fun o => o.elim w z' := by + rw [ContinuousLinearEquiv.symm_apply_eq] + rfl + +/-- Updating the missing coordinate of a split point changes only the fiber. -/ +theorem optionSplit_symm_update_none (z' : κ → ℂ) (w v : ℂ) : + update ((optionSplit κ).symm (z', w)) none v = (optionSplit κ).symm (z', v) := by + rw [optionSplit_symm_apply, optionSplit_symm_apply] + funext o + cases o <;> simp [update] + +/-- Updating a present coordinate of a split point changes only the corresponding base +coordinate. -/ +theorem optionSplit_symm_update_some (z' : κ → ℂ) (w v : ℂ) (i : κ) : + update ((optionSplit κ).symm (z', w)) (some i) v = + (optionSplit κ).symm (update z' i v, w) := by + rw [optionSplit_symm_apply, optionSplit_symm_apply] + funext o + cases o with + | none => simp + | some j => by_cases hji : j = i <;> simp [hji, update] + +omit [DecidableEq κ] in +/-- Closed balls in the product coordinates are products of closed balls. -/ +theorem optionSplit_symm_mem_closedBall {c : Option κ → ℂ} {R : ℝ} (hR : 0 ≤ R) + (z' : κ → ℂ) (w : ℂ) : + (optionSplit κ).symm (z', w) ∈ closedBall c R ↔ + z' ∈ closedBall ((optionSplit κ) c).1 R ∧ w ∈ closedBall ((optionSplit κ) c).2 R := by + have hnone : (optionSplit κ).symm (z', w) none = w := by rw [optionSplit_symm_apply]; rfl + have hsome (i : κ) : (optionSplit κ).symm (z', w) (some i) = z' i := by + rw [optionSplit_symm_apply]; rfl + rw [mem_closedBall, dist_pi_le_iff hR, Option.forall, mem_closedBall, mem_closedBall, + dist_pi_le_iff hR, hnone] + simp only [hsome, optionSplit_apply] + exact and_comm + +end Split + +/-- The induction step of Hartogs' theorem: one further coordinate. The hypothesis is Hartogs' +theorem for the coordinate type `κ`. -/ +theorem analyticOnNhd_of_separately_analytic_option {κ : Type*} [Fintype κ] [DecidableEq κ] + (ih : ∀ {U : Set (κ → ℂ)} {g : (κ → ℂ) → F}, IsOpen U → + (∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => g (update z i w)) (z i)) → AnalyticOnNhd ℂ g U) + {U : Set (Option κ → ℂ)} {f : (Option κ → ℂ) → F} (hU : IsOpen U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + AnalyticOnNhd ℂ f U := by + set L := optionSplit κ with hL + -- analyticity of the base slices, by the induction hypothesis + have hslice_base (w : ℂ) : + AnalyticOnNhd ℂ (fun z' => f (L.symm (z', w))) {z' | L.symm (z', w) ∈ U} := by + apply ih (hU.preimage (by fun_prop)) + intro z' hz' i + have h := hf _ hz' (some i) + dsimp only at h + have : L.symm (z', w) (some i) = z' i := by rw [optionSplit_symm_apply]; rfl + rw [this] at h + convert h using 2 + rw [optionSplit_symm_update_some] + -- analyticity of the fiber slices + have hslice_fiber (z' : κ → ℂ) : + AnalyticOnNhd ℂ (fun w => f (L.symm (z', w))) {w | L.symm (z', w) ∈ U} := by + intro w hw + have h := hf _ hw none + have : L.symm (z', w) none = w := by rw [optionSplit_symm_apply]; rfl + rw [this] at h + convert h using 2 + rw [optionSplit_symm_update_none] + -- the decidability instance of the coordinate type is adjusted by `convert` + refine analyticOnNhd_of_separately_analytic_locally_bounded hU + (fun z hz i => by convert hf z hz i) ?_ + intro c hc + obtain ⟨R, hR, hRU⟩ := nhds_basis_closedBall.mem_iff.mp (hU.mem_nhds hc) + set z₀ : κ → ℂ := (L c).1 with hz₀ + set w₀ : ℂ := (L c).2 with hw₀ + have hmem (z' : κ → ℂ) (w : ℂ) : + L.symm (z', w) ∈ closedBall c R ↔ z' ∈ closedBall z₀ R ∧ w ∈ closedBall w₀ R := by + simpa [hz₀, hw₀] using optionSplit_symm_mem_closedBall hR.le z' w + -- Baire: a bounded cylinder over the whole closed base ball + have hR2 : 0 < R / 2 := by positivity + obtain ⟨W, hWo, hWne, hWsub, M₁, hM₁⟩ := exists_open_bounded_cylinder_of_separately_continuous + (X := ℂ) (Y := κ → ℂ) (f := fun w z' => f (L.symm (z', w))) isOpen_ball + (nonempty_ball.mpr hR2) (isCompact_closedBall z₀ R) + (fun z' hz' => (hslice_fiber z').continuousOn.mono fun w hw => hRU ((hmem z' w).mpr + ⟨hz', ball_subset_closedBall (ball_subset_ball (half_le_self hR.le) hw)⟩)) + (fun w hw => (hslice_base w).continuousOn.mono fun z' hz' => hRU ((hmem z' w).mpr + ⟨hz', ball_subset_closedBall (ball_subset_ball (half_le_self hR.le) hw)⟩)) + obtain ⟨b, hb⟩ := hWne + obtain ⟨ε₁, hε₁, hbW⟩ := nhds_basis_closedBall.mem_iff.mp (hWo.mem_nhds hb) + have hbw₀ : dist b w₀ < R / 2 := mem_ball.mp (hWsub hb) + -- Osgood: joint analyticity on the bounded cylinder + set Ω := L ⁻¹' (ball z₀ R ×ˢ W) with hΩ + have hΩo : IsOpen Ω := (isOpen_ball.prod hWo).preimage L.continuous + have hΩU : Ω ⊆ U := by + intro z hz + have := (hmem (L z).1 (L z).2).mpr ⟨ball_subset_closedBall hz.1, + ball_subset_closedBall (ball_subset_ball (half_le_self hR.le) (hWsub hz.2))⟩ + rw [Prod.mk.eta, L.symm_apply_apply] at this + exact hRU this + have hfΩ : AnalyticOnNhd ℂ f Ω := by + refine analyticOnNhd_of_separately_analytic_locally_bounded hΩo + (fun z hz i => by convert hf z (hΩU hz) i) ?_ + intro z hz + refine ⟨M₁, Filter.mem_of_superset (hΩo.mem_nhds hz) fun y hy => ?_⟩ + have := hM₁ (L y).2 hy.2 (L y).1 (ball_subset_closedBall hy.1) + rwa [Prod.mk.eta, L.symm_apply_apply] at this + -- Hartogs' fiber extension lemma in product coordinates + have hg1 : AnalyticOnNhd ℂ (f ∘ L.symm) (ball z₀ R ×ˢ ball b ε₁) := by + intro q hq + have hq' : L.symm q ∈ Ω := by + change L (L.symm q) ∈ ball z₀ R ×ˢ W + rw [L.apply_symm_apply] + exact ⟨hq.1, hbW (ball_subset_closedBall hq.2)⟩ + exact (hfΩ _ hq').comp_of_eq (L.symm.analyticAt q) rfl + have hg2 : ∀ z' ∈ ball z₀ R, + AnalyticOnNhd ℂ (fun w => (f ∘ L.symm) (z', w)) (ball b (R - dist b w₀)) := by + intro z' hz' + apply (hslice_fiber z').mono + intro w hw + apply hRU + rw [hmem] + refine ⟨ball_subset_closedBall hz', ?_⟩ + rw [mem_closedBall] + have := mem_ball.mp hw + calc dist w w₀ ≤ dist w b + dist b w₀ := dist_triangle _ _ _ + _ ≤ R := by linarith + have hw₀ : w₀ ∈ ball b (R - dist b w₀) := by + rw [mem_ball, dist_comm] + linarith + obtain ⟨M, hM⟩ := exists_eventually_norm_le_of_fiber_analytic isOpen_ball hε₁ hg1 hg2 + (mem_ball_self hR) hw₀ + refine ⟨M, ?_⟩ + have := (L.continuous.tendsto c).eventually hM + simpa only [Function.comp_def, L.symm_apply_apply] using this + +omit [CompleteSpace F] in +/-- Hartogs' theorem transports along a bijection of coordinate types. -/ +theorem analyticOnNhd_of_separately_analytic_of_equiv {α β : Type*} + [Fintype α] [DecidableEq α] [Fintype β] [DecidableEq β] (e : α ≃ β) + (hα : ∀ {U : Set (α → ℂ)} {g : (α → ℂ) → F}, IsOpen U → + (∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => g (update z i w)) (z i)) → AnalyticOnNhd ℂ g U) + {U : Set (β → ℂ)} {f : (β → ℂ) → F} (hU : IsOpen U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + AnalyticOnNhd ℂ f U := by + let L : (α → ℂ) ≃L[ℂ] (β → ℂ) := ContinuousLinearEquiv.piCongrLeft ℂ (fun _ : β => ℂ) e + have hL_apply (z : α → ℂ) (j : α) : L z (e j) = z j := + Equiv.piCongrLeft_apply_apply (fun _ : β => ℂ) e z j + have hL_update (z : α → ℂ) (j : α) (w : ℂ) : L (update z j w) = update (L z) (e j) w := by + funext i + obtain ⟨k, rfl⟩ := e.surjective i + by_cases hkj : k = j + · subst k + simp [hL_apply] + · have hek : e k ≠ e j := fun he => hkj (e.injective he) + simp [hkj, hek, hL_apply] + have hg : AnalyticOnNhd ℂ (f ∘ L) (L ⁻¹' U) := by + apply hα (hU.preimage L.continuous) + intro z hz j + have h := hf (L z) hz (e j) + rw [← hL_apply z j] + convert h using 2 + simp only [Function.comp_apply, hL_update] + intro z hz + have hzV : L.symm z ∈ L ⁻¹' U := by + change L (L.symm z) ∈ U + simpa + have := (hg _ hzV).comp_of_eq (L.symm.analyticAt z) rfl + simpa only [Function.comp_def, L.apply_symm_apply] using this + +/-- **Hartogs' separate-holomorphy theorem.** On an open finite complex coordinate domain, +analyticity of every coordinate slice implies joint analyticity, with no continuity or local +boundedness hypothesis. Empty and singleton coordinate types are included. -/ +theorem analyticOnNhd_of_separately_analytic + {ι : Type*} [Fintype ι] [DecidableEq ι] {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hU : IsOpen U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + AnalyticOnNhd ℂ f U := by + suffices H : ∀ [DecidableEq ι] {U : Set (ι → ℂ)} {f : (ι → ℂ) → F}, IsOpen U → + (∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) → AnalyticOnNhd ℂ f U from + H hU hf + refine Fintype.induction_empty_option + (P := fun ι _ => ∀ [DecidableEq ι] {U : Set (ι → ℂ)} {f : (ι → ℂ) → F}, IsOpen U → + (∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) → AnalyticOnNhd ℂ f U) + ?_ ?_ ?_ ι + · intro α β _ e hα _ U f hU hf + classical + let _ : Fintype α := Fintype.ofEquiv β e.symm + exact analyticOnNhd_of_separately_analytic_of_equiv e (fun hU hf => hα hU hf) hU hf + · intro _ U f hU hf + exact analyticOnNhd_of_separately_analytic_locally_bounded hU hf fun c _ => + ⟨‖f c‖, .of_forall fun z => by rw [Subsingleton.elim z c]⟩ + · intro α _ ih _ U f hU hf + classical + exact analyticOnNhd_of_separately_analytic_option (fun hU hf => ih hU hf) hU + (fun z hz i => by convert hf z hz i) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/Baire.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/Baire.lean new file mode 100644 index 0000000000..385cd44c40 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/Baire.lean @@ -0,0 +1,156 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Baire.Lemmas +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyBounded + +/-! +# The Baire step in Hartogs' separate-analyticity theorem + +A separately continuous function on a product with a compact second factor is uniformly bounded +on some open cylinder. For separately analytic functions of two complex variables, locally +bounded Osgood then gives joint analyticity on that cylinder, retaining the entire interior of +the second factor. + +This is the initial cylinder in the proof of Hartogs' theorem in [Boas][Boas2013] (2013), +Section 2.7, Theorem 8. No joint continuity or boundedness is assumed. + +## Main results + +`exists_open_bounded_cylinder_of_separately_continuous` produces an open cylinder of uniform +boundedness. `exists_analytic_cylinder_of_separately_analytic` is joint analyticity on that +cylinder for separately analytic functions of two variables. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +-/ + +public section + +open Filter Function Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +/-- Baire's theorem gives a uniform bound on an open cylinder from separate continuity and +compactness of the second factor. The compact set may be empty. -/ +theorem exists_open_bounded_cylinder_of_separately_continuous + {X Y F : Type*} [TopologicalSpace X] [BaireSpace X] [TopologicalSpace Y] + [NormedAddCommGroup F] {U : Set X} {K : Set Y} {f : X → Y → F} + (hU : IsOpen U) (hne : U.Nonempty) (hK : IsCompact K) + (hx : ∀ y ∈ K, ContinuousOn (fun x => f x y) U) + (hy : ∀ x ∈ U, ContinuousOn (f x) K) : + ∃ V : Set X, IsOpen V ∧ V.Nonempty ∧ V ⊆ U ∧ + ∃ M : ℝ, ∀ x ∈ V, ∀ y ∈ K, ‖f x y‖ ≤ M := by + let : BaireSpace U := hU.baireSpace + let : Nonempty U := hne.to_subtype + let S : ℕ → Set U := fun n => {x | ∀ y ∈ K, ‖f x y‖ ≤ n} + have hclosed (n : ℕ) : IsClosed (S n) := by + simp only [S, ofPred_forall] + exact isClosed_iInter fun y => isClosed_iInter fun hy => + isClosed_le ((continuousOn_iff_continuous_domRestrict.mp (hx y hy)).norm) continuous_const + have hcover : ⋃ n, S n = univ := by + apply eq_univ_of_forall + intro x + obtain ⟨M, hM⟩ := hK.bddAbove_image (hy x x.property).norm + obtain ⟨n, hn⟩ := exists_nat_ge M + exact mem_iUnion.mpr ⟨n, fun y hy => (hM (mem_image_of_mem _ hy)).trans hn⟩ + obtain ⟨n, hn⟩ := nonempty_interior_of_iUnion_of_closed hclosed hcover + refine ⟨Subtype.val '' interior (S n), + hU.isOpenMap_subtype_val _ isOpen_interior, hn.image _, ?_, n, ?_⟩ + · rintro _ ⟨x, _, rfl⟩ + exact x.property + · rintro _ ⟨x, hx, rfl⟩ y hy + exact interior_subset hx y hy + +/-- A separately analytic function on a two-variable cylinder is jointly analytic on a smaller +nonempty base times the entire open fiber disc. Only the base shrinks. -/ +theorem exists_analytic_cylinder_of_separately_analytic + {U : Set ℂ} {c : ℂ} {R : ℝ} {F : Type*} + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {f : (Fin 2 → ℂ) → F} (hU : IsOpen U) (hne : U.Nonempty) + (hf : ∀ z : Fin 2 → ℂ, z 0 ∈ U → z 1 ∈ closedBall c R → + ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + ∃ V : Set ℂ, IsOpen V ∧ V.Nonempty ∧ V ⊆ U ∧ + AnalyticOnNhd ℂ f {z | z 0 ∈ V ∧ z 1 ∈ ball c R} := by + have hx (y : ℂ) (hy : y ∈ closedBall c R) : + ContinuousOn (fun x => f ![x, y]) U := by + intro x hx + have h := (hf ![x, y] hx hy 0).continuousAt + simpa [show (fun w => update ![x, y] 0 w) = (fun w => ![w, y]) by + funext w i; fin_cases i <;> simp] using h.continuousWithinAt (s := U) + have hy (x : ℂ) (hx : x ∈ U) : + ContinuousOn (fun y => f ![x, y]) (closedBall c R) := by + intro y hy + have h := (hf ![x, y] hx hy 1).continuousAt + simpa [show (fun w => update ![x, y] 1 w) = (fun w => ![x, w]) by + funext w i; fin_cases i <;> simp] using + h.continuousWithinAt (s := closedBall c R) + obtain ⟨V, hV, hneV, hVU, M, hM⟩ := + exists_open_bounded_cylinder_of_separately_continuous hU hne + (isCompact_closedBall c R) hx hy + have hopen : IsOpen {z : Fin 2 → ℂ | z 0 ∈ V ∧ z 1 ∈ ball c R} := by + change IsOpen ((fun z : Fin 2 → ℂ => z 0) ⁻¹' V ∩ + (fun z : Fin 2 → ℂ => z 1) ⁻¹' ball c R) + exact (hV.preimage (continuous_apply 0)).inter + (isOpen_ball.preimage (continuous_apply 1)) + refine ⟨V, hV, hneV, hVU, + analyticOnNhd_of_separately_analytic_locally_bounded hopen + (fun z hz i => by + simpa +unfoldPartialApp only [update] using + hf z (hVU hz.1) (ball_subset_closedBall hz.2) i) ?_⟩ + intro z hz + refine ⟨M, Filter.mem_of_superset (hopen.mem_nhds hz) ?_⟩ + intro w hw + change ‖f w‖ ≤ M + have he : ![w 0, w 1] = w := by ext i; fin_cases i <;> rfl + simpa only [he] using hM (w 0) hw.1 (w 1) (ball_subset_closedBall hw.2) + +/-- A separately analytic function of two complex variables has a point of joint analyticity in +every nonempty open part of its domain. -/ +theorem exists_analyticAt_of_separately_analytic_fin_two + {U : Set (Fin 2 → ℂ)} {F : Type*} + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {f : (Fin 2 → ℂ) → F} (hU : IsOpen U) (hne : U.Nonempty) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + ∃ z ∈ U, AnalyticAt ℂ f z := by + obtain ⟨a, ha⟩ := hne + obtain ⟨R, hR, hRU⟩ := nhds_basis_closedBall.mem_iff.mp (hU.mem_nhds ha) + have hprod {z : Fin 2 → ℂ} (h0 : z 0 ∈ ball (a 0) R) + (h1 : z 1 ∈ closedBall (a 1) R) : z ∈ U := by + apply hRU + rw [mem_closedBall, dist_pi_le_iff hR.le] + intro i + fin_cases i + · exact (mem_ball.mp h0).le + · exact h1 + obtain ⟨V, hV, ⟨x, hx⟩, hVB, hfa⟩ := exists_analytic_cylinder_of_separately_analytic + isOpen_ball (nonempty_ball.mpr hR) (fun z h0 h1 => hf z (hprod h0 h1)) + have hz : (![x, a 1] : Fin 2 → ℂ) ∈ {z | z 0 ∈ V ∧ z 1 ∈ ball (a 1) R} := + ⟨hx, mem_ball_self hR⟩ + exact ⟨![x, a 1], hprod (hVB hx) (mem_closedBall_self hR.le), hfa _ hz⟩ + +/-- The locus of joint analyticity of a separately analytic two-variable function is a dense open +subset of its open domain. -/ +theorem dense_isOpen_analyticAt_of_separately_analytic_fin_two + {U : Set (Fin 2 → ℂ)} {F : Type*} + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {f : (Fin 2 → ℂ) → F} (hU : IsOpen U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + Dense {z : U | AnalyticAt ℂ f z} ∧ IsOpen {z : U | AnalyticAt ℂ f z} := by + refine ⟨dense_iff_inter_open.mpr ?_, + (isOpen_analyticAt ℂ f).preimage continuous_subtype_val⟩ + intro V hV hne + have hVU : Subtype.val '' V ⊆ U := by rintro _ ⟨z, _, rfl⟩; exact z.property + obtain ⟨z, ⟨w, hw, rfl⟩, ha⟩ := exists_analyticAt_of_separately_analytic_fin_two + (hU.isOpenMap_subtype_val V hV) (hne.image _) (fun z hz => hf z (hVU hz)) + exact ⟨w, hw, ha⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/FiberExtension.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/FiberExtension.lean new file mode 100644 index 0000000000..122e5f9199 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/FiberExtension.lean @@ -0,0 +1,308 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.CauchyIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.Cauchy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.HartogsLemma + +/-! +# Hartogs' fiber extension lemma + +A function of a base variable and one fiber variable, jointly analytic on a thin cylinder and +analytic on a larger disc in each fiber, is locally bounded on the larger cylinder. The fiber +Taylor coefficients are analytic in the base variable by Cauchy's formula on a small circle. +Cauchy's estimates on the large discs give a pointwise eventual bound on their roots, and +Hartogs' lemma makes this bound uniform near each base point, so the fiber Taylor series is +dominated by a geometric series near every point of the larger cylinder. + +This is the continuation step in the proof of Hartogs' separate-analyticity theorem. Reference: +[Hörmander][Hormander1973] (1973), proof of Theorem 2.2.8; [Boas][Boas2013] (2013), Section 2.7, +proof of Theorem 6. + +## Main results + +`fiberCoeff` is the Taylor coefficient of a fiber slice. `analyticOnNhd_fiberCoeff` is its +holomorphy in the base. `exists_eventually_norm_le_of_fiber_analytic` is local boundedness on +the larger cylinder. `exists_hartogs_fiber_radii` chooses the intermediate radii for the +geometric majorant. + +## References + +* [H. P. Boas, *Lecture Notes on Several Complex Variables*][Boas2013] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +-/ + +public noncomputable section + +open Complex Filter Function MeasureTheory Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +omit [CompleteSpace F] in +/-- Radii for the geometric majorant in Hartogs' fiber extension: an intermediate circle `σ < ρ` and +a contraction ratio `q < 1`. -/ +theorem exists_hartogs_fiber_radii {b w₁ : ℂ} {R : ℝ} (hdist : dist w₁ b < R) : + ∃ σ ρ ε q : ℝ, dist w₁ b < σ ∧ σ < ρ ∧ ρ < R ∧ 0 < σ ∧ 0 < ρ ∧ 0 < ε ∧ + 0 < q ∧ q < 1 ∧ q = σ * (ρ⁻¹ + ε) := by + obtain ⟨ρ, hρ₁, hρR⟩ := exists_between hdist + have hρ : 0 < ρ := dist_nonneg.trans_lt hρ₁ + set σ : ℝ := (dist w₁ b + ρ) / 2 + have hσ₁ : dist w₁ b < σ := by dsimp [σ]; linarith + have hσρ : σ < ρ := by dsimp [σ]; linarith + have hσ0 : 0 < σ := by + dsimp [σ] + nlinarith [dist_nonneg (x := w₁) (y := b)] + set ε : ℝ := (1 - σ / ρ) / (2 * σ) + have hσρ' : σ / ρ < 1 := (div_lt_one hρ).mpr hσρ + have hε0 : 0 < ε := div_pos (by linarith) (by positivity) + set q : ℝ := σ * (ρ⁻¹ + ε) + have hq_eq : q = (1 + σ / ρ) / 2 := by + dsimp [q, ε]; field_simp; ring + have hq1 : q < 1 := by rw [hq_eq]; linarith + have hq0 : 0 < q := by rw [hq_eq]; positivity + exact ⟨σ, ρ, ε, q, hσ₁, hσρ, hρR, hσ0, hρ, hε0, hq0, hq1, rfl⟩ + +omit [CompleteSpace F] in +/-- Cauchy's estimate for the scalar values of the Cauchy power series coefficients, from a bound on +the closed disc. -/ +theorem norm_cauchyPowerSeries_apply_one_le {g : ℂ → F} {b : ℂ} {ρ M : ℝ} (hρ : 0 < ρ) + (hM : ∀ w ∈ closedBall b ρ, ‖g w‖ ≤ M) (k : ℕ) : + ‖cauchyPowerSeries g b ρ k (fun _ => 1)‖ ≤ M * ρ⁻¹ ^ k := by + have hint : ∫ θ in (0:ℝ)..2 * π, ‖g (circleMap b ρ θ)‖ ≤ M * (2 * π) := by + have := intervalIntegral.norm_integral_le_of_norm_le_const (a := 0) (b := 2 * π) + (f := fun θ => ‖g (circleMap b ρ θ)‖) (C := M) (fun θ _ => by + rw [Real.norm_eq_abs, abs_of_nonneg (norm_nonneg _)] + exact hM _ (circleMap_mem_closedBall b hρ.le θ)) + rw [sub_zero, abs_of_pos Real.two_pi_pos, Real.norm_eq_abs] at this + exact (le_abs_self _).trans this + calc ‖cauchyPowerSeries g b ρ k (fun _ => 1)‖ + ≤ ‖cauchyPowerSeries g b ρ k‖ * ∏ _i : Fin k, ‖(1 : ℂ)‖ := + ContinuousMultilinearMap.le_opNorm _ _ + _ = ‖cauchyPowerSeries g b ρ k‖ := by simp + _ ≤ ((2 * π)⁻¹ * ∫ θ in (0:ℝ)..2 * π, ‖g (circleMap b ρ θ)‖) * |ρ|⁻¹ ^ k := + norm_cauchyPowerSeries_le g b ρ k + _ ≤ M * ρ⁻¹ ^ k := by + rw [abs_of_pos hρ] + apply mul_le_mul_of_nonneg_right _ (by positivity) + calc (2 * π)⁻¹ * ∫ θ in (0:ℝ)..2 * π, ‖g (circleMap b ρ θ)‖ + ≤ (2 * π)⁻¹ * (M * (2 * π)) := by gcongr + _ = M := by field_simp + +/-- The Cauchy power series of a function analytic on a closed disc converges on the open disc, with +the radius given as an extended real number. -/ +theorem hasFPowerSeriesOnBall_cauchyPowerSeries_of_analyticOnNhd {g : ℂ → F} {b : ℂ} + {r : ℝ} (hr : 0 < r) (hg : AnalyticOnNhd ℂ g (closedBall b r)) : + HasFPowerSeriesOnBall g (cauchyPowerSeries g b r) b (ENNReal.ofReal r) := by + have := hg.differentiableOn.hasFPowerSeriesOnBall (R := ⟨r, hr.le⟩) hr + rwa [ENNReal.ofReal_eq_coe_nnreal hr.le] + +/-- Roots of a fixed positive constant tend to one. -/ +theorem tendsto_rpow_inv_natCast_succ {M : ℝ} (hM : 0 < M) : + Tendsto (fun n : ℕ => M ^ ((n + 1 : ℕ) : ℝ)⁻¹) atTop (𝓝 1) := by + have h : Tendsto (fun n : ℕ => Real.log M * ((n + 1 : ℕ) : ℝ)⁻¹) atTop (𝓝 0) := by + have := (tendsto_const_div_atTop_nhds_zero_nat (Real.log M)).comp (tendsto_add_atTop_nat 1) + simpa [Function.comp_def, div_eq_mul_inv] using this + simpa [Function.comp_def, Real.rpow_def_of_pos hM] using + Real.tendsto_exp_nhds_zero_nhds_one.comp h + +/-- A root of an exponential-type bound is bounded by a root of the constant times the reciprocal +radius. -/ +theorem rpow_inv_succ_le_of_le_mul_pow {x M ρ : ℝ} (hx : 0 ≤ x) (hM : 0 ≤ M) (hρ : 0 < ρ) + (n : ℕ) (h : x ≤ M * ρ⁻¹ ^ (n + 1)) : + x ^ ((n + 1 : ℕ) : ℝ)⁻¹ ≤ M ^ ((n + 1 : ℕ) : ℝ)⁻¹ * ρ⁻¹ := by + calc x ^ ((n + 1 : ℕ) : ℝ)⁻¹ ≤ (M * ρ⁻¹ ^ (n + 1)) ^ ((n + 1 : ℕ) : ℝ)⁻¹ := + Real.rpow_le_rpow hx h (by positivity) + _ = M ^ ((n + 1 : ℕ) : ℝ)⁻¹ * ρ⁻¹ := by + rw [Real.mul_rpow hM (by positivity), + Real.pow_rpow_inv_natCast (inv_nonneg.mpr hρ.le) n.succ_ne_zero] + +/-- A sequence with a uniform exponential bound and an eventual geometric bound has a single +geometric majorant. -/ +theorem le_geometric_of_bounds {a : ℕ → ℝ} {M s q : ℝ} {N : ℕ} (hM : 0 ≤ M) (hs : 0 ≤ s) + (hq0 : 0 < q) (hq1 : q ≤ 1) (h1 : ∀ k, a k ≤ M * s ^ k) + (h2 : ∀ k, N + 1 ≤ k → a k ≤ q ^ k) (k : ℕ) : + a k ≤ max 1 (M * max 1 s ^ N / q ^ N) * q ^ k := by + have hqk : 0 ≤ q ^ k := pow_nonneg hq0.le k + by_cases hk : N + 1 ≤ k + · exact (h2 k hk).trans (le_mul_of_one_le_left hqk (le_max_left _ _)) + · have hkN : k ≤ N := by omega + have hqN : q ^ N ≤ q ^ k := pow_le_pow_of_le_one hq0.le hq1 hkN + have hC₀ : M * s ^ k ≤ M * max 1 s ^ N := + mul_le_mul_of_nonneg_left ((pow_le_pow_left₀ hs (le_max_right 1 s) k).trans + (pow_le_pow_right₀ (le_max_left 1 s) hkN)) hM + have hqN0 : 0 < q ^ N := pow_pos hq0 N + calc a k ≤ M * max 1 s ^ N := (h1 k).trans hC₀ + _ = M * max 1 s ^ N / q ^ N * q ^ N := by field_simp + _ ≤ M * max 1 s ^ N / q ^ N * q ^ k := + mul_le_mul_of_nonneg_left hqN (div_nonneg (by positivity) hqN0.le) + _ ≤ max 1 (M * max 1 s ^ N / q ^ N) * q ^ k := + mul_le_mul_of_nonneg_right (le_max_right _ _) hqk + +/-- Fiber Taylor coefficients of a function of a base variable and a fiber variable, computed by +Cauchy's formula on the circle of radius `r` about `b` in the fiber. -/ +private def fiberCoeff (f : E × ℂ → F) (b : ℂ) (r : ℝ) (k : ℕ) (z : E) : F := + cauchyPowerSeries (fun w => f (z, w)) b r k (fun _ => 1) + +/-- The fiber coefficients are analytic in the base variable wherever the function is jointly +analytic on a cylinder containing the integration circle. -/ +private theorem analyticOnNhd_fiberCoeff {D : Set E} (hD : IsOpen D) {b : ℂ} {r ε₁ : ℝ} + (hr : 0 < r) (hrε : r < ε₁) {f : E × ℂ → F} + (hf : AnalyticOnNhd ℂ f (D ×ˢ ball b ε₁)) (k : ℕ) : + AnalyticOnNhd ℂ (fiberCoeff f b r k) D := by + have hH : AnalyticOnNhd ℂ (fun q : E × ℂ => (1 / (q.2 - b)) ^ k • (q.2 - b)⁻¹ • f q) + {q | q ∈ D ×ˢ ball b ε₁ ∧ q.2 ≠ b} := by + intro q hq + have hsub : AnalyticAt ℂ (fun q : E × ℂ => q.2 - b) q := analyticAt_snd.sub analyticAt_const + have hne : q.2 - b ≠ 0 := sub_ne_zero.mpr hq.2 + exact ((analyticAt_const.div hsub hne).pow k).smul ((hsub.inv hne).smul (hf q hq.1)) + have h := analyticOnNhd_circleIntegral_kernel hD hH hr.le (c := b) (R := r) ?_ + · unfold fiberCoeff + simp_rw [cauchyPowerSeries_apply] + exact analyticOnNhd_const.smul h + · intro z hz t ht + have htb : dist t b = r := mem_sphere.mp ht + refine ⟨⟨hz, ?_⟩, ?_⟩ + · rw [mem_ball, htb]; exact hrε + · intro h + have h' : t = b := h + rw [h', dist_self] at htb + exact hr.ne htb + +omit [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] [CompleteSpace F] in +/-- A bound on a closed cylinder bounds all fiber coefficients over its base. -/ +private theorem norm_fiberCoeff_le {f : E × ℂ → F} {b : ℂ} {r M : ℝ} (hr : 0 < r) {z : E} + (hM : ∀ w ∈ closedBall b r, ‖f (z, w)‖ ≤ M) (k : ℕ) : + ‖fiberCoeff f b r k z‖ ≤ M * r⁻¹ ^ k := + norm_cauchyPowerSeries_apply_one_le hr hM k + +omit [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] in +/-- Fiber coefficients are independent of the radius when the fiber function is analytic on both +closed discs. -/ +private theorem fiberCoeff_eq_of_radii {f : E × ℂ → F} {b : ℂ} {r ρ : ℝ} (hr : 0 < r) (hρ : 0 < ρ) + {z : E} (hgr : AnalyticOnNhd ℂ (fun w => f (z, w)) (closedBall b r)) + (hgρ : AnalyticOnNhd ℂ (fun w => f (z, w)) (closedBall b ρ)) (k : ℕ) : + fiberCoeff f b r k z = cauchyPowerSeries (fun w => f (z, w)) b ρ k (fun _ => 1) := by + unfold fiberCoeff + rw [(hasFPowerSeriesOnBall_cauchyPowerSeries_of_analyticOnNhd hr + hgr).hasFPowerSeriesAt.eq_formalMultilinearSeries + (hasFPowerSeriesOnBall_cauchyPowerSeries_of_analyticOnNhd hρ hgρ).hasFPowerSeriesAt] + +variable [MeasureSpace E] [BorelSpace E] [(volume : Measure E).IsAddHaarMeasure] + +/-- **Hartogs' fiber extension lemma.** A function jointly analytic on a thin cylinder over +an open base, whose fiber slices are analytic on a larger disc, is locally bounded on the +larger cylinder. The fiber Taylor series is dominated by a geometric series near each point, +by Hartogs' lemma applied to the roots of the fiber coefficients. -/ +theorem exists_eventually_norm_le_of_fiber_analytic {D : Set E} (hD : IsOpen D) {b : ℂ} + {ε₁ R : ℝ} (hε₁ : 0 < ε₁) {f : E × ℂ → F} (hf : AnalyticOnNhd ℂ f (D ×ˢ ball b ε₁)) + (hfib : ∀ z ∈ D, AnalyticOnNhd ℂ (fun w => f (z, w)) (ball b R)) + {z₁ : E} (hz₁ : z₁ ∈ D) {w₁ : ℂ} (hw₁ : w₁ ∈ ball b R) : + ∃ M : ℝ, ∀ᶠ q in 𝓝 (z₁, w₁), ‖f q‖ ≤ M := by + have hdist : dist w₁ b < R := mem_ball.mp hw₁ + obtain ⟨σ, ρ, ε, q, hσ₁, hσρ, hρR, hσ0, hρ, hε0, hq0, hq1, hq⟩ := + exists_hartogs_fiber_radii hdist + obtain ⟨r₀, hr₀, hr₀D⟩ := nhds_basis_closedBall.mem_iff.mp (hD.mem_nhds hz₁) + set r : ℝ := min r₀ (ε₁ / 2) + have hr0 : 0 < r := lt_min hr₀ (by positivity) + have hrε : r < ε₁ := (min_le_right _ _).trans_lt (by linarith) + have hrD : closedBall z₁ r ⊆ D := + (closedBall_subset_closedBall (min_le_left _ _)).trans hr₀D + have hcyl : closedBall z₁ r ×ˢ closedBall b r ⊆ D ×ˢ ball b ε₁ := + prod_mono hrD (closedBall_subset_ball hrε) + obtain ⟨M₀, hM₀⟩ := ((isCompact_closedBall z₁ r).prod + (isCompact_closedBall b r)).exists_bound_of_continuousOn (hf.continuousOn.mono hcyl) + set M₁ : ℝ := max M₀ 1 + have hM₁1 : 1 ≤ M₁ := le_max_right _ _ + have hM₁0 : 0 < M₁ := by linarith + have hM₁' : ∀ z ∈ closedBall z₁ r, ∀ w ∈ closedBall b r, ‖f (z, w)‖ ≤ M₁ := + fun z hz w hw => (hM₀ (z, w) ⟨hz, hw⟩).trans (le_max_left _ _) + -- slice analyticity on the small and large closed discs + have hgr : ∀ z ∈ D, AnalyticOnNhd ℂ (fun w => f (z, w)) (closedBall b r) := by + intro z hz w hw + exact (hf (z, w) ⟨hz, closedBall_subset_ball hrε hw⟩).comp_of_eq + (analyticAt_const.prod analyticAt_id) rfl + have hgρ : ∀ z ∈ D, AnalyticOnNhd ℂ (fun w => f (z, w)) (closedBall b ρ) := + fun z hz => (hfib z hz).mono (closedBall_subset_ball hρR) + -- the coefficient family and its bounds + have hp0 : ∀ n : ℕ, (0 : ℝ) < ((n + 1 : ℕ) : ℝ)⁻¹ := fun n => by positivity + have hcan : ∀ n : ℕ, AnalyticOnNhd ℂ (fiberCoeff f b r (n + 1)) (closedBall z₁ r) := + fun n => (analyticOnNhd_fiberCoeff hD hr0 hrε hf (n + 1)).mono hrD + have hB : ∀ n : ℕ, ∀ z ∈ closedBall z₁ r, + ‖fiberCoeff f b r (n + 1) z‖ ^ ((n + 1 : ℕ) : ℝ)⁻¹ ≤ M₁ * r⁻¹ := by + intro n z hz + refine (rpow_inv_succ_le_of_le_mul_pow (norm_nonneg _) hM₁0.le hr0 n + (norm_fiberCoeff_le hr0 (hM₁' z hz) (n + 1))).trans ?_ + gcongr + exact Real.rpow_le_self_of_one_le hM₁1 (inv_le_one_of_one_le₀ (by exact_mod_cast n.succ_pos)) + have hlim : ∀ z ∈ closedBall z₁ r, ∀ δ > 0, ∀ᶠ n : ℕ in atTop, + ‖fiberCoeff f b r (n + 1) z‖ ^ ((n + 1 : ℕ) : ℝ)⁻¹ ≤ ρ⁻¹ + δ := by + intro z hz δ hδ + have hzD : z ∈ D := hrD hz + obtain ⟨M₂, hM₂⟩ := (isCompact_closedBall b ρ).exists_bound_of_continuousOn + (hgρ z hzD).continuousOn + have hM₃0 : 0 < max M₂ 1 := lt_of_lt_of_le one_pos (le_max_right _ _) + have hcoef : ∀ n : ℕ, ‖fiberCoeff f b r (n + 1) z‖ ^ ((n + 1 : ℕ) : ℝ)⁻¹ ≤ + (max M₂ 1) ^ ((n + 1 : ℕ) : ℝ)⁻¹ * ρ⁻¹ := by + intro n + apply rpow_inv_succ_le_of_le_mul_pow (norm_nonneg _) hM₃0.le hρ + rw [fiberCoeff_eq_of_radii hr0 hρ (hgr z hzD) (hgρ z hzD)] + exact norm_cauchyPowerSeries_apply_one_le hρ + (fun w hw => (hM₂ w hw).trans (le_max_left _ _)) _ + have ht := ((tendsto_rpow_inv_natCast_succ hM₃0).mul_const ρ⁻¹).eventually + (eventually_le_nhds (show 1 * ρ⁻¹ < ρ⁻¹ + δ by linarith)) + filter_upwards [ht] with n hn using (hcoef n).trans hn + obtain ⟨r', hr'0, hev⟩ := eventually_norm_rpow_lt_on_ball hr0 hp0 hcan hB hlim hε0 + obtain ⟨N, hN⟩ := eventually_atTop.mp hev + have hbig : ∀ k, N + 1 ≤ k → ∀ z ∈ ball z₁ r', + ‖fiberCoeff f b r k z‖ ≤ (ρ⁻¹ + ε) ^ k := by + intro k hk z hz + obtain ⟨n, rfl⟩ : ∃ n, k = n + 1 := ⟨k - 1, by omega⟩ + have := hN n (by omega) z hz + rw [Real.rpow_inv_lt_iff_of_pos (norm_nonneg _) (by positivity) (by positivity), + Real.rpow_natCast] at this + exact this.le + -- the geometric majorant + refine ⟨max 1 (M₁ * max 1 (σ / r) ^ N / q ^ N) * (1 - q)⁻¹, ?_⟩ + have hopen : IsOpen (ball z₁ (min r' r) ×ˢ ball b σ) := isOpen_ball.prod isOpen_ball + have hmem : (z₁, w₁) ∈ ball z₁ (min r' r) ×ˢ ball b σ := + ⟨mem_ball_self (lt_min hr'0 hr0), mem_ball.mpr hσ₁⟩ + filter_upwards [hopen.mem_nhds hmem] + rintro ⟨z, w⟩ ⟨hz, hw⟩ + have hzr' : z ∈ ball z₁ r' := ball_subset_ball (min_le_left _ _) hz + have hzr : z ∈ closedBall z₁ r := ball_subset_closedBall (ball_subset_ball (min_le_right _ _) hz) + have hzD : z ∈ D := hrD hzr + have hwσ : ‖w - b‖ < σ := by rwa [← dist_eq_norm] + have hps := hasFPowerSeriesOnBall_cauchyPowerSeries_of_analyticOnNhd hρ (hgρ z hzD) + have hsum := hps.hasSum (y := w - b) (by + change edist (w - b) 0 < ENNReal.ofReal ρ + rw [edist_lt_ofReal, dist_zero_right] + exact hwσ.trans hσρ) + rw [add_sub_cancel] at hsum + have hterm (k : ℕ) : (cauchyPowerSeries (fun w => f (z, w)) b ρ k fun _ => w - b) = + (w - b) ^ k • fiberCoeff f b r k z := by + rw [fiberCoeff_eq_of_radii hr0 hρ (hgr z hzD) (hgρ z hzD)] + simp + refine hsum.norm_le_of_bounded ((hasSum_geometric_of_lt_one hq0.le hq1).mul_left _) ?_ + apply le_geometric_of_bounds (s := σ / r) hM₁0.le (by positivity) hq0 hq1.le + · intro k + rw [hterm, norm_smul, norm_pow] + calc ‖w - b‖ ^ k * ‖fiberCoeff f b r k z‖ ≤ σ ^ k * (M₁ * r⁻¹ ^ k) := + mul_le_mul (pow_le_pow_left₀ (norm_nonneg _) hwσ.le k) + (norm_fiberCoeff_le hr0 (hM₁' z hzr) k) (norm_nonneg _) (by positivity) + _ = M₁ * (σ / r) ^ k := by rw [div_pow, inv_pow]; ring + · intro k hk + rw [hterm, norm_smul, norm_pow, hq, mul_pow] + exact mul_le_mul (pow_le_pow_left₀ (norm_nonneg _) hwσ.le k) (hbig k hk z hzr') + (norm_nonneg _) (by positivity) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/HartogsLemma.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/HartogsLemma.lean new file mode 100644 index 0000000000..0b59bb09ed --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/HartogsLemma.lean @@ -0,0 +1,143 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Integral.DominatedConvergence +public import Mathlib.MeasureTheory.Measure.Lebesgue.VolumeOfBalls +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.MeanValue + +/-! +# Hartogs' lemma for powers of holomorphic norms + +Under a common upper bound, pointwise eventual bounds for positive powers of holomorphic norms +become uniform on a neighborhood of each point. The exponents may vary with the sequence, so the +result applies to roots of Taylor coefficients. The domain is a closed ball in a +finite-dimensional complex normed space carrying an additive Haar volume, such as a finite +complex coordinate space. + +The proof combines dominated convergence for the positive excess above the limiting bound with +the ball submean inequality. A ball centered at a nearby point fits inside a fixed ball; +nonnegativity bounds its integral by the fixed integral. + +## Main results + +`eventually_norm_rpow_lt_on_ball` is Hartogs' lemma: a pointwise eventual bound on positive +powers of holomorphic norms becomes uniform on a neighborhood of each point. +`exists_radius_area_bound` produces a nearby ball of controlled volume. +-/ + +public section + +open Complex Filter MeasureTheory Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [MeasureSpace E] [BorelSpace E] [(volume : Measure E).IsAddHaarMeasure] + +omit [NormedSpace ℂ E] [FiniteDimensional ℂ E] in +/-- On a compact set, a uniformly bounded-above sequence of continuous functions with pointwise +eventual upper bound `A` has the corresponding integral upper bound. -/ +theorem eventually_integral_lt_of_pointwise_eventually_le + {K : Set E} {u : ℕ → E → ℝ} {A B ε : ℝ} (hK : IsCompact K) + (hu : ∀ n, ContinuousOn (u n) K) (hB : ∀ n, ∀ z ∈ K, u n z ≤ B) + (hlim : ∀ z ∈ K, ∀ δ > 0, ∀ᶠ n in atTop, u n z ≤ A + δ) (hε : 0 < ε) : + ∀ᶠ n in atTop, ∫ z in K, u n z < volume.real K * A + ε := by + let v := fun n z => max (u n z - A) 0 + have hv (n : ℕ) : ContinuousOn (v n) K := ((hu n).sub continuousOn_const).sup continuousOn_const + have ht (z : E) (hz : z ∈ K) : Tendsto (fun n => v n z) atTop (𝓝 0) := by + apply tendsto_order.mpr + constructor + · intro a ha + exact .of_forall fun n => ha.trans_le (le_max_right _ _) + · intro b hb + filter_upwards [hlim z hz (b / 2) (by positivity)] with n hn + exact max_lt (by linarith) hb + have hdom := tendsto_integral_of_dominated_convergence + (μ := volume.restrict K) (fun _ => max (B - A) 0) + (fun n => ((hv n).integrableOn_compact hK).aestronglyMeasurable) + (integrableOn_const hK.measure_lt_top.ne) + (fun n => (ae_restrict_mem hK.measurableSet).mono fun z hz => by + change |max (u n z - A) 0| ≤ max (B - A) 0 + rw [abs_of_nonneg (le_max_right _ _)] + exact max_le_max (sub_le_sub_right (hB n z hz) A) le_rfl) + ((ae_restrict_mem hK.measurableSet).mono fun z hz => ht z hz) + simp only [integral_zero] at hdom + filter_upwards [hdom.eventually (gt_mem_nhds hε)] with n hn + have hi : (∫ z in K, u n z - A) ≤ ∫ z in K, v n z := + setIntegral_mono_on (((hu n).sub continuousOn_const).integrableOn_compact hK) + ((hv n).integrableOn_compact hK) hK.measurableSet (fun z _ => le_max_left _ _) + rw [integral_sub ((hu n).integrableOn_compact hK) (integrableOn_const hK.measure_lt_top.ne), + integral_const] at hi + simp only [Measure.real, Measure.restrict_apply_univ, smul_eq_mul] at hi + change (∫ z in K, u n z) - volume.real K * A ≤ ∫ z in K, v n z at hi + linarith + +/-- The Haar volume of a closed ball scales with the real dimension. -/ +private theorem real_volume_closedBall (c : E) {R : ℝ} (hR : 0 ≤ R) : + volume.real (closedBall c R) = + R ^ Module.finrank ℝ E * volume.real (ball (0 : E) 1) := + Measure.addHaar_real_closedBall volume c hR + +omit [NormedSpace ℂ E] [FiniteDimensional ℂ E] [MeasureSpace E] [BorelSpace E] + [(volume : Measure E).IsAddHaarMeasure] in +/-- A slightly smaller ball retains enough volume to absorb an arbitrarily small increase in an +average bound. -/ +private theorem exists_radius_area_bound {R A ε v : ℝ} (d : ℕ) (hR : 0 < R) + (hv : 0 < v) (hε : 0 < ε) : + ∃ r ∈ Ioo 0 R, R ^ d * v * (A + ε / 2) < r ^ d * v * (A + ε) := by + have hcont : Continuous (fun r : ℝ => r ^ d * v * (A + ε)) := by fun_prop + have hstrict : R ^ d * v * (A + ε / 2) < R ^ d * v * (A + ε) := by + have hp : 0 < R ^ d * v := mul_pos (pow_pos hR d) hv + nlinarith + have hnhds := (isOpen_lt continuous_const hcont).mem_nhds hstrict + exact nonempty_of_mem (inter_mem (Ioo_mem_nhdsLT hR) (nhdsWithin_le_nhds hnhds)) + +/-- **Hartogs' lemma for holomorphic norms.** A pointwise eventual bound on +positive powers of holomorphic norms, under a common upper bound on a closed +ball, becomes uniform on a neighborhood of its center. The powers may vary. -/ +theorem eventually_norm_rpow_lt_on_ball + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + {f : ℕ → E → F} {p : ℕ → ℝ} {c : E} {R A B ε : ℝ} + (hR : 0 < R) (hp : ∀ n, 0 < p n) + (hf : ∀ n, AnalyticOnNhd ℂ (f n) (closedBall c R)) + (hB : ∀ n, ∀ z ∈ closedBall c R, ‖f n z‖ ^ p n ≤ B) + (hlim : ∀ z ∈ closedBall c R, ∀ δ > 0, + ∀ᶠ n in atTop, ‖f n z‖ ^ p n ≤ A + δ) (hε : 0 < ε) : + ∃ r > 0, ∀ᶠ n in atTop, ∀ z ∈ ball c r, ‖f n z‖ ^ p n < A + ε := by + have hunit : 0 < volume.real (ball (0 : E) 1) := + ENNReal.toReal_pos (measure_ball_pos volume (0 : E) one_pos).ne' measure_ball_lt_top.ne + obtain ⟨s, ⟨hs, hsR⟩, harea⟩ := + exists_radius_area_bound (A := A) (Module.finrank ℝ E) hR hunit hε + have hvol : 0 < volume.real (closedBall c R) := by + rw [real_volume_closedBall c hR.le] + positivity + have hint := eventually_integral_lt_of_pointwise_eventually_le (isCompact_closedBall c R) + (fun n => (hf n).continuousOn.norm.rpow_const (fun _ _ => Or.inr (hp n).le)) hB hlim + (mul_pos hvol (half_pos hε)) + refine ⟨R - s, sub_pos.mpr hsR, ?_⟩ + filter_upwards [hint] with n hn z hz + have hsub : closedBall z s ⊆ closedBall c R := + closedBall_subset_closedBall' (by have := mem_ball.mp hz; linarith) + have hmean := volume_mul_norm_rpow_le_integral_closedBall (E := E) (hp n) ((hf n).mono hsub) + have hmono : (∫ w in closedBall z s, ‖f n w‖ ^ p n) ≤ + ∫ w in closedBall c R, ‖f n w‖ ^ p n := + setIntegral_mono_set + (((hf n).continuousOn.norm.rpow_const (fun _ _ => Or.inr (hp n).le)).integrableOn_compact + (isCompact_closedBall c R)) + (.of_forall fun w => Real.rpow_nonneg (norm_nonneg _) _) hsub.eventuallySubset + rw [real_volume_closedBall z hs.le] at hmean + rw [real_volume_closedBall c hR.le] at hn + have hbound : s ^ Module.finrank ℝ E * volume.real (ball (0 : E) 1) * (‖f n z‖ ^ p n) < + s ^ Module.finrank ℝ E * volume.real (ball (0 : E) 1) * (A + ε) := + (hmean.trans hmono).trans_lt (hn.trans_le (by nlinarith only [harea])) + exact (mul_lt_mul_iff_right₀ + (mul_pos (pow_pos hs _) hunit)).mp hbound + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/MeanValue.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/MeanValue.lean new file mode 100644 index 0000000000..e849583c02 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/MeanValue.lean @@ -0,0 +1,139 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.MeasureTheory.Integral.Prod +public import Mathlib.MeasureTheory.Measure.Haar.InnerProductSpace +public import Mathlib.MeasureTheory.Measure.Lebesgue.Complex +public import Mathlib.MeasureTheory.Measure.Lebesgue.EqHaar +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Submean + +/-! +# Ball submean estimates for holomorphic norms + +Averaging unit complex rotations converts the circle submean inequality into a volume submean +inequality on closed balls of a finite-dimensional complex normed space carrying an additive +Haar volume. This avoids polar-coordinate integration and applies to all positive powers of +norms, including the roots used in Hartogs' lemma. The one-variable case is the disc inequality; +the case of a finite coordinate space is used for the base variables in Hartogs' +separate-analyticity theorem. + +## Main results + +`volume_mul_norm_rpow_le_integral_closedBall` is the volume submean inequality for positive +powers of holomorphic norms on a closed ball. `integral_closedBall_smul_rotation` averages unit +complex rotations. +-/ + +public section + +open Complex Filter Function MeasureTheory Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [MeasureSpace E] [BorelSpace E] [(volume : Measure E).IsAddHaarMeasure] + +/-- Unit complex rotations preserve the integral of any real function on a closed ball. Rotation +preserves the unit ball, so it has unit determinant and preserves Haar volume. -/ +private theorem integral_closedBall_smul_rotation (u : E → ℝ) (R : ℝ) + {w : ℂ} (hw : ‖w‖ = 1) : + ∫ z in closedBall (0 : E) R, u (w • z) = ∫ z in closedBall (0 : E) R, u z := by + have hw0 : w ≠ 0 := by intro h; simp [h] at hw + let e : E ≃L[ℝ] E := + ((LinearEquiv.smulOfNeZero ℂ E w hw0).restrictScalars ℝ).toContinuousLinearEquiv + have he (z : E) : e z = w • z := rfl + have hpre (s : ℝ) : e ⁻¹' closedBall 0 s = closedBall 0 s := by + ext z + simp only [mem_preimage, mem_closedBall, dist_zero_right, he, norm_smul, hw, one_mul] + have hdet : ENNReal.ofReal |LinearMap.det (e.symm : E →ₗ[ℝ] E)| = 1 := by + have h := Measure.addHaar_preimage_continuousLinearEquiv volume e (closedBall (0 : E) 1) + rw [hpre] at h + exact (ENNReal.mul_left_inj (measure_closedBall_pos volume (0 : E) one_pos).ne' + measure_closedBall_lt_top.ne).mp (by rw [one_mul]; exact h.symm) + have hmp : MeasurePreserving e volume volume := by + refine ⟨e.continuous.measurable, Measure.ext fun s hs => ?_⟩ + rw [Measure.map_apply e.continuous.measurable hs, + Measure.addHaar_preimage_continuousLinearEquiv, hdet, one_mul] + simpa only [hpre, he] using hmp.setIntegral_preimage_emb + e.toHomeomorph.isClosedEmbedding.measurableEmbedding u (closedBall 0 R) + +/-- Averaging rotations turns circle submean inequalities into a ball inequality. Only continuity on +the ball is required of the real-valued function. -/ +theorem volume_mul_le_integral_closedBall_of_circle_submean {u : E → ℝ} {R A : ℝ} + (hu : ContinuousOn u (closedBall 0 R)) + (hmean : ∀ z ∈ closedBall (0 : E) R, + A ≤ Real.circleAverage (fun w => u (w • z)) 0 1) : + volume.real (closedBall (0 : E) R) * A ≤ ∫ z in closedBall (0 : E) R, u z := by + let B := closedBall (0 : E) R + let T := Icc (0 : ℝ) (2 * π) + let H := fun (z : E) (θ : ℝ) => u (circleMap 0 1 θ • z) + have hrot (θ : ℝ) : ‖circleMap 0 1 θ‖ = 1 := by simp + have hmap : MapsTo (fun p : E × ℝ => circleMap 0 1 p.2 • p.1) (B ×ˢ T) B := by + intro z hz + simpa only [B, mem_closedBall, dist_zero_right, norm_smul, hrot, one_mul] using hz.1 + have hcont : ContinuousOn (uncurry H) (B ×ˢ T) := hu.comp (by fun_prop) hmap + have hint : Integrable (uncurry H) ((volume.restrict B).prod (volume.restrict T)) := by + rw [Measure.prod_restrict, ← Measure.volume_eq_prod] + exact hcont.integrableOn_compact ((isCompact_closedBall _ _).prod isCompact_Icc) + have hpoint (z : E) (hz : z ∈ B) : (2 * π) * A ≤ ∫ θ in T, H z θ := by + have h := hmean z hz + rw [Real.circleAverage, intervalIntegral.integral_of_le Real.two_pi_pos.le, + ← integral_Icc_eq_integral_Ioc, smul_eq_mul] at h + exact (le_inv_mul_iff₀ Real.two_pi_pos).mp h + have hbound := setIntegral_mono_on + (integrableOn_const (isCompact_closedBall (0 : E) R).measure_lt_top.ne) + hint.integral_prod_left measurableSet_closedBall hpoint + have hswap := integral_integral_swap hint + have hright : (∫ θ in T, ∫ z in B, H z θ) = (2 * π) * ∫ z in B, u z := by + simp_rw [H, B, integral_closedBall_smul_rotation u R (hrot _)] + simp [T, integral_const, Real.volume_Icc, Measure.real, ENNReal.toReal_ofReal Real.pi_pos.le] + simp only [uncurry_apply_pair] at hbound + rw [integral_const, hswap, hright] at hbound + simp only [Measure.real, Measure.restrict_apply_univ, smul_eq_mul] at hbound + change volume.real B * (2 * π * A) ≤ 2 * π * ∫ z in B, u z at hbound + change volume.real B * A ≤ ∫ z in B, u z + apply (mul_le_mul_iff_right₀ Real.two_pi_pos).mp + nlinarith only [hbound] + +/-- Every positive power of a holomorphic norm satisfies the volume submean inequality on a closed +ball. No completeness of the target is needed. -/ +theorem volume_mul_norm_rpow_le_integral_closedBall + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + {f : E → F} {c : E} {R p : ℝ} (hp : 0 < p) + (hf : AnalyticOnNhd ℂ f (closedBall c R)) : + volume.real (closedBall c R) * ‖f c‖ ^ p ≤ ∫ z in closedBall c R, ‖f z‖ ^ p := by + have hpre : (fun z : E => c + z) ⁻¹' closedBall c R = closedBall 0 R := by + ext z + simp [mem_closedBall, dist_eq_norm] + have hvol : volume (closedBall (0 : E) R) = volume (closedBall c R) := by + rw [← hpre] + exact measure_preimage_add volume c _ + have htrans : AnalyticOnNhd ℂ (fun z => f (c + z)) (closedBall 0 R) := by + intro z hz + exact (hf _ (by simpa [mem_closedBall, dist_eq_norm] using hz)).comp_of_eq + (analyticAt_const.add analyticAt_id) rfl + have hb := volume_mul_le_integral_closedBall_of_circle_submean + (htrans.continuousOn.norm.rpow_const (fun _ _ => Or.inr hp.le)) (A := ‖f c‖ ^ p) ?_ + · have hm := (measurePreserving_add_left (volume : Measure E) c).setIntegral_preimage_emb + (Homeomorph.addLeft c).isClosedEmbedding.measurableEmbedding + (fun z => ‖f z‖ ^ p) (closedBall c R) + rw [hpre] at hm + simpa only [Measure.real, hvol, hm] using hb + · intro z hz + have hline : AnalyticOnNhd ℂ (fun w : ℂ => f (c + w • z)) (closedBall 0 1) := by + intro w hw + apply (hf (c + w • z) ?_).comp_of_eq + (analyticAt_const.add (analyticAt_id.smul analyticAt_const)) rfl + rw [mem_closedBall, dist_eq_norm, add_sub_cancel_left, norm_smul] + exact (mul_le_mul_of_nonneg_right (mem_closedBall_zero_iff.mp hw) + (norm_nonneg z)).trans (by simpa using hz) + simpa only [zero_smul, add_zero] using norm_rpow_le_circleAverage zero_lt_one hp hline + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/Submean.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/Submean.lean new file mode 100644 index 0000000000..14463c2e73 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SeparateAnalytic/Submean.lean @@ -0,0 +1,155 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.JensenFormula +public import Mathlib.Analysis.Normed.Module.HahnBanach + +/-! +# Submean estimates for positive powers of holomorphic norms + +Jensen's formula and the tangent-line inequality for the exponential give the submean inequality +for every positive real power of a holomorphic norm. In particular, the exponent may be less +than one, as needed for the roots of Taylor coefficients in the proof of Hartogs' +separate-analyticity theorem. + +Hahn–Banach transfers the scalar estimate to arbitrary complex normed targets. + +## Main results + +`norm_rpow_le_circleAverage` is the circle submean inequality for every positive real power of a +holomorphic norm. `log_norm_le_circleAverage` is Jensen's formula for a nonvanishing holomorphic +function. +-/ + +public section + +open Complex Filter MeasureTheory MeromorphicOn Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +/-- Circle averages preserve inequalities outside a discrete exceptional set. -/ +theorem circleAverage_le_of_eventually_le {u v : ℂ → ℝ} {c : ℂ} {R : ℝ} + (hR : R ≠ 0) (hu : CircleIntegrable u c R) (hv : CircleIntegrable v c R) + (h : ∀ᶠ z in codiscreteWithin (sphere c |R|), u z ≤ v z) : + Real.circleAverage u c R ≤ Real.circleAverage v c R := by + simp only [Real.circleAverage, smul_eq_mul] + apply mul_le_mul_of_nonneg_left _ (by positivity) + apply intervalIntegral.integral_mono_ae_restrict Real.two_pi_pos.le hu hv + apply ae_restrict_le_codiscreteWithin measurableSet_Icc + exact codiscreteWithin_mono (by simp) (circleMap_preimage_codiscrete hR h) + +/-- For an analytic scalar function nonzero at the center, Jensen's zero terms are nonnegative, so +the mean of its logarithmic norm bounds the center value. -/ +theorem log_norm_le_circleAverage {f : ℂ → ℂ} {c : ℂ} {R : ℝ} + (hR : 0 < R) (hf : AnalyticOnNhd ℂ f (closedBall c R)) (hc : f c ≠ 0) : + Real.log ‖f c‖ ≤ Real.circleAverage (fun z => Real.log ‖f z‖) c R := by + have hf' : AnalyticOnNhd ℂ f (closedBall c |R|) := by simpa [abs_of_pos hR] using hf + rw [hf'.circleAverage_log_norm hR.ne' hc] + apply le_add_of_nonneg_left + apply finsum_nonneg + intro z + by_cases hz : MeromorphicOn.divisor f (closedBall c |R|) z = 0 + · simp [hz] + have hzmem : z ∈ closedBall c |R| := + (MeromorphicOn.divisor f (closedBall c |R|)).supportWithinDomain hz + have hzc : c ≠ z := by + rintro rfl + apply hz + rw [hf'.divisor_apply hzmem, (hf' c hzmem).analyticOrderAt_eq_zero.mpr hc] + simp + apply mul_nonneg (by exact_mod_cast hf'.divisor_nonneg z) + apply Real.log_nonneg + rw [← div_eq_mul_inv, one_le_div (norm_pos_iff.mpr (sub_ne_zero.mpr hzc))] + simpa [mem_closedBall, dist_eq_norm, norm_sub_rev, abs_of_pos hR] using hzmem + +/-- A positive power lies above the affine tangent expressed in logarithmic coordinates. This form +can be integrated even when the exponent is below one. -/ +private theorem rpow_log_tangent_le {a b : ℝ} (ha : 0 < a) (hb : 0 < b) (p : ℝ) : + a ^ p * (1 + p * (Real.log b - Real.log a)) ≤ b ^ p := by + rw [Real.rpow_def_of_pos ha, Real.rpow_def_of_pos hb] + calc + Real.exp (Real.log a * p) * (1 + p * (Real.log b - Real.log a)) ≤ + Real.exp (Real.log a * p) * Real.exp (p * (Real.log b - Real.log a)) := + mul_le_mul_of_nonneg_left + (by simpa [add_comm] using Real.add_one_le_exp (p * (Real.log b - Real.log a))) + (Real.exp_pos _).le + _ = Real.exp (Real.log b * p) := by rw [← Real.exp_add]; congr 1; ring + +/-- Every positive real power of the norm of a scalar holomorphic function satisfies the circle +submean inequality, including powers less than one. -/ +theorem norm_rpow_le_circleAverage_scalar {f : ℂ → ℂ} {c : ℂ} {R p : ℝ} + (hR : 0 < R) (hp : 0 < p) (hf : AnalyticOnNhd ℂ f (closedBall c R)) : + ‖f c‖ ^ p ≤ Real.circleAverage (fun z => ‖f z‖ ^ p) c R := by + by_cases hc : f c = 0 + · simpa [hc, Real.zero_rpow hp.ne'] using + Real.circleAverage_nonneg_of_nonneg (c := c) (R := R) + (fun z _ => Real.rpow_nonneg (norm_nonneg (f z)) p) + have hn : 0 < ‖f c‖ := norm_pos_iff.mpr hc + have hlog : CircleIntegrable (fun z => Real.log ‖f z‖) c R := by + apply MeromorphicOn.circleIntegrable_log_norm + simpa [abs_of_pos hR] using (hf.mono sphere_subset_closedBall).meromorphicOn + have hpow : CircleIntegrable (fun z => ‖f z‖ ^ p) c R := by + apply ContinuousOn.circleIntegrable hR.le + exact (hf.continuousOn.mono sphere_subset_closedBall).norm.rpow_const + (fun z _ => Or.inr hp.le) + have hne : ∀ᶠ z in codiscreteWithin (sphere c |R|), f z ≠ 0 := by + apply codiscreteWithin_mono (by simpa [abs_of_pos hR] using + (sphere_subset_closedBall : sphere c R ⊆ closedBall c R)) + exact (hf.eqOn_zero_or_eventually_ne_zero_of_preconnected + (convex_closedBall c R).isPreconnected).resolve_left + (fun h => hc (h (mem_closedBall_self hR.le))) + have htan : CircleIntegrable + (fun z => ‖f c‖ ^ p * (1 + p * (Real.log ‖f z‖ - Real.log ‖f c‖))) c R := by + exact ((circleIntegrable_const 1 c R).add + ((hlog.sub (circleIntegrable_const _ c R)).const_smul (a := p))).const_smul + have hbound := circleAverage_le_of_eventually_le hR.ne' htan hpow + (hne.mono fun z hz => rpow_log_tangent_le hn (norm_pos_iff.mpr hz) p) + have hsub : CircleIntegrable (fun z => Real.log ‖f z‖ - Real.log ‖f c‖) c R := + hlog.sub (circleIntegrable_const _ c R) + have hmul : CircleIntegrable (fun z => p • (Real.log ‖f z‖ - Real.log ‖f c‖)) c R := + hsub.const_smul + have hmean : Real.circleAverage + (fun z => ‖f c‖ ^ p * (1 + p * (Real.log ‖f z‖ - Real.log ‖f c‖))) c R = + ‖f c‖ ^ p * (1 + p * + (Real.circleAverage (fun z => Real.log ‖f z‖) c R - Real.log ‖f c‖)) := by + simp only [← smul_eq_mul, Real.circleAverage_fun_smul] + rw [Real.circleAverage_fun_add (circleIntegrable_const 1 c R) hmul, Real.circleAverage_const, + Real.circleAverage_fun_smul, + Real.circleAverage_fun_sub hlog (circleIntegrable_const _ c R), Real.circleAverage_const] + rw [hmean] at hbound + have hlogbound := log_norm_le_circleAverage hR hf hc + refine le_trans ?_ hbound + calc + ‖f c‖ ^ p = ‖f c‖ ^ p * 1 := (mul_one _).symm + _ ≤ _ := mul_le_mul_of_nonneg_left + (by nlinarith) (Real.rpow_nonneg (norm_nonneg _) _) + +/-- The submean inequality for positive powers of a holomorphic norm also holds for complex normed +targets, by applying a norming linear functional at the center. -/ +theorem norm_rpow_le_circleAverage {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + {f : ℂ → F} {c : ℂ} {R p : ℝ} (hR : 0 < R) (hp : 0 < p) + (hf : AnalyticOnNhd ℂ f (closedBall c R)) : + ‖f c‖ ^ p ≤ Real.circleAverage (fun z => ‖f z‖ ^ p) c R := by + obtain ⟨L, hL, hLc⟩ := exists_dual_vector'' ℂ (f c) + have hLf : AnalyticOnNhd ℂ (fun z => L (f z)) (closedBall c R) := + fun z hz => (L.analyticAt (f z)).comp_of_eq (hf z hz) rfl + have hcenter : ‖L (f c)‖ = ‖f c‖ := by simp [hLc] + rw [← hcenter] + refine (norm_rpow_le_circleAverage_scalar hR hp hLf).trans ?_ + apply Real.circleAverage_mono + · exact (hLf.continuousOn.mono sphere_subset_closedBall).norm.rpow_const + (fun z _ => Or.inr hp.le) |>.circleIntegrable hR.le + · exact (hf.continuousOn.mono sphere_subset_closedBall).norm.rpow_const + (fun z _ => Or.inr hp.le) |>.circleIntegrable hR.le + · intro z _ + exact Real.rpow_le_rpow (norm_nonneg _) ((L.le_opNorm (f z)).trans + (by simpa using mul_le_mul_of_nonneg_right hL (norm_nonneg (f z)))) hp.le + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SphericalShell.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SphericalShell.lean new file mode 100644 index 0000000000..e364a59936 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/SphericalShell.lean @@ -0,0 +1,109 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.LinearAlgebra.Complex.FiniteDimensional +public import Mathlib.LinearAlgebra.Dimension.Finrank +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HartogsExtension + +/-! +# Punctured polydiscs, spherical shells, and exteriors of balls + +Punctured product polydiscs extend by the proved Hartogs continuity theorem, without boundedness +assumptions. A radial argument proves connectedness of norm shells; spherical shell extension is +then a corollary of the general compact-hole theorem. For Euclidean spheres instantiate the +source with `EuclideanSpace ℂ ι`, not the supremum norm on `ι → ℂ`. References: +[Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), Applications 2.6.2 and 2.8.3. + +## Main results + +* `exists_extension_sphericalShell`: **Spherical-shell extension.** This works for any norm in + finite complex dimension at least two. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public section + +open Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- An isolated puncture in a product polydisc is removable in complex dimension at least two. The +nonempty base index type makes the dimension restriction explicit. -/ +theorem exists_extension_punctured_polydisc {ι : Type*} [Fintype ι] [Nonempty ι] + {r R : ℝ} (hr : 0 < r) (hR : 0 < R) + {f : ((ι → ℂ) × ℂ) → F} + (hf : AnalyticOnNhd ℂ f ((ball 0 r ×ˢ ball 0 R) \ {0})) : + ∃ g, AnalyticOnNhd ℂ g (ball 0 r ×ˢ ball 0 R) ∧ + EqOn g f ((ball 0 r ×ˢ ball 0 R) \ {0}) := by + classical + have he : hartogsCylinder (ball (0 : ι → ℂ) r) (ball 0 r \ {0}) 0 R = + (ball 0 r ×ˢ ball 0 R) \ {0} := by + ext ⟨z, w⟩ + simp only [hartogsCylinder, mem_union, mem_prod, mem_sdiff, closedBall_zero, + mem_singleton_iff, Prod.zero_eq_mk, Prod.mk.injEq] + tauto + have hn : (ball (0 : ι → ℂ) r \ {0}).Nonempty := by + refine ⟨fun _ => (r / 2 : ℂ), ?_, ?_⟩ + · rw [mem_ball, dist_pi_lt_iff hr] + intro i + simpa [abs_of_pos hr] using half_lt_self hr + · intro hz + have heq := congrFun hz (Classical.arbitrary ι) + change (r / 2 : ℂ) = 0 at heq + have : (r / 2 : ℝ) = 0 := by exact_mod_cast heq + linarith + obtain ⟨g, hg, heq⟩ := exists_extension_hartogsCylinder isOpen_ball isPreconnected_ball + (isOpen_ball.sdiff isClosed_singleton) hn sdiff_subset (le_refl 0) hR (he ▸ hf) + exact ⟨g, hg, he ▸ heq⟩ + +/-- **Spherical-shell extension.** This works for any norm in finite complex dimension at +least two. The proof applies the general compact-hole theorem. -/ +theorem exists_extension_sphericalShell {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] (hdim : 2 ≤ Module.finrank ℂ E) + {ρ R : ℝ} (hρ : 0 ≤ ρ) (hρR : ρ < R) {f : E → F} + (hf : AnalyticOnNhd ℂ f (ball 0 R \ closedBall 0 ρ)) : + ∃ g, AnalyticOnNhd ℂ g (ball 0 R) ∧ EqOn g f (ball 0 R \ closedBall 0 ρ) := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + have hdimR : 1 < Module.finrank ℝ E := by + rw [← Module.finrank_mul_finrank ℝ ℂ E, Complex.finrank_real_complex] + omega + have hrank : 1 < Module.rank ℝ E := by + rw [← Module.finrank_eq_rank] + exact_mod_cast hdimR + exact exists_analyticOnNhd_extension_of_isCompact hdim isOpen_ball + (isCompact_closedBall 0 ρ) (closedBall_subset_ball hρR) + (isPreconnected_ball_diff_closedBall_zero hrank hρ) hf + +/-- The infinite-outer-radius case of shell extension: a function outside a closed ball extends to +the whole space. This follows from the compact-hole theorem and imposes no boundedness at +infinity or near the inner sphere. -/ +theorem exists_extension_exterior_closedBall {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [FiniteDimensional ℂ E] (hdim : 2 ≤ Module.finrank ℂ E) {ρ : ℝ} (hρ : 0 ≤ ρ) + {f : E → F} (hf : AnalyticOnNhd ℂ f (closedBall (0 : E) ρ)ᶜ) : + ∃ g, AnalyticOnNhd ℂ g univ ∧ EqOn g f (closedBall (0 : E) ρ)ᶜ := by + let : ProperSpace E := FiniteDimensional.proper ℂ E + have hdimR : 1 < Module.finrank ℝ E := by + rw [← Module.finrank_mul_finrank ℝ ℂ E, Complex.finrank_real_complex] + omega + have hrank : 1 < Module.rank ℝ E := by + rw [← Module.finrank_eq_rank] + exact_mod_cast hdimR + simpa only [← compl_eq_univ_sdiff] using exists_analyticOnNhd_extension_of_isCompact hdim + isOpen_univ (isCompact_closedBall 0 ρ) (subset_univ _) + (by simpa only [← compl_eq_univ_sdiff] using isPreconnected_compl_closedBall_zero hrank hρ) + (by simpa only [← compl_eq_univ_sdiff] using hf) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic.lean new file mode 100644 index 0000000000..f8a0ef11be --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic.lean @@ -0,0 +1,390 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.MeanValue +public import Mathlib.MeasureTheory.Integral.CircleAverage +public import Mathlib.Topology.Semicontinuity.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Integral.Circle +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.SeparateAnalytic.Submean +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.UpperSemicontinuous + +/-! +# Subharmonic functions of one complex variable + +A real-valued function on an open subset of `ℂ` is subharmonic if it is upper semicontinuous and +satisfies the local submean inequality: at every point, for all sufficiently small radii the +function is integrable on the circle and its value at the center is at most its circle average. +This is the definition of [Ransford][Ransford1995], *Potential Theory in the Complex Plane*, +Definition 2.2.1, and of [Fritzsche–Grauert][FritzscheGrauert2002], Chapter II, Section 2, with +the harmonic-majorant condition replaced by the submean inequality. Locality is then immediate. +The submean inequality on every closed disc in the domain and the plurisubharmonic theory are +developed in later files. + +Only real-valued functions are considered; the value `-∞` is not admitted. + +This file proves closure under sums, nonnegative multiples and maxima, gives the holomorphic +examples (real parts, positive powers of norms, logarithms of nonvanishing moduli), and proves +the maximum principle: a subharmonic function on a preconnected open set that attains its +supremum is constant. On a disc, if it is upper semicontinuous on the closed disc, it is +bounded by its supremum on the boundary circle. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 2; +[Range][Range1986] (1986), Chapter II, Section 5; [Ransford][Ransford1995] (1995), Chapter 2. + +## Main definitions + +* `HasSubmeanAt`: The local submean property at a point: for every sufficiently small radius, the + function is integrable on the circle and its value at the center is bounded by its circle average. +* `SubharmonicOn`: A real function is subharmonic on a set if it is upper semicontinuous there and + has the local submean property at each of its points. + +## Main results + +* `SubharmonicOn.eqOn_const_of_isMaxOn`: **Maximum principle.** A subharmonic function on a + preconnected open set that attains its supremum at a point is constant. +* `SubharmonicOn.le_of_le_sphere`: **Maximum principle on a disc.** A function subharmonic on an + open disc and upper semicontinuous on the closed disc is bounded by any bound valid on the + boundary circle. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [R. M. Range, *Holomorphic Functions and Integral Representations in Several Complex + Variables*][Range1986] +* [T. Ransford, *Potential Theory in the Complex Plane*][Ransford1995] +-/ + +public section + +open Filter MeasureTheory Metric Set Real +open scoped Interval Topology + +namespace SeveralComplexVariables + +/-- The local submean property at a point: for every sufficiently small radius, the function is +integrable on the circle and its value at the center is bounded by its circle average. -/ +@[expose] def HasSubmeanAt (u : ℂ → ℝ) (a : ℂ) : Prop := + ∀ᶠ r in 𝓝[>] (0 : ℝ), CircleIntegrable u a r ∧ u a ≤ circleAverage u a r + +/-- A real function is subharmonic on a set if it is upper semicontinuous there and has the local +submean property at each of its points. The set is intended to be open. -/ +@[expose] def SubharmonicOn (u : ℂ → ℝ) (U : Set ℂ) : Prop := + UpperSemicontinuousOn u U ∧ ∀ a ∈ U, HasSubmeanAt u a + +variable {u v : ℂ → ℝ} {U V : Set ℂ} {a : ℂ} + +/-- A subharmonic function is upper semicontinuous. -/ +theorem SubharmonicOn.upperSemicontinuousOn (h : SubharmonicOn u U) : + UpperSemicontinuousOn u U := h.1 + +/-- A subharmonic function has the local submean property at each point of its domain. -/ +theorem SubharmonicOn.hasSubmeanAt (h : SubharmonicOn u U) (ha : a ∈ U) : HasSubmeanAt u a := + h.2 a ha + +/-- Subharmonicity restricts to subsets. -/ +theorem SubharmonicOn.mono (h : SubharmonicOn u U) (hV : V ⊆ U) : SubharmonicOn u V := + ⟨h.1.mono hV, fun a ha => h.2 a (hV ha)⟩ + +/-- The local submean property provides a radius below which the inequality holds. -/ +theorem HasSubmeanAt.exists_forall_lt (h : HasSubmeanAt u a) : + ∃ ρ > 0, ∀ r, 0 < r → r < ρ → CircleIntegrable u a r ∧ u a ≤ circleAverage u a r := by + obtain ⟨ρ, hρ, hsub⟩ := mem_nhdsGT_iff_exists_Ioo_subset.mp h + exact ⟨ρ, hρ, fun r h0 hr => hsub ⟨h0, hr⟩⟩ + +/-- Conversely, a radius bound gives the local submean property. -/ +theorem hasSubmeanAt_of_forall_lt {ρ : ℝ} (hρ : 0 < ρ) + (h : ∀ r, 0 < r → r < ρ → CircleIntegrable u a r ∧ u a ≤ circleAverage u a r) : + HasSubmeanAt u a := + mem_nhdsGT_iff_exists_Ioo_subset.mpr ⟨ρ, hρ, fun r hr => h r hr.1 hr.2⟩ + +/-- Subharmonicity is a local property. -/ +theorem subharmonicOn_of_locally (h : ∀ a ∈ U, ∃ V ∈ 𝓝 a, SubharmonicOn u (V ∩ U)) : + SubharmonicOn u U := by + refine ⟨fun a ha => ?_, fun a ha => ?_⟩ + · obtain ⟨V, hV, hu⟩ := h a ha + intro y hy + have := hu.1 a ⟨mem_of_mem_nhds hV, ha⟩ y hy + rwa [nhdsWithin_inter_of_mem (mem_nhdsWithin_of_mem_nhds hV)] at this + · obtain ⟨V, hV, hu⟩ := h a ha + exact hu.2 a ⟨mem_of_mem_nhds hV, ha⟩ + +section Algebra + +/-- Constants have the local submean property. -/ +theorem hasSubmeanAt_const (c : ℝ) (a : ℂ) : HasSubmeanAt (fun _ => c) a := + Filter.Eventually.of_forall fun _ => ⟨circleIntegrable_const c a _, by rw [circleAverage_const]⟩ + +/-- Constants are subharmonic. -/ +theorem subharmonicOn_const (c : ℝ) (U : Set ℂ) : SubharmonicOn (fun _ => c) U := + ⟨continuousOn_const.upperSemicontinuousOn, fun a _ => hasSubmeanAt_const c a⟩ + +/-- The local submean property is additive. -/ +theorem HasSubmeanAt.add (hu : HasSubmeanAt u a) (hv : HasSubmeanAt v a) : + HasSubmeanAt (fun z => u z + v z) a := by + filter_upwards [hu, hv] with r ⟨hui, hu'⟩ ⟨hvi, hv'⟩ + refine ⟨hui.add hvi, ?_⟩ + rw [circleAverage_fun_add hui hvi] + exact add_le_add hu' hv' + +/-- Sums of subharmonic functions are subharmonic. -/ +theorem SubharmonicOn.add (hu : SubharmonicOn u U) (hv : SubharmonicOn v U) : + SubharmonicOn (fun z => u z + v z) U := + ⟨hu.1.add hv.1, fun a ha => (hu.2 a ha).add (hv.2 a ha)⟩ + +/-- Nonnegative multiples preserve the local submean property. -/ +theorem HasSubmeanAt.const_mul {c : ℝ} (hc : 0 ≤ c) (hu : HasSubmeanAt u a) : + HasSubmeanAt (fun z => c * u z) a := by + filter_upwards [hu] with r ⟨hui, hu'⟩ + refine ⟨(circleIntegrable_def _ a r).mpr (((circleIntegrable_def u a r).mp hui).const_mul c), ?_⟩ + simp only [← smul_eq_mul, circleAverage_fun_smul] + exact smul_le_smul_of_nonneg_left hu' hc + +/-- Nonnegative multiples of subharmonic functions are subharmonic. -/ +theorem SubharmonicOn.const_mul {c : ℝ} (hc : 0 ≤ c) (hu : SubharmonicOn u U) : + SubharmonicOn (fun z => c * u z) U := + ⟨hu.1.const_mul hc, fun a ha => (hu.2 a ha).const_mul hc⟩ + +/-- The pointwise maximum preserves the local submean property. -/ +theorem HasSubmeanAt.sup (hu : HasSubmeanAt u a) (hv : HasSubmeanAt v a) : + HasSubmeanAt (fun z => max (u z) (v z)) a := by + filter_upwards [hu, hv] with r ⟨hui, hu'⟩ ⟨hvi, hv'⟩ + have hm := CircleIntegrable.max hui hvi + refine ⟨hm, max_le ?_ ?_⟩ + · exact hu'.trans (circleAverage_mono hui hm fun z _ => le_max_left _ _) + · exact hv'.trans (circleAverage_mono hvi hm fun z _ => le_max_right _ _) + +/-- The pointwise maximum of two subharmonic functions is subharmonic. -/ +theorem SubharmonicOn.sup (hu : SubharmonicOn u U) (hv : SubharmonicOn v U) : + SubharmonicOn (fun z => max (u z) (v z)) U := + ⟨hu.1.sup hv.1, fun a ha => (hu.2 a ha).sup (hv.2 a ha)⟩ + +end Algebra + +section Holomorphic + +variable {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- A continuous function whose circle averages over all small circles equal its value at the center +has the local submean property; this applies to harmonic functions. -/ +theorem hasSubmeanAt_of_circleAverage_eq {ρ : ℝ} (hρ : 0 < ρ) (hc : ContinuousOn u (ball a ρ)) + (h : ∀ r, 0 < r → r < ρ → circleAverage u a r = u a) : HasSubmeanAt u a := + hasSubmeanAt_of_forall_lt hρ fun r hr hrρ => + ⟨(hc.mono (sphere_subset_closedBall.trans (closedBall_subset_ball hrρ))).circleIntegrable + hr.le, (h r hr hrρ).ge⟩ + +/-- Real parts of holomorphic functions have the local submean property, with equality. -/ +theorem circleAverage_re_eq_of_analyticAt {f : ℂ → ℂ} (hf : AnalyticAt ℂ f a) : + ∃ ρ > 0, ∀ r, 0 < r → r < ρ → circleAverage (fun z => (f z).re) a r = (f a).re := by + obtain ⟨ρ, hρ, hball⟩ := Metric.mem_nhds_iff.mp hf.eventually_analyticAt + have han : AnalyticOnNhd ℂ f (ball a ρ) := fun z hz => hball hz + refine ⟨ρ, hρ, fun r hr hrρ => ?_⟩ + have hd : DiffContOnCl ℂ f (ball a |r|) := by + rw [abs_of_pos hr] + refine DifferentiableOn.diffContOnCl ?_ + rw [closure_ball a hr.ne'] + exact fun z hz => (han z (closedBall_subset_ball hrρ + hz)).differentiableAt.differentiableWithinAt + have hint : CircleIntegrable f a r := + ((han.mono (sphere_subset_closedBall.trans (closedBall_subset_ball + hrρ))).continuousOn).circleIntegrable hr.le + have := Complex.reCLM.circleAverage_comp_comm (f := f) (c := a) (R := r) + simp only [Function.comp_def, Complex.reCLM_apply] at this + rw [this hint, hd.circleAverage] + +/-- The real part of a holomorphic function is subharmonic. -/ +theorem _root_.AnalyticOnNhd.subharmonicOn_re {f : ℂ → ℂ} (hf : AnalyticOnNhd ℂ f U) : + SubharmonicOn (fun z => (f z).re) U := by + refine ⟨(Complex.continuous_re.comp_continuousOn hf.continuousOn).upperSemicontinuousOn, + fun a ha => ?_⟩ + obtain ⟨ρ, hρ, h⟩ := circleAverage_re_eq_of_analyticAt (hf a ha) + obtain ⟨ρ', hρ', hball⟩ := Metric.mem_nhds_iff.mp (hf a ha).eventually_analyticAt + refine hasSubmeanAt_of_circleAverage_eq (lt_min hρ hρ') ?_ fun r hr hrρ => h r hr (hrρ.trans_le + (min_le_left _ _)) + exact Complex.continuous_re.comp_continuousOn + ((AnalyticOnNhd.continuousOn fun z hz => hball (ball_subset_ball (min_le_right _ _) hz))) + +/-- Minus the real part of a holomorphic function is subharmonic. -/ +theorem _root_.AnalyticOnNhd.subharmonicOn_neg_re {f : ℂ → ℂ} (hf : AnalyticOnNhd ℂ f U) : + SubharmonicOn (fun z => -(f z).re) U := by + have := AnalyticOnNhd.subharmonicOn_re (U := U) (f := fun z => -f z) (hf.neg) + simpa using this + +/-- Positive powers of the norm of a holomorphic function are subharmonic. -/ +theorem _root_.AnalyticOnNhd.subharmonicOn_norm_rpow (hU : IsOpen U) {f : ℂ → F} {p : ℝ} + (hp : 0 < p) + (hf : AnalyticOnNhd ℂ f U) : SubharmonicOn (fun z => ‖f z‖ ^ p) U := by + refine ⟨(hf.continuousOn.norm.rpow_const fun _ _ => Or.inr hp.le).upperSemicontinuousOn, + fun a ha => ?_⟩ + obtain ⟨ρ, hρ, hball⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds ha) + refine hasSubmeanAt_of_forall_lt hρ fun r hr hrρ => ?_ + have hsub : closedBall a r ⊆ U := (closedBall_subset_ball hrρ).trans hball + refine ⟨((hf.mono hsub).continuousOn.norm.rpow_const fun _ _ => Or.inr hp.le).mono + sphere_subset_closedBall |>.circleIntegrable hr.le, ?_⟩ + exact norm_rpow_le_circleAverage hr hp (hf.mono hsub) + +/-- The logarithm of the modulus of a nonvanishing holomorphic function is subharmonic. -/ +theorem _root_.AnalyticOnNhd.subharmonicOn_log_norm (hU : IsOpen U) {f : ℂ → ℂ} + (hf : AnalyticOnNhd ℂ f U) (hne : ∀ z ∈ U, f z ≠ 0) : + SubharmonicOn (fun z => Real.log ‖f z‖) U := by + have hcont : ContinuousOn (fun z => Real.log ‖f z‖) U := by + refine ContinuousOn.log hf.continuousOn.norm fun z hz => norm_ne_zero_iff.mpr (hne z hz) + refine ⟨hcont.upperSemicontinuousOn, fun a ha => ?_⟩ + obtain ⟨ρ, hρ, hball⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds ha) + refine hasSubmeanAt_of_forall_lt hρ fun r hr hrρ => ?_ + have hsub : closedBall a r ⊆ U := (closedBall_subset_ball hrρ).trans hball + refine ⟨(hcont.mono (sphere_subset_closedBall.trans hsub)).circleIntegrable hr.le, ?_⟩ + exact log_norm_le_circleAverage hr (hf.mono hsub) (hne a ha) + +end Holomorphic + +section MaximumPrinciple + +/-- A circle-integrable function bounded by `M` on a circle, upper semicontinuous there and strictly +below `M` at one point, has circle average strictly below `M`. -/ +theorem circleAverage_lt_of_lt {r M : ℝ} (hr : 0 < r) (hint : CircleIntegrable u a r) + (hle : ∀ z ∈ sphere a r, u z ≤ M) (husc : UpperSemicontinuousOn u (sphere a r)) + {z : ℂ} (hz : z ∈ sphere a r) (hlt : u z < M) : circleAverage u a r < M := by + -- a parameter in `[0, 2π)` for the point `z` + obtain ⟨θ, hθ⟩ : ∃ θ, circleMap a r θ = z := by + have : z ∈ range (circleMap a r) := by rw [range_circleMap, abs_of_pos hr]; exact hz + exact this + set θ₀ := toIcoMod two_pi_pos 0 θ with hθ₀ + have hθ₀mem : θ₀ ∈ Ico 0 (2 * π) := by simpa using toIcoMod_mem_Ico two_pi_pos 0 θ + have hθ₀z : circleMap a r θ₀ = z := by + rw [hθ₀, ← self_sub_toIcoDiv_zsmul two_pi_pos 0 θ, (periodic_circleMap a r).sub_zsmul_eq, hθ] + -- upper semicontinuity gives a small arc on which `u < M - ε` + set ε := (M - u z) / 2 with hε + have hε0 : 0 < ε := by rw [hε]; linarith + have husc' := husc z hz (u z + ε) (by linarith) + obtain ⟨δ, hδ, hδsub⟩ := Metric.mem_nhdsWithin_iff.mp husc' + have hballnhds : ball z δ ∈ 𝓝 (circleMap a r θ₀) := by + rw [hθ₀z] + exact ball_mem_nhds z hδ + obtain ⟨η, hη, hηsub⟩ := Metric.mem_nhds_iff.mp + ((continuous_circleMap a r).continuousAt.preimage_mem_nhds hballnhds) + set θ₁ := min (θ₀ + η / 2) (2 * π) with hθ₁ + have hθ₀₁ : θ₀ < θ₁ := lt_min (by linarith) hθ₀mem.2 + have hθ₁le : θ₁ ≤ 2 * π := min_le_right _ _ + have harc : ∀ x ∈ Icc θ₀ θ₁, u (circleMap a r x) ≤ M - ε := by + intro x hx + have hxη : x ∈ ball θ₀ η := by + rw [mem_ball, Real.dist_eq, abs_lt] + constructor <;> linarith [hx.1, hx.2, min_le_left (θ₀ + η / 2) (2 * π)] + have hmem : circleMap a r x ∈ ball z δ := hηsub hxη + have : u (circleMap a r x) < u z + ε := + hδsub ⟨hmem, circleMap_mem_sphere a hr.le x⟩ + linarith + -- compare integrals of the nonnegative function `M - u` + set g : ℝ → ℝ := fun x => M - u (circleMap a r x) with hg + have hgint : IntervalIntegrable g volume 0 (2 * π) := + (intervalIntegrable_const).sub ((circleIntegrable_def u a r).mp hint) + have hgnn : 0 ≤ᵐ[volume.restrict (Ioc 0 (2 * π))] g := by + refine (ae_restrict_iff' measurableSet_Ioc).mpr (Filter.Eventually.of_forall fun x _ => ?_) + exact sub_nonneg.mpr (hle _ (circleMap_mem_sphere a hr.le x)) + have hsmall : (θ₁ - θ₀) * ε ≤ ∫ x in θ₀..θ₁, g x := by + have hsub : [[θ₀, θ₁]] ⊆ [[0, 2 * π]] := by + rw [uIcc_of_le hθ₀₁.le, uIcc_of_le Real.two_pi_pos.le] + exact Icc_subset_Icc hθ₀mem.1 hθ₁le + have := intervalIntegral.integral_mono_on hθ₀₁.le intervalIntegrable_const + (hgint.mono_set hsub) fun x hx => (by linarith [harc x hx] : ε ≤ g x) + simpa using this + have hbig : ∫ x in θ₀..θ₁, g x ≤ ∫ x in (0:ℝ)..2 * π, g x := + intervalIntegral.integral_mono_interval hθ₀mem.1 hθ₀₁.le hθ₁le hgnn hgint + have hpos : 0 < ∫ x in (0:ℝ)..2 * π, g x := + (mul_pos (sub_pos.mpr hθ₀₁) hε0).trans_le (hsmall.trans hbig) + have hcalc : ∫ x in (0:ℝ)..2 * π, g x = 2 * π * (M - circleAverage u a r) := by + rw [hg, intervalIntegral.integral_sub intervalIntegrable_const + ((circleIntegrable_def u a r).mp hint), intervalIntegral.integral_const, + circleAverage_def, smul_eq_mul, smul_eq_mul, sub_zero] + field_simp + rw [hcalc] at hpos + nlinarith [Real.two_pi_pos] + +/-- A subharmonic function attaining its supremum at a point is constant near that point. -/ +theorem SubharmonicOn.eventually_eq_of_isMaxOn (hU : IsOpen U) (hu : SubharmonicOn u U) + (ha : a ∈ U) (hmax : ∀ z ∈ U, u z ≤ u a) : ∀ᶠ z in 𝓝 a, u z = u a := by + obtain ⟨ρ₁, hρ₁, hsub⟩ := (hu.hasSubmeanAt ha).exists_forall_lt + obtain ⟨ρ₂, hρ₂, hball⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds ha) + filter_upwards [ball_mem_nhds a (lt_min hρ₁ hρ₂)] with z hz + by_cases hza : z = a + · rw [hza] + · have hr0 : 0 < dist z a := dist_pos.mpr hza + have hrρ₁ : dist z a < ρ₁ := (mem_ball.mp hz).trans_le (min_le_left _ _) + have hsph : sphere a (dist z a) ⊆ U := fun w hw => hball (by + rw [mem_ball, mem_sphere.mp hw] + exact (mem_ball.mp hz).trans_le (min_le_right _ _)) + obtain ⟨hint, havg⟩ := hsub _ hr0 hrρ₁ + by_contra hne + have hzs : z ∈ sphere a (dist z a) := mem_sphere.mpr rfl + have hlt : u z < u a := lt_of_le_of_ne (hmax z (hsph hzs)) hne + have := circleAverage_lt_of_lt hr0 hint (fun w hw => hmax w (hsph hw)) (hu.1.mono hsph) hzs hlt + linarith + +/-- **Maximum principle.** A subharmonic function on a preconnected open set that attains +its supremum at a point is constant. -/ +theorem SubharmonicOn.eqOn_const_of_isMaxOn (hU : IsOpen U) (hc : IsPreconnected U) + (hu : SubharmonicOn u U) (ha : a ∈ U) (hmax : ∀ z ∈ U, u z ≤ u a) : + ∀ z ∈ U, u z = u a := by + let W := U ∩ {z | ∀ᶠ w in 𝓝 z, u w = u a} + have hWo : IsOpen W := hU.inter isOpen_setOfPred_eventually_nhds + have hWne : (U ∩ W).Nonempty := ⟨a, ha, ha, hu.eventually_eq_of_isMaxOn hU ha hmax⟩ + have hWval : ∀ w ∈ W, u w = u a := fun w hw => (mem_ofPred.mp hw.2).self_of_nhds + have hcl : closure W ∩ U ⊆ W := by + rintro z ⟨hz, hzU⟩ + have hle : u a ≤ u z := by + by_contra hlt + push Not at hlt + have hne : NeBot (𝓝[W] z) := mem_closure_iff_nhdsWithin_neBot.mp hz + have h1 : ∀ᶠ w in 𝓝[W] z, u w < u a := + nhdsWithin_mono z inter_subset_left (hu.1 z hzU (u a) hlt) + have h2 : ∀ᶠ w in 𝓝[W] z, u w = u a := eventually_nhdsWithin_of_forall hWval + obtain ⟨w, hw1, hw2⟩ := (h1.and h2).exists + linarith + have heq : u z = u a := le_antisymm (hmax z hzU) hle + refine ⟨hzU, ?_⟩ + have := hu.eventually_eq_of_isMaxOn hU hzU (fun w hw => (hmax w hw).trans heq.ge) + change ∀ᶠ w in 𝓝 z, u w = u a + simpa only [heq] using this + intro z hz + exact hWval z (hc.subset_of_closure_inter_subset hWo hWne hcl hz) + +/-- **Maximum principle on a disc.** A function subharmonic on an open disc and upper +semicontinuous on the closed disc is bounded by any bound valid on the boundary circle. -/ +theorem SubharmonicOn.le_of_le_sphere {r M : ℝ} (hr : 0 < r) (hu : SubharmonicOn u (ball a r)) + (husc : UpperSemicontinuousOn u (closedBall a r)) (hM : ∀ z ∈ sphere a r, u z ≤ M) : + ∀ z ∈ closedBall a r, u z ≤ M := by + obtain ⟨z₀, hz₀, hmax⟩ := + husc.exists_isMaxOn (nonempty_closedBall.mpr hr.le) (isCompact_closedBall a r) + suffices h : u z₀ ≤ M from fun z hz => (hmax hz).trans h + by_cases hs : z₀ ∈ sphere a r + · exact hM z₀ hs + · have hz₀b : z₀ ∈ ball a r := by + rw [mem_closedBall] at hz₀ + exact mem_ball.mpr (lt_of_le_of_ne hz₀ fun h => hs (mem_sphere.mpr h)) + have hconst := hu.eqOn_const_of_isMaxOn isOpen_ball isPreconnected_ball hz₀b + fun z hz => hmax (ball_subset_closedBall hz) + obtain ⟨p, hp⟩ : (sphere a r).Nonempty := NormedSpace.sphere_nonempty.mpr hr.le + have hpcl : p ∈ closedBall a r := sphere_subset_closedBall hp + have hle : u z₀ ≤ u p := by + by_contra hlt + push Not at hlt + have hne : NeBot (𝓝[ball a r] p) := mem_closure_iff_nhdsWithin_neBot.mp (by + rw [closure_ball a hr.ne'] + exact hpcl) + have h1 : ∀ᶠ w in 𝓝[ball a r] p, u w < u z₀ := + nhdsWithin_mono p ball_subset_closedBall (husc p hpcl (u z₀) hlt) + have h2 : ∀ᶠ w in 𝓝[ball a r] p, u w = u z₀ := eventually_nhdsWithin_of_forall hconst + obtain ⟨w, hw1, hw2⟩ := (h1.and h2).exists + linarith + exact hle.trans (hM p hp) + +end MaximumPrinciple + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic/Majorant.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic/Majorant.lean new file mode 100644 index 0000000000..dd67146e95 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic/Majorant.lean @@ -0,0 +1,206 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.Deriv.Polynomial +public import Mathlib.Analysis.Fourier.AddCircle +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic + +/-! +# Harmonic polynomial majorants and the submean inequality + +Real parts of complex polynomials in `(z - a) / r` are harmonic and approximate every continuous +function on the circle of radius `r` about `a` uniformly, by density of trigonometric +polynomials. Consequently a continuous function satisfies the submean inequality on a closed +disc as soon as it lies below the center value of every such harmonic polynomial that dominates +it on the boundary circle. + +Combined with the maximum principle on discs, this gives the submean inequality on every closed +disc in the domain for continuous subharmonic functions, whose definition only asks for the +inequality on small circles. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Section 2; +[Ransford][Ransford1995] (1995), Chapter 2. + +## Main results + +* `le_circleAverage_of_forall_polynomial_majorant`: **Harmonic-majorant criterion.** A function + continuous on a circle whose center value is dominated by the center value of every harmonic + polynomial majorant on the circle satisfies the submean inequality. +* `SubharmonicOn.le_circleAverage_of_continuousOn`: **Submean inequality on closed discs.** A + continuous subharmonic function satisfies the submean inequality on every closed disc contained in + its domain. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [T. Ransford, *Potential Theory in the Complex Plane*][Ransford1995] +-/ + +public section + +open Filter Metric Set Real +open scoped Topology + +namespace SeveralComplexVariables + +/-- Every trigonometric polynomial is the sum of a polynomial and a conjugated polynomial in the +circle variable. -/ +theorem exists_polynomial_of_mem_span_fourier (ψ : C(AddCircle (2 * π), ℂ)) + (hψ : ψ ∈ Submodule.span ℂ (Set.range (fourier (T := 2 * π)))) : + ∃ Q₁ Q₂ : Polynomial ℂ, ∀ x : AddCircle (2 * π), + ψ x = Q₁.eval ((AddCircle.toCircle x : Circle) : ℂ) + + (starRingEnd ℂ) (Q₂.eval ((AddCircle.toCircle x : Circle) : ℂ)) := by + induction hψ using Submodule.span_induction with + | mem ψ hψ => + obtain ⟨n, rfl⟩ := hψ + rcases le_or_gt 0 n with hn | hn + · refine ⟨Polynomial.X ^ n.toNat, 0, fun x => ?_⟩ + simp only [fourier_apply, AddCircle.toCircle_zsmul, Circle.coe_zpow, Polynomial.eval_pow, + Polynomial.eval_X, Polynomial.eval_zero, map_zero, add_zero] + rw [← zpow_natCast, Int.toNat_of_nonneg hn] + · set m := (-n).toNat with hmdef + refine ⟨0, Polynomial.X ^ m, fun x => ?_⟩ + simp only [fourier_apply, AddCircle.toCircle_zsmul, Polynomial.eval_pow, Polynomial.eval_X, + Polynomial.eval_zero, zero_add] + have hm : (n : ℤ) = -(m : ℤ) := by + rw [hmdef, Int.toNat_of_nonneg (neg_nonneg.mpr hn.le), neg_neg] + rw [hm, zpow_neg, zpow_natCast, Circle.coe_inv_eq_conj, Circle.coe_pow] + | zero => exact ⟨0, 0, fun x => by simp⟩ + | add ψ₁ ψ₂ _ _ ih₁ ih₂ => + obtain ⟨Q₁, Q₂, h₁⟩ := ih₁ + obtain ⟨Q₃, Q₄, h₂⟩ := ih₂ + refine ⟨Q₁ + Q₃, Q₂ + Q₄, fun x => ?_⟩ + simp only [ContinuousMap.add_apply, h₁, h₂, Polynomial.eval_add, map_add] + ring + | smul c ψ _ ih => + obtain ⟨Q₁, Q₂, h⟩ := ih + refine ⟨Polynomial.C c * Q₁, Polynomial.C ((starRingEnd ℂ) c) * Q₂, fun x => ?_⟩ + simp only [ContinuousMap.smul_apply, smul_eq_mul, h, Polynomial.eval_mul, Polynomial.eval_C, + map_mul, Complex.conj_conj] + ring + +/-- Continuous functions on a circle are uniformly approximated by real parts of polynomials in the +normalized circle variable. -/ +theorem exists_polynomial_re_approx {v : ℂ → ℝ} {a : ℂ} {r : ℝ} (hr : 0 < r) + (hv : ContinuousOn v (sphere a r)) {ε : ℝ} (hε : 0 < ε) : + ∃ Q : Polynomial ℂ, ∀ z ∈ sphere a r, |v z - (Q.eval ((z - a) / r)).re| < ε := by + have hpos : (0 : ℝ) < 2 * π := Real.two_pi_pos + have : Fact (0 < 2 * π) := ⟨hpos⟩ + let e : AddCircle (2 * π) → ℂ := fun x => a + r * (AddCircle.toCircle x : ℂ) + have he_cont : Continuous e := by + have := continuous_subtype_val.comp (AddCircle.continuous_toCircle (T := 2 * π)) + fun_prop + have he_mem : ∀ x, e x ∈ sphere a r := fun x => by + simp [e, abs_of_pos hr] + let φ : C(AddCircle (2 * π), ℂ) := + ⟨fun x => (v (e x) : ℂ), Complex.continuous_ofReal.comp (hv.comp_continuous he_cont he_mem)⟩ + have hφ : φ ∈ closure ((Submodule.span ℂ (Set.range (fourier (T := 2 * π)))) : Set _) := by + rw [← Submodule.topologicalClosure_coe, span_fourier_closure_eq_top] + trivial + obtain ⟨ψ, hψ, hdist⟩ := Metric.mem_closure_iff.mp hφ ε hε + obtain ⟨Q₁, Q₂, hQ⟩ := exists_polynomial_of_mem_span_fourier ψ hψ + refine ⟨Q₁ + Q₂, fun z hz => ?_⟩ + -- a parameter for the point `z` + obtain ⟨θ, hθ⟩ : ∃ θ : ℝ, circleMap a r θ = z := by + have : z ∈ Set.range (circleMap a r) := by rw [range_circleMap, abs_of_pos hr]; exact hz + exact this + set x : AddCircle (2 * π) := (θ : AddCircle (2 * π)) with hx + have hex : e x = z := by + rw [← hθ] + simp only [e, hx, AddCircle.toCircle_apply_mk, Circle.coe_exp, circleMap] + congr 3 + field_simp + have hr' : (r : ℂ) ≠ 0 := by exact_mod_cast hr.ne' + have hz' : (z - a) / r = (AddCircle.toCircle x : ℂ) := by + rw [← hex] + simp only [e] + rw [add_sub_cancel_left, mul_div_cancel_left₀ _ hr'] + have hre : (ψ x).re = ((Q₁ + Q₂).eval ((z - a) / r)).re := by + rw [hQ x, hz', Polynomial.eval_add, Complex.add_re, Complex.add_re, Complex.conj_re] + have h1 : v z = (φ x).re := by simp [φ, hex] + rw [h1, ← hre] + have := (ContinuousMap.dist_lt_iff hε).mp hdist x + rw [dist_eq_norm] at this + calc |(φ x).re - (ψ x).re| = |(φ x - ψ x).re| := by rw [Complex.sub_re] + _ ≤ ‖φ x - ψ x‖ := Complex.abs_re_le_norm _ + _ < ε := this + +/-- The real part of a polynomial in the normalized circle variable has circle average equal to its +value at the center. -/ +theorem circleAverage_re_polynomial (Q : Polynomial ℂ) (a : ℂ) {r : ℝ} (hr : 0 < r) : + circleAverage (fun z => (Q.eval ((z - a) / r)).re) a r = (Q.eval 0).re := by + have hd : Differentiable ℂ fun z : ℂ => Q.eval ((z - a) / r) := + Q.differentiable.comp (by fun_prop) + have hcl : DiffContOnCl ℂ (fun z : ℂ => Q.eval ((z - a) / r)) (ball a |r|) := + hd.diffContOnCl + have hint : CircleIntegrable (fun z : ℂ => Q.eval ((z - a) / r)) a r := + hd.continuous.continuousOn.circleIntegrable hr.le + have := Complex.reCLM.circleAverage_comp_comm (f := fun z : ℂ => Q.eval ((z - a) / r)) + (c := a) (R := r) hint + simp only [Function.comp_def, Complex.reCLM_apply] at this + rw [this, hcl.circleAverage] + simp + +/-- **Harmonic-majorant criterion.** A function continuous on a circle whose center value is +dominated by the center value of every harmonic polynomial majorant on the circle satisfies +the submean inequality. -/ +theorem le_circleAverage_of_forall_polynomial_majorant {v : ℂ → ℝ} {a : ℂ} {r : ℝ} (hr : 0 < r) + (hv : ContinuousOn v (sphere a r)) + (h : ∀ Q : Polynomial ℂ, (∀ z ∈ sphere a r, v z ≤ (Q.eval ((z - a) / r)).re) → + v a ≤ (Q.eval 0).re) : + v a ≤ circleAverage v a r := by + have hint : CircleIntegrable v a r := hv.circleIntegrable hr.le + refine le_of_forall_pos_le_add fun ε hε => ?_ + obtain ⟨Q, hQ⟩ := exists_polynomial_re_approx hr hv (half_pos hε) + have hQre : ∀ z, ((Q + Polynomial.C (ε / 2 : ℂ)).eval ((z - a) / r)).re = + (Q.eval ((z - a) / r)).re + ε / 2 := fun z => by + simp [Polynomial.eval_add] + have hmaj : ∀ z ∈ sphere a r, v z ≤ ((Q + Polynomial.C (ε / 2 : ℂ)).eval ((z - a) / r)).re := by + intro z hz + rw [hQre] + linarith [(abs_lt.mp (hQ z hz)).2] + have h1 := h _ hmaj + rw [Polynomial.eval_add, Polynomial.eval_C, Complex.add_re] at h1 + have hcont : ContinuousOn (fun z => (Q.eval ((z - a) / r)).re) (sphere a r) := + (Complex.continuous_re.comp (Q.differentiable.comp (by fun_prop)).continuous).continuousOn + have h2 : circleAverage (fun z => (Q.eval ((z - a) / r)).re) a r ≤ + circleAverage (fun z => v z + ε / 2) a r := by + refine circleAverage_mono (hcont.circleIntegrable hr.le) + (hint.add (circleIntegrable_const _ a r)) fun z hz => ?_ + have := (abs_lt.mp (hQ z (by simpa [abs_of_pos hr] using hz))).1 + linarith + rw [circleAverage_re_polynomial Q a hr] at h2 + rw [circleAverage_fun_add hint (circleIntegrable_const _ a r), circleAverage_const] at h2 + have h3 : ((ε / 2 : ℂ)).re = ε / 2 := by simp + linarith + +/-- **Submean inequality on closed discs.** A continuous subharmonic function satisfies the +submean inequality on every closed disc contained in its domain. -/ +theorem SubharmonicOn.le_circleAverage_of_continuousOn {u : ℂ → ℝ} {U : Set ℂ} + (hu : SubharmonicOn u U) (hc : ContinuousOn u U) {a : ℂ} {r : ℝ} (hr : 0 < r) + (hsub : closedBall a r ⊆ U) : u a ≤ circleAverage u a r := by + refine le_circleAverage_of_forall_polynomial_majorant hr + (hc.mono (sphere_subset_closedBall.trans hsub)) fun Q hQ => ?_ + have hQan : AnalyticOnNhd ℂ (fun z : ℂ => Q.eval ((z - a) / r)) (ball a r) := + fun z _ => (Q.differentiable.comp (by fun_prop)).analyticAt z + have hw : SubharmonicOn (fun z => u z + -(Q.eval ((z - a) / r)).re) (ball a r) := + (hu.mono (ball_subset_closedBall.trans hsub)).add + (AnalyticOnNhd.subharmonicOn_neg_re hQan) + have husc : UpperSemicontinuousOn (fun z => u z + -(Q.eval ((z - a) / r)).re) + (closedBall a r) := + ((hc.mono hsub).add (Complex.continuous_re.comp + (Q.differentiable.comp (by fun_prop)).continuous).continuousOn.neg).upperSemicontinuousOn + have := hw.le_of_le_sphere hr husc (M := 0) (fun z hz => by linarith [hQ z hz]) a + (mem_closedBall_self hr.le) + have h0 : ((a - a) / r) = 0 := by simp + rw [h0] at this + linarith + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic/SmoothCriterion.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic/SmoothCriterion.lean new file mode 100644 index 0000000000..65e4989615 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Subharmonic/SmoothCriterion.lean @@ -0,0 +1,407 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Calculus.FDeriv.Symmetric +public import Mathlib.Analysis.InnerProductSpace.Laplacian +public import Mathlib.Analysis.SpecialFunctions.Integrals.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analysis.TaylorBounds +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Subharmonic.Majorant + +/-! +# The Laplacian criterion for subharmonicity + +A `C²` function of one complex variable is subharmonic exactly when its Laplacian is +nonnegative. The proof expands the circle average of a `C²` function to second order: the +difference between the circle average of radius `r` and the center value is `r ^ 2 / 4` times +the Laplacian, up to `o(r ^ 2)`. A positive Laplacian therefore gives the strict submean +inequality on small circles and a negative one the reverse inequality. The nonstrict direction +adds a small multiple of `‖z - t₀‖ ^ 2`, whose Laplacian is `4`, and uses the submean inequality +on closed discs for continuous subharmonic functions. + +The Laplacian is Mathlib's `InnerProductSpace` Laplacian on `ℂ`, written in terms of the second +Fréchet derivative in the directions `1` and `I`. + +References: [Fritzsche–Grauert][FritzscheGrauert2002] (2002), Chapter II, Theorem 2.8; +[Hörmander][Hormander1973] (1973), Section 1.6 and Theorem 2.6.2. + +## Main results + +* `exists_taylor_bound`: **Uniform second-order Taylor bound.** For a `C²` function on a real normed + space, the second-order Taylor remainder at a point is bounded by `ε ‖h‖ ^ 2` for all small + increments `h`. +* `exists_circleAverage_sub_le`: **Second-order expansion of circle averages.** For a `C²` function, + the circle average of radius `r` differs from the center value by `r ^ 2 / 4` times the Laplacian, + up to `ε r ^ 2` for all small `r`. +* `HasSubmeanAt.laplacian_nonneg`: **Necessity.** A `C²` subharmonic function has nonnegative + Laplacian. +* `subharmonicOn_of_laplacian_nonneg`: **Sufficiency.** A `C²` function with nonnegative Laplacian + on an open set is subharmonic. + +## References + +* [K. Fritzsche and H. Grauert, *From Holomorphic Functions to Complex + Manifolds*][FritzscheGrauert2002] +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +-/ + +public section + +open Complex Filter MeasureTheory Metric Set Real +open scoped Topology InnerProductSpace Laplacian + +namespace SeveralComplexVariables + +variable {g : ℂ → ℝ} {t₀ : ℂ} + +/-- The Laplacian on `ℂ` in terms of the iterated Fréchet derivative. -/ +theorem laplacian_eq_fderiv_fderiv (g : ℂ → ℝ) (t : ℂ) : + Δ g t = fderiv ℝ (fderiv ℝ g) t 1 1 + fderiv ℝ (fderiv ℝ g) t I I := by + rw [InnerProductSpace.laplacian_eq_iteratedFDeriv_complexPlane] + simp [iteratedFDeriv_two_apply] + +/-- A point on the circle of radius `r` about `0`, as a real combination of `1` and `I`. -/ +theorem circleMap_zero_eq_smul (r θ : ℝ) : + circleMap 0 r θ = (r * Real.cos θ) • (1 : ℂ) + (r * Real.sin θ) • I := by + simp only [circleMap, zero_add, Complex.exp_mul_I, Complex.real_smul] + push_cast + ring + +/-- **Uniform second-order Taylor bound.** For a `C²` function on a real normed space, the +second-order Taylor remainder at a point is bounded by `ε ‖h‖ ^ 2` for all small increments +`h`. The bound is uniform in the direction of `h`. -/ +theorem exists_taylor_bound {G : Type*} [NormedAddCommGroup G] [NormedSpace ℝ G] {g : G → ℝ} + {t₀ : G} (hg : ContDiffAt ℝ 2 g t₀) {ε : ℝ} (hε : 0 < ε) : + ∃ δ > 0, ∀ h : G, ‖h‖ < δ → + |g (t₀ + h) - g t₀ - fderiv ℝ g t₀ h - (1 / 2) * fderiv ℝ (fderiv ℝ g) t₀ h h| + ≤ ε * ‖h‖ ^ 2 := by + set D := fderiv ℝ g with hDdef + set B := fderiv ℝ (fderiv ℝ g) t₀ with hBdef + have hD : HasFDerivAt D B t₀ := + ((hg.fderiv_right (m := 1) (by norm_num)).differentiableAt (by norm_num)).hasFDerivAt + have hev : ∀ᶠ y in 𝓝 t₀, HasFDerivAt g (D y) y := by + filter_upwards [hg.eventually (by simp)] with y hy + exact (hy.differentiableAt (by norm_num)).hasFDerivAt + have hsymm : ∀ v w, B v w = B w v := second_derivative_symmetric_of_eventually hev hD + have hlo : ∀ᶠ h in 𝓝 (0 : G), ‖D (t₀ + h) - D t₀ - B h‖ ≤ ε * ‖h‖ := + (hasFDerivAt_iff_isLittleO_nhds_zero.mp hD).def hε + obtain ⟨δ₁, hδ₁, hball₁⟩ := Metric.mem_nhds_iff.mp hlo + obtain ⟨δ₂, hδ₂, hball₂⟩ := Metric.mem_nhds_iff.mp hev + refine ⟨min δ₁ δ₂, lt_min hδ₁ hδ₂, fun h hh => ?_⟩ + set φ : G → ℝ := fun k => g (t₀ + k) - g t₀ - D t₀ k - (1 / 2) * B k k with hφdef + have hφ' : ∀ k : G, ‖k‖ < min δ₁ δ₂ → HasFDerivAt φ (D (t₀ + k) - D t₀ - B k) k := by + intro k hk + have hk₂ : t₀ + k ∈ ball t₀ δ₂ := by + simpa [dist_eq_norm] using hk.trans_le (min_le_right _ _) + have h1 : HasFDerivAt (fun k => g (t₀ + k)) (D (t₀ + k)) k := + ((hball₂ hk₂).comp k ((hasFDerivAt_id k).const_add t₀)).congr_fderiv + (ContinuousLinearMap.comp_id _) + have h2 : HasFDerivAt (fun k => D t₀ k) (D t₀) k := (D t₀).hasFDerivAt + have h3 : HasFDerivAt (fun k => (1 / 2 : ℝ) * B k k) (B k) k := by + have hb := (B.hasFDerivAt (x := k)).clm_apply (hasFDerivAt_id k) + have := hb.const_mul (1 / 2 : ℝ) + refine this.congr_fderiv ?_ + ext s + simp + linarith [hsymm s k] + have := (h1.sub_const (g t₀)).sub h2 |>.sub h3 + convert this using 1 + have hbound : ∀ k ∈ closedBall (0 : G) ‖h‖, ‖D (t₀ + k) - D t₀ - B k‖ ≤ ε * ‖h‖ := by + intro k hk + have hk' : ‖k‖ ≤ ‖h‖ := by simpa using hk + have hk₁ : k ∈ ball (0 : G) δ₁ := by + simpa using hk'.trans_lt (hh.trans_le (min_le_left _ _)) + exact (hball₁ hk₁).trans (mul_le_mul_of_nonneg_left hk' hε.le) + have hmvt := Convex.norm_image_sub_le_of_norm_hasFDerivWithin_le + (f := φ) (f' := fun k => D (t₀ + k) - D t₀ - B k) (s := closedBall (0 : G) ‖h‖) + (fun k hk => (hφ' k (by + have hk' : ‖k‖ ≤ ‖h‖ := by simpa using hk + exact hk'.trans_lt hh)).hasFDerivWithinAt) + hbound (convex_closedBall _ _) (mem_closedBall_self (norm_nonneg h)) + (mem_closedBall_zero_iff.mpr le_rfl) + have hφ0 : φ 0 = 0 := by simp [hφdef] + rw [hφ0, sub_zero, sub_zero, Real.norm_eq_abs] at hmvt + calc |g (t₀ + h) - g t₀ - fderiv ℝ g t₀ h - (1 / 2) * fderiv ℝ (fderiv ℝ g) t₀ h h| + = |φ h| := rfl + _ ≤ ε * ‖h‖ * ‖h‖ := hmvt + _ = ε * ‖h‖ ^ 2 := by ring + +/-- The integral of the cosine over a period vanishes. -/ +private theorem integral_cos_two_pi : ∫ θ in (0 : ℝ)..2 * π, Real.cos θ = 0 := by + simp [integral_cos] + +/-- The integral of the sine over a period vanishes. -/ +private theorem integral_sin_two_pi : ∫ θ in (0 : ℝ)..2 * π, Real.sin θ = 0 := by + simp [integral_sin] + +/-- The integral of the squared cosine over a period is `π`. -/ +private theorem integral_cos_sq_two_pi : ∫ θ in (0 : ℝ)..2 * π, Real.cos θ ^ 2 = π := by + rw [integral_cos_sq] + simp + +/-- The integral of the squared sine over a period is `π`. -/ +private theorem integral_sin_sq_two_pi : ∫ θ in (0 : ℝ)..2 * π, Real.sin θ ^ 2 = π := by + rw [integral_sin_sq] + simp + +/-- The integral of `sin θ cos θ` over a period vanishes. -/ +private theorem integral_sin_mul_cos_two_pi : + ∫ θ in (0 : ℝ)..2 * π, Real.sin θ * Real.cos θ = 0 := by + rw [integral_sin_mul_cos₁] + simp + +/-- The circle integral of a real-linear form vanishes. -/ +theorem integral_clm_circleMap_zero (L : ℂ →L[ℝ] ℝ) (r : ℝ) : + ∫ θ in (0 : ℝ)..2 * π, L (circleMap 0 r θ) = 0 := by + have : (fun θ => L (circleMap 0 r θ)) = + fun θ => (r * L 1) * Real.cos θ + (r * L I) * Real.sin θ := by + funext θ + rw [circleMap_zero_eq_smul, map_add, map_smul, map_smul, smul_eq_mul, smul_eq_mul] + ring + rw [this, intervalIntegral.integral_add, intervalIntegral.integral_const_mul, + intervalIntegral.integral_const_mul, integral_cos_two_pi, integral_sin_two_pi] + · ring + · exact (continuous_const.mul Real.continuous_cos).intervalIntegrable _ _ + · exact (continuous_const.mul Real.continuous_sin).intervalIntegrable _ _ + +/-- The circle integral of a real bilinear form on the diagonal is `π r ^ 2` times its trace in the +directions `1` and `I`. -/ +theorem integral_bilinear_circleMap (B : ℂ →L[ℝ] ℂ →L[ℝ] ℝ) (r : ℝ) : + ∫ θ in (0 : ℝ)..2 * π, B (circleMap 0 r θ) (circleMap 0 r θ) = + π * r ^ 2 * (B 1 1 + B I I) := by + have : (fun θ => B (circleMap 0 r θ) (circleMap 0 r θ)) = + fun θ => (r ^ 2 * B 1 1) * Real.cos θ ^ 2 + (r ^ 2 * (B 1 I + B I 1)) * + (Real.sin θ * Real.cos θ) + (r ^ 2 * B I I) * Real.sin θ ^ 2 := by + funext θ + rw [circleMap_zero_eq_smul] + simp only [map_add, map_smul, add_apply, smul_apply, smul_eq_mul] + ring + rw [this, intervalIntegral.integral_add, intervalIntegral.integral_add, + intervalIntegral.integral_const_mul, intervalIntegral.integral_const_mul, + intervalIntegral.integral_const_mul, integral_cos_sq_two_pi, integral_sin_mul_cos_two_pi, + integral_sin_sq_two_pi] + · ring + · exact (continuous_const.mul (Real.continuous_cos.pow 2)).intervalIntegrable _ _ + · exact (continuous_const.mul (Real.continuous_sin.mul Real.continuous_cos)).intervalIntegrable + _ _ + · exact ((continuous_const.mul (Real.continuous_cos.pow 2)).add + (continuous_const.mul (Real.continuous_sin.mul Real.continuous_cos))).intervalIntegrable _ _ + · exact (continuous_const.mul (Real.continuous_sin.pow 2)).intervalIntegrable _ _ + +/-- **Second-order expansion of circle averages.** For a `C²` function, the circle average +of radius `r` differs from the center value by `r ^ 2 / 4` times the Laplacian, up to +`ε r ^ 2` for all small `r`. -/ +theorem exists_circleAverage_sub_le (hg : ContDiffAt ℝ 2 g t₀) {ε : ℝ} (hε : 0 < ε) : + ∃ δ > 0, ∀ r, 0 < r → r < δ → CircleIntegrable g t₀ r ∧ + |circleAverage g t₀ r - g t₀ - r ^ 2 / 4 * Δ g t₀| ≤ ε * r ^ 2 := by + obtain ⟨δ₁, hδ₁, htaylor⟩ := exists_taylor_bound hg hε + obtain ⟨δ₂, hδ₂, hcont⟩ := Metric.mem_nhds_iff.mp (hg.eventually (by simp)) + have hgc : ContinuousOn g (ball t₀ δ₂) := fun y hy => + (show ContDiffAt ℝ 2 g y from hcont hy).continuousAt.continuousWithinAt + refine ⟨min δ₁ δ₂, lt_min hδ₁ hδ₂, fun r hr hrδ => ?_⟩ + set D := fderiv ℝ g with hDdef + set B := fderiv ℝ (fderiv ℝ g) t₀ with hBdef + have hmap : ∀ θ : ℝ, circleMap t₀ r θ = t₀ + circleMap 0 r θ := fun θ => by + simp [circleMap] + have hnorm : ∀ θ : ℝ, ‖circleMap 0 r θ‖ = r := fun θ => by + simp [circleMap, abs_of_pos hr] + have hint : CircleIntegrable g t₀ r := by + refine ContinuousOn.circleIntegrable hr.le (hgc.mono fun z hz => ?_) + exact sphere_subset_closedBall.trans (closedBall_subset_ball (hrδ.trans_le (min_le_right _ + _))) hz + refine ⟨hint, ?_⟩ + -- the remainder as a function of the angle + set R : ℝ → ℝ := fun θ => g (t₀ + circleMap 0 r θ) - g t₀ - D t₀ (circleMap 0 r θ) - + (1 / 2) * B (circleMap 0 r θ) (circleMap 0 r θ) with hRdef + have hRle : ∀ θ, |R θ| ≤ ε * r ^ 2 := fun θ => by + have := htaylor (circleMap 0 r θ) (by rw [hnorm]; exact hrδ.trans_le (min_le_left _ _)) + rwa [hnorm] at this + have hRint : ‖∫ θ in (0 : ℝ)..2 * π, R θ‖ ≤ ε * r ^ 2 * |2 * π - 0| := + intervalIntegral.norm_integral_le_of_norm_le_const fun θ _ => by + rw [Real.norm_eq_abs]; exact hRle θ + rw [sub_zero, abs_of_pos Real.two_pi_pos, Real.norm_eq_abs] at hRint + -- integrability of the pieces + have hcm : Continuous fun θ : ℝ => circleMap 0 r θ := continuous_circleMap 0 r + have hi₁ : IntervalIntegrable (fun θ => g (t₀ + circleMap 0 r θ)) volume 0 (2 * π) := by + have := (circleIntegrable_def g t₀ r).mp hint + simpa only [hmap] using this + have hi₂ : IntervalIntegrable (fun θ => D t₀ (circleMap 0 r θ)) volume 0 (2 * π) := + ((D t₀).continuous.comp hcm).intervalIntegrable _ _ + have hi₃ : IntervalIntegrable (fun θ => (1 / 2 : ℝ) * B (circleMap 0 r θ) (circleMap 0 r θ)) + volume 0 (2 * π) := + (continuous_const.mul (B.continuous₂.comp (hcm.prodMk hcm))).intervalIntegrable _ _ + -- the integral identity + have hsplit : ∫ θ in (0 : ℝ)..2 * π, R θ = + (∫ θ in (0 : ℝ)..2 * π, g (t₀ + circleMap 0 r θ)) - 2 * π * g t₀ - + (∫ θ in (0 : ℝ)..2 * π, D t₀ (circleMap 0 r θ)) - + ∫ θ in (0 : ℝ)..2 * π, (1 / 2 : ℝ) * B (circleMap 0 r θ) (circleMap 0 r θ) := by + simp only [hRdef] + rw [intervalIntegral.integral_sub ((hi₁.sub intervalIntegrable_const).sub hi₂) hi₃, + intervalIntegral.integral_sub (hi₁.sub intervalIntegrable_const) hi₂, + intervalIntegral.integral_sub hi₁ intervalIntegrable_const, intervalIntegral.integral_const] + simp [smul_eq_mul] + rw [integral_clm_circleMap_zero, intervalIntegral.integral_const_mul, integral_bilinear_circleMap, + sub_zero] at hsplit + have havg : circleAverage g t₀ r = (2 * π)⁻¹ * ∫ θ in (0 : ℝ)..2 * π, g (t₀ + circleMap 0 r θ) + := by + rw [circleAverage_def, smul_eq_mul] + simp only [hmap] + have hlap : Δ g t₀ = B 1 1 + B I I := laplacian_eq_fderiv_fderiv g t₀ + have hkey : circleAverage g t₀ r - g t₀ - r ^ 2 / 4 * Δ g t₀ = + (2 * π)⁻¹ * ∫ θ in (0 : ℝ)..2 * π, R θ := by + rw [havg, hlap, hsplit] + field_simp + ring + rw [hkey, abs_mul, abs_of_pos (inv_pos.mpr Real.two_pi_pos)] + calc (2 * π)⁻¹ * |∫ θ in (0 : ℝ)..2 * π, R θ| ≤ (2 * π)⁻¹ * (ε * r ^ 2 * (2 * π)) := + mul_le_mul_of_nonneg_left hRint (inv_pos.mpr Real.two_pi_pos).le + _ = ε * r ^ 2 := by field_simp + +/-- A positive Laplacian gives the strict submean inequality on all small circles. -/ +theorem eventually_lt_circleAverage_of_laplacian_pos (hg : ContDiffAt ℝ 2 g t₀) + (hΔ : 0 < Δ g t₀) : + ∀ᶠ r in 𝓝[>] (0 : ℝ), CircleIntegrable g t₀ r ∧ g t₀ < circleAverage g t₀ r := by + obtain ⟨δ, hδ, h⟩ := exists_circleAverage_sub_le hg (ε := Δ g t₀ / 8) (by positivity) + refine mem_nhdsGT_iff_exists_Ioo_subset.mpr ⟨δ, hδ, fun r hr => ?_⟩ + obtain ⟨hint, hle⟩ := h r hr.1 hr.2 + refine ⟨hint, ?_⟩ + have := (abs_le.mp hle).1 + nlinarith [sq_pos_of_pos hr.1] + +/-- A negative Laplacian gives the strict reverse inequality on all small circles. -/ +theorem eventually_circleAverage_lt_of_laplacian_neg (hg : ContDiffAt ℝ 2 g t₀) + (hΔ : Δ g t₀ < 0) : + ∀ᶠ r in 𝓝[>] (0 : ℝ), CircleIntegrable g t₀ r ∧ circleAverage g t₀ r < g t₀ := by + obtain ⟨δ, hδ, h⟩ := exists_circleAverage_sub_le hg (ε := -Δ g t₀ / 8) (by linarith) + refine mem_nhdsGT_iff_exists_Ioo_subset.mpr ⟨δ, hδ, fun r hr => ?_⟩ + obtain ⟨hint, hle⟩ := h r hr.1 hr.2 + refine ⟨hint, ?_⟩ + have := (abs_le.mp hle).2 + nlinarith [sq_pos_of_pos hr.1] + +/-- A `C²` function with positive Laplacian has the local submean property. -/ +theorem hasSubmeanAt_of_laplacian_pos (hg : ContDiffAt ℝ 2 g t₀) (hΔ : 0 < Δ g t₀) : + HasSubmeanAt g t₀ := + (eventually_lt_circleAverage_of_laplacian_pos hg hΔ).mono fun _ h => ⟨h.1, h.2.le⟩ + +/-- **Necessity.** A `C²` subharmonic function has nonnegative Laplacian. -/ +theorem HasSubmeanAt.laplacian_nonneg (hg : ContDiffAt ℝ 2 g t₀) (hs : HasSubmeanAt g t₀) : + 0 ≤ Δ g t₀ := by + by_contra hlt + push Not at hlt + obtain ⟨r, ⟨_, h₁⟩, ⟨_, h₂⟩⟩ := + ((eventually_circleAverage_lt_of_laplacian_neg hg hlt).and hs).exists + linarith + +/-- The Laplacian of the squared distance to a point is `4`. -/ +theorem laplacian_normSq_sub (t₀ t : ℂ) : Δ (fun z : ℂ => ‖z - t₀‖ ^ 2) t = 4 := by + have hq : (fun z : ℂ => ‖z - t₀‖ ^ 2) = fun z => (Complex.reCLM (z - t₀)) ^ 2 + + (Complex.imCLM (z - t₀)) ^ 2 := by + funext z + simp only [Complex.reCLM_apply, Complex.imCLM_apply, Complex.sq_norm, Complex.normSq_apply] + ring + have hD : ∀ z, HasFDerivAt (fun z : ℂ => ‖z - t₀‖ ^ 2) + ((2 * (z - t₀).re) • Complex.reCLM + (2 * (z - t₀).im) • Complex.imCLM) z := by + intro z + rw [hq] + have h1 : HasFDerivAt (fun z : ℂ => Complex.reCLM (z - t₀)) Complex.reCLM z := + Complex.reCLM.hasFDerivAt.comp z ((hasFDerivAt_id z).sub_const t₀) |>.congr_fderiv (by simp) + have h2 : HasFDerivAt (fun z : ℂ => Complex.imCLM (z - t₀)) Complex.imCLM z := + Complex.imCLM.hasFDerivAt.comp z ((hasFDerivAt_id z).sub_const t₀) |>.congr_fderiv (by simp) + have := (h1.pow 2).add (h2.pow 2) + convert this using 1 + ext s + simp [Complex.reCLM_apply, Complex.imCLM_apply] + have hfd : fderiv ℝ (fun z : ℂ => ‖z - t₀‖ ^ 2) = + fun z => (2 * (z - t₀).re) • Complex.reCLM + (2 * (z - t₀).im) • Complex.imCLM := + funext fun z => (hD z).fderiv + -- second derivative: differentiate the coefficient functions + have h1 : HasFDerivAt (fun z : ℂ => 2 * (z - t₀).re) ((2 : ℝ) • Complex.reCLM) t := by + have h := Complex.reCLM.hasFDerivAt.comp t ((hasFDerivAt_id t).sub_const t₀) + have := h.const_mul (2 : ℝ) + refine this.congr_fderiv ?_ + ext s + simp + have h2 : HasFDerivAt (fun z : ℂ => 2 * (z - t₀).im) ((2 : ℝ) • Complex.imCLM) t := by + have h := Complex.imCLM.hasFDerivAt.comp t ((hasFDerivAt_id t).sub_const t₀) + have := h.const_mul (2 : ℝ) + refine this.congr_fderiv ?_ + ext s + simp + have hD2 : HasFDerivAt (fun z : ℂ => (2 * (z - t₀).re) • Complex.reCLM + + (2 * (z - t₀).im) • Complex.imCLM) _ t := + (h1.smul_const Complex.reCLM).add (h2.smul_const Complex.imCLM) + rw [laplacian_eq_fderiv_fderiv, hfd, hD2.fderiv] + simp + norm_num + +/-- **Sufficiency.** A `C²` function with nonnegative Laplacian on an open set is subharmonic. -/ +theorem subharmonicOn_of_laplacian_nonneg {U : Set ℂ} (hU : IsOpen U) (hg : ContDiffOn ℝ 2 g U) + (hΔ : ∀ t ∈ U, 0 ≤ Δ g t) : SubharmonicOn g U := by + refine ⟨hg.continuousOn.upperSemicontinuousOn, fun a ha => ?_⟩ + obtain ⟨ρ, hρ, hball⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds ha) + refine hasSubmeanAt_of_forall_lt hρ fun r hr hrρ => ?_ + have hsub : closedBall a r ⊆ U := (closedBall_subset_ball hrρ).trans hball + have hint : CircleIntegrable g a r := + (hg.continuousOn.mono (sphere_subset_closedBall.trans hsub)).circleIntegrable hr.le + refine ⟨hint, le_of_forall_pos_le_add fun ε hε => ?_⟩ + set η : ℝ := ε / r ^ 2 with hη + have hη0 : 0 < η := div_pos hε (by positivity) + -- the perturbed function + set q : ℂ → ℝ := fun z => ‖z - a‖ ^ 2 with hqdef + have hqc : ContDiff ℝ 2 q := by + have : q = fun z : ℂ => (Complex.reCLM (z - a)) ^ 2 + (Complex.imCLM (z - a)) ^ 2 := by + funext z + simp only [hqdef, Complex.reCLM_apply, Complex.imCLM_apply, Complex.sq_norm, + Complex.normSq_apply] + ring + rw [this] + fun_prop + set gε : ℂ → ℝ := fun z => g z + η * q z with hgεdef + have hgε : ContDiffOn ℝ 2 gε U := hg.add (hqc.contDiffOn.const_smul η |>.congr fun z _ => rfl) + have hΔε : ∀ t ∈ U, 0 < Δ gε t := by + intro t ht + have h1 : ContDiffAt ℝ 2 g t := hg.contDiffAt (hU.mem_nhds ht) + have h2 : ContDiffAt ℝ 2 (fun z => η * q z) t := by + have := hqc.contDiffAt (x := t) + exact this.const_smul η |>.congr_of_eventuallyEq (Filter.Eventually.of_forall fun z => rfl) + have hadd := ContDiffAt.laplacian_add h1 h2 + have hsm : Δ (fun z => η * q z) t = η * Δ q t := by + have := InnerProductSpace.laplacian_smul (𝕜 := ℝ) η (hqc.contDiffAt (x := t)) + simpa [Pi.smul_def, smul_eq_mul] using this + have hq4 : Δ q t = 4 := laplacian_normSq_sub a t + have : Δ gε t = Δ g t + η * 4 := by + rw [hgεdef] + change Δ (g + fun z => η * q z) t = _ + rw [hadd, hsm, hq4] + rw [this] + linarith [hΔ t ht] + have hsub_ε : SubharmonicOn gε U := + ⟨hgε.continuousOn.upperSemicontinuousOn, fun t ht => + hasSubmeanAt_of_laplacian_pos (hgε.contDiffAt (hU.mem_nhds ht)) (hΔε t ht)⟩ + have hmean := hsub_ε.le_circleAverage_of_continuousOn hgε.continuousOn hr hsub + have hqint : CircleIntegrable (fun z => η * q z) a r := + (continuous_const.mul (hqc.continuous)).continuousOn.circleIntegrable hr.le + have hqavg : circleAverage (fun z => η * q z) a r = η * r ^ 2 := by + rw [circleAverage_congr_sphere (f₂ := fun _ => η * r ^ 2), circleAverage_const] + intro z hz + simp only [hqdef] + rw [abs_of_pos hr] at hz + rw [mem_sphere, dist_eq_norm] at hz + rw [hz] + have havg : circleAverage gε a r = circleAverage g a r + η * r ^ 2 := by + rw [hgεdef, circleAverage_fun_add hint hqint, hqavg] + have hga : gε a = g a := by simp [hgεdef, hqdef] + rw [havg, hga] at hmean + have hηr : η * r ^ 2 = ε := by + rw [hη] + field_simp + rw [hηr] at hmean + exact hmean + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology.lean new file mode 100644 index 0000000000..2fc154bb2c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology.lean @@ -0,0 +1,16 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.CompactExhaustion +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Frontier +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Graph +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Path +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.UpperSemicontinuous + +/-! Supporting modules for Classical several complex variables. -/ + diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/CompactExhaustion.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/CompactExhaustion.lean new file mode 100644 index 0000000000..254f7a0d4b --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/CompactExhaustion.lean @@ -0,0 +1,49 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Compactness.SigmaCompact + +/-! +# Compact exhaustions of open subsets + +## Main results + +* `IsOpen.exists_compact_exhaustion`: An open subset of a locally compact, second-countable + topological space has an increasing sequence of compact subsets containing every compact + subset of the open set in some term. The construction uses `CompactExhaustion.choice` on + the open subtype and maps its terms into the ambient space. + +In particular, the result applies to open subsets of proper metric spaces. No norm, group +structure, or nonemptiness assumption is needed. +-/ + +public section + +open Set + +/-- An open subset of a locally compact, second-countable space has an increasing compact +exhaustion containing each compact subset in some term. -/ +theorem IsOpen.exists_compact_exhaustion {E : Type*} [TopologicalSpace E] + [LocallyCompactSpace E] [SecondCountableTopology E] {U : Set E} (hU : IsOpen U) : + ∃ L : ℕ → Set E, (∀ k, IsCompact (L k)) ∧ (∀ k, L k ⊆ U) ∧ (∀ k, L k ⊆ L (k + 1)) ∧ + ∀ K, IsCompact K → K ⊆ U → ∃ k, K ⊆ L k := by + let : LocallyCompactSpace U := hU.locallyCompactSpace + let B := CompactExhaustion.choice U + refine ⟨fun k => Subtype.val '' B k, + fun k => (B.isCompact k).image continuous_subtype_val, + fun k z hz => ?_, fun k => image_mono (B.subset_succ k), fun K hK hKU => ?_⟩ + · obtain ⟨z, _, rfl⟩ := hz + exact z.property + · have hpre : IsCompact ((Subtype.val : U → E) ⁻¹' K) := by + apply Topology.IsEmbedding.subtypeVal.isCompact_iff.mpr + rwa [image_preimage_eq_of_subset (by simpa using hKU)] + obtain ⟨k, hk⟩ := B.exists_superset_of_isCompact hpre + exact ⟨k, fun z hz => ⟨⟨z, hKU hz⟩, hk hz, rfl⟩⟩ + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Frontier.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Frontier.lean new file mode 100644 index 0000000000..19631245f6 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Frontier.lean @@ -0,0 +1,28 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Closure + +/-! +# Frontier points of open sets + +## Main results + +* `IsOpen.notMem_of_mem_frontier`: A frontier point of an open set does not belong to the set. +-/ + +public section + +/-- A frontier point of an open set does not belong to the set. -/ +theorem IsOpen.notMem_of_mem_frontier {X : Type*} [TopologicalSpace X] {s : Set X} + (hs : IsOpen s) {x : X} (hx : x ∈ frontier s) : x ∉ s := by + rw [hs.frontier_eq] at hx + exact hx.2 + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Graph.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Graph.lean new file mode 100644 index 0000000000..650f635743 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Graph.lean @@ -0,0 +1,63 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Constructions +public import Mathlib.Topology.ContinuousOn +public import Mathlib.Topology.Homeomorph.Defs + +/-! +# Graphs characterized by equations + +An equation determining a unique fiber value gives uniqueness of solution maps. For a continuous +solution, projection from the zero set is a homeomorphism onto its parameter domain. Neither +result requires differentiability. + +## Main definitions + +* `Homeomorph.implicitGraph`: A continuous graph characterization makes projection a homeomorphism. + +## Main results + +* `Set.eqOn_of_forall_mem_eq_iff`: A graph characterization gives uniqueness among all solution maps + staying in the specified fiber neighborhood; no regularity assumption on the competing solution is + needed. +-/ + +public section +open Set +variable {P Q R : Type*} + +/-- A graph characterization gives uniqueness among all solution maps staying in the specified fiber +neighborhood; no regularity assumption on the competing solution is needed. -/ +theorem Set.eqOn_of_forall_mem_eq_iff {U : Set P} {V : Set Q} {f : P × Q → R} {c : R} + {g h : P → Q} (hgraph : ∀ x ∈ U, ∀ y ∈ V, f (x, y) = c ↔ y = g x) + (hh : MapsTo h U V) (hsol : ∀ x ∈ U, f (x, h x) = c) : EqOn h g U := + fun x hx => (hgraph x hx (h x) (hh hx)).mp (hsol x hx) + +variable [TopologicalSpace P] [TopologicalSpace Q] [Zero R] + +/-- A continuous graph characterization makes projection a homeomorphism. -/ +@[expose] def Homeomorph.implicitGraph {U : Set P} {V : Set Q} {f : P × Q → R} {g : P → Q} + (hg : ContinuousOn g U) (hm : MapsTo g U V) + (hgraph : ∀ x ∈ U, ∀ y ∈ V, f (x, y) = 0 ↔ y = g x) : + {p : P × Q // p ∈ U ×ˢ V ∧ f p = 0} ≃ₜ U where + toFun p := ⟨p.val.1, p.property.1.1⟩ + invFun x := ⟨(x.val, g x), ⟨⟨x.property, hm x.property⟩, + (hgraph x x.property (g x) (hm x.property)).mpr rfl⟩⟩ + left_inv p := by + apply Subtype.ext + change (p.val.1, g p.val.1) = p.val + apply Prod.ext + · rfl + · exact ((hgraph p.val.1 p.property.1.1 p.val.2 p.property.1.2).mp p.property.2).symm + right_inv x := rfl + continuous_toFun := (continuous_fst.comp continuous_subtype_val).subtype_mk _ + continuous_invFun := (continuous_subtype_val.prodMk hg.domRestrict).subtype_mk _ + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Path.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Path.lean new file mode 100644 index 0000000000..426e71627c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/Path.lean @@ -0,0 +1,46 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Order.Basic +public import Mathlib.Topology.Path + +/-! +# First exit of a path from an open set + +A path starting inside an open set and ending outside it has a positive first exit time. The +path is extended to real parameters using Mathlib’s `Path.extend`. + +## Main results + +* `Path.extend_exists_first_notMem`: First time a path starting in an open set leaves that set. +-/ + +public section + +open Set + +/-- First time a path starting in an open set leaves that set. -/ +theorem Path.extend_exists_first_notMem {X : Type*} [TopologicalSpace X] {x y : X} + (γ : Path x y) {A : Set X} (hA : IsOpen A) + (hx : γ.extend 0 ∈ A) (hy : γ.extend 1 ∉ A) : + ∃ t, t ∈ Icc (0 : ℝ) 1 ∧ γ.extend t ∉ A ∧ 0 < t ∧ + ∀ s, 0 ≤ s → s < t → γ.extend s ∈ A := by + set S : Set ℝ := Icc (0 : ℝ) 1 ∩ γ.extend ⁻¹' Aᶜ + have hSc : IsClosed S := isClosed_Icc.inter (hA.isClosed_compl.preimage γ.continuous_extend) + have hSne : S.Nonempty := ⟨1, ⟨zero_le_one, le_rfl⟩, hy⟩ + have hSbdd : BddBelow S := ⟨0, fun t ht => ht.1.1⟩ + have hsS : sInf S ∈ S := hSc.csInf_mem hSne hSbdd + have hs01 : sInf S ∈ Icc (0 : ℝ) 1 := hsS.1 + have h0S : (0 : ℝ) ∉ S := fun h => h.2 hx + have hs0 : 0 < sInf S := lt_of_le_of_ne hs01.1 fun h => h0S (h ▸ hsS) + refine ⟨sInf S, hs01, hsS.2, hs0, fun s hs0' hst => ?_⟩ + by_contra h + exact notMem_of_lt_csInf hst hSbdd ⟨⟨hs0', hst.le.trans hs01.2⟩, h⟩ + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/UpperSemicontinuous.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/UpperSemicontinuous.lean new file mode 100644 index 0000000000..499eca7be7 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/Topology/UpperSemicontinuous.lean @@ -0,0 +1,35 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Algebra.Order.Field +public import Mathlib.Topology.Semicontinuity.Basic + +/-! +# Nonnegative multiples of upper semicontinuous functions + +Multiplication by a nonnegative real constant preserves upper semicontinuity on a set. + +## Main results + +* `UpperSemicontinuousOn.const_mul`: Nonnegative multiples of upper semicontinuous functions are + upper semicontinuous. +-/ + +public section + +open Set + +/-- Nonnegative multiples of upper semicontinuous functions are upper semicontinuous. -/ +theorem UpperSemicontinuousOn.const_mul {X : Type*} [TopologicalSpace X] {f : X → ℝ} {s : Set X} + {c : ℝ} (hf : UpperSemicontinuousOn f s) (hc : 0 ≤ c) : + UpperSemicontinuousOn (fun x => c * f x) s := fun z hz => + (continuous_const.mul continuous_id).continuousAt.comp_upperSemicontinuousWithinAt + (hf z hz) (fun _ _ hxy => mul_le_mul_of_nonneg_left hxy hc) + +end + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain.lean new file mode 100644 index 0000000000..2e0de4270f --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain.lean @@ -0,0 +1,177 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Convex.Topology +public import Mathlib.Analysis.Normed.Module.Connected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.DomainOfHolomorphy +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Bochner + +/-! +# Tube domains and Bochner's tube theorem + +The tube over a real base consists of complex points whose real parts belong to that base. The +tube theorem extends functions to the tube over the real convex hull, inside the same complex +coordinate space. No abstract envelope is constructed. Connectedness of the base is essential to +the extension theorem. Banach-valued targets and empty coordinate types are retained. A +preconnected empty base is handled separately. + +Bochner extension is proved by [Hörmander][Hormander1973]'s argument: the maximal star-convex +extension tube is convex by the parabolic disc hull lemma and Thullen's continuation lemma, and +a path argument handles connected bases (`TubeDomain/Bochner`). The statement for a general +finite index type is obtained by reindexing. Uniqueness of extensions and the convex-base +characterization of tube domains of holomorphy follow. + +References: [Scheidemann][Scheidemann2005] §6.3; [Hörmander][Hormander1973] §2.5, Theorem +2.5.10. + +## Main results + +* `exists_extension_tubeDomain_convexHull`: **Bochner's tube theorem.** Every Banach-valued + holomorphic function on a tube with preconnected open base extends to the tube over its real + convex hull. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter +open scoped Topology + +namespace SeveralComplexVariables + +variable {ι : Type*} + +variable [Fintype ι] + +/-- Bochner extension for a nonempty connected base, obtained by reindexing the coordinate +proof. This is the prerequisite for the empty-inclusive public theorem below. -/ +private theorem exists_extension_tubeDomain_convexHull_nonempty {F : Type*} [NormedAddCommGroup F] + [NormedSpace ℂ F] [CompleteSpace F] {Ω : Set (ι → ℝ)} + (ho : IsOpen Ω) (hc : IsConnected Ω) {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f (tubeDomain Ω)) : + ∃ g : (ι → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain (convexHull ℝ Ω)) ∧ + EqOn g f (tubeDomain Ω) := by + set e := Fintype.equivFin ι with he + set L : (ι → ℝ) →ₗ[ℝ] (Fin (Fintype.card ι) → ℝ) := LinearMap.funLeft ℝ ℝ e.symm with hL + have hLapply : ∀ x : ι → ℝ, L x = x ∘ e.symm := fun x => rfl + have himg : L '' Ω = (fun x' : Fin (Fintype.card ι) → ℝ => x' ∘ e) ⁻¹' Ω := by + ext x' + constructor + · rintro ⟨x, hx, rfl⟩ + simpa [hLapply, Function.comp_assoc] using hx + · intro hx' + refine ⟨x' ∘ e, hx', ?_⟩ + rw [hLapply, Function.comp_assoc, e.self_comp_symm, Function.comp_id] + have hΩ'o : IsOpen (L '' Ω) := by + rw [himg] + exact ho.preimage (continuous_pi fun i => continuous_apply (e i)) + have hΩ'c : IsConnected (L '' Ω) := + hc.image L (continuous_pi fun j => continuous_apply (e.symm j)).continuousOn + have hre : ∀ (z : ι → ℂ), rePi (z ∘ e.symm) = L (rePi z) := fun z => rfl + have hre' : ∀ (z' : Fin (Fintype.card ι) → ℂ), rePi (z' ∘ e) = rePi z' ∘ e := fun z' => rfl + -- the reindexing maps are analytic + have hM : AnalyticOnNhd ℂ (fun z' : Fin (Fintype.card ι) → ℂ => z' ∘ e) univ := + (LinearMap.toContinuousLinearMap (LinearMap.funLeft ℂ ℂ e)).analyticOnNhd univ + have hM' : AnalyticOnNhd ℂ (fun z : ι → ℂ => z ∘ e.symm) univ := + (LinearMap.toContinuousLinearMap (LinearMap.funLeft ℂ ℂ e.symm)).analyticOnNhd univ + have hmaps : MapsTo (fun z' : Fin (Fintype.card ι) → ℂ => z' ∘ e) (tubeDomain (L '' Ω)) + (tubeDomain Ω) := by + intro z' hz' + rw [mem_tubeDomain, himg] at hz' + rw [mem_tubeDomain, hre'] + exact hz' + have hf' : AnalyticOnNhd ℂ (fun z' => f (z' ∘ e)) (tubeDomain (L '' Ω)) := + hf.comp (hM.mono (subset_univ _)) hmaps + obtain ⟨g', hg', hg'f⟩ := exists_extension_tubeDomain_convexHull_fin hΩ'o hΩ'c hf' + have hconv : L '' convexHull ℝ Ω = convexHull ℝ (L '' Ω) := LinearMap.image_convexHull L Ω + have hmaps' : MapsTo (fun z : ι → ℂ => z ∘ e.symm) (tubeDomain (convexHull ℝ Ω)) + (tubeDomain (convexHull ℝ (L '' Ω))) := by + intro z hz + rw [mem_tubeDomain, hre, ← hconv] + exact mem_image_of_mem L hz + refine ⟨fun z => g' (z ∘ e.symm), hg'.comp (hM'.mono (subset_univ _)) hmaps', fun z hz => ?_⟩ + have hz' : z ∘ e.symm ∈ tubeDomain (L '' Ω) := by + rw [mem_tubeDomain, hre] + exact mem_image_of_mem L hz + change g' (z ∘ e.symm) = f z + rw [hg'f hz'] + simp only [Function.comp_assoc, e.symm_comp_self, Function.comp_id] + +/-- **Bochner's tube theorem.** Every Banach-valued holomorphic function on a tube with +preconnected open base extends to the tube over its real convex hull. -/ +theorem exists_extension_tubeDomain_convexHull {F : Type*} [NormedAddCommGroup F] + [NormedSpace ℂ F] [CompleteSpace F] {Ω : Set (ι → ℝ)} + (ho : IsOpen Ω) (hc : IsPreconnected Ω) {f : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f (tubeDomain Ω)) : + ∃ g : (ι → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain (convexHull ℝ Ω)) ∧ + EqOn g f (tubeDomain Ω) := by + by_cases hn : Ω.Nonempty + · exact exists_extension_tubeDomain_convexHull_nonempty ho ⟨hn, hc⟩ hf + · have hΩ : Ω = ∅ := Set.not_nonempty_iff_eq_empty.mp hn + subst Ω + exact ⟨f, by simp [tubeDomain], by simp [tubeDomain]⟩ + +/-- Uniqueness of a tube extension to the convexified base, independently of Bochner's existence +theorem. Only a nonempty open original base is needed. -/ +theorem eqOn_of_tubeDomain_extension {F : Type*} [NormedAddCommGroup F] + [NormedSpace ℂ F] {Ω : Set (ι → ℝ)} + (ho : IsOpen Ω) (hn : Ω.Nonempty) {f g : (ι → ℂ) → F} + (hf : AnalyticOnNhd ℂ f (tubeDomain (convexHull ℝ Ω))) + (hg : AnalyticOnNhd ℂ g (tubeDomain (convexHull ℝ Ω))) + (he : EqOn f g (tubeDomain Ω)) : EqOn f g (tubeDomain (convexHull ℝ Ω)) := by + obtain ⟨a, ha⟩ := nonempty_tubeDomain hn + apply hf.eqOn_of_preconnected_of_eventuallyEq hg + (convex_tubeDomain (convex_convexHull ℝ Ω)).isPreconnected + (tubeDomain_subset_convexHull_base Ω ha) + filter_upwards [(isOpen_tubeDomain ho).mem_nhds ha] with z hz + exact he hz + +/-- The convexified tube is a common scalar extension domain, by Bochner's extension theorem, +without asserting a universal abstract envelope property. -/ +theorem isCommonAnalyticExtension_tubeDomain_convexHull {Ω : Set (ι → ℝ)} + (ho : IsOpen Ω) (hc : IsPreconnected Ω) : + IsCommonAnalyticExtension (tubeDomain Ω) (tubeDomain (convexHull ℝ Ω)) := + isCommonAnalyticExtension_of_forall (tubeDomain_subset_convexHull_base Ω) + (fun _ hf => exists_extension_tubeDomain_convexHull ho hc hf) + +/-- A tube with preconnected open base is a domain of holomorphy exactly when its base is convex. +The forward implication uses Bochner's extension theorem. -/ +theorem isDomainOfHolomorphy_tubeDomain_iff {Ω : Set (ι → ℝ)} + (ho : IsOpen Ω) (hc : IsPreconnected Ω) : + IsDomainOfHolomorphy (tubeDomain Ω) ↔ Convex ℝ Ω := by + by_cases hn : Ω.Nonempty + swap + · have hΩ : Ω = ∅ := Set.not_nonempty_iff_eq_empty.mp hn + subst Ω + exact ⟨fun _ => convex_empty, fun _ => + isDomainOfHolomorphy_of_convex (convex_tubeDomain convex_empty) (isOpen_tubeDomain ho)⟩ + constructor + · intro h + have he := h.eq_of_commonExtension (isOpen_tubeDomain ho) (nonempty_tubeDomain hn) + (isOpen_tubeDomain (ho.convexHull (𝕜 := ℝ))) + ⟨(nonempty_tubeDomain hn).mono (tubeDomain_subset_convexHull_base Ω), + (convex_tubeDomain (convex_convexHull ℝ Ω)).isPreconnected⟩ + (isCommonAnalyticExtension_tubeDomain_convexHull ho hc) + have heq : convexHull ℝ Ω = Ω := by + apply Subset.antisymm _ (_root_.subset_convexHull ℝ Ω) + intro x hx + apply ofReal_mem_tubeDomain.mp + rw [← he] + exact ofReal_mem_tubeDomain.mpr hx + rw [← heq] + exact convex_convexHull ℝ Ω + · intro h + exact isDomainOfHolomorphy_of_convex (convex_tubeDomain h) (isOpen_tubeDomain ho) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Basic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Basic.lean new file mode 100644 index 0000000000..d35025cc33 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Basic.lean @@ -0,0 +1,231 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.Analysis.Convex.Topology +public import Mathlib.Analysis.Normed.Module.Connected +public import Mathlib.Topology.Connected.PathConnected + +/-! +# Tube domains: definition and elementary geometry + +The tube over a real base consists of complex points whose real parts belong to that base. This +file contains the definition, the real and imaginary coordinate projections, and elementary +facts: tubes over open, convex or preconnected bases are open, convex or preconnected, tubes are +invariant under imaginary translations, and sup-norm balls around a point of a tube lie in the +tube when the corresponding real ball lies in the base. + +References: [Scheidemann][Scheidemann2005] §6.1; [Hörmander][Hormander1973] §2.5, Definition +2.5.9. + +## Notation + +`tubeDomain Ω` is the set of points of `ι → ℂ` whose real parts lie in `Ω`. `rePi`, `imPi`, and +`ofRealPi` are the real-part, imaginary-part, and complexification maps. + +## Main results + +`isOpen_tubeDomain`, `convex_tubeDomain`, and `isPreconnected_tubeDomain` transport openness, +convexity, and preconnectedness from the base. `tubeDomain_union` and `tubeDomain_inter` commute +with unions and intersections. `ball_subset_tubeDomain` places a sup-norm ball in the tube when +the corresponding real ball lies in the base. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Complex +open scoped Topology + +namespace SeveralComplexVariables + +variable {ι : Type*} + +/-- The tube over a real coordinate set; imaginary coordinates are unrestricted. -/ +@[expose] def tubeDomain (Ω : Set (ι → ℝ)) : Set (ι → ℂ) := + {z | (fun i => (z i).re) ∈ Ω} + +/-- The real part of a complex coordinate vector. -/ +@[expose] def rePi (z : ι → ℂ) : ι → ℝ := fun i => (z i).re + +/-- The imaginary part of a complex coordinate vector. -/ +@[expose] def imPi (z : ι → ℂ) : ι → ℝ := fun i => (z i).im + +/-- A real coordinate vector as a complex coordinate vector. -/ +@[expose] def ofRealPi (x : ι → ℝ) : ι → ℂ := fun i => (x i : ℂ) + +/-- Membership in a tube is membership of the real part in the base. -/ +theorem mem_tubeDomain {Ω : Set (ι → ℝ)} {z : ι → ℂ} : z ∈ tubeDomain Ω ↔ rePi z ∈ Ω := Iff.rfl + +/-- The real part of a real vector is the vector. -/ +@[simp] theorem rePi_ofRealPi (x : ι → ℝ) : rePi (ofRealPi x) = x := by + funext i; simp [rePi, ofRealPi] + +/-- A real vector has zero imaginary part. -/ +@[simp] theorem imPi_ofRealPi (x : ι → ℝ) : imPi (ofRealPi x) = 0 := by + funext i; simp [imPi, ofRealPi] + +/-- The real part is additive. -/ +@[simp] theorem rePi_add (z w : ι → ℂ) : rePi (z + w) = rePi z + rePi w := by + funext i; simp [rePi] + +/-- The real part respects differences. -/ +@[simp] theorem rePi_sub (z w : ι → ℂ) : rePi (z - w) = rePi z - rePi w := by + funext i; simp [rePi] + +/-- A purely imaginary vector has zero real part. -/ +@[simp] theorem rePi_I_smul_ofRealPi (y : ι → ℝ) : rePi (I • ofRealPi y) = 0 := by + funext i; simp [rePi, ofRealPi] + +/-- The real part commutes with real scalars. -/ +@[simp] theorem rePi_real_smul (t : ℝ) (z : ι → ℂ) : rePi (t • z) = t • rePi z := by + funext i; simp [rePi, Complex.real_smul] + +/-- Complexification is additive. -/ +theorem ofRealPi_add (x y : ι → ℝ) : ofRealPi (x + y) = ofRealPi x + ofRealPi y := by + funext i; simp [ofRealPi] + +/-- Complexification respects differences. -/ +theorem ofRealPi_sub (x y : ι → ℝ) : ofRealPi (x - y) = ofRealPi x - ofRealPi y := by + funext i; simp [ofRealPi] + +/-- Complexification commutes with real scalars. -/ +theorem ofRealPi_smul (t : ℝ) (x : ι → ℝ) : ofRealPi (t • x) = t • ofRealPi x := by + funext i; simp [ofRealPi, Complex.real_smul] + +/-- The complexification of zero is zero. -/ +@[simp] theorem ofRealPi_zero : ofRealPi (0 : ι → ℝ) = 0 := by + funext i; simp [ofRealPi] + +/-- Real and imaginary parts recover a complex coordinate vector. -/ +theorem ofRealPi_rePi_add_I_smul_ofRealPi_imPi (z : ι → ℂ) : + ofRealPi (rePi z) + I • ofRealPi (imPi z) = z := by + funext i + simp only [Pi.add_apply, ofRealPi, rePi, imPi, Pi.smul_apply, smul_eq_mul] + rw [mul_comm] + exact Complex.re_add_im (z i) + +/-- A real point belongs to a tube exactly when it belongs to the base. -/ +@[simp] theorem ofReal_mem_tubeDomain {Ω : Set (ι → ℝ)} {x : ι → ℝ} : + (fun i => (x i : ℂ)) ∈ tubeDomain Ω ↔ x ∈ Ω := by simp [tubeDomain] + +/-- A real vector lies in a tube exactly when it lies in the base. -/ +@[simp] theorem ofRealPi_mem_tubeDomain {Ω : Set (ι → ℝ)} {x : ι → ℝ} : + ofRealPi x ∈ tubeDomain Ω ↔ x ∈ Ω := ofReal_mem_tubeDomain + +/-- Tubes are invariant under imaginary translations. -/ +theorem add_I_smul_ofRealPi_mem_tubeDomain {Ω : Set (ι → ℝ)} {z : ι → ℂ} (y : ι → ℝ) : + z + I • ofRealPi y ∈ tubeDomain Ω ↔ z ∈ tubeDomain Ω := by + simp [mem_tubeDomain] + +/-- Tubes are monotone in their real bases. -/ +theorem tubeDomain_mono {Ω Ξ : Set (ι → ℝ)} (h : Ω ⊆ Ξ) : tubeDomain Ω ⊆ tubeDomain Ξ := + fun _ hz => h hz + +/-- Tubes commute with intersections of bases. -/ +theorem tubeDomain_inter (Ω Ξ : Set (ι → ℝ)) : + tubeDomain (Ω ∩ Ξ) = tubeDomain Ω ∩ tubeDomain Ξ := rfl + +/-- Tubes commute with unions of bases. -/ +theorem tubeDomain_union (Ω Ξ : Set (ι → ℝ)) : + tubeDomain (Ω ∪ Ξ) = tubeDomain Ω ∪ tubeDomain Ξ := rfl + +/-- Tubes commute with unions of families of bases. -/ +theorem tubeDomain_sUnion (S : Set (Set (ι → ℝ))) : + tubeDomain (⋃₀ S) = ⋃ Ω ∈ S, tubeDomain Ω := by + ext z; simp [mem_tubeDomain] + +/-- The tube over the empty base is empty. -/ +@[simp] theorem tubeDomain_empty : tubeDomain (∅ : Set (ι → ℝ)) = ∅ := rfl + +/-- The tube over the whole real space is the whole complex space. -/ +@[simp] theorem tubeDomain_univ : tubeDomain (univ : Set (ι → ℝ)) = univ := rfl + +/-- A nonempty real base has a nonempty tube. -/ +theorem nonempty_tubeDomain {Ω : Set (ι → ℝ)} (h : Ω.Nonempty) : (tubeDomain Ω).Nonempty := by + obtain ⟨x, hx⟩ := h + exact ⟨fun i => (x i : ℂ), ofReal_mem_tubeDomain.mpr hx⟩ + +/-- The real-part projection is continuous. -/ +@[fun_prop] theorem continuous_rePi : Continuous (rePi : (ι → ℂ) → ι → ℝ) := by + unfold rePi; fun_prop + +/-- The imaginary-part projection is continuous. -/ +@[fun_prop] theorem continuous_imPi : Continuous (imPi : (ι → ℂ) → ι → ℝ) := by + unfold imPi; fun_prop + +/-- Complexification is continuous. -/ +@[fun_prop] theorem continuous_ofRealPi : Continuous (ofRealPi : (ι → ℝ) → ι → ℂ) := by + unfold ofRealPi; fun_prop + +/-- The tube over an open base is open. -/ +theorem isOpen_tubeDomain {Ω : Set (ι → ℝ)} (ho : IsOpen Ω) : IsOpen (tubeDomain Ω) := + ho.preimage (by fun_prop) + +/-- Real convexity of the base implies real convexity of its tube. -/ +theorem convex_tubeDomain {Ω : Set (ι → ℝ)} (hc : Convex ℝ Ω) : Convex ℝ (tubeDomain Ω) := by + intro x hx y hy a b ha hb hab + have h := hc hx hy ha hb hab + simpa [tubeDomain, Pi.smul_def, Pi.add_def, smul_eq_mul] using h + +/-- Every tube is contained in the tube over the convex hull of its base. -/ +theorem tubeDomain_subset_convexHull_base (Ω : Set (ι → ℝ)) : + tubeDomain Ω ⊆ tubeDomain (convexHull ℝ Ω) := tubeDomain_mono (_root_.subset_convexHull ℝ Ω) + +/-- A tube is the image of the product of its base with the imaginary coordinate space. -/ +theorem tubeDomain_eq_image (Ω : Set (ι → ℝ)) : + tubeDomain Ω = (fun p : (ι → ℝ) × (ι → ℝ) => ofRealPi p.1 + I • ofRealPi p.2) '' + (Ω ×ˢ univ) := by + ext z + constructor + · intro hz + refine ⟨(rePi z, imPi z), ⟨hz, mem_univ _⟩, ?_⟩ + exact ofRealPi_rePi_add_I_smul_ofRealPi_imPi z + · rintro ⟨⟨x, y⟩, ⟨hx, -⟩, rfl⟩ + simpa [mem_tubeDomain] using hx + +/-- The tube over a preconnected base is preconnected. -/ +theorem isPreconnected_tubeDomain {Ω : Set (ι → ℝ)} (h : IsPreconnected Ω) : + IsPreconnected (tubeDomain Ω) := by + rw [tubeDomain_eq_image] + exact (h.prod isPreconnected_univ).image _ (by fun_prop : Continuous fun p : (ι → ℝ) × (ι → ℝ) => + ofRealPi p.1 + I • ofRealPi p.2).continuousOn + +section Norms + +variable [Fintype ι] + +/-- Complexification preserves the supremum norm. -/ +theorem norm_ofRealPi (x : ι → ℝ) : ‖ofRealPi x‖ = ‖x‖ := by + simp [ofRealPi, Pi.norm_def] + +/-- The real part does not increase the supremum norm. -/ +theorem norm_rePi_le (z : ι → ℂ) : ‖rePi z‖ ≤ ‖z‖ := by + rw [pi_norm_le_iff_of_nonneg (norm_nonneg _)] + intro i + exact (Complex.abs_re_le_norm (z i)).trans (norm_le_pi_norm z i) + +/-- A sup-norm ball around a point of a tube lies in the tube when the real ball around its real +part lies in the base. -/ +theorem ball_subset_tubeDomain {Ω : Set (ι → ℝ)} {z : ι → ℂ} {r : ℝ} + (h : Metric.ball (rePi z) r ⊆ Ω) : Metric.ball z r ⊆ tubeDomain Ω := by + intro w hw + apply h + rw [Metric.mem_ball, dist_eq_norm] at hw ⊢ + change ‖rePi w - rePi z‖ < r + rw [← rePi_sub] + exact (norm_rePi_le _).trans_lt hw + +end Norms + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Bochner.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Bochner.lean new file mode 100644 index 0000000000..111989ea04 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Bochner.lean @@ -0,0 +1,170 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Topology.Connected.LocallyPathConnected +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Topology.Path +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.StarConvex + +/-! +# Bochner's tube theorem for connected bases in coordinates + +Let `Ω ⊆ ℝⁿ` be open and connected, `p ∈ Ω`, and let `Ã` be the maximal star-convex extension +base with respect to `p`, which is convex. If `Ω` were not contained in `Ã`, a path in `Ω` from +`p` would leave `Ã` at a first point `x₁ ∈ Ω ∩ ∂Ã`. Every extension agrees with the original +function near the path points before `x₁`, by propagation of local agreement along the path, +hence on the tube over the convex set `à ∩ B(x₁, r)`. The two functions therefore define a +holomorphic function on the tube over `à ∪ B(x₁, r)`, which is star-convex with respect to `x₁`; +the star-convex case of the theorem extends it to the tube over the convex hull, which belongs +to the family, contradicting maximality. Hence `Ω ⊆ Ã`, and the extension to the tube over the +convex hull of `Ω` follows. + +References: [Hörmander][Hormander1973] §2.5, Theorem 2.5.10 (b); [Scheidemann][Scheidemann2005] +§6.3, Theorem 6.3.1, Step 2. + +## Main results + +* `exists_extension_tubeDomain_convexHull_fin`: **Bochner's tube theorem in coordinates.** Every + Banach-valued holomorphic function on the tube over an open connected base in `ℝⁿ` extends to the + tube over the convex hull. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Metric Complex +open scoped Topology + +namespace SeveralComplexVariables + +open BochnerTube + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- The union of an open convex set with a ball around a point of its closure is star-convex with +respect to that point. -/ +theorem starConvex_union_ball_of_mem_closure {A : Set (Fin n → ℝ)} (hA : Convex ℝ A) + (hAo : IsOpen A) {x : Fin n → ℝ} (hx : x ∈ closure A) {r : ℝ} (hr : 0 < r) : + StarConvex ℝ x (A ∪ ball x r) := by + intro y hy a b ha hb hab + rcases hy with hyA | hyB + · rcases ha.lt_or_eq with ha' | ha' + · rcases hb.lt_or_eq with hb' | hb' + · left + have hmem : a • x + b • y ∈ openSegment ℝ x y := ⟨a, b, ha', hb', hab, rfl⟩ + have hint := hA.openSegment_closure_interior_subset_interior hx + (by rwa [hAo.interior_eq] : y ∈ interior A) hmem + rwa [hAo.interior_eq] at hint + · right + subst hb' + rw [add_zero] at hab + rw [zero_smul, add_zero, hab, one_smul] + exact mem_ball_self hr + · left + subst ha' + rw [zero_add] at hab + rw [zero_smul, zero_add, hab, one_smul] + exact hyA + · right + exact (convex_ball x r) (mem_ball_self hr) hyB ha hb hab + +/-- **Bochner's tube theorem in coordinates.** Every Banach-valued holomorphic function on the +tube over an open connected base in `ℝⁿ` extends to the tube over the convex hull. -/ +theorem exists_extension_tubeDomain_convexHull_fin {Ω : Set (Fin n → ℝ)} (hΩ : IsOpen Ω) + (hc : IsConnected Ω) {f : (Fin n → ℂ) → F} (hf : AnalyticOnNhd ℂ f (tubeDomain Ω)) : + ∃ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain (convexHull ℝ Ω)) ∧ + EqOn g f (tubeDomain Ω) := by + classical + obtain ⟨p, hp⟩ := hc.nonempty + obtain ⟨r, hr, hrΩ⟩ := Metric.isOpen_iff.mp hΩ p hp + have hpà : p ∈ maxStar F Ω p := mem_maxStar_of_ball hr hrΩ + have hÃo : IsOpen (maxStar F Ω p) := isOpen_maxStar + have hÃc : Convex ℝ (maxStar F Ω p) := convex_maxStar hpà + have hΩà : Ω ⊆ maxStar F Ω p := by + by_contra hnot + obtain ⟨x₀, hx₀Ω, hx₀⟩ := not_subset.mp hnot + obtain ⟨γ, hγ⟩ := (hΩ.isConnected_iff_isPathConnected.mp hc).joinedIn p hp x₀ hx₀Ω + have hγΩ : ∀ t, γ.extend t ∈ Ω := by + intro t + have hmem : γ.extend t ∈ range γ.extend := mem_range_self t + rw [Path.extend_range] at hmem + obtain ⟨u, hu⟩ := hmem + rw [← hu] + exact hγ u + obtain ⟨t₁, ht₁I, hx₁, hs0, hprefix⟩ := + Path.extend_exists_first_notMem γ hÃo (by rw [Path.extend_zero]; exact hpÃ) + (by rw [Path.extend_one]; exact hx₀) + have hx₁Ω : γ.extend t₁ ∈ Ω := hγΩ _ + have htend : Tendsto γ.extend (𝓝[<] t₁) (𝓝 (γ.extend t₁)) := + (γ.continuous_extend.tendsto _).mono_left nhdsWithin_le_nhds + have hx₁cl : γ.extend t₁ ∈ closure (maxStar F Ω p) := by + apply mem_closure_of_tendsto htend + filter_upwards [Ioo_mem_nhdsLT hs0] with t ht + exact hprefix t ht.1.le ht.2 + obtain ⟨r₁, hr₁, hr₁Ω⟩ := Metric.isOpen_iff.mp hΩ _ hx₁Ω + have hev : ∀ᶠ t in 𝓝[<] t₁, γ.extend t ∈ ball (γ.extend t₁) r₁ := + htend (isOpen_ball.mem_nhds (mem_ball_self hr₁)) + obtain ⟨t₀, ht₀, ht₀ball⟩ := Filter.nonempty_of_mem (Filter.inter_mem (Ioo_mem_nhdsLT hs0) hev) + have ht₀à : γ.extend t₀ ∈ maxStar F Ω p := hprefix t₀ ht₀.1.le ht₀.2 + have hA₁o : IsOpen (maxStar F Ω p ∪ ball (γ.extend t₁) r₁) := hÃo.union isOpen_ball + have hA₁s : StarConvex ℝ (γ.extend t₁) (maxStar F Ω p ∪ ball (γ.extend t₁) r₁) := + starConvex_union_ball_of_mem_closure hÃc hÃo hx₁cl hr₁ + have hx₁A₁ : γ.extend t₁ ∈ maxStar F Ω p ∪ ball (γ.extend t₁) r₁ := + Or.inr (mem_ball_self hr₁) + have hBmem : convexHull ℝ (maxStar F Ω p ∪ ball (γ.extend t₁) r₁) ∈ starFamily F Ω p := by + refine ⟨hA₁o.convexHull, (convex_convexHull ℝ _).starConvex + (subset_convexHull ℝ _ (Or.inl hpÃ)), ?_⟩ + intro f₀ hf₀ + obtain ⟨g₀, hg₀, hg₀f⟩ := tubeExtends_maxStar hpà f₀ hf₀ + have hK : IsPreconnected ((fun t => ofRealPi (γ.extend t)) '' Icc 0 t₀) := + isPreconnected_Icc.image _ + (by fun_prop : Continuous fun t => ofRealPi (γ.extend t)).continuousOn + have hKU : (fun t => ofRealPi (γ.extend t)) '' Icc 0 t₀ ⊆ tubeDomain (Ω ∩ maxStar F Ω p) := by + rintro _ ⟨t, ht, rfl⟩ + rw [ofRealPi_mem_tubeDomain] + exact ⟨hγΩ t, hprefix t ht.1 (ht.2.trans_lt ht₀.2)⟩ + have hnear : g₀ =ᶠ[𝓝 (ofRealPi (γ.extend t₀))] f₀ := by + refine eventuallyEq_of_isPreconnected (isOpen_tubeDomain (hΩ.inter hÃo)) + (hf₀.mono (tubeDomain_mono inter_subset_left)) + (hg₀.mono (tubeDomain_mono inter_subset_right)) hK hKU + ⟨0, ⟨le_rfl, ht₀.1.le⟩, ?_⟩ hg₀f ⟨t₀, ⟨ht₀.1.le, le_rfl⟩, rfl⟩ + simp + have hAB : EqOn g₀ f₀ (tubeDomain (maxStar F Ω p ∩ ball (γ.extend t₁) r₁)) := by + have hpt : γ.extend t₀ ∈ maxStar F Ω p ∩ ball (γ.extend t₁) r₁ := ⟨ht₀Ã, ht₀ball⟩ + exact (hg₀.mono (tubeDomain_mono inter_subset_left)).eqOn_of_preconnected_of_eventuallyEq + (hf₀.mono (tubeDomain_mono (inter_subset_right.trans hr₁Ω))) + (isPreconnected_tubeDomain (hÃc.inter (convex_ball _ r₁)).isPreconnected) + (ofRealPi_mem_tubeDomain.mpr hpt) hnear + set g₁ : (Fin n → ℂ) → F := fun z => if z ∈ tubeDomain (maxStar F Ω p) then g₀ z else f₀ z + have hg₁a : AnalyticOnNhd ℂ g₁ (tubeDomain (maxStar F Ω p ∪ ball (γ.extend t₁) r₁)) := + analyticOnNhd_ite_tubeDomain hÃo isOpen_ball hg₀ + (hf₀.mono (tubeDomain_mono hr₁Ω)) hAB + have hg₁f : g₁ =ᶠ[𝓝 (ofRealPi p)] f₀ := by + have : g₁ =ᶠ[𝓝 (ofRealPi p)] g₀ := + eventuallyEq_of_mem ((isOpen_tubeDomain hÃo).mem_nhds (ofRealPi_mem_tubeDomain.mpr hpÃ)) + fun w hw => by simp [g₁, hw] + exact this.trans hg₀f + obtain ⟨g₂, hg₂, hg₂g₁⟩ := + exists_extension_tubeDomain_convexHull_of_starConvex hA₁o hA₁s hx₁A₁ hg₁a + refine ⟨g₂, hg₂, ?_⟩ + have : g₂ =ᶠ[𝓝 (ofRealPi p)] g₁ := + eventuallyEq_of_mem ((isOpen_tubeDomain hA₁o).mem_nhds + (ofRealPi_mem_tubeDomain.mpr (Or.inl hpÃ))) hg₂g₁ + exact this.trans hg₁f + exact hx₁ (subset_maxStar_of_mem hBmem (subset_convexHull ℝ _ hx₁A₁)) + have hconv : convexHull ℝ Ω ⊆ maxStar F Ω p := convexHull_min hΩà hÃc + obtain ⟨g, hg, hgf⟩ := tubeExtends_maxStar hpà f hf + refine ⟨g, hg.mono (tubeDomain_mono hconv), ?_⟩ + exact (hg.mono (tubeDomain_mono hΩÃ)).eqOn_of_preconnected_of_eventuallyEq hf + (isPreconnected_tubeDomain hc.isPreconnected) (ofRealPi_mem_tubeDomain.mpr hp) hgf + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Disc.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Disc.lean new file mode 100644 index 0000000000..4cb6536bec --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Disc.lean @@ -0,0 +1,414 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.AbsMax +public import Mathlib.Analysis.Convex.Segment +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Hull +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Basic + +/-! +# Parabolic analytic discs in tubes and the hull of two segments + +For a vertex `p` and two points `t₁, t₂` of the real base, the triangle with these vertices is +parametrized by `p + u • v₁ + v • v₂` with `|u| ≤ v ≤ 1`, where `v₁ = (t₁ - t₂)/2` and `v₂ = (t₁ ++ t₂)/2 - p`. The parabolic analytic disc `ζ ↦ p + ζ • v₁ + (c ζ² + 1 - c) • v₂`, restricted to +the planar region where its real part lies in the triangle, has boundary over the two sides `[p, +t₁]` and `[p, t₂]`. By the planar maximum principle, every point of the disc lies in the +holomorphic hull of the boundary, relative to any tube whose base contains the triangle. As `c` +varies, the discs cover all points of the triangle with `|u| < v < 1`. No coordinate +normalization is needed, and the two points may be linearly dependent. + +References: [Korevaar–Wiegerinck][KorevaarWiegerinck2017], Exercise 6.28; +[Hörmander][Hormander1973] §2.5, Lemma 2.5.11. + +## Main definitions + +* `triDir₁`: The half-difference direction of a triangle with vertex `p` and points `t₁, t₂`. +* `triDir₂`: The half-sum direction of a triangle with vertex `p` and points `t₁, t₂`. +* `triPt`: The point of the triangle with parameters `u, v`. +* `tri`: The triangle with vertex `p` and points `t₁, t₂`, scaled by `b` toward `p`. +* `parabolaHeight`: The real-quadratic function defining the parabolic disc region. +* `parabolaRegion`: The planar region over which the parabolic disc lies inside the triangle. +* `parabolaDisc`: The parabolic analytic disc with parameter `c`, translated by the imaginary vector + `η`. + +## Main results + +* `convex_tri`: Scaled triangles are convex. +* `segment_subset_tri`: The segment between `t₁` and `t₂` lies in the triangle of scale one. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +-/ + +public noncomputable section + +open Set Filter Metric Complex +open scoped Topology + +namespace SeveralComplexVariables.BochnerTube + +variable {ι : Type*} + +section Triangle + +/-- The half-difference direction of a triangle with vertex `p` and points `t₁, t₂`. -/ +@[expose] def triDir₁ (_p t₁ t₂ : ι → ℝ) : ι → ℝ := (1 / 2 : ℝ) • (t₁ - t₂) + +/-- The half-sum direction of a triangle with vertex `p` and points `t₁, t₂`. -/ +@[expose] def triDir₂ (p t₁ t₂ : ι → ℝ) : ι → ℝ := (1 / 2 : ℝ) • (t₁ + t₂) - p + +/-- The point of the triangle with parameters `u, v`. -/ +@[expose] def triPt (p t₁ t₂ : ι → ℝ) (u v : ℝ) : ι → ℝ := + p + u • triDir₁ p t₁ t₂ + v • triDir₂ p t₁ t₂ + +/-- The triangle with vertex `p` and points `t₁, t₂`, scaled by `b` toward `p`. -/ +@[expose] def tri (p t₁ t₂ : ι → ℝ) (b : ℝ) : Set (ι → ℝ) := + {x | ∃ u v : ℝ, |u| ≤ v ∧ v ≤ b ∧ x = triPt p t₁ t₂ u v} + +variable (p t₁ t₂ : ι → ℝ) + +/-- The triangle point as a combination of the vertex and the two points. -/ +theorem triPt_eq (u v : ℝ) : + triPt p t₁ t₂ u v = p + ((v + u) / 2) • (t₁ - p) + ((v - u) / 2) • (t₂ - p) := by + unfold triPt triDir₁ triDir₂ + module + +/-- The parameters `(0, 0)` give the vertex. -/ +@[simp] theorem triPt_zero : triPt p t₁ t₂ 0 0 = p := by simp [triPt] + +/-- The parameters `(1, 1)` give the first point. -/ +theorem triPt_one_one : triPt p t₁ t₂ 1 1 = t₁ := by rw [triPt_eq]; module + +/-- The parameters `(-1, 1)` give the second point. -/ +theorem triPt_neg_one_one : triPt p t₁ t₂ (-1) 1 = t₂ := by rw [triPt_eq]; module + +/-- Points with `|u| = v` lie on the two sides through the vertex. -/ +theorem triPt_mem_union_segment {u v : ℝ} (huv : |u| = v) (hv1 : v ≤ 1) : + triPt p t₁ t₂ u v ∈ segment ℝ p t₁ ∪ segment ℝ p t₂ := by + have hv0 : 0 ≤ v := huv ▸ abs_nonneg u + rcases le_or_gt 0 u with hu | hu + · rw [abs_of_nonneg hu] at huv + subst huv + left + rw [segment_eq_image'] + refine ⟨u, ⟨hu, hv1⟩, ?_⟩ + rw [triPt_eq] + simp only + module + · rw [abs_of_neg hu] at huv + subst huv + right + rw [segment_eq_image'] + refine ⟨-u, ⟨by linarith, hv1⟩, ?_⟩ + rw [triPt_eq] + simp only + module + +/-- The segment between `t₁` and `t₂` lies in the triangle of scale one. -/ +theorem segment_subset_tri : segment ℝ t₁ t₂ ⊆ tri p t₁ t₂ 1 := by + intro x hx + rw [segment_eq_image'] at hx + obtain ⟨θ, ⟨h0, h1⟩, rfl⟩ := hx + refine ⟨1 - 2 * θ, 1, ?_, le_rfl, ?_⟩ + · rw [abs_le]; constructor <;> linarith + · rw [triPt_eq] + simp only + module + +/-- Scaled triangles increase with the scale. -/ +theorem tri_mono {b b' : ℝ} (h : b ≤ b') : tri p t₁ t₂ b ⊆ tri p t₁ t₂ b' := by + rintro x ⟨u, v, huv, hv, rfl⟩ + exact ⟨u, v, huv, hv.trans h, rfl⟩ + +/-- The vertex lies in every scaled triangle of nonnegative scale. -/ +theorem mem_tri_self {b : ℝ} (hb : 0 ≤ b) : p ∈ tri p t₁ t₂ b := + ⟨0, 0, by simp, hb, by simp⟩ + +/-- The triangle of scale zero is the vertex. -/ +theorem tri_zero : tri p t₁ t₂ 0 = {p} := by + ext x + constructor + · rintro ⟨u, v, huv, hv, rfl⟩ + have hv0 : v = 0 := le_antisymm hv ((abs_nonneg u).trans huv) + have hu0 : u = 0 := abs_eq_zero.mp (le_antisymm (hv0 ▸ huv) (abs_nonneg u)) + simp [hu0, hv0] + · rintro rfl + exact mem_tri_self _ _ _ le_rfl + +/-- Scaled triangles are convex. -/ +theorem convex_tri (b : ℝ) : Convex ℝ (tri p t₁ t₂ b) := by + rintro x ⟨u, v, huv, hv, rfl⟩ y ⟨u', v', huv', hv', rfl⟩ a a' ha ha' haa + refine ⟨a * u + a' * u', a * v + a' * v', ?_, ?_, ?_⟩ + · calc |a * u + a' * u'| ≤ |a * u| + |a' * u'| := abs_add_le _ _ + _ = a * |u| + a' * |u'| := by rw [abs_mul, abs_mul, abs_of_nonneg ha, abs_of_nonneg ha'] + _ ≤ a * v + a' * v' := by gcongr + · calc a * v + a' * v' ≤ a * b + a' * b := + add_le_add (mul_le_mul_of_nonneg_left hv ha) (mul_le_mul_of_nonneg_left hv' ha') + _ = b := by rw [← add_mul, haa, one_mul] + · simp only [triPt] + linear_combination (norm := module) haa • p + +/-- Scaling the two points toward the vertex scales the first direction. -/ +theorem triDir₁_scale (b : ℝ) : + triDir₁ p (p + b • (t₁ - p)) (p + b • (t₂ - p)) = b • triDir₁ p t₁ t₂ := by + unfold triDir₁; module + +/-- Scaling the two points toward the vertex scales the second direction. -/ +theorem triDir₂_scale (b : ℝ) : + triDir₂ p (p + b • (t₁ - p)) (p + b • (t₂ - p)) = b • triDir₂ p t₁ t₂ := by + unfold triDir₂; module + +/-- Points of a scaled triangle in terms of the original parametrization. -/ +theorem triPt_scale {a : ℝ} (ha : a ≠ 0) (u v : ℝ) : + triPt p (p + a • (t₁ - p)) (p + a • (t₂ - p)) (u / a) (v / a) = triPt p t₁ t₂ u v := by + simp only [triPt, triDir₁_scale, triDir₂_scale, smul_smul, div_mul_cancel₀ _ ha] + +/-- Scaling the two points toward the vertex scales the triangle. -/ +theorem tri_scale {b : ℝ} (hb : 0 < b) : + tri p t₁ t₂ b = tri p (p + b • (t₁ - p)) (p + b • (t₂ - p)) 1 := by + have hd₁ := triDir₁_scale p t₁ t₂ b + have hd₂ := triDir₂_scale p t₁ t₂ b + ext x + constructor + · rintro ⟨u, v, huv, hv, rfl⟩ + refine ⟨u / b, v / b, ?_, ?_, ?_⟩ + · rw [abs_div, abs_of_pos hb]; exact div_le_div_of_nonneg_right huv hb.le + · exact (div_le_one hb).mpr hv + · simp only [triPt, hd₁, hd₂, smul_smul, div_mul_cancel₀ _ hb.ne'] + · rintro ⟨u, v, huv, hv, rfl⟩ + refine ⟨b * u, b * v, ?_, ?_, ?_⟩ + · rw [abs_mul, abs_of_pos hb]; exact mul_le_mul_of_nonneg_left huv hb.le + · calc b * v ≤ b * 1 := mul_le_mul_of_nonneg_left hv hb.le + _ = b := mul_one b + · simp only [triPt, hd₁, hd₂, smul_smul, mul_comm b] + +/-- For `0 ≤ b ≤ 1`, the segment from `p` toward `t` scaled by `b` lies on the original segment. -/ +theorem segment_scaled_subset {b : ℝ} (hb0 : 0 ≤ b) (hb1 : b ≤ 1) (t : ι → ℝ) : + segment ℝ p (p + b • (t - p)) ⊆ segment ℝ p t := by + intro x hx + rw [segment_eq_image'] at hx ⊢ + obtain ⟨θ, ⟨h0, h1⟩, rfl⟩ := hx + refine ⟨θ * b, ⟨by positivity, ?_⟩, ?_⟩ + · calc θ * b ≤ 1 * 1 := by gcongr + _ = 1 := one_mul 1 + · simp only [add_sub_cancel_left, smul_smul] + +end Triangle + +section Disc + +variable (p t₁ t₂ : ι → ℝ) + +/-- The real-quadratic function defining the parabolic disc region. -/ +def parabolaHeight (c : ℝ) (ζ : ℂ) : ℝ := c * (ζ.re ^ 2 - ζ.im ^ 2) + (1 - c) + +/-- The planar region over which the parabolic disc lies inside the triangle. -/ +@[expose] def parabolaRegion (c : ℝ) : Set ℂ := + {ζ | |ζ.re| < parabolaHeight c ζ ∧ parabolaHeight c ζ < 1} + +/-- The parabolic analytic disc with parameter `c`, translated by the imaginary vector `η`. -/ +@[expose] def parabolaDisc (c : ℝ) (η : ι → ℝ) (ζ : ℂ) : ι → ℂ := + ofRealPi p + ζ • ofRealPi (triDir₁ p t₁ t₂) + + (c * ζ ^ 2 + (1 - c)) • ofRealPi (triDir₂ p t₁ t₂) + I • ofRealPi η + +/-- The height function of the parabolic region is continuous. -/ +theorem continuous_parabolaHeight (c : ℝ) : Continuous (parabolaHeight c) := by + unfold parabolaHeight; fun_prop + +/-- The real part of a complex multiple of a real vector. -/ +theorem rePi_smul_ofRealPi (ζ : ℂ) (v : ι → ℝ) : rePi (ζ • ofRealPi v) = ζ.re • v := by + funext i + simp [rePi, ofRealPi, Complex.mul_re] + +/-- The imaginary part of a complex multiple of a real vector. -/ +theorem imPi_smul_ofRealPi (ζ : ℂ) (v : ι → ℝ) : imPi (ζ • ofRealPi v) = ζ.im • v := by + funext i + simp [imPi, ofRealPi, Complex.mul_im] + +/-- The real part of the parabolic coefficient is the height function. -/ +theorem re_parabolaCoeff (c : ℝ) (ζ : ℂ) : (c * ζ ^ 2 + (1 - c) : ℂ).re = parabolaHeight c ζ := by + simp [parabolaHeight, sq, Complex.mul_re] + +/-- The real part of a disc point is the triangle point with parameters given by the real part of +`ζ` and the height. -/ +theorem rePi_parabolaDisc (c : ℝ) (η : ι → ℝ) (ζ : ℂ) : + rePi (parabolaDisc p t₁ t₂ c η ζ) = triPt p t₁ t₂ ζ.re (parabolaHeight c ζ) := by + unfold parabolaDisc triPt + rw [rePi_add, rePi_add, rePi_add, rePi_ofRealPi, rePi_smul_ofRealPi, rePi_smul_ofRealPi, + rePi_I_smul_ofRealPi, re_parabolaCoeff, add_zero] + +/-- The imaginary part of a disc point expands in the triangle directions, shifted by `η`. -/ +theorem imPi_parabolaDisc (c : ℝ) (η : ι → ℝ) (ζ : ℂ) : + imPi (parabolaDisc p t₁ t₂ c η ζ) = + ζ.im • triDir₁ p t₁ t₂ + (c * ζ ^ 2 + (1 - c) : ℂ).im • triDir₂ p t₁ t₂ + η := by + unfold parabolaDisc + funext i + simp [imPi, ofRealPi, Complex.mul_im] + +/-- The disc map is continuous. -/ +theorem continuous_parabolaDisc (c : ℝ) (η : ι → ℝ) : Continuous (parabolaDisc p t₁ t₂ c η) := by + unfold parabolaDisc; fun_prop + +/-- The disc map is entire. -/ +theorem differentiable_parabolaDisc (c : ℝ) (η : ι → ℝ) : + Differentiable ℂ (parabolaDisc p t₁ t₂ c η) := by + rw [differentiable_pi] + intro i + simp only [parabolaDisc, Pi.add_apply, Pi.smul_apply, smul_eq_mul, ofRealPi] + fun_prop + +/-- The parabolic region is open. -/ +theorem isOpen_parabolaRegion (c : ℝ) : IsOpen (parabolaRegion c) := + (isOpen_lt (by fun_prop) (continuous_parabolaHeight c)).inter + (isOpen_lt (continuous_parabolaHeight c) continuous_const) + +/-- The closure of the parabolic region is contained in the corresponding closed sublevel set. -/ +theorem closure_parabolaRegion_subset (c : ℝ) : + closure (parabolaRegion c) ⊆ {ζ | |ζ.re| ≤ parabolaHeight c ζ ∧ parabolaHeight c ζ ≤ 1} := + closure_minimal (fun ζ hζ => ⟨hζ.1.le, hζ.2.le⟩) + ((isClosed_le (by fun_prop) (continuous_parabolaHeight c)).inter + (isClosed_le (continuous_parabolaHeight c) continuous_const)) + +/-- If the height equals one and `|Re ζ| ≤ 1`, then `|Re ζ| = 1`. -/ +theorem abs_re_eq_one_of_parabolaHeight_eq_one {c : ℝ} (hc : 0 < c) {ζ : ℂ} + (hre : |ζ.re| ≤ 1) (h : parabolaHeight c ζ = 1) : |ζ.re| = 1 := by + unfold parabolaHeight at h + have h1 : ζ.re ^ 2 - ζ.im ^ 2 = 1 := by + have : c * (ζ.re ^ 2 - ζ.im ^ 2) = c := by linarith + exact mul_left_cancel₀ hc.ne' (this.trans (mul_one c).symm) + have h2 : 1 ≤ ζ.re ^ 2 := by nlinarith [sq_nonneg ζ.im] + have h3 : 1 ≤ |ζ.re| := by + rw [← sq_le_sq₀ zero_le_one (abs_nonneg _), one_pow, sq_abs] + exact h2 + exact le_antisymm hre h3 + +/-- Frontier points of the region have `|Re ζ| = parabolaHeight c ζ ≤ 1`. -/ +theorem frontier_parabolaRegion_subset {c : ℝ} (hc : 0 < c) : + frontier (parabolaRegion c) ⊆ {ζ | |ζ.re| = parabolaHeight c ζ ∧ parabolaHeight c ζ ≤ 1} := by + intro ζ hζ + have hcl := closure_parabolaRegion_subset c hζ.1 + have hnot : ζ ∉ parabolaRegion c := fun h => hζ.2 (by rwa [(isOpen_parabolaRegion c).interior_eq]) + refine ⟨?_, hcl.2⟩ + rcases hcl.1.lt_or_eq with hlt | heq + · exfalso + apply hnot + refine ⟨hlt, ?_⟩ + rcases hcl.2.lt_or_eq with hlt2 | heq2 + · exact hlt2 + · exfalso + have := abs_re_eq_one_of_parabolaHeight_eq_one hc (hcl.1.trans hcl.2) heq2 + linarith + · exact heq + +/-- The region is bounded. -/ +theorem isBounded_parabolaRegion {c : ℝ} (hc : 0 < c) : + Bornology.IsBounded (parabolaRegion c) := by + rw [Metric.isBounded_iff_subset_closedBall 0] + refine ⟨2 + 1 / c, fun ζ hζ => ?_⟩ + obtain ⟨h1, h2⟩ := hζ + have hre : |ζ.re| ≤ 1 := h1.le.trans h2.le + have hre2 : ζ.re ^ 2 ≤ 1 := by + rw [← sq_abs] + exact pow_le_one₀ (abs_nonneg _) hre + have him : c * ζ.im ^ 2 ≤ 1 := by + unfold parabolaHeight at h1 + nlinarith [abs_nonneg ζ.re] + have him2 : ζ.im ^ 2 ≤ 1 / c := by + rw [le_div_iff₀ hc]; linarith + have him3 : |ζ.im| ≤ 1 + 1 / c := by + have : |ζ.im| ≤ ζ.im ^ 2 + 1 := by + rcases le_or_gt |ζ.im| 1 with h | h + · linarith [sq_nonneg ζ.im] + · have : |ζ.im| ≤ |ζ.im| ^ 2 := by nlinarith [abs_nonneg ζ.im] + rw [sq_abs] at this + linarith + linarith + rw [mem_closedBall, dist_zero_right] + calc ‖ζ‖ ≤ |ζ.re| + |ζ.im| := Complex.norm_le_abs_re_add_abs_im ζ + _ ≤ 1 + (1 + 1 / c) := add_le_add hre him3 + _ = 2 + 1 / c := by ring + +/-- The image of the frontier of the region under the disc map is compact. -/ +theorem isCompact_image_frontier_parabolaRegion {c : ℝ} (hc : 0 < c) (η : ι → ℝ) : + IsCompact (parabolaDisc p t₁ t₂ c η '' frontier (parabolaRegion c)) := + (((isBounded_parabolaRegion hc).isCompact_closure).of_isClosed_subset isClosed_frontier + frontier_subset_closure).image (continuous_parabolaDisc p t₁ t₂ c η) + +/-- The disc over the closed region lies in the tube over the triangle. -/ +theorem parabolaDisc_mem_tubeDomain_tri (c : ℝ) (η : ι → ℝ) {ζ : ℂ} + (hζ : ζ ∈ closure (parabolaRegion c)) : + parabolaDisc p t₁ t₂ c η ζ ∈ tubeDomain (tri p t₁ t₂ 1) := by + have h := closure_parabolaRegion_subset c hζ + rw [mem_tubeDomain, rePi_parabolaDisc] + exact ⟨ζ.re, parabolaHeight c ζ, h.1, h.2, rfl⟩ + +/-- The disc boundary lies in the tube over the two sides through the vertex. -/ +theorem parabolaDisc_frontier_subset {c : ℝ} (hc : 0 < c) (η : ι → ℝ) : + parabolaDisc p t₁ t₂ c η '' frontier (parabolaRegion c) ⊆ + tubeDomain (segment ℝ p t₁ ∪ segment ℝ p t₂) := by + rintro _ ⟨ζ, hζ, rfl⟩ + have h := frontier_parabolaRegion_subset hc hζ + rw [mem_tubeDomain, rePi_parabolaDisc] + exact triPt_mem_union_segment p t₁ t₂ h.1 h.2 + +/-- **Disc points lie in the hull of the disc boundary.** For any open base containing the +triangle, every point of the parabolic disc over the closed region lies in the holomorphic hull, +relative to the tube, of the image of the frontier of the region. -/ +theorem parabolaDisc_mem_holomorphicHull [Fintype ι] {A : Set (ι → ℝ)} + (hT : tri p t₁ t₂ 1 ⊆ A) {c : ℝ} (hc : 0 < c) (η : ι → ℝ) {ζ₀ : ℂ} + (hζ₀ : ζ₀ ∈ closure (parabolaRegion c)) : + parabolaDisc p t₁ t₂ c η ζ₀ ∈ + holomorphicHull (tubeDomain A) (parabolaDisc p t₁ t₂ c η '' frontier (parabolaRegion c)) := by + refine ⟨tubeDomain_mono hT (parabolaDisc_mem_tubeDomain_tri p t₁ t₂ c η hζ₀), ?_⟩ + intro g hg M hM + have hmaps : MapsTo (parabolaDisc p t₁ t₂ c η) (closure (parabolaRegion c)) (tubeDomain A) := + fun ζ hζ => tubeDomain_mono hT (parabolaDisc_mem_tubeDomain_tri p t₁ t₂ c η hζ) + have hd : DiffContOnCl ℂ (g ∘ parabolaDisc p t₁ t₂ c η) (parabolaRegion c) := by + apply DifferentiableOn.diffContOnCl + exact hg.differentiableOn.comp (differentiable_parabolaDisc p t₁ t₂ c η).differentiableOn hmaps + exact Complex.norm_le_of_forall_mem_frontier_norm_le (isBounded_parabolaRegion hc) hd + (fun ζ hζ => hM _ (mem_image_of_mem _ hζ)) hζ₀ + +/-- Every point of the triangle with `|u| < v < 1` lies on a parabolic disc. -/ +theorem exists_parabolaDisc_of_lt {u v : ℝ} (huv : |u| < v) (hv1 : v < 1) (η : ι → ℝ) : + ∃ c : ℝ, 0 < c ∧ c < 1 ∧ (u : ℂ) ∈ parabolaRegion c ∧ + parabolaDisc p t₁ t₂ c η u = ofRealPi (triPt p t₁ t₂ u v) + I • ofRealPi η := by + have hu1 : |u| < 1 := huv.trans hv1 + have hu2 : u ^ 2 < 1 := by + rw [← sq_abs] + exact pow_lt_one₀ (abs_nonneg _) hu1 two_ne_zero + have hu2v : u ^ 2 < v := by + calc u ^ 2 = |u| ^ 2 := (sq_abs u).symm + _ ≤ |u| := by nlinarith [abs_nonneg u] + _ < v := huv + set c : ℝ := (1 - v) / (1 - u ^ 2) with hc + have hden : 0 < 1 - u ^ 2 := by linarith + have hc0 : 0 < c := div_pos (by linarith) hden + have hc1 : c < 1 := by rw [hc, div_lt_one hden]; linarith + have hheight : parabolaHeight c u = v := by + unfold parabolaHeight + simp only [Complex.ofReal_re, Complex.ofReal_im] + rw [hc] + field_simp + ring + refine ⟨c, hc0, hc1, ⟨?_, ?_⟩, ?_⟩ + · rw [hheight]; simpa using huv + · rw [hheight]; exact hv1 + · have him : (c * (u : ℂ) ^ 2 + (1 - c) : ℂ).im = 0 := by simp [sq, Complex.mul_im] + have := ofRealPi_rePi_add_I_smul_ofRealPi_imPi (parabolaDisc p t₁ t₂ c η u) + rw [rePi_parabolaDisc, hheight, imPi_parabolaDisc, him] at this + rw [← this] + simp + +end Disc + +end SeveralComplexVariables.BochnerTube + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Gluing.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Gluing.lean new file mode 100644 index 0000000000..b8eea0c5cb --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/Gluing.lean @@ -0,0 +1,156 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Uniqueness +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.Analysis.Convex.Segment +public import Mathlib.Analysis.Normed.Affine.AddTorsor +public import Mathlib.Analysis.Normed.Module.Connected +public import Mathlib.Analysis.Normed.Module.Convex + +/-! +# Gluing local analytic continuations along a convex set + +Let `g` be holomorphic on an open set `U` of a complex normed space and let `L ⊆ U` be convex. +Suppose that at every point `ζ` of `L` there is a holomorphic function on the ball of radius `δ` +around `ζ` agreeing with `g` near `ζ`. Then these local continuations agree on overlaps and +define a holomorphic function on the `δ`-neighborhood of `L` agreeing with `g` near every point +of `L`. The overlap argument passes through the midpoint of two centers, which lies in `L` and +in both balls, and uses the identity theorem on a thickened segment. + +References: [Scheidemann][Scheidemann2005] §6.3, proof of Theorem 6.3.1; +[Hörmander][Hormander1973] §2.5, proof of Theorem 2.5.10. + +## Main results + +* `eventuallyEq_of_isPreconnected`: **Propagation of local agreement along a preconnected set.** Two + holomorphic functions on an open set that agree near one point of a preconnected subset agree near + every point of that subset. +* `exists_glue_of_local_continuations`: **Gluing lemma.** Local holomorphic continuations of `g` on + balls of a fixed radius around the points of a convex set `L ⊆ U` glue to a holomorphic function + on the `δ`-neighborhood of `L` agreeing with `g` near every point of `L`. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- **Propagation of local agreement along a preconnected set.** Two holomorphic functions +on an open set that agree near one point of a preconnected subset agree near every point of +that subset. -/ +theorem eventuallyEq_of_isPreconnected {U K : Set E} (hU : IsOpen U) {g h : E → F} + (hg : AnalyticOnNhd ℂ g U) (hh : AnalyticOnNhd ℂ h U) (hK : IsPreconnected K) (hKU : K ⊆ U) + {a : E} (ha : a ∈ K) (hab : h =ᶠ[𝓝 a] g) {b : E} (hb : b ∈ K) : h =ᶠ[𝓝 b] g := by + set u : Set E := {x | h =ᶠ[𝓝 x] g} with hu + set v : Set E := {x | x ∈ U ∧ ¬ h =ᶠ[𝓝 x] g} with hv + have huo : IsOpen u := by + rw [isOpen_iff_mem_nhds] + intro x hx + exact hx.eventually_nhds + have hvo : IsOpen v := by + rw [isOpen_iff_forall_mem_open] + intro x ⟨hxU, hx⟩ + obtain ⟨r, hr, hrU⟩ := Metric.isOpen_iff.mp hU x hxU + refine ⟨ball x r, fun y hy => ⟨hrU hy, fun hy' => hx ?_⟩, isOpen_ball, mem_ball_self hr⟩ + have heq : EqOn h g (ball x r) := + (hh.mono hrU).eqOn_of_preconnected_of_eventuallyEq (hg.mono hrU) + (convex_ball x r).isPreconnected hy hy' + exact eventuallyEq_of_mem (isOpen_ball.mem_nhds (mem_ball_self hr)) heq + have hcover : K ⊆ u ∪ v := fun x hx => by + by_cases h : h =ᶠ[𝓝 x] g + · exact Or.inl h + · exact Or.inr ⟨hKU hx, h⟩ + have hdisj : K ∩ (u ∩ v) = ∅ := by + ext x + simp only [mem_inter_iff, mem_empty_iff_false, iff_false, not_and] + intro _ hxu hxv + exact hxv.2 hxu + rcases isPreconnected_iff_subset_of_disjoint.mp hK u v huo hvo hcover hdisj with h | h + · exact h hb + · exact absurd hab (h ha).2 + +/-- Agreement of two holomorphic functions near a point propagates along a segment inside their +common domain: if they agree near one endpoint, they agree near the other. -/ +theorem eventuallyEq_of_segment_subset {U : Set E} (hU : IsOpen U) {g h : E → F} + (hg : AnalyticOnNhd ℂ g U) (hh : AnalyticOnNhd ℂ h U) {a b : E} + (hseg : segment ℝ a b ⊆ U) (hab : h =ᶠ[𝓝 a] g) : h =ᶠ[𝓝 b] g := + eventuallyEq_of_isPreconnected hU hg hh (convex_segment a b).isPreconnected hseg + (left_mem_segment ℝ a b) hab (right_mem_segment ℝ a b) + +/-- **Gluing lemma.** Local holomorphic continuations of `g` on balls of a fixed radius +around the points of a convex set `L ⊆ U` glue to a holomorphic function on the +`δ`-neighborhood of `L` agreeing with `g` near every point of `L`. -/ +theorem exists_glue_of_local_continuations {U L : Set E} (hU : IsOpen U) (hL : Convex ℝ L) + (hLU : L ⊆ U) {g : E → F} (hg : AnalyticOnNhd ℂ g U) {δ : ℝ} (hδ : 0 < δ) + (h : ∀ ζ ∈ L, ∃ k : E → F, AnalyticOnNhd ℂ k (ball ζ δ) ∧ k =ᶠ[𝓝 ζ] g) : + ∃ H : E → F, AnalyticOnNhd ℂ H (⋃ ζ ∈ L, ball ζ δ) ∧ ∀ ζ ∈ L, H =ᶠ[𝓝 ζ] g := by + classical + choose! k hka hkg using h + -- each local continuation agrees with `g` near every point of `L` inside its ball + have hkL : ∀ ζ ∈ L, ∀ m ∈ L, m ∈ ball ζ δ → k ζ =ᶠ[𝓝 m] g := by + intro ζ hζ m hm hmζ + have hseg : segment ℝ ζ m ⊆ ball ζ δ ∩ U := + subset_inter ((convex_ball ζ δ).segment_subset (mem_ball_self hδ) hmζ) + ((hL.segment_subset hζ hm).trans hLU) + exact eventuallyEq_of_segment_subset (isOpen_ball.inter hU) + (hg.mono inter_subset_right) ((hka ζ hζ).mono inter_subset_left) hseg (hkg ζ hζ) + -- two local continuations agree on the intersection of their balls + have hconsist : ∀ ζ ∈ L, ∀ ζ' ∈ L, EqOn (k ζ) (k ζ') (ball ζ δ ∩ ball ζ' δ) := by + intro ζ hζ ζ' hζ' + rcases (ball ζ δ ∩ ball ζ' δ).eq_empty_or_nonempty with hemp | ⟨z, hz⟩ + · rw [hemp]; exact fun _ h => h.elim + set m : E := midpoint ℝ ζ ζ' with hm + have hmL : m ∈ L := hL.segment_subset hζ hζ' (midpoint_mem_segment ζ ζ') + have hdist : dist ζ ζ' < 2 * δ := by + calc dist ζ ζ' ≤ dist ζ z + dist z ζ' := dist_triangle _ _ _ + _ < δ + δ := add_lt_add (by simpa [dist_comm] using hz.1) (mem_ball.mp hz.2) + _ = 2 * δ := by ring + have hmζ : m ∈ ball ζ δ := by + rw [mem_ball, hm, dist_comm, dist_left_midpoint, Real.norm_eq_abs, abs_of_pos two_pos, + inv_mul_lt_iff₀ two_pos] + exact hdist + have hmζ' : m ∈ ball ζ' δ := by + rw [mem_ball, hm, dist_comm, dist_right_midpoint, Real.norm_eq_abs, abs_of_pos two_pos, + inv_mul_lt_iff₀ two_pos] + exact hdist + have h1 : k ζ =ᶠ[𝓝 m] k ζ' := + (hkL ζ hζ m hmL hmζ).trans (hkL ζ' hζ' m hmL hmζ').symm + exact ((hka ζ hζ).mono inter_subset_left).eqOn_of_preconnected_of_eventuallyEq + ((hka ζ' hζ').mono inter_subset_right) + ((convex_ball ζ δ).inter (convex_ball ζ' δ)).isPreconnected ⟨hmζ, hmζ'⟩ h1 + let H : E → F := fun z => + if hz : ∃ ζ ∈ L, z ∈ ball ζ δ then k (Classical.choose hz) z else 0 + have hH : ∀ ζ ∈ L, ∀ z ∈ ball ζ δ, H z = k ζ z := by + intro ζ hζ z hz + have hex : ∃ ζ ∈ L, z ∈ ball ζ δ := ⟨ζ, hζ, hz⟩ + simp only [H] + split_ifs + obtain ⟨hζ', hz'⟩ := Classical.choose_spec hex + exact hconsist _ hζ' ζ hζ ⟨hz', hz⟩ + refine ⟨H, ?_, fun ζ hζ => ?_⟩ + · intro z hz + obtain ⟨ζ, hζ, hzζ⟩ := mem_iUnion₂.mp hz + have : H =ᶠ[𝓝 z] k ζ := eventuallyEq_of_mem (isOpen_ball.mem_nhds hzζ) fun w hw => hH ζ hζ w hw + exact ((hka ζ hζ) z hzζ).congr this.symm + · have : H =ᶠ[𝓝 ζ] k ζ := + eventuallyEq_of_mem (isOpen_ball.mem_nhds (mem_ball_self hδ)) fun w hw => hH ζ hζ w hw + exact this.trans (hkg ζ hζ) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/StarConvex.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/StarConvex.lean new file mode 100644 index 0000000000..e49c8fe54c --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/TubeDomain/StarConvex.lean @@ -0,0 +1,495 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.HolomorphicConvexity.Thullen +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Disc +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.TubeDomain.Gluing + +/-! +# The maximal star-convex extension tube and Bochner's theorem for star-convex bases + +Fix a Banach space `F`, a base `Ω ⊆ ℝⁿ` and a point `p`. The star-convex open sets `A` with +respect to `p` such that every `F`-valued holomorphic function on the tube over `Ω` extends +holomorphically to the tube over `A`, agreeing with it near the real point `p`, form a family +closed under unions: the union `maxStar` again has the extension property, because two members +meet in a star-convex set whose tube is connected. The maximal tube is convex. Indeed, for two +points `t₁, t₂` of `maxStar`, the scaled triangles with vertex `p` lie in `maxStar` by an +induction on the scale: on a slightly smaller triangle every point lies on a parabolic analytic +disc with boundary over the two sides through `p`, so by the disc hull lemma and Thullen's +continuation lemma every function continues to a ball of a uniform radius, these local +continuations glue along the convex triangle, and maximality absorbs the enlarged tube. + +Consequently, for an open star-convex base, every holomorphic function on the tube extends to +the tube over the convex hull. This is part (a) of [Hörmander][Hormander1973]'s proof of +Bochner's theorem. + +References: [Hörmander][Hormander1973] §2.5, Theorem 2.5.10 (a); [Scheidemann][Scheidemann2005] +§6.3, Theorem 6.3.1, Step 1. + +## Main definitions + +* `TubeExtends`: Every `F`-valued holomorphic function on the tube over `Ω` extends holomorphically + to the tube over `A`, agreeing with the original near the real point `p`. +* `starFamily`: The family of open star-convex extension bases. +* `maxStar`: The maximal star-convex extension base. + +## Main results + +* `maxStar_maximal`: **Maximality.** An open star-convex base to which every function on the maximal + tube extends is contained in the maximal base. +* `exists_local_continuation_tri`: **Local continuation on a shrunken triangle.** If the tube over + the triangle of scale `a` lies in the tube over `A` and balls of radius `δ` around the two sides + through `p` lie in the tube over `A`, then every function holomorphic on the tube over `A` + continues to the ball of radius `δ` around each point of the tube over the triangle of a smaller + scale `b`. +* `thickening_tri_subset_of_maximal`: **One step of the triangle induction.** Under maximality, the + `δ`-thickening of the tube over the triangle of a smaller scale is absorbed into `A`. +* `tri_subset_of_maximal`: **The triangle lemma.** Under maximality, the full triangle with vertex + `p` and two points of `A` lies in `A`. +* `convex_maxStar`: **The maximal star-convex extension base is convex.** +* `exists_extension_tubeDomain_convexHull_of_starConvex`: **Bochner's tube theorem for star-convex + bases.** Every Banach-valued holomorphic function on the tube over an open star-convex base + extends to the tube over the convex hull. + +## References + +* [L. Hörmander, *An Introduction to Complex Analysis in Several Variables*][Hormander1973] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public noncomputable section + +open Set Filter Metric Complex +open scoped Topology + +namespace SeveralComplexVariables + +namespace BochnerTube + +variable {n : ℕ} (F : Type*) [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + +/-- Every `F`-valued holomorphic function on the tube over `Ω` extends holomorphically to the tube +over `A`, agreeing with the original near the real point `p`. -/ +@[expose] def TubeExtends (Ω A : Set (Fin n → ℝ)) (p : Fin n → ℝ) : Prop := + ∀ f : (Fin n → ℂ) → F, AnalyticOnNhd ℂ f (tubeDomain Ω) → + ∃ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain A) ∧ g =ᶠ[𝓝 (ofRealPi p)] f + +/-- The family of open star-convex extension bases. -/ +@[expose] def starFamily (Ω : Set (Fin n → ℝ)) (p : Fin n → ℝ) : Set (Set (Fin n → ℝ)) := + {A | IsOpen A ∧ StarConvex ℝ p A ∧ TubeExtends F Ω A p} + +/-- The maximal star-convex extension base. -/ +@[expose] def maxStar (Ω : Set (Fin n → ℝ)) (p : Fin n → ℝ) : Set (Fin n → ℝ) := + ⋃₀ starFamily F Ω p + +variable {F} + +section Family + +variable {Ω : Set (Fin n → ℝ)} {p : Fin n → ℝ} + +omit [CompleteSpace F] in +/-- The maximal base is open. -/ +theorem isOpen_maxStar : IsOpen (maxStar F Ω p) := isOpen_sUnion fun _ hA => hA.1 + +omit [CompleteSpace F] in +/-- The maximal base is star-convex with respect to `p`. -/ +theorem starConvex_maxStar : StarConvex ℝ p (maxStar F Ω p) := + starConvex_sUnion fun _ hA => hA.2.1 + +omit [CompleteSpace F] in +/-- Members of the family lie in the maximal base. -/ +theorem subset_maxStar_of_mem {A : Set (Fin n → ℝ)} (hA : A ∈ starFamily F Ω p) : + A ⊆ maxStar F Ω p := subset_sUnion_of_mem hA + +omit [CompleteSpace F] in +/-- A ball around `p` inside `Ω` belongs to the family. -/ +theorem ball_mem_starFamily {r : ℝ} (hr0 : 0 < r) (hr : ball p r ⊆ Ω) : + ball p r ∈ starFamily F Ω p := + ⟨isOpen_ball, (convex_ball p r).starConvex (mem_ball_self hr0), + fun f hf => ⟨f, hf.mono (tubeDomain_mono hr), EventuallyEq.rfl⟩⟩ + +omit [CompleteSpace F] in +/-- The center lies in the maximal base when a ball around it lies in `Ω`. -/ +theorem mem_maxStar_of_ball {r : ℝ} (hr0 : 0 < r) (hr : ball p r ⊆ Ω) : p ∈ maxStar F Ω p := + subset_maxStar_of_mem (ball_mem_starFamily hr0 hr) (mem_ball_self hr0) + +/-- The tube over a star-convex set containing its center is preconnected. -/ +theorem isPreconnected_tubeDomain_of_starConvex {A : Set (Fin n → ℝ)} (hA : StarConvex ℝ p A) + (hp : p ∈ A) : IsPreconnected (tubeDomain A) := + isPreconnected_tubeDomain (hA.isPathConnected hp).isConnected.isPreconnected + +omit [CompleteSpace F] in +/-- Two extensions agreeing with a function near `p` agree on the tube over the intersection of +star-convex bases. -/ +theorem eqOn_of_starConvex {A B : Set (Fin n → ℝ)} (hA : StarConvex ℝ p A) + (hB : StarConvex ℝ p B) {f g₁ g₂ : (Fin n → ℂ) → F} + (hg₁ : AnalyticOnNhd ℂ g₁ (tubeDomain A)) (hg₂ : AnalyticOnNhd ℂ g₂ (tubeDomain B)) + (h₁ : g₁ =ᶠ[𝓝 (ofRealPi p)] f) (h₂ : g₂ =ᶠ[𝓝 (ofRealPi p)] f) : + EqOn g₁ g₂ (tubeDomain (A ∩ B)) := by + rcases (A ∩ B).eq_empty_or_nonempty with he | hne + · rw [he, tubeDomain_empty] + exact fun _ h => h.elim + have hp : p ∈ A ∩ B := (hA.inter hB).mem hne + exact (hg₁.mono (tubeDomain_mono inter_subset_left)).eqOn_of_preconnected_of_eventuallyEq + (hg₂.mono (tubeDomain_mono inter_subset_right)) + (isPreconnected_tubeDomain_of_starConvex (hA.inter hB) hp) + (ofRealPi_mem_tubeDomain.mpr hp) (h₁.trans h₂.symm) + +omit [CompleteSpace F] in +/-- The maximal base has the extension property. -/ +theorem tubeExtends_maxStar (hp : p ∈ maxStar F Ω p) : TubeExtends F Ω (maxStar F Ω p) p := by + classical + intro f hf + have hchoice : ∀ A : Set (Fin n → ℝ), A ∈ starFamily F Ω p → + ∃ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain A) ∧ g =ᶠ[𝓝 (ofRealPi p)] f := + fun A hA => hA.2.2 f hf + choose! g hga hgf using hchoice + let G : (Fin n → ℂ) → F := fun z => + if hz : ∃ A ∈ starFamily F Ω p, z ∈ tubeDomain A then g (Classical.choose hz) z else 0 + have hG : ∀ A ∈ starFamily F Ω p, ∀ z ∈ tubeDomain A, G z = g A z := by + intro A hA z hz + have hex : ∃ A ∈ starFamily F Ω p, z ∈ tubeDomain A := ⟨A, hA, hz⟩ + simp only [G] + split_ifs + obtain ⟨hA', hz'⟩ := Classical.choose_spec hex + exact eqOn_of_starConvex hA'.2.1 hA.2.1 (hga _ hA') (hga A hA) (hgf _ hA') (hgf A hA) + ⟨hz', hz⟩ + obtain ⟨A₀, hA₀, hpA₀⟩ := mem_sUnion.mp hp + refine ⟨G, ?_, ?_⟩ + · intro z hz + obtain ⟨A, hA, hzA⟩ := mem_sUnion.mp hz + have : G =ᶠ[𝓝 z] g A := + eventuallyEq_of_mem ((isOpen_tubeDomain hA.1).mem_nhds hzA) fun w hw => hG A hA w hw + exact (hga A hA z hzA).congr this.symm + · have : G =ᶠ[𝓝 (ofRealPi p)] g A₀ := + eventuallyEq_of_mem ((isOpen_tubeDomain hA₀.1).mem_nhds (ofRealPi_mem_tubeDomain.mpr hpA₀)) + fun w hw => hG A₀ hA₀ w hw + exact this.trans (hgf A₀ hA₀) + +omit [CompleteSpace F] in +/-- **Maximality.** An open star-convex base to which every function on the maximal tube +extends is contained in the maximal base. -/ +theorem maxStar_maximal (hp : p ∈ maxStar F Ω p) {B : Set (Fin n → ℝ)} (hB : IsOpen B) + (hBs : StarConvex ℝ p B) + (hext : ∀ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain (maxStar F Ω p)) → + ∃ G : (Fin n → ℂ) → F, AnalyticOnNhd ℂ G (tubeDomain B) ∧ + EqOn G g (tubeDomain (maxStar F Ω p))) : + B ⊆ maxStar F Ω p := by + apply subset_maxStar_of_mem + refine ⟨hB, hBs, fun f hf => ?_⟩ + obtain ⟨g, hg, hgf⟩ := tubeExtends_maxStar hp f hf + obtain ⟨G, hG, hGg⟩ := hext g hg + refine ⟨G, hG, ?_⟩ + have : G =ᶠ[𝓝 (ofRealPi p)] g := + eventuallyEq_of_mem ((isOpen_tubeDomain isOpen_maxStar).mem_nhds + (ofRealPi_mem_tubeDomain.mpr hp)) hGg + exact this.trans hgf + +omit [CompleteSpace F] in +open scoped Classical in +/-- Piecewise gluing of holomorphic functions on tubes over an open union, agreeing on the +intersection. -/ +theorem analyticOnNhd_ite_tubeDomain {A B : Set (Fin n → ℝ)} (hA : IsOpen A) (hB : IsOpen B) + {g h : (Fin n → ℂ) → F} + (hg : AnalyticOnNhd ℂ g (tubeDomain A)) (hh : AnalyticOnNhd ℂ h (tubeDomain B)) + (heq : EqOn g h (tubeDomain (A ∩ B))) : + AnalyticOnNhd ℂ (fun z => if z ∈ tubeDomain A then g z else h z) (tubeDomain (A ∪ B)) := by + classical + intro z hz + rw [tubeDomain_union] at hz + rcases hz with hzA | hzB + · have : (fun z => if z ∈ tubeDomain A then g z else h z) =ᶠ[𝓝 z] g := + eventuallyEq_of_mem ((isOpen_tubeDomain hA).mem_nhds hzA) fun w hw => by simp [hw] + exact (hg z hzA).congr this.symm + · have : (fun z => if z ∈ tubeDomain A then g z else h z) =ᶠ[𝓝 z] h := by + refine eventuallyEq_of_mem ((isOpen_tubeDomain hB).mem_nhds hzB) fun w hw => ?_ + by_cases hwA : w ∈ tubeDomain A + · simp only [hwA, ite_true] + exact heq ⟨hwA, hw⟩ + · simp only [hwA, ite_false] + exact (hh z hzB).congr this.symm + +end Family + +section Triangle + +variable {A : Set (Fin n → ℝ)} {p t₁ t₂ : Fin n → ℝ} + +/-- **Local continuation on a shrunken triangle.** If the tube over the triangle of scale `a` +lies in the tube over `A` and balls of radius `δ` around the two sides through `p` lie in the +tube over `A`, then every function holomorphic on the tube over `A` continues to the ball of +radius `δ` around each point of the tube over the triangle of a smaller scale `b`. -/ +theorem exists_local_continuation_tri (hA : IsOpen A) {a : ℝ} (ha1 : a ≤ 1) + (htri : tri p t₁ t₂ a ⊆ A) {δ : ℝ} (hδ : 0 < δ) + (hS : ∀ w ∈ tubeDomain (segment ℝ p t₁ ∪ segment ℝ p t₂), ball w δ ⊆ tubeDomain A) + {b : ℝ} (hba : b ≤ a) (hlt : b = 0 ∨ b < a) + {g : (Fin n → ℂ) → F} (hg : AnalyticOnNhd ℂ g (tubeDomain A)) : + ∀ ζ ∈ tubeDomain (tri p t₁ t₂ b), ∃ k : (Fin n → ℂ) → F, + AnalyticOnNhd ℂ k (ball ζ δ) ∧ k =ᶠ[𝓝 ζ] g := by + intro ζ hζ + obtain ⟨u, v, huv, hvb, hre⟩ := mem_tubeDomain.mp hζ + rcases huv.lt_or_eq with hlt' | heq + · have hv0 : 0 < v := (abs_nonneg u).trans_lt hlt' + have hbpos : 0 < b := hv0.trans_le hvb + have hba' : b < a := by + rcases hlt with h | h + · exact absurd h hbpos.ne' + · exact h + have ha : 0 < a := hbpos.trans hba' + set s₁ : Fin n → ℝ := p + a • (t₁ - p) with hs₁ + set s₂ : Fin n → ℝ := p + a • (t₂ - p) with hs₂ + have htri' : tri p s₁ s₂ 1 ⊆ A := by rw [← tri_scale p t₁ t₂ ha]; exact htri + have huv' : |u / a| < v / a := by + rw [abs_div, abs_of_pos ha] + exact div_lt_div_of_pos_right hlt' ha + have hv1 : v / a < 1 := (div_lt_one ha).mpr (hvb.trans_lt hba') + obtain ⟨c, hc0, -, hreg, hdisc⟩ := exists_parabolaDisc_of_lt p s₁ s₂ huv' hv1 (imPi ζ) + have hζeq : parabolaDisc p s₁ s₂ c (imPi ζ) ((u / a : ℝ) : ℂ) = ζ := by + rw [hdisc, hs₁, hs₂, triPt_scale p t₁ t₂ ha.ne', ← hre] + exact ofRealPi_rePi_add_I_smul_ofRealPi_imPi ζ + have hhull := parabolaDisc_mem_holomorphicHull p s₁ s₂ htri' hc0 (imPi ζ) (subset_closure hreg) + rw [hζeq] at hhull + have hK : IsCompact (parabolaDisc p s₁ s₂ c (imPi ζ) '' frontier (parabolaRegion c)) := + isCompact_image_frontier_parabolaRegion p s₁ s₂ hc0 _ + have hKS : parabolaDisc p s₁ s₂ c (imPi ζ) '' frontier (parabolaRegion c) ⊆ + tubeDomain (segment ℝ p t₁ ∪ segment ℝ p t₂) := by + refine (parabolaDisc_frontier_subset p s₁ s₂ hc0 _).trans (tubeDomain_mono ?_) + exact union_subset_union (segment_scaled_subset p ha.le ha1 t₁) + (segment_scaled_subset p ha.le ha1 t₂) + have hball : ∀ w ∈ parabolaDisc p s₁ s₂ c (imPi ζ) '' frontier (parabolaRegion c), + ball w δ ⊆ tubeDomain A := fun w hw => hS w (hKS hw) + exact exists_continuation_ball_of_mem_holomorphicHull (isOpen_tubeDomain hA) hK + (fun w hw => hball w hw (mem_ball_self hδ)) hδ hball hhull hg + · have hmem : ζ ∈ tubeDomain (segment ℝ p t₁ ∪ segment ℝ p t₂) := by + rw [mem_tubeDomain, hre] + exact triPt_mem_union_segment p t₁ t₂ heq (hvb.trans (hba.trans ha1)) + exact ⟨g, hg.mono (hS ζ hmem), EventuallyEq.rfl⟩ + +/-- **One step of the triangle induction.** Under maximality, the `δ`-thickening of the tube +over the triangle of a smaller scale is absorbed into `A`. -/ +theorem thickening_tri_subset_of_maximal (hA : IsOpen A) (hAs : StarConvex ℝ p A) (hp : p ∈ A) + (hmax : ∀ B : Set (Fin n → ℝ), IsOpen B → StarConvex ℝ p B → + (∀ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain A) → + ∃ G : (Fin n → ℂ) → F, AnalyticOnNhd ℂ G (tubeDomain B) ∧ EqOn G g (tubeDomain A)) → + B ⊆ A) + {δ : ℝ} (hδ : 0 < δ) + (hS : ∀ w ∈ tubeDomain (segment ℝ p t₁ ∪ segment ℝ p t₂), ball w δ ⊆ tubeDomain A) + {a b : ℝ} (ha1 : a ≤ 1) (hb0 : 0 ≤ b) (hba : b ≤ a) (hlt : b = 0 ∨ b < a) + (htri : tri p t₁ t₂ a ⊆ A) : thickening δ (tri p t₁ t₂ b) ⊆ A := by + classical + set L := tri p t₁ t₂ b with hL + set N := thickening δ L with hN + have hLconv : Convex ℝ L := convex_tri p t₁ t₂ b + have hpL : p ∈ L := mem_tri_self p t₁ t₂ hb0 + have hLA : L ⊆ A := (tri_mono p t₁ t₂ hba).trans htri + have hNo : IsOpen N := isOpen_thickening + have hNc : Convex ℝ N := hLconv.thickening δ + have hpN : p ∈ N := self_subset_thickening hδ L hpL + have hNs : StarConvex ℝ p N := hNc.starConvex hpN + have hTN : tubeDomain N ⊆ ⋃ ζ ∈ tubeDomain L, ball ζ δ := by + intro z hz + rw [mem_tubeDomain, hN, Metric.mem_thickening_iff] at hz + obtain ⟨y, hy, hdist⟩ := hz + refine mem_iUnion₂.mpr ⟨ofRealPi y + I • ofRealPi (imPi z), ?_, ?_⟩ + · rw [mem_tubeDomain, rePi_add, rePi_ofRealPi, rePi_I_smul_ofRealPi, add_zero] + exact hy + · rw [mem_ball, dist_eq_norm] + have hz := ofRealPi_rePi_add_I_smul_ofRealPi_imPi z + have : z - (ofRealPi y + I • ofRealPi (imPi z)) = ofRealPi (rePi z - y) := by + rw [ofRealPi_sub] + nth_rewrite 1 [← hz] + abel + rw [this, norm_ofRealPi, ← dist_eq_norm] + exact hdist + have hsub : A ∪ N ⊆ A := by + refine hmax (A ∪ N) (hA.union hNo) (hAs.union hNs) fun g hg => ?_ + have hloc := exists_local_continuation_tri hA ha1 htri hδ hS hba hlt hg + obtain ⟨H, hHa, hHg⟩ := exists_glue_of_local_continuations (isOpen_tubeDomain hA) + (convex_tubeDomain hLconv) (tubeDomain_mono hLA) hg hδ hloc + have hHN : AnalyticOnNhd ℂ H (tubeDomain N) := hHa.mono hTN + have hAN : EqOn H g (tubeDomain (A ∩ N)) := by + have hpAN : p ∈ A ∩ N := ⟨hp, hpN⟩ + exact (hHN.mono (tubeDomain_mono inter_subset_right)).eqOn_of_preconnected_of_eventuallyEq + (hg.mono (tubeDomain_mono inter_subset_left)) + (isPreconnected_tubeDomain_of_starConvex (hAs.inter hNs) hpAN) + (ofRealPi_mem_tubeDomain.mpr hpAN) (hHg _ (ofRealPi_mem_tubeDomain.mpr hpL)) + refine ⟨fun z => if z ∈ tubeDomain A then g z else H z, ?_, fun z hz => by simp [hz]⟩ + exact analyticOnNhd_ite_tubeDomain hA hNo hg hHN (fun z hz => (hAN hz).symm) + exact subset_union_right.trans hsub + +/-- A triangle with vanishing direction vectors is the vertex. -/ +theorem tri_subset_of_dirs_zero {b : ℝ} {B : Set (Fin n → ℝ)} + (h1 : triDir₁ p t₁ t₂ = 0) (h2 : triDir₂ p t₁ t₂ = 0) (hpB : p ∈ B) : + tri p t₁ t₂ b ⊆ B := by + rintro x ⟨u, v, -, -, rfl⟩ + simpa [triPt, h1, h2] using hpB + +/-- One scale step in the triangle lemma: a slightly larger scaled triangle still lies in `A`. -/ +theorem tri_subset_scale_step_of_maximal (hA : IsOpen A) (hAs : StarConvex ℝ p A) (hp : p ∈ A) + (hmax : ∀ B : Set (Fin n → ℝ), IsOpen B → StarConvex ℝ p B → + (∀ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain A) → + ∃ G : (Fin n → ℂ) → F, AnalyticOnNhd ℂ G (tubeDomain B) ∧ EqOn G g (tubeDomain A)) → + B ⊆ A) + {δ D ε δ₁ a a' : ℝ} (hδ : 0 < δ) (hDpos : 0 < D) + (hD : D = ‖triDir₁ p t₁ t₂‖ + ‖triDir₂ p t₁ t₂‖) + (hS : ∀ w ∈ tubeDomain (segment ℝ p t₁ ∪ segment ℝ p t₂), ball w δ ⊆ tubeDomain A) + (hδ₁ : δ₁ = δ / (4 * D)) (hε : ε = min (1 / 2) (δ / (4 * D))) + (ha0 : 0 ≤ a) (ha1 : a ≤ 1) (htri : tri p t₁ t₂ a ⊆ A) + (ha'δ : a' ≤ a + δ₁) : + tri p t₁ t₂ a' ⊆ A := by + set b : ℝ := (1 - ε) * a + have hεle : ε ≤ 1 / 2 := by rw [hε]; exact min_le_left _ _ + have hεpos : 0 < ε := by rw [hε]; positivity + have hε1 : 0 ≤ 1 - ε := sub_nonneg.mpr (hεle.trans (by norm_num)) + have hb0 : 0 ≤ b := mul_nonneg hε1 ha0 + have hba : b ≤ a := mul_le_of_le_one_left ha0 (by linarith) + have hlt : b = 0 ∨ b < a := by + rcases ha0.lt_or_eq with h | h + · right; exact mul_lt_of_lt_one_left h (by linarith) + · left; dsimp [b]; rw [← h, mul_zero] + have hthick := thickening_tri_subset_of_maximal hA hAs hp hmax hδ hS ha1 hb0 hba hlt htri + rintro x ⟨u, v, huv, hva', rfl⟩ + by_cases hvb : v ≤ b + · exact hthick (self_subset_thickening hδ _ ⟨u, v, huv, hvb, rfl⟩) + · push Not at hvb + have hv0 : 0 < v := hb0.trans_lt hvb + set μ : ℝ := b / v + have hμ0 : 0 ≤ μ := div_nonneg hb0 hv0.le + have hμ1 : μ ≤ 1 := (div_le_one hv0).mpr hvb.le + have hμv : μ * v = b := div_mul_cancel₀ b hv0.ne' + apply hthick + rw [Metric.mem_thickening_iff] + refine ⟨triPt p t₁ t₂ (μ * u) (μ * v), ⟨μ * u, μ * v, ?_, ?_, rfl⟩, ?_⟩ + · rw [abs_mul, abs_of_nonneg hμ0] + exact mul_le_mul_of_nonneg_left huv hμ0 + · rw [hμv] + · rw [dist_eq_norm] + have hdiff : triPt p t₁ t₂ u v - triPt p t₁ t₂ (μ * u) (μ * v) = + ((1 - μ) * u) • triDir₁ p t₁ t₂ + ((1 - μ) * v) • triDir₂ p t₁ t₂ := by + simp only [triPt] + module + have h1 : v - b ≤ (a' - a) + ε * a := by + dsimp [b] + nlinarith [hva'] + have h2 : (a' - a) + ε * a ≤ δ₁ + ε := by nlinarith + have hεD : ε ≤ δ / (4 * D) := by rw [hε]; exact min_le_right _ _ + calc ‖triPt p t₁ t₂ u v - triPt p t₁ t₂ (μ * u) (μ * v)‖ + = ‖((1 - μ) * u) • triDir₁ p t₁ t₂ + ((1 - μ) * v) • triDir₂ p t₁ t₂‖ := by rw [hdiff] + _ ≤ ‖((1 - μ) * u) • triDir₁ p t₁ t₂‖ + ‖((1 - μ) * v) • triDir₂ p t₁ t₂‖ := + norm_add_le _ _ + _ = (1 - μ) * |u| * ‖triDir₁ p t₁ t₂‖ + (1 - μ) * v * ‖triDir₂ p t₁ t₂‖ := by + rw [norm_smul, norm_smul, Real.norm_eq_abs, Real.norm_eq_abs, abs_mul, abs_mul, + abs_of_nonneg (by linarith : (0 : ℝ) ≤ 1 - μ), abs_of_pos hv0] + _ ≤ (1 - μ) * v * ‖triDir₁ p t₁ t₂‖ + (1 - μ) * v * ‖triDir₂ p t₁ t₂‖ := by + gcongr + _ = (v - b) * D := by rw [hD, ← hμv]; ring + _ ≤ (δ₁ + ε) * D := mul_le_mul_of_nonneg_right (h1.trans h2) hDpos.le + _ ≤ (δ / (4 * D) + δ / (4 * D)) * D := + mul_le_mul_of_nonneg_right (add_le_add (le_of_eq hδ₁) hεD) hDpos.le + _ = δ / 2 := by field_simp; ring + _ < δ := half_lt_self hδ + +/-- **The triangle lemma.** Under maximality, the full triangle with vertex `p` and two +points of `A` lies in `A`. -/ +theorem tri_subset_of_maximal (hA : IsOpen A) (hAs : StarConvex ℝ p A) (hp : p ∈ A) + (hmax : ∀ B : Set (Fin n → ℝ), IsOpen B → StarConvex ℝ p B → + (∀ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain A) → + ∃ G : (Fin n → ℂ) → F, AnalyticOnNhd ℂ G (tubeDomain B) ∧ EqOn G g (tubeDomain A)) → + B ⊆ A) + (ht₁ : t₁ ∈ A) (ht₂ : t₂ ∈ A) : tri p t₁ t₂ 1 ⊆ A := by + have hS_sub : segment ℝ p t₁ ∪ segment ℝ p t₂ ⊆ A := + union_subset (hAs.segment_subset ht₁) (hAs.segment_subset ht₂) + have hS_cpt : IsCompact (segment ℝ p t₁ ∪ segment ℝ p t₂) := by + refine IsCompact.union ?_ ?_ <;> + · rw [segment_eq_image'] + exact isCompact_Icc.image (by fun_prop) + obtain ⟨δ, hδ, hδA⟩ := hS_cpt.exists_thickening_subset_open hA hS_sub + have hS : ∀ w ∈ tubeDomain (segment ℝ p t₁ ∪ segment ℝ p t₂), ball w δ ⊆ tubeDomain A := + fun w hw => ball_subset_tubeDomain + ((ball_subset_thickening (E := segment ℝ p t₁ ∪ segment ℝ p t₂) (x := rePi w) hw δ).trans hδA) + set D : ℝ := ‖triDir₁ p t₁ t₂‖ + ‖triDir₂ p t₁ t₂‖ with hD + have hD0 : 0 ≤ D := by positivity + rcases hD0.lt_or_eq with hDpos | hDzero + swap + · have h1 : triDir₁ p t₁ t₂ = 0 := + norm_eq_zero.mp (by linarith [norm_nonneg (triDir₁ p t₁ t₂), norm_nonneg (triDir₂ p t₁ t₂)]) + have h2 : triDir₂ p t₁ t₂ = 0 := + norm_eq_zero.mp (by linarith [norm_nonneg (triDir₁ p t₁ t₂), norm_nonneg (triDir₂ p t₁ t₂)]) + exact tri_subset_of_dirs_zero h1 h2 hp + set δ₁ : ℝ := δ / (4 * D) + set ε : ℝ := min (1 / 2) (δ / (4 * D)) + have hδ₁ : 0 < δ₁ := by positivity + have hind : ∀ k : ℕ, tri p t₁ t₂ (min 1 (k * δ₁)) ⊆ A := by + intro k + induction k with + | zero => + rw [Nat.cast_zero, zero_mul, min_eq_right zero_le_one, tri_zero] + simpa using hp + | succ k ih => + have hk0 : (0 : ℝ) ≤ k * δ₁ := by positivity + refine tri_subset_scale_step_of_maximal hA hAs hp hmax hδ hDpos hD hS rfl rfl + (le_min zero_le_one hk0) (min_le_left _ _) ih ?_ + rcases le_or_gt 1 (k * δ₁) with h | h + · rw [min_eq_left h] + exact le_add_of_le_of_nonneg (min_le_left _ _) hδ₁.le + · rw [min_eq_right h.le] + push_cast + refine (min_le_right _ _).trans ?_ + rw [add_mul, one_mul] + obtain ⟨k, hk⟩ := exists_nat_ge (1 / δ₁) + have hk1 : 1 ≤ k * δ₁ := by + rw [div_le_iff₀ hδ₁] at hk + linarith + have := hind k + rwa [min_eq_left hk1] at this + +end Triangle + +section Convex + +variable {Ω : Set (Fin n → ℝ)} {p : Fin n → ℝ} + +/-- **The maximal star-convex extension base is convex.** -/ +theorem convex_maxStar (hp : p ∈ maxStar F Ω p) : Convex ℝ (maxStar F Ω p) := by + rw [convex_iff_segment_subset] + intro t₁ ht₁ t₂ ht₂ + exact (segment_subset_tri p t₁ t₂).trans (tri_subset_of_maximal isOpen_maxStar starConvex_maxStar + hp (fun _ hB hBs hext => maxStar_maximal hp hB hBs hext) ht₁ ht₂) + +end Convex + +end BochnerTube + +open BochnerTube + +section Convex + +variable {n : ℕ} {F : Type*} [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {Ω : Set (Fin n → ℝ)} {p : Fin n → ℝ} + +/-- **Bochner's tube theorem for star-convex bases.** Every Banach-valued holomorphic function +on the tube over an open star-convex base extends to the tube over the convex hull. -/ +theorem exists_extension_tubeDomain_convexHull_of_starConvex (hΩ : IsOpen Ω) + (hs : StarConvex ℝ p Ω) (hp : p ∈ Ω) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f (tubeDomain Ω)) : + ∃ g : (Fin n → ℂ) → F, AnalyticOnNhd ℂ g (tubeDomain (convexHull ℝ Ω)) ∧ + EqOn g f (tubeDomain Ω) := by + have hΩmem : Ω ∈ starFamily F Ω p := ⟨hΩ, hs, fun f hf => ⟨f, hf, EventuallyEq.rfl⟩⟩ + have hΩsub : Ω ⊆ maxStar F Ω p := subset_maxStar_of_mem hΩmem + have hpm : p ∈ maxStar F Ω p := hΩsub hp + have hconv : convexHull ℝ Ω ⊆ maxStar F Ω p := convexHull_min hΩsub (convex_maxStar hpm) + obtain ⟨g, hg, hgf⟩ := tubeExtends_maxStar hpm f hf + refine ⟨g, hg.mono (tubeDomain_mono hconv), ?_⟩ + exact (hg.mono (tubeDomain_mono hΩsub)).eqOn_of_preconnected_of_eventuallyEq hf + (isPreconnected_tubeDomain_of_starConvex hs hp) (ofRealPi_mem_tubeDomain.mpr hp) hgf + +end Convex + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision.lean new file mode 100644 index 0000000000..25e652ecd1 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision.lean @@ -0,0 +1,657 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.AnalyticGerm +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Picard + +/-! +# Analytic Weierstrass division + +A divisor of finite order in the distinguished scalar coordinate admits a unique quotient and a +polynomial remainder. We normalize the divisor by a nonvanishing leading factor, make the +remaining perturbation small, and apply the Picard iteration. Uniqueness holds on smaller +neighborhoods and hence for germs. The uniform statement applies to bounded numerators on a +common polydisc; the local statement applies to arbitrary analytic numerators. + +This module also exports the supporting theory: + +* `WeierstrassDivision.Basic`: division predicates and elementary properties; +* `WeierstrassDivision.CoordinatePower`: Cauchy division by a coordinate power; +* `WeierstrassDivision.Picard`: contraction estimates, limits, and uniqueness. + +Reference: [Jakóbczak–Jarnicki][JakobczakJarnicki2021], §1.7, Theorem 1.7.3. These analytic +statements do not follow just from Mathlib's formal, adic division theorem. + +## Main results + +* `exists_coordinatePower_leadingFactor_ne_zero`: **Coordinate-power normalization with a + nonvanishing leading factor.** A holomorphic function of finite order `d` in the distinguished + coordinate decomposes, on some initial polydisc-ball, as `f1 * z.2 ^ d` plus a Weierstrass + remainder whose coefficients vanish at the parameter origin; moreover `f1` itself is nonzero + throughout a (possibly smaller) polydisc-ball. +* `exists_perturbation_bound_of_coordinatePower_leadingFactor`: **A uniformly small perturbation of + the coordinate power.** Given a coordinate-power decomposition `f = f1 * z.2 ^ d + + weierstrassRemainder c` with `f1` nonvanishing on a polydisc-ball of radius `ε₁`, the perturbation + `weierstrassRemainder c / f1` is analytic there and, on a smaller polydisc-ball, uniformly bounded + by `R₂ ^ d / (2 * (d + 1))`: small enough for the Picard iteration against the divisor `z ^ d` to + contract in `exists_isWeierstrassDivisionOn_of_bounded`. +* `exists_isWeierstrassDivisionOn_of_bounded`: **Weierstrass division + ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.7.3).** A divisor whose central scalar slice has + finite order `d` admits division of every bounded holomorphic numerator on a fixed polydisc. +* `exists_isWeierstrassDivisionAt_of_finiteDimensional`: **Weierstrass division for analytic germs + on any finite-dimensional parameter space.** Obtained by transporting the coordinate version along + a basis; no choice of coordinates occurs in the statement. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Complex Filter Finset Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +open WeierstrassDivision + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +variable {ι : Type*} [Fintype ι] + +/-- **Coordinate-power normalization with a nonvanishing leading factor.** A holomorphic +function of finite order `d` in the distinguished coordinate decomposes, on some initial +polydisc-ball, as `f1 * z.2 ^ d` plus a Weierstrass remainder whose coefficients vanish at +the parameter origin; moreover `f1` itself is nonzero throughout a (possibly smaller) +polydisc-ball. This supplies the normalization in `exists_isWeierstrassDivisionOn_of_bounded`. -/ +theorem exists_coordinatePower_leadingFactor_ne_zero {d : ℕ} {f : (ι → ℂ) × ℂ → ℂ} + {U : Set ((ι → ℂ) × ℂ)} (hU : IsOpen U) (h0 : 0 ∈ U) (hf : DifferentiableOn ℂ f U) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (f1 : (ι → ℂ) × ℂ → ℂ) (c : Fin d → (ι → ℂ) → ℂ) (ε₀ ε₁ : ℝ), 0 < ε₀ ∧ 0 < ε₁ ∧ + polydisc (0 : ι → ℂ) (fun _ => ε₀) ×ˢ ball (0 : ℂ) ε₀ ⊆ U ∧ + IsWeierstrassDivisionOn (fun z => z.2 ^ d) f f1 c + (polydisc (0 : ι → ℂ) (fun _ => ε₀)) ε₀ ∧ + (∀ j, c j 0 = 0) ∧ + polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁ ⊆ + polydisc (0 : ι → ℂ) (fun _ => ε₀) ×ˢ ball (0 : ℂ) ε₀ ∧ + ∀ z ∈ polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁, f1 z ≠ 0 := by + obtain ⟨ε₀, hε₀, hε₀U⟩ := exists_polydisc_ball_subset hU h0 + have hf0 : DifferentiableOn ℂ f (polydisc (0 : ι → ℂ) (fun _ => ε₀) ×ˢ ball 0 ε₀) := + hf.mono hε₀U + obtain ⟨f1, c, hfdiv, hf1bound, hf1uniq⟩ := + coordinatePower_division d hε₀ hf0 + have hz0V : (0 : ι → ℂ) ∈ polydisc (0 : ι → ℂ) (fun _ => ε₀) := + mem_polydisc.mpr fun i => by simpa using hε₀ + have hforder : AnalyticAt ℂ (fun w : ℂ => f (0, w)) 0 := + (differentiableOn_snd_slice hf0 hz0V).analyticOnNhd_of_finiteDimensional isOpen_ball + 0 (mem_ball_self hε₀) + have hcj0 : ∀ j : Fin d, c j 0 = 0 := by + intro j + rw [coeff_eq_iteratedDeriv_of_coordinatePower_division hfdiv hε₀ hz0V j] + have hle : (d : ℕ∞) ≤ analyticOrderAt (fun w : ℂ => f (0, w)) 0 := horder.ge + rw [(natCast_le_analyticOrderAt_iff_iteratedDeriv_eq_zero hforder).mp hle (j : ℕ) j.isLt] + simp + have hf1_eq : ∀ ζ ∈ ball (0 : ℂ) ε₀, f (0, ζ) = f1 (0, ζ) * ζ ^ d := by + intro ζ hζ + have := hfdiv.eq (Set.mk_mem_prod hz0V hζ) + simpa [weierstrassRemainder, hcj0, mul_comm] using this + have hf1A0 : AnalyticAt ℂ (fun ζ : ℂ => f1 (0, ζ)) 0 := + (differentiableOn_snd_slice hfdiv.differentiableOn_quotient + hz0V).analyticOnNhd_of_finiteDimensional + isOpen_ball 0 (mem_ball_self hε₀) + have horder' : analyticOrderAt (fun ζ : ℂ => f1 (0, ζ) * ζ ^ d) 0 = d := by + rw [← analyticOrderAt_congr (Filter.eventuallyEq_of_mem (isOpen_ball.mem_nhds + (mem_ball_self hε₀)) hf1_eq)] + exact horder + have hf1ord0 : analyticOrderAt (fun ζ : ℂ => f1 (0, ζ)) 0 = 0 := by + have hpow : AnalyticAt ℂ (fun ζ : ℂ => ζ ^ d) 0 := analyticAt_id.pow d + have hpow' : analyticOrderAt (fun ζ : ℂ => ζ ^ d) 0 = d := by + have h := analyticOrderAt_pow (analyticAt_id (𝕜 := ℂ) (z := (0 : ℂ))) d + simpa [analyticOrderAt_id, Pi.pow_def] using h + have hmul : analyticOrderAt (fun ζ : ℂ => f1 (0, ζ) * ζ ^ d) 0 = + analyticOrderAt (fun ζ : ℂ => f1 (0, ζ)) 0 + analyticOrderAt (fun ζ : ℂ => ζ ^ d) 0 := + analyticOrderAt_mul hf1A0 hpow + rw [hmul, hpow'] at horder' + set y := analyticOrderAt (fun ζ : ℂ => f1 (0, ζ)) 0 with hy + clear_value y + induction y using ENat.recTopCoe with + | top => + exfalso + rw [show ((⊤ : ℕ∞) + (d : ℕ∞)) = ⊤ from rfl] at horder' + exact absurd horder' (ENat.natCast_ne_top d).symm + | coe n => + have hcast : ((n + d : ℕ) : ℕ∞) = ((d : ℕ) : ℕ∞) := horder' + have hn : n + d = d := WithTop.coe_injective hcast + have hn0 : n = 0 := by omega + rw [hn0] + rfl + have hf1ne0 : f1 (0, 0) ≠ 0 := hf1A0.analyticOrderAt_eq_zero.mp hf1ord0 + have hz00 : ((0 : ι → ℂ), (0 : ℂ)) ∈ + polydisc (0 : ι → ℂ) (fun _ => ε₀) ×ˢ ball (0 : ℂ) ε₀ := + ⟨hz0V, mem_ball_self hε₀⟩ + have hf1contAt : ContinuousAt f1 (0, 0) := + ((hfdiv.differentiableOn_quotient.analyticOnNhd_of_finiteDimensional + ((isOpen_polydisc _ _).prod isOpen_ball)) _ hz00).continuousAt + have hf1ev : ∀ᶠ z in 𝓝 ((0 : ι → ℂ), (0 : ℂ)), f1 z ≠ 0 := + hf1contAt.eventually_ne hf1ne0 + obtain ⟨S, hSf1, hSopen, hS0⟩ := _root_.eventually_nhds_iff.mp hf1ev + obtain ⟨ε₁, hε₁, hε₁sub⟩ := exists_polydisc_ball_subset + (hSopen.inter ((isOpen_polydisc (0 : ι → ℂ) (fun _ => ε₀)).prod isOpen_ball)) + ⟨hS0, hz00⟩ + have hε₁ε₀ : polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁ ⊆ + polydisc (0 : ι → ℂ) (fun _ => ε₀) ×ˢ ball (0 : ℂ) ε₀ := + fun z hz => (hε₁sub hz).2 + have hf1ne0' : ∀ z ∈ polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁, f1 z ≠ 0 := + fun z hz => hSf1 z (hε₁sub hz).1 + exact ⟨f1, c, ε₀, ε₁, hε₀, hε₁, hε₀U, hfdiv, hcj0, hε₁ε₀, hf1ne0'⟩ + +omit [Fintype ι] in +/-- Uniform coefficient bounds give a uniform bound for a Weierstrass remainder on a scalar disc, +including the empty remainder when `d = 0`. -/ +private theorem norm_weierstrassRemainder_le {d : ℕ} {c : Fin d → (ι → ℂ) → ℂ} + {w : ι → ℂ} {ζ : ℂ} {R ε : ℝ} (hε : 0 ≤ ε) + (hc : ∀ j, ‖c j w‖ ≤ ε) (hζ : ‖ζ‖ ≤ R) : + ‖weierstrassRemainder c (w, ζ)‖ ≤ (d : ℝ) * ε * (max R 1) ^ d := by + have hpow (j : Fin d) : ‖ζ‖ ^ (j : ℕ) ≤ (max R 1) ^ d := + (pow_le_pow_left₀ (norm_nonneg _) (hζ.trans (le_max_left _ _)) _).trans + (pow_le_pow_right₀ (le_max_right _ _) j.isLt.le) + calc + ‖weierstrassRemainder c (w, ζ)‖ ≤ ∑ j : Fin d, ‖c j w * ζ ^ (j : ℕ)‖ := + norm_sum_le _ _ + _ ≤ ∑ _j : Fin d, ε * (max R 1) ^ d := by + apply Finset.sum_le_sum + intro j _ + rw [norm_mul, norm_pow] + exact mul_le_mul (hc j) (hpow j) (by positivity) hε + _ = (d : ℝ) * ε * (max R 1) ^ d := by simp; ring + +omit [Fintype ι] in +/-- If the remainder coefficients tend to zero and the leading factor is bounded away from zero, +shrinking only the parameter polydisc gives the contraction bound. The scalar radius and an +upper bound for the parameter radius can be prescribed. -/ +private theorem exists_small_remainder_div [Finite ι] {d : ℕ} {c : Fin d → (ι → ℂ) → ℂ} + {f1 : (ι → ℂ) × ℂ → ℂ} {R δ r₀ : ℝ} (hR : 0 < R) (hδ : 0 < δ) (hr₀ : 0 < r₀) + (hc : ∀ j, Tendsto (c j) (𝓝 0) (𝓝 0)) + (hlower : ∀ z ∈ polydisc (0 : ι → ℂ) (fun _ => r₀) ×ˢ ball (0 : ℂ) R, + δ ≤ ‖f1 z‖) : + ∃ r : ℝ, 0 < r ∧ r ≤ r₀ ∧ + ∀ z ∈ polydisc (0 : ι → ℂ) (fun _ => r) ×ˢ ball (0 : ℂ) R, + ‖weierstrassRemainder c z / f1 z‖ ≤ R ^ d / (2 * (d + 1)) := by + classical + let := Fintype.ofFinite ι + let ε := δ * R ^ d / (2 * (d + 1) * (d + 1) * (max R 1) ^ d) + have hε : 0 < ε := by dsimp [ε]; positivity + have hev : ∀ᶠ w in 𝓝 (0 : ι → ℂ), ∀ j, ‖c j w‖ < ε := by + apply eventually_all.mpr + intro j + have ht : Tendsto (fun w => ‖c j w‖) (𝓝 0) (𝓝 0) := by simpa using (hc j).norm + exact ht.eventually_lt_const hε + obtain ⟨s, hs, hsmall⟩ := Metric.eventually_nhds_iff.mp hev + refine ⟨min s r₀, lt_min hs hr₀, min_le_right _ _, ?_⟩ + rintro ⟨w, ζ⟩ ⟨hw, hζ⟩ + have hw' : ‖w‖ < min s r₀ := by + simpa [pi_norm_lt_iff (lt_min hs hr₀), mem_polydisc] using hw + have hcw : ∀ j, ‖c j w‖ ≤ ε := fun j => + (hsmall (by simpa [dist_zero_right] using hw'.trans_le (min_le_left s r₀)) j).le + have hnum := norm_weierstrassRemainder_le hε.le hcw (mem_ball_zero_iff.mp hζ).le + have hl := hlower (w, ζ) ⟨polydisc_mono _ (fun _ => min_le_right s r₀) hw, hζ⟩ + rw [norm_div] + calc + ‖weierstrassRemainder c (w, ζ)‖ / ‖f1 (w, ζ)‖ ≤ + ((d : ℝ) * ε * (max R 1) ^ d) / δ := + (div_le_div_of_nonneg_right hnum (hδ.trans_le hl).le).trans + (div_le_div_of_nonneg_left (by positivity) hδ hl) + _ = (d : ℝ) * R ^ d / (2 * (d + 1) * (d + 1)) := by dsimp [ε]; field_simp + _ ≤ R ^ d / (2 * (d + 1)) := by + rw [div_le_div_iff₀ (by positivity) (by positivity)] + nlinarith [pow_pos hR d] + +/-- **A uniformly small perturbation of the coordinate power.** Given a coordinate-power +decomposition `f = f1 * z.2 ^ d + weierstrassRemainder c` with `f1` nonvanishing on a +polydisc-ball of radius `ε₁`, the perturbation `weierstrassRemainder c / f1` is analytic +there and, on a smaller polydisc-ball, uniformly bounded by `R₂ ^ d / (2 * (d + 1))`: small +enough for the Picard iteration against the divisor `z ^ d` to contract in +`exists_isWeierstrassDivisionOn_of_bounded`. The bound `δ` on `‖f1‖` over a fixed compact set is +also returned, since the germ-uniqueness argument reuses it at a further-shrunk radius. -/ +theorem exists_perturbation_bound_of_coordinatePower_leadingFactor {d : ℕ} {f : (ι → ℂ) × ℂ → ℂ} + {f1 : (ι → ℂ) × ℂ → ℂ} {c : Fin d → (ι → ℂ) → ℂ} {ε₀ ε₁ : ℝ} (hε₁ : 0 < ε₁) + (hε₁ε₀ : polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁ ⊆ + polydisc (0 : ι → ℂ) (fun _ => ε₀) ×ˢ ball (0 : ℂ) ε₀) + (hfdiv : IsWeierstrassDivisionOn (fun z => z.2 ^ d) f f1 c + (polydisc (0 : ι → ℂ) (fun _ => ε₀)) ε₀) + (hcj0 : ∀ j, c j 0 = 0) + (hf1ne0' : ∀ z ∈ polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁, f1 z ≠ 0) : + ∃ R₂ δ r₃ : ℝ, 0 < R₂ ∧ R₂ < ε₁ ∧ 0 < δ ∧ 0 < r₃ ∧ r₃ ≤ ε₁ / 2 ∧ + DifferentiableOn ℂ (fun z => weierstrassRemainder c z / f1 z) + (polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁) ∧ + (∀ j, Tendsto (c j) (𝓝 0) (𝓝 0)) ∧ + (∀ z ∈ closedPolydisc (0 : ι → ℂ) (fun _ => ε₁ / 2) ×ˢ closedBall (0 : ℂ) R₂, + δ ≤ ‖f1 z‖) ∧ + ∀ w ∈ polydisc (0 : ι → ℂ) (fun _ => r₃), ∀ ζ ∈ ball (0 : ℂ) R₂, + ‖weierstrassRemainder c (w, ζ) / f1 (w, ζ)‖ ≤ R₂ ^ d / (2 * (d + 1)) := by + have hpoly1sub : polydisc (0 : ι → ℂ) (fun _ => ε₁) ⊆ + polydisc (0 : ι → ℂ) (fun _ => ε₀) := + fun z hz => (hε₁ε₀ (Set.mk_mem_prod hz (mem_ball_self hε₁))).1 + have hcA1 : ∀ j, DifferentiableOn ℂ (c j) (polydisc (0 : ι → ℂ) (fun _ => ε₁)) := + fun j => (hfdiv.differentiableOn_coeff j).mono hpoly1sub + have hremA1 : DifferentiableOn ℂ (weierstrassRemainder c) + (polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁) := by + unfold weierstrassRemainder + apply DifferentiableOn.fun_sum + intro j _ + exact ((hcA1 j).comp differentiableOn_fst (fun z hz => hz.1)).mul + (differentiableOn_snd.pow (j : ℕ)) + have hf1A1 : DifferentiableOn ℂ f1 + (polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁) := + hfdiv.differentiableOn_quotient.mono hε₁ε₀ + have hhA1 : DifferentiableOn ℂ (fun z => weierstrassRemainder c z / f1 z) + (polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁) := by + simp_rw [div_eq_mul_inv] + exact hremA1.mul (hf1A1.inv hf1ne0') + set R₂ : ℝ := ε₁ / 2 with hR₂def + have hR₂pos : 0 < R₂ := by positivity + have hR₂ε₁ : R₂ < ε₁ := by rw [hR₂def]; linarith + set K : Set ((ι → ℂ) × ℂ) := + closedPolydisc (0 : ι → ℂ) (fun _ => ε₁ / 2) ×ˢ closedBall (0 : ℂ) R₂ with hKdef + have hKsub : K ⊆ polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁ := by + apply Set.prod_mono + · exact closedPolydisc_subset_polydisc _ (fun _ => by linarith) + · exact closedBall_subset_ball hR₂ε₁ + have hKcompact : IsCompact K := + (isCompact_closedPolydisc _ _).prod (isCompact_closedBall _ _) + have hKne : K.Nonempty := ⟨(0, 0), by + refine ⟨mem_closedPolydisc.mpr fun i => ?_, mem_closedBall_self hR₂pos.le⟩ + simpa using (half_pos hε₁).le⟩ + have hf1contK : ContinuousOn f1 K := (hf1A1.mono hKsub).continuousOn + obtain ⟨zmin, hzminK, hzminmin⟩ := hKcompact.exists_isMinOn hKne hf1contK.norm + set δ : ℝ := ‖f1 zmin‖ with hδdef + have hδpos : 0 < δ := norm_pos_iff.mpr (hf1ne0' zmin (hKsub hzminK)) + have hδle : ∀ z ∈ K, δ ≤ ‖f1 z‖ := fun z hz => hzminmin hz + have hcj0' : ∀ j : Fin d, Tendsto (c j) (𝓝 0) (𝓝 0) := fun j => + (hcj0 j) ▸ ((hcA1 j).continuousOn.continuousAt (isOpen_polydisc _ _ |>.mem_nhds + (mem_polydisc.mpr fun i => by simpa using half_pos hε₁))) + obtain ⟨r₃, hr₃pos, hr₃ε₁, hhbound⟩ := + exists_small_remainder_div hR₂pos hδpos (half_pos hε₁) hcj0' + (fun z hz => hδle z ⟨mem_closedPolydisc.mpr (fun i => (mem_polydisc.mp + hz.1 i).le), + ball_subset_closedBall hz.2⟩) + exact ⟨R₂, δ, r₃, hR₂pos, hR₂ε₁, hδpos, hr₃pos, hr₃ε₁, hhA1, hcj0', hδle, + fun w hw ζ hζ => hhbound (w, ζ) ⟨hw, hζ⟩⟩ + +/-- Germ uniqueness for division by a normalized divisor. A fresh small-remainder estimate allows +comparison on any smaller neighborhood supporting the other decomposition; bounded fixed-point +uniqueness then identifies both germs. -/ +private theorem normalized_division_germ_unique {d : ℕ} {r₃ R₂ δ : ℝ} + {f f1 g S : (ι → ℂ) × ℂ → ℂ} {c aOut : Fin d → (ι → ℂ) → ℂ} + (hr₃pos : 0 < r₃) (hR₂pos : 0 < R₂) (hδpos : 0 < δ) + (hf1FINAL : DifferentiableOn ℂ f1 + (polydisc 0 (fun _ => r₃) ×ˢ ball 0 R₂)) + (hlower : ∀ z ∈ polydisc 0 (fun _ => r₃) ×ˢ ball 0 R₂, δ ≤ ‖f1 z‖) + (hcj0' : ∀ j, Tendsto (c j) (𝓝 0) (𝓝 0)) + (hhFINAL : DifferentiableOn ℂ (fun z => weierstrassRemainder c z / f1 z) + (polydisc 0 (fun _ => r₃) ×ˢ ball 0 R₂)) + (hf_eq2 : ∀ z ∈ polydisc 0 (fun _ => r₃) ×ˢ ball 0 R₂, + f z = f1 z * (z.2 ^ d + weierstrassRemainder c z / f1 z)) + (hfixed : IsWeierstrassDivisionOn (fun z => z.2 ^ d) + (g - (fun z => weierstrassRemainder c z / f1 z) * S) S aOut + (polydisc 0 (fun _ => r₃)) R₂) + {q' : (ι → ℂ) × ℂ → ℂ} {a' : Fin d → (ι → ℂ) → ℂ} + (hdiv' : IsWeierstrassDivisionAt f g q' a') : + (fun z => S z / f1 z) =ᶠ[𝓝 0] q' ∧ ∀ j, aOut j =ᶠ[𝓝 0] a' j := by + let domFINAL := polydisc (0 : ι → ℂ) (fun _ => r₃) ×ˢ ball (0 : ℂ) R₂ + let hh := fun z => weierstrassRemainder c z / f1 z + let q := fun z => S z / f1 z + have hf1ne0FINAL : ∀ z ∈ domFINAL, f1 z ≠ 0 := + fun z hz => norm_pos_iff.mp (hδpos.trans_le (hlower z hz)) + have h00 : (0 : (ι → ℂ) × ℂ) ∈ domFINAL := + ⟨mem_polydisc.mpr fun i => by simpa using hr₃pos, mem_ball_self hR₂pos⟩ + obtain ⟨ρ₀, hρ₀pos, hρ₀sub, hlocal⟩ := hdiv'.exists_divisionOn + ((isOpen_polydisc _ _).prod isOpen_ball) h00 + obtain ⟨ρ, hρpos, hρρ₀⟩ := exists_between hρ₀pos + have hρsub : polydisc (0 : ι → ℂ) (fun _ => ρ) ×ˢ ball (0 : ℂ) ρ ⊆ domFINAL := + (Set.prod_mono (polydisc_mono _ (fun _ => hρρ₀.le)) + (ball_subset_ball hρρ₀.le)).trans hρ₀sub + -- The same small-remainder lemma applies at this smaller scalar radius. + obtain ⟨r₅, hr₅pos, hr₅ρ, hhb3⟩ := + exists_small_remainder_div hρpos hδpos hρpos hcj0' + (fun z hz => hlower z (hρsub hz)) + have hdomsub5 : polydisc (0 : ι → ℂ) (fun _ => r₅) ×ˢ ball (0 : ℂ) ρ ⊆ domFINAL := + fun z hz => hρsub ⟨polydisc_mono _ (fun _ => hr₅ρ) hz.1, hz.2⟩ + set dom5 : Set ((ι → ℂ) × ℂ) := polydisc (0 : ι → ℂ) (fun _ => r₅) ×ˢ ball (0 : ℂ) ρ + with hdom5def + have hlocalSub : dom5 ⊆ polydisc 0 (fun _ => ρ₀) ×ˢ ball 0 ρ₀ := + Set.prod_mono (polydisc_mono _ (fun _ => hr₅ρ.trans hρρ₀.le)) + (ball_subset_ball hρρ₀.le) + have hq'Adiff : DifferentiableOn ℂ q' dom5 := hlocal.differentiableOn_quotient.mono hlocalSub + have ha'Adiff : ∀ j, DifferentiableOn ℂ (a' j) (polydisc 0 (fun _ => r₅)) := + fun j => (hlocal.differentiableOn_coeff j).mono + (polydisc_mono _ (fun _ => hr₅ρ.trans hρρ₀.le)) + have hf1diff5 : DifferentiableOn ℂ f1 dom5 := hf1FINAL.mono hdomsub5 + set s' : (ι → ℂ) × ℂ → ℂ := fun z => q' z * f1 z with hs'def + have hs'diff : DifferentiableOn ℂ s' dom5 := hq'Adiff.mul hf1diff5 + have hhFINAL5 : DifferentiableOn ℂ hh dom5 := hhFINAL.mono hdomsub5 + have hpoly53 : polydisc (0 : ι → ℂ) (fun _ => r₅) ⊆ + polydisc (0 : ι → ℂ) (fun _ => r₃) := + fun w hw => (hdomsub5 (⟨hw, mem_ball_self hρpos⟩ : (w, (0:ℂ)) ∈ dom5)).1 + have hdiv' : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (g - hh * s') s' a' + (polydisc (0 : ι → ℂ) (fun _ => r₅)) ρ := by + refine ⟨hs'diff, ha'Adiff, ?_⟩ + intro z hz + have heqz : g z = q' z * f z + weierstrassRemainder a' z := hlocal.eq (hlocalSub hz) + have heqf5 : f z = f1 z * (z.2 ^ d + hh z) := hf_eq2 z (hdomsub5 hz) + change g z - hh z * s' z = s' z * z.2 ^ d + weierstrassRemainder a' z + simp only [hs'def] + rw [heqz, heqf5] + ring + have hSdiv : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (g - hh * S) S aOut + (polydisc (0 : ι → ℂ) (fun _ => r₅)) ρ := + ⟨hfixed.differentiableOn_quotient.mono hdomsub5, + fun j => (hfixed.differentiableOn_coeff j).mono hpoly53, fun _ hz => hfixed.eq (hdomsub5 hz)⟩ + -- Compact containment bounds the difference of the two fixed-point candidates. + let K := closedPolydisc (0 : ι → ℂ) (fun _ => ρ) ×ˢ closedBall (0 : ℂ) ρ + have hclosedsub : K ⊆ polydisc 0 (fun _ => ρ₀) ×ˢ ball 0 ρ₀ := + Set.prod_mono (closedPolydisc_subset_polydisc _ (fun _ => hρρ₀)) + (closedBall_subset_ball hρρ₀) + have hKfinal := hclosedsub.trans hρ₀sub + have hcompact : IsCompact K := + (isCompact_closedPolydisc _ _).prod (isCompact_closedBall _ _) + have hcont : ContinuousOn (fun z => S z - s' z) K := + (hfixed.differentiableOn_quotient.continuousOn.mono hKfinal).sub + ((hlocal.differentiableOn_quotient.continuousOn.mono hclosedsub).mul + (hf1FINAL.continuousOn.mono hKfinal)) + obtain ⟨C1, hC1⟩ := hcompact.bddAbove_image hcont.norm + have hM3b : ∀ z ∈ dom5, ‖S z - s' z‖ ≤ max C1 0 := by + intro z hz + apply (hC1 ⟨z, ?_, rfl⟩).trans (le_max_left _ _) + exact ⟨mem_closedPolydisc.mpr fun i => + (mem_polydisc.mp hz.1 i).le.trans hr₅ρ, ball_subset_closedBall hz.2⟩ + obtain ⟨hSeqs', haOuteqa'⟩ := eqOn_of_isWeierstrassDivisionOn_selfPerturbed + hρpos hh g S s' aOut a' hhFINAL5 hhb3 hSdiv hdiv' (max C1 0) (le_max_right _ _) hM3b + have hqeqq' : EqOn q q' dom5 := by + intro z hz + change S z / f1 z = q' z + rw [hSeqs' hz] + show s' z / f1 z = q' z + rw [hs'def] + exact mul_div_cancel_right₀ _ (hf1ne0FINAL z (hdomsub5 hz)) + have h05 : (0 : (ι → ℂ) × ℂ) ∈ dom5 := + ⟨mem_polydisc.mpr fun i => by simpa using hr₅pos, mem_ball_self hρpos⟩ + have hnbhd : dom5 ∈ 𝓝 (0 : (ι → ℂ) × ℂ) := + (isOpen_polydisc _ _ |>.prod isOpen_ball).mem_nhds h05 + refine ⟨Filter.eventuallyEq_of_mem hnbhd hqeqq', fun j => Filter.eventuallyEq_of_mem + ((isOpen_polydisc (0 : ι → ℂ) (fun _ => r₅)).mem_nhds + (mem_polydisc.mpr fun i => by simpa using hr₅pos)) (haOuteqa' j)⟩ + +/-- Undoing the nonvanishing leading factor converts a normalized fixed-point division into division +by the original divisor. The remainder is unchanged. -/ +private theorem divisionOn_div_leadingFactor {d : ℕ} {r : ι → ℝ} {R : ℝ} + {f f1 g h S : (ι → ℂ) × ℂ → ℂ} {a : Fin d → (ι → ℂ) → ℂ} + (hf1 : DifferentiableOn ℂ f1 (polydisc 0 r ×ˢ ball 0 R)) + (hne : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, f1 z ≠ 0) + (heq : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, f z = f1 z * (z.2 ^ d + h z)) + (hfixed : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (g - h * S) S a + (polydisc 0 r) R) : + IsWeierstrassDivisionOn f g (fun z => S z / f1 z) a (polydisc 0 r) R := by + refine ⟨?_, hfixed.differentiableOn_coeff, ?_⟩ + · change DifferentiableOn ℂ (fun z => S z / f1 z) _ + simp_rw [div_eq_mul_inv] + exact hfixed.differentiableOn_quotient.mul (hf1.inv hne) + · intro z hz + change g z = S z / f1 z * f z + weierstrassRemainder a z + have hqf : S z / f1 z * f z = S z * (z.2 ^ d + h z) := by + rw [heq z hz] + field_simp [hne z hz] + rw [hqf] + have h := hfixed.eq hz + dsimp only [Pi.sub_apply, Pi.mul_apply] at h + linear_combination h + +/-- **Weierstrass division ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.7.3).** A divisor whose +central +scalar slice has finite order `d` admits division of every bounded holomorphic numerator +on a fixed polydisc. The quotient bound is uniform in the numerator. Uniqueness is local, +so it also compares decompositions initially defined on smaller neighborhoods. +The proof combines normalization, the Picard limit, and local fixed-point uniqueness. -/ +theorem exists_isWeierstrassDivisionOn_of_bounded {d : ℕ} {f : (ι → ℂ) × ℂ → ℂ} + {U : Set ((ι → ℂ) × ℂ)} (hU : IsOpen U) (h0 : 0 ∈ U) + (hf : DifferentiableOn ℂ f U) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (r : ι → ℝ) (R C : ℝ), (∀ i, 0 < r i) ∧ 0 < R ∧ 0 < C ∧ + polydisc 0 r ×ˢ ball 0 R ⊆ U ∧ + ∀ (g : (ι → ℂ) × ℂ → ℂ), + DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R) → + ∀ M : ℝ, 0 ≤ M → (∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖g z‖ ≤ M) → + ∃ (q : (ι → ℂ) × ℂ → ℂ) (a : Fin d → (ι → ℂ) → ℂ), + IsWeierstrassDivisionOn f g q a (polydisc 0 r) R ∧ + (∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖q z‖ ≤ C * M) ∧ + (∀ q' a', IsWeierstrassDivisionAt f g q' a' → + q =ᶠ[𝓝 0] q' ∧ ∀ j, a j =ᶠ[𝓝 0] a' j) := by + -- Normalize the divisor and choose a nonvanishing leading factor. + obtain ⟨f1, c, ε₀, ε₁, hε₀, hε₁, hε₀U, hfdiv, hcj0, hε₁ε₀, hf1ne0'⟩ := + exists_coordinatePower_leadingFactor_ne_zero hU h0 hf horder + -- Choose a domain on which the normalized perturbation contracts. + obtain ⟨R₂, δ, r₃, hR₂pos, hR₂ε₁, hδpos, hr₃pos, hr₃ε₁, hhA1, hcj0', hδle, hhbound⟩ := + exists_perturbation_bound_of_coordinatePower_leadingFactor hε₁ hε₁ε₀ hfdiv hcj0 hf1ne0' + set hh : (ι → ℂ) × ℂ → ℂ := fun z => weierstrassRemainder c z / f1 z with hhdef + set K : Set ((ι → ℂ) × ℂ) := + closedPolydisc (0 : ι → ℂ) (fun _ => ε₁ / 2) ×ˢ closedBall (0 : ℂ) R₂ with hKdef + -- Restrict to the common domain for all bounded numerators. + have hr₃ε₁' : r₃ ≤ ε₁ := hr₃ε₁.trans (by linarith) + have hR₂ε₁' : R₂ ≤ ε₁ := hR₂ε₁.le + have hFINALsubε₁ : polydisc (0 : ι → ℂ) (fun _ => r₃) ×ˢ ball (0 : ℂ) R₂ ⊆ + polydisc (0 : ι → ℂ) (fun _ => ε₁) ×ˢ ball (0 : ℂ) ε₁ := + Set.prod_mono (polydisc_mono _ (fun _ => hr₃ε₁')) (ball_subset_ball hR₂ε₁') + have hFINALsub : polydisc (0 : ι → ℂ) (fun _ => r₃) ×ˢ ball (0 : ℂ) R₂ ⊆ U := + hFINALsubε₁.trans (fun z hz => hε₀U (hε₁ε₀ hz)) + have hhFINAL : DifferentiableOn ℂ (fun z => weierstrassRemainder c z / f1 z) + (polydisc (0 : ι → ℂ) (fun _ => r₃) ×ˢ ball (0 : ℂ) R₂) := + hhA1.mono hFINALsubε₁ + have hhboundFINAL : ∀ z ∈ polydisc (0 : ι → ℂ) (fun _ => r₃) ×ˢ ball (0 : ℂ) R₂, + ‖weierstrassRemainder c z / f1 z‖ ≤ R₂ ^ d / (2 * (d + 1)) := + fun z hz => hhbound z.1 hz.1 z.2 hz.2 + refine ⟨fun _ => r₃, R₂, 2 * ((d : ℝ) + 1) / (R₂ ^ d * δ), fun _ => hr₃pos, hR₂pos, + by positivity, hFINALsub, ?_⟩ + intro g hg M hM0 hMb + set domFINAL : Set ((ι → ℂ) × ℂ) := + polydisc (0 : ι → ℂ) (fun _ => r₃) ×ˢ ball (0 : ℂ) R₂ with hdomFINALdef + set sSeq := fun k => picardApprox d (fun _ => r₃) R₂ (fun _ => hr₃pos) hR₂pos hh g hg hhFINAL k + with hsSeqdef + set B : ℝ := ((d + 1 : ℕ) : ℝ) / R₂ ^ d * M with hBdef + obtain ⟨S, hSanalytic, hSbound⟩ := exists_tendstoUniformlyOn_picardApprox d (fun _ => r₃) R₂ + (fun _ => hr₃pos) hR₂pos hh g hg hhFINAL M hM0 hMb hhboundFINAL + obtain ⟨aOut, haFINAL, hkey⟩ := exists_weierstrassRemainder_eq_of_tendstoUniformlyOn_picardApprox + d (fun _ => r₃) R₂ (fun _ => hr₃pos) hR₂pos hh g hg hhFINAL hhboundFINAL M hM0 S + hSanalytic.differentiableOn hSbound + -- Undo normalization, retaining the uniform quotient estimate. + have hf1ne0FINAL : ∀ z ∈ domFINAL, f1 z ≠ 0 := fun z hz => hf1ne0' z (hFINALsubε₁ hz) + have hf_eq2 : ∀ z ∈ domFINAL, f z = f1 z * (z.2 ^ d + hh z) := by + intro z hz + have hz0 : z ∈ polydisc (0 : ι → ℂ) (fun _ => ε₀) ×ˢ ball (0 : ℂ) ε₀ := + hε₁ε₀ (hFINALsubε₁ hz) + have h1 : f z = f1 z * z.2 ^ d + weierstrassRemainder c z := hfdiv.eq hz0 + have h2 : weierstrassRemainder c z = hh z * f1 z := by + change weierstrassRemainder c z = weierstrassRemainder c z / f1 z * f1 z + rw [div_mul_cancel₀ _ (hf1ne0FINAL z hz)] + rw [h2] at h1 + rw [h1]; ring + set q : (ι → ℂ) × ℂ → ℂ := fun z => S z / f1 z with hqdef + have hf1FINAL : DifferentiableOn ℂ f1 domFINAL := + hfdiv.differentiableOn_quotient.mono (hFINALsubε₁.trans hε₁ε₀) + have hfixed : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (g - hh * S) S aOut + (polydisc 0 (fun _ => r₃)) R₂ := by + refine ⟨hSanalytic.differentiableOn, haFINAL, ?_⟩ + intro z hz + have h := hkey z.1 hz.1 z.2 hz.2 + dsimp only [Pi.sub_apply, Pi.mul_apply] + linear_combination h + have hdivision := divisionOn_div_leadingFactor hf1FINAL hf1ne0FINAL hf_eq2 hfixed + have hdomFINALsubK : domFINAL ⊆ K := by + apply Set.prod_mono + · intro w hw + exact mem_closedPolydisc.mpr fun i => + (mem_polydisc.mp hw i).le.trans hr₃ε₁ + · exact ball_subset_closedBall + refine ⟨q, aOut, hdivision, ?_, ?_⟩ + · intro z hz + have hS0eq : (sSeq 0).1 = 0 := rfl + have hb0 := hSbound 0 z hz + rw [hS0eq] at hb0 + have hSb : ‖S z‖ ≤ 2 * B := by + have hthis : ‖(0:ℂ) - S z‖ ≤ B * (1/2)^0 / (1 - 1/2) := hb0 + rw [zero_sub, norm_neg] at hthis + norm_num at hthis + linarith + have hf1ge : δ ≤ ‖f1 z‖ := hδle _ (hdomFINALsubK hz) + have hf1pos' : 0 < ‖f1 z‖ := hδpos.trans_le hf1ge + change ‖S z / f1 z‖ ≤ 2 * ((d:ℝ) + 1) / (R₂ ^ d * δ) * M + rw [norm_div] + calc ‖S z‖ / ‖f1 z‖ ≤ (2 * B) / ‖f1 z‖ := div_le_div_of_nonneg_right hSb hf1pos'.le + _ ≤ (2 * B) / δ := div_le_div_of_nonneg_left (by positivity) hδpos hf1ge + _ = 2 * ((d:ℝ) + 1) / (R₂ ^ d * δ) * M := by + rw [hBdef]; push_cast; field_simp + · intro q' a' hdiv' + exact normalized_division_germ_unique hr₃pos hR₂pos hδpos hf1FINAL + (fun z hz => hδle z (hdomFINALsubK hz)) hcj0' hhFINAL hf_eq2 + hfixed hdiv' + +/-- Analytic Weierstrass division for arbitrary numerator germs. No boundedness assumption is needed +because the representatives can be restricted to a smaller neighborhood. The uniform division +theorem supplies the quotient and its germ uniqueness. -/ +theorem exists_isWeierstrassDivisionAt {d : ℕ} {f g : (ι → ℂ) × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (hg : AnalyticAt ℂ g 0) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (q : (ι → ℂ) × ℂ → ℂ) (a : Fin d → (ι → ℂ) → ℂ), + IsWeierstrassDivisionAt f g q a ∧ + ∀ q' a', IsWeierstrassDivisionAt f g q' a' → + q =ᶠ[𝓝 0] q' ∧ ∀ j, a j =ᶠ[𝓝 0] a' j := by + have hb : ∀ᶠ z in 𝓝 0, ‖g z‖ < ‖g 0‖ + 1 := + hg.continuousAt.norm.eventually_lt_const (lt_add_one _) + obtain ⟨U, hsub, hU, h0⟩ := _root_.eventually_nhds_iff.mp + (hf.eventually_analyticAt.and (hg.eventually_analyticAt.and hb)) + obtain ⟨r, R, C, hr, hR, _, hPU, hdiv⟩ := + exists_isWeierstrassDivisionOn_of_bounded hU h0 + (fun z hz => (hsub z hz).1.differentiableAt.differentiableWithinAt) + horder + obtain ⟨q, a, hqa, _, huniq⟩ := hdiv g + (fun z hz => (hsub z (hPU hz)).2.1.differentiableAt.differentiableWithinAt) + (‖g 0‖ + 1) (by positivity) (fun z hz => (hsub z (hPU hz)).2.2.le) + refine ⟨q, a, hqa.at_zero (isOpen_polydisc _ _) ?_ hR, huniq⟩ + simpa using hr + +/-- Two local division decompositions agree as germs, including every remainder coefficient. This +follows from the uniform division theorem. -/ +theorem IsWeierstrassDivisionAt.unique {d : ℕ} {f g q q' : (ι → ℂ) × ℂ → ℂ} + {a a' : Fin d → (ι → ℂ) → ℂ} + (h : IsWeierstrassDivisionAt f g q a) (h' : IsWeierstrassDivisionAt f g q' a') + (hf : AnalyticAt ℂ f 0) (hg : AnalyticAt ℂ g 0) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + q =ᶠ[𝓝 0] q' ∧ ∀ j, a j =ᶠ[𝓝 0] a' j := by + obtain ⟨q₀, a₀, _, hu⟩ := exists_isWeierstrassDivisionAt hf hg horder + exact ⟨(hu q a h).1.symm.trans (hu q' a' h').1, + fun j => ((hu q a h).2 j).symm.trans ((hu q' a' h').2 j)⟩ + +/-- Local uniqueness extends to the whole product domain by the identity theorem. In particular this +gives uniqueness on the fixed polydisc in the bounded division theorem. -/ +theorem IsWeierstrassDivisionOn.unique {d : ℕ} {f g q q' : (ι → ℂ) × ℂ → ℂ} + {a a' : Fin d → (ι → ℂ) → ℂ} {V : Set (ι → ℂ)} {R : ℝ} + (h : IsWeierstrassDivisionOn f g q a V R) (h' : IsWeierstrassDivisionOn f g q' a' V R) + (hV : IsOpen V) (hconn : IsPreconnected V) (h0 : 0 ∈ V) (hR : 0 < R) + (hf : DifferentiableOn ℂ f (V ×ˢ ball 0 R)) + (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + EqOn q q' (V ×ˢ ball 0 R) ∧ ∀ j, EqOn (a j) (a' j) V := by + have hz : (0 : (ι → ℂ) × ℂ) ∈ V ×ˢ ball 0 R := ⟨h0, mem_ball_self hR⟩ + have ho : IsOpen (V ×ˢ ball (0 : ℂ) R) := hV.prod isOpen_ball + obtain ⟨hq, ha⟩ := (h.at_zero hV h0 hR).unique (h'.at_zero hV h0 hR) + ((hf.analyticOnNhd_of_finiteDimensional ho) _ hz) + ((hg.analyticOnNhd_of_finiteDimensional ho) _ hz) horder + exact ⟨DifferentiableOn.eqOn_of_preconnected_of_eventuallyEq ho + (hconn.prod (convex_ball (0 : ℂ) R).isPreconnected) + h.differentiableOn_quotient h'.differentiableOn_quotient hz hq, + fun j => DifferentiableOn.eqOn_of_preconnected_of_eventuallyEq hV hconn + (h.differentiableOn_coeff j) (h'.differentiableOn_coeff j) h0 (ha j)⟩ + +/-- Division transports along a continuous linear equivalence of the parameter space. -/ +theorem IsWeierstrassDivisionAt.comp_equiv {F : Type*} [NormedAddCommGroup F] + [NormedSpace ℂ F] (φ : F ≃L[ℂ] E) {d : ℕ} {f g q : E × ℂ → ℂ} {a : Fin d → E → ℂ} + (h : IsWeierstrassDivisionAt f g q a) : + IsWeierstrassDivisionAt (fun z : F × ℂ => f (φ z.1, z.2)) (fun z : F × ℂ => g (φ z.1, z.2)) + (fun z : F × ℂ => q (φ z.1, z.2)) (fun j x => a j (φ x)) := by + have hφ : AnalyticAt ℂ φ (0 : F) := φ.toContinuousLinearMap.analyticAt 0 + have hφmap : φ (0 : F) = 0 := φ.map_zero + have hpair : AnalyticAt ℂ (fun z : F × ℂ => (φ z.1, z.2)) (0 : F × ℂ) := + (hφ.comp_of_eq analyticAt_fst rfl).prod analyticAt_snd + have h0 : (fun z : F × ℂ => (φ z.1, z.2)) 0 = (0 : E × ℂ) := by simp [hφmap] + have ht : Tendsto (fun z : F × ℂ => (φ z.1, z.2)) (𝓝 0) (𝓝 (0 : E × ℂ)) := by + rw [← h0]; exact hpair.continuousAt.tendsto + refine ⟨h.analyticAt_quotient.comp_of_eq hpair h0, + fun j => (h.analyticAt_coeff j).comp_of_eq hφ hφmap, + (h.eq.comp_tendsto ht).mono fun z hz => by + simpa [weierstrassRemainder] using hz⟩ + +/-- **Weierstrass division for analytic germs on any finite-dimensional parameter space.** +Obtained by transporting the coordinate version along a basis; no choice of coordinates +occurs in the statement. -/ +theorem exists_isWeierstrassDivisionAt_of_finiteDimensional [FiniteDimensional ℂ E] {d : ℕ} + {f g : E × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (hg : AnalyticAt ℂ g 0) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (q : E × ℂ → ℂ) (a : Fin d → E → ℂ), + IsWeierstrassDivisionAt f g q a ∧ + ∀ q' a', IsWeierstrassDivisionAt f g q' a' → + q =ᶠ[𝓝 0] q' ∧ ∀ j, a j =ᶠ[𝓝 0] a' j := by + set e := (Module.finBasis ℂ E).equivFunL with he_def + set fg : (Fin (Module.finrank ℂ E) → ℂ) × ℂ → ℂ := fun z => f (e.symm z.1, z.2) with hfg_def + set gg : (Fin (Module.finrank ℂ E) → ℂ) × ℂ → ℂ := fun z => g (e.symm z.1, z.2) with hgg_def + have hfg0 : (fun w : ℂ => fg (0, w)) = fun w : ℂ => f (0, w) := by funext w; simp [hfg_def] + have hfgan : AnalyticAt ℂ fg 0 := + hf.comp_of_eq (((e.symm.toContinuousLinearMap.analyticAt 0).comp_of_eq analyticAt_fst rfl).prod + analyticAt_snd) (by simp) + have hggan : AnalyticAt ℂ gg 0 := + hg.comp_of_eq (((e.symm.toContinuousLinearMap.analyticAt 0).comp_of_eq analyticAt_fst rfl).prod + analyticAt_snd) (by simp) + have hfgorder : analyticOrderAt (fun w : ℂ => fg (0, w)) 0 = d := by rw [hfg0]; exact horder + obtain ⟨q, a, Hq, huniqq⟩ := exists_isWeierstrassDivisionAt hfgan hggan hfgorder + have hf_eq : f = fun z : E × ℂ => fg (e z.1, z.2) := by funext z; simp [hfg_def] + have hg_eq : g = fun z : E × ℂ => gg (e z.1, z.2) := by funext z; simp [hgg_def] + have Hf : IsWeierstrassDivisionAt f g (fun z : E × ℂ => q (e z.1, z.2)) + (fun j x => a j (e x)) := by + rw [hf_eq, hg_eq]; exact Hq.comp_equiv e + refine ⟨_, _, Hf, fun q' a' Hq' => ?_⟩ + have Hq'' : IsWeierstrassDivisionAt fg gg (fun z => q' (e.symm z.1, z.2)) + (fun j x => a' j (e.symm x)) := by + rw [hfg_def, hgg_def]; exact Hq'.comp_equiv e.symm + obtain ⟨huq, hab⟩ := huniqq _ _ Hq'' + have ht : Tendsto (fun z : E × ℂ => (e z.1, z.2)) (𝓝 0) + (𝓝 (0 : (Fin (Module.finrank ℂ E) → ℂ) × ℂ)) := by + have h0 : (fun z : E × ℂ => (e z.1, z.2)) 0 = (0 : (Fin (Module.finrank ℂ E) → ℂ) × ℂ) := by + simp + rw [← h0] + exact (((e.toContinuousLinearMap.analyticAt 0).comp_of_eq analyticAt_fst rfl).prod + analyticAt_snd).continuousAt.tendsto + refine ⟨(huq.comp_tendsto ht).mono fun z hz => ?_, fun j => ?_⟩ + · simpa using hz + · have htj : Tendsto e (𝓝 (0 : E)) (𝓝 (0 : Fin (Module.finrank ℂ E) → ℂ)) := by + simpa using (e.toContinuousLinearMap.analyticAt 0).continuousAt.tendsto + exact ((hab j).comp_tendsto htj).mono fun x hx => by simpa using hx + +/-- A local division identity is an identity in the project's ring of analytic germs. -/ +theorem IsWeierstrassDivisionAt.germ_eq {d : ℕ} {f g q : E × ℂ → ℂ} + {a : Fin d → E → ℂ} (h : IsWeierstrassDivisionAt f g q a) + (hf : AnalyticAt ℂ f 0) (hg : AnalyticAt ℂ g 0) : + AnalyticGerm.ofAnalyticAt g hg = + AnalyticGerm.ofAnalyticAt q h.analyticAt_quotient * AnalyticGerm.ofAnalyticAt f hf + + AnalyticGerm.ofAnalyticAt (weierstrassRemainder a) + (analyticAt_weierstrassRemainder h.analyticAt_coeff) := by + apply Subtype.ext + exact Germ.coe_eq.mpr h.eq + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/Basic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/Basic.lean new file mode 100644 index 0000000000..3a8b0fe53e --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/Basic.lean @@ -0,0 +1,170 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Polydisc + +/-! +# Weierstrass division predicates + +A remainder of degree less than `d` is represented by its `Fin d` coefficient functions on the +parameter space. We define division at the origin and on a product domain, prove the elementary +order-zero case, and pass between local division and division on a sufficiently small polydisc. +The case `d = 0` and empty finite parameter index types are included. + +The existence theorem for a general divisor is in `SeveralComplexVariables.WeierstrassDivision`. + +## Main definitions + +* `weierstrassRemainder`: Evaluate a polynomial of degree less than `d` in the distinguished scalar + coordinate. +* `IsWeierstrassDivisionAt`: Local analytic division, with remainder degree encoded by its + coefficient index. +* `IsWeierstrassDivisionOn`: Division on a product of a parameter domain and a scalar disc. + +## Main results + +* `IsWeierstrassDivisionOn.at_zero`: An open-domain division identity induces division at the + origin. +* `isWeierstrassDivisionAt_zero`: Division by a nonvanishing analytic function is ordinary division, + with zero remainder. +* `IsWeierstrassDivisionAt.exists_divisionOn`: A germ division identity holds as a holomorphic + division on a sufficiently small polydisc-ball inside any prescribed open neighborhood of the + origin. +-/ + +public noncomputable section + +open Complex Filter Finset Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- Evaluate a polynomial of degree less than `d` in the distinguished scalar coordinate. The +coefficients are functions of the parameter alone. -/ +@[expose] def weierstrassRemainder {d : ℕ} (a : Fin d → E → ℂ) (z : E × ℂ) : ℂ := + ∑ j : Fin d, a j z.1 * z.2 ^ (j : ℕ) + +omit [NormedAddCommGroup E] [NormedSpace ℂ E] in +/-- The only remainder of degree less than zero is the zero function. -/ +@[simp] theorem weierstrassRemainder_zero (a : Fin 0 → E → ℂ) : + weierstrassRemainder a = 0 := by + funext z + simp [weierstrassRemainder] + +/-- Analytic coefficients give a jointly analytic polynomial in the scalar coordinate. -/ +theorem analyticAt_weierstrassRemainder {d : ℕ} {a : Fin d → E → ℂ} {z : E × ℂ} + (ha : ∀ j, AnalyticAt ℂ (a j) z.1) : AnalyticAt ℂ (weierstrassRemainder a) z := by + apply Finset.analyticAt_fun_sum + intro j _ + exact ((ha j).comp analyticAt_fst).mul (analyticAt_snd.pow (j : ℕ)) + +/-- Local analytic division, with remainder degree encoded by its coefficient index. -/ +structure IsWeierstrassDivisionAt {d : ℕ} (f g q : E × ℂ → ℂ) + (a : Fin d → E → ℂ) : Prop where + /-- The quotient is analytic at the origin. -/ + analyticAt_quotient : AnalyticAt ℂ q 0 + /-- Each remainder coefficient is analytic at the parameter origin. -/ + analyticAt_coeff : ∀ j, AnalyticAt ℂ (a j) 0 + /-- As germs, the dividend equals quotient times divisor plus remainder. -/ + eq : g =ᶠ[𝓝 0] fun z => q z * f z + weierstrassRemainder a z + +/-- Division on a product of a parameter domain and a scalar disc. -/ +structure IsWeierstrassDivisionOn {d : ℕ} (f g q : E × ℂ → ℂ) + (a : Fin d → E → ℂ) (V : Set E) (R : ℝ) : Prop where + /-- The quotient is holomorphic on the product domain. -/ + differentiableOn_quotient : DifferentiableOn ℂ q (V ×ˢ ball 0 R) + /-- Each remainder coefficient is holomorphic on the parameter domain. -/ + differentiableOn_coeff : ∀ j, DifferentiableOn ℂ (a j) V + /-- On the product domain, the dividend equals quotient times divisor plus remainder. -/ + eq : EqOn g (fun z => q z * f z + weierstrassRemainder a z) (V ×ˢ ball 0 R) + +/-- An open-domain division identity induces division at the origin. -/ +theorem IsWeierstrassDivisionOn.at_zero [FiniteDimensional ℂ E] + {d : ℕ} {f g q : E × ℂ → ℂ} {a : Fin d → E → ℂ} {V : Set E} {R : ℝ} + (h : IsWeierstrassDivisionOn f g q a V R) (hV : IsOpen V) (h0 : 0 ∈ V) + (hR : 0 < R) : IsWeierstrassDivisionAt f g q a := by + have hz : (0 : E × ℂ) ∈ V ×ˢ ball 0 R := ⟨h0, mem_ball_self hR⟩ + exact ⟨(h.differentiableOn_quotient.analyticOnNhd_of_finiteDimensional + (hV.prod isOpen_ball)) _ hz, + fun j => ((h.differentiableOn_coeff j).analyticOnNhd_of_finiteDimensional hV) _ h0, + Filter.mem_of_superset ((hV.prod isOpen_ball).mem_nhds hz) (fun _ hx => h.eq hx)⟩ + +/-- Division by a nonvanishing analytic function is ordinary division, with zero remainder. This +proves the order-zero existence case without Weierstrass division. -/ +theorem isWeierstrassDivisionAt_zero {f g : E × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (hg : AnalyticAt ℂ g 0) (h0 : f 0 ≠ 0) : + IsWeierstrassDivisionAt f g (fun z => g z / f z) (fun j : Fin 0 => Fin.elim0 j) := by + refine ⟨hg.div hf h0, fun j => Fin.elim0 j, ?_⟩ + filter_upwards [hf.continuousAt.eventually_ne h0] with z hz + simp [weierstrassRemainder, hz] + +/-- In order zero the quotient germ is unique whenever the divisor is nonvanishing. -/ +theorem IsWeierstrassDivisionAt.unique_zero {f g q q' : E × ℂ → ℂ} + {a a' : Fin 0 → E → ℂ} (h : IsWeierstrassDivisionAt f g q a) + (h' : IsWeierstrassDivisionAt f g q' a') + (hf : AnalyticAt ℂ f 0) (h0 : f 0 ≠ 0) : q =ᶠ[𝓝 0] q' := by + filter_upwards [h.eq, h'.eq, hf.continuousAt.eventually_ne h0] with z hz hz' hne + have he : q z * f z = q' z * f z := by simpa using hz.symm.trans hz' + exact mul_right_cancel₀ hne he + +/-- The Weierstrass remainder is linear (here, additive) in its coefficient tuple. -/ +theorem weierstrassRemainder_sub {E : Type*} + {d : ℕ} (a b : Fin d → E → ℂ) (z : E × ℂ) : + weierstrassRemainder a z - weierstrassRemainder b z = + weierstrassRemainder (fun j => a j - b j) z := by + unfold weierstrassRemainder + rw [← Finset.sum_sub_distrib] + exact Finset.sum_congr rfl fun j _ => by simp; ring + +variable {ι : Type*} [Fintype ι] + +omit [Fintype ι] in +/-- Every open neighborhood of the origin in `(ι → ℂ) × ℂ` contains a product of a constant-radius +polydisc and a ball of the same radius. -/ +theorem exists_polydisc_ball_subset [Finite ι] {U : Set ((ι → ℂ) × ℂ)} + (hU : IsOpen U) (h0 : (0 : (ι → ℂ) × ℂ) ∈ U) : + ∃ ε : ℝ, 0 < ε ∧ polydisc (0 : ι → ℂ) (fun _ => ε) ×ˢ ball (0 : ℂ) ε ⊆ U := by + classical + let := Fintype.ofFinite ι + obtain ⟨ε, hε, hsub⟩ := Metric.mem_nhds_iff.mp (hU.mem_nhds h0) + refine ⟨ε, hε, fun z hz => hsub ?_⟩ + rw [mem_ball, dist_zero_right, Prod.norm_def] + rw [polydisc_const_eq_ball (0 : ι → ℂ) hε] at hz + obtain ⟨h1, h2⟩ := hz + apply max_lt + · simpa [mem_ball, dist_zero_right] using h1 + · simpa [mem_ball, dist_zero_right] using h2 + +/-- A germ division identity holds as a holomorphic division on a sufficiently small polydisc-ball +inside any prescribed open neighborhood of the origin. -/ +theorem IsWeierstrassDivisionAt.exists_divisionOn {d : ℕ} + {f g q : (ι → ℂ) × ℂ → ℂ} {a : Fin d → (ι → ℂ) → ℂ} + (h : IsWeierstrassDivisionAt f g q a) + {U : Set ((ι → ℂ) × ℂ)} (hU : IsOpen U) (h0 : 0 ∈ U) : + ∃ ρ : ℝ, 0 < ρ ∧ polydisc 0 (fun _ => ρ) ×ˢ ball 0 ρ ⊆ U ∧ + IsWeierstrassDivisionOn f g q a (polydisc 0 (fun _ => ρ)) ρ := by + obtain ⟨V, hV, hVo, hV0⟩ := _root_.eventually_nhds_iff.mp + (h.analyticAt_quotient.eventually_analyticAt.and h.eq) + obtain ⟨W, hW, hWo, hW0⟩ := _root_.eventually_nhds_iff.mp + (Filter.eventually_all.mpr fun j => (h.analyticAt_coeff j).eventually_analyticAt) + obtain ⟨ρ, hρ, hsub⟩ := exists_polydisc_ball_subset + (hVo.inter ((hWo.prod isOpen_univ).inter hU)) ⟨hV0, ⟨hW0, trivial⟩, h0⟩ + refine ⟨ρ, hρ, fun z hz => (hsub hz).2.2, ?_, ?_, ?_⟩ + · intro z hz + exact (hV z (hsub hz).1).1.differentiableAt.differentiableWithinAt + · intro j w hw + exact (hW w (hsub (show (w, (0 : ℂ)) ∈ _ from ⟨hw, mem_ball_self hρ⟩)).2.1.1 + j).differentiableAt.differentiableWithinAt + · intro z hz + exact (hV z (hsub hz).1).2 + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/CoordinatePower.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/CoordinatePower.lean new file mode 100644 index 0000000000..b569e61494 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/CoordinatePower.lean @@ -0,0 +1,781 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Algebra.Field.GeomSum +public import Mathlib.Analysis.Analytic.Order +public import Mathlib.Analysis.Calculus.IteratedDeriv.Lemmas +public import Mathlib.Analysis.Complex.AbsMax +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.CauchyDerivatives +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ContourIntegral +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IdentityPrinciple +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.Basic + +/-! +# Division by a coordinate power + +Cauchy integrals construct division by `z.2 ^ d`, with a remainder of degree less than `d`. We +establish holomorphic dependence on the parameters, compatibility of the quotient at different +integration radii, uniqueness, and the uniform quotient estimate for bounded numerators. + +The main result is `coordinatePower_division`, corresponding to +[Jakóbczak–Jarnicki][JakobczakJarnicki2021], Lemma 1.7.4. + +## Main results + +* `coordinatePower_division`: **Coordinate-power division + ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.7.4).** Every holomorphic function on a polydisc + has a unique quotient and polynomial remainder on division by `w^d`. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Complex Filter Finset Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +variable {ι : Type*} [Fintype ι] + +/-- Algebraic splitting of the Cauchy kernel into a polynomial part of degree `< d` and a remainder +with a factor `w^d`. -/ +theorem weierstrass_kernel_identity (d : ℕ) {s w : ℂ} (hs : s ≠ 0) (hsw : s ≠ w) : + (∑ j ∈ range d, w ^ j / s ^ (j + 1)) + w ^ d / (s ^ d * (s - w)) = (s - w)⁻¹ := by + have hne : s - w ≠ 0 := sub_ne_zero.mpr hsw + have hsne : s ^ d ≠ 0 := pow_ne_zero d hs + have hgeom : ∑ i ∈ range d, s ^ i * w ^ (d - 1 - i) = (s ^ d - w ^ d) / (s - w) := + (Commute.all s w).geom_sum₂ hsw d + have hpoly : ∑ j ∈ range d, w ^ j / s ^ (j + 1) = (s ^ d - w ^ d) / (s ^ d * (s - w)) := by + have hreindex : ∑ i ∈ range d, w ^ (d - 1 - i) / s ^ (d - i) = + ∑ j ∈ range d, w ^ j / s ^ (j + 1) := by + refine Eq.trans ?_ (sum_range_reflect (fun j => w ^ j / s ^ (j + 1)) d) + refine sum_congr rfl fun i hi => ?_ + have : d - 1 - i + 1 = d - i := by + have := mem_range.mp hi + omega + rw [this] + trans ∑ i ∈ range d, w ^ (d - 1 - i) / s ^ (d - i) + · exact hreindex.symm + trans (∑ i ∈ range d, s ^ i * w ^ (d - 1 - i)) / s ^ d + · rw [sum_div] + refine sum_congr rfl fun i hi => ?_ + have hle : i ≤ d := (mem_range.mp hi).le + have hsi : s ^ (d - i) ≠ 0 := pow_ne_zero _ hs + field_simp [hsne, hsi, pow_ne_zero i hs] + rw [mul_assoc, ← pow_add, Nat.sub_add_cancel hle] + · rw [hgeom, div_div, mul_comm (s - w)] + have hsplit : (s ^ d - w ^ d) / (s ^ d * (s - w)) + w ^ d / (s ^ d * (s - w)) = + (s - w)⁻¹ := by + rw [← add_div, sub_add_cancel, div_mul_eq_div_div, div_self hsne, one_div] + rw [hpoly, hsplit] + +/-- A jointly holomorphic function on a product remains holomorphic in the last coordinate. -/ +theorem differentiableOn_snd_slice {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + {V : Set E} {R : ℝ} {g : E × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) {z : E} (hz : z ∈ V) : + DifferentiableOn ℂ (fun w => g (z, w)) (ball 0 R) := by + intro w hw + exact (hg (z, w) ⟨hz, hw⟩).comp w + ((differentiableAt_const z).prodMk differentiableAt_id).differentiableWithinAt + (fun t ht => ⟨hz, ht⟩) + +/-- Restricting a product slice to a strictly smaller disc gives continuity up to the closed +disc. -/ +theorem diffContOnCl_snd_slice {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + {V : Set E} {R ρ : ℝ} {g : E × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) {z : E} (hz : z ∈ V) + (hρ : 0 < ρ) (hρR : ρ < R) : + DiffContOnCl ℂ (fun w => g (z, w)) (ball 0 ρ) := by + refine ⟨(differentiableOn_snd_slice hg hz).mono (ball_subset_ball hρR.le), ?_⟩ + rw [closure_ball _ hρ.ne'] + exact hg.continuousOn.comp (continuousOn_const.prodMk continuousOn_id) + (fun w hw => ⟨hz, closedBall_subset_ball hρR hw⟩) + +/-- The Taylor coefficients of a polynomial remainder of degree less than `d`. -/ +theorem iteratedDeriv_weierstrassRemainder_const {d : ℕ} (a : Fin d → ℂ) (k : ℕ) : + iteratedDeriv k (fun w : ℂ => ∑ j : Fin d, a j * w ^ (j : ℕ)) 0 = + if h : k < d then (k.factorial : ℂ) * a ⟨k, h⟩ else 0 := by + have hsum := iteratedDeriv_fun_sum (I := Finset.univ) (n := k) + (f := fun j : Fin d => fun w : ℂ => a j * w ^ (j : ℕ)) + (x := (0 : ℂ)) (fun _ _ => by fun_prop) + simp only [hsum, iteratedDeriv_const_mul_field, iteratedDeriv_fun_pow_zero] + split_ifs with hk + · rw [Fintype.sum_eq_single ⟨k, hk⟩] + · simp [mul_comm] + · intro j hj + have hjk : k ≠ (j : ℕ) := by + intro h + exact hj (Fin.ext h.symm) + simp [hjk] + · apply Finset.sum_eq_zero + intro j _ + have hjk : k ≠ (j : ℕ) := + ne_of_gt (j.isLt.trans_le (le_of_not_gt hk)) + simp [hjk] + +/-- In coordinate-power division the remainder coefficients are the Taylor coefficients of the +last-coordinate slice. -/ +theorem coeff_eq_iteratedDeriv_of_coordinatePower_division {d : ℕ} + {V : Set (ι → ℂ)} {R : ℝ} {g q : (ι → ℂ) × ℂ → ℂ} {a : Fin d → (ι → ℂ) → ℂ} + (h : IsWeierstrassDivisionOn (fun z => z.2 ^ d) g q a V R) + (hR : 0 < R) {z : ι → ℂ} (hz : z ∈ V) (j : Fin d) : + a j z = ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun w => g (z, w)) 0 := by + have hz0 : (0 : ℂ) ∈ ball 0 R := mem_ball_self hR + have hqA : AnalyticAt ℂ (fun w => q (z, w)) 0 := + ((differentiableOn_snd_slice h.differentiableOn_quotient hz).analyticOnNhd_of_finiteDimensional + isOpen_ball) _ hz0 + have hpow : AnalyticAt ℂ (fun w : ℂ => w ^ d) 0 := analyticAt_id.pow d + have hprod : AnalyticAt ℂ (fun w => w ^ d * q (z, w)) 0 := hpow.mul hqA + have hrem : AnalyticAt ℂ (fun w => ∑ k : Fin d, a k z * w ^ (k : ℕ)) 0 := by fun_prop + have hid : (fun w => g (z, w)) =ᶠ[𝓝 0] + (fun w => w ^ d * q (z, w) + ∑ k : Fin d, a k z * w ^ (k : ℕ)) := + Filter.mem_of_superset (isOpen_ball.mem_nhds hz0) fun w hw => by + have hmem : (z, w) ∈ V ×ˢ ball (0 : ℂ) R := ⟨hz, hw⟩ + simpa [weierstrassRemainder, mul_comm] using h.eq hmem + have hord : (d : ℕ∞) ≤ analyticOrderAt (fun w => w ^ d * q (z, w)) 0 := by + have hmul := analyticOrderAt_mul hpow hqA + have hpow' : analyticOrderAt (fun w : ℂ => w ^ d) 0 = d := by + have h := analyticOrderAt_pow (analyticAt_id (𝕜 := ℂ) (z := (0 : ℂ))) d + simpa [analyticOrderAt_id, Pi.pow_def] using h + have heq : analyticOrderAt (fun w => w ^ d * q (z, w)) 0 = + analyticOrderAt ((fun w : ℂ => w ^ d) * fun w => q (z, w)) 0 := by + congr 1 + rw [heq, hmul, hpow'] + exact le_self_add + have hvan (k : ℕ) (hk : k < d) : + iteratedDeriv k (fun w => w ^ d * q (z, w)) 0 = 0 := + ((natCast_le_analyticOrderAt_iff_iteratedDeriv_eq_zero hprod).mp hord) k hk + have hder := hid.iteratedDeriv_eq (j : ℕ) + have hadd : + iteratedDeriv (j : ℕ) + (fun w => w ^ d * q (z, w) + ∑ k : Fin d, a k z * w ^ (k : ℕ)) 0 = + iteratedDeriv (j : ℕ) (fun w => w ^ d * q (z, w)) 0 + + iteratedDeriv (j : ℕ) (fun w => ∑ k : Fin d, a k z * w ^ (k : ℕ)) 0 := by + convert iteratedDeriv_add (n := (j : ℕ)) (x := (0 : ℂ)) + hprod.contDiffAt hrem.contDiffAt + have hj : (j : ℕ) < d := j.isLt + rw [hder, hadd, hvan _ hj, zero_add, iteratedDeriv_weierstrassRemainder_const, dite_eq_left hj] + field_simp [Nat.cast_ne_zero.mpr (Nat.factorial_ne_zero (j : ℕ))] + +/-- Coordinate-power decompositions are unique: remainder coefficients are Taylor coefficients of +the last-coordinate slice, and the quotient is then recovered from the identity. Continuity +fills in the central fibre `w = 0`. -/ +theorem unique_coordinatePower_division {d : ℕ} {V : Set (ι → ℂ)} {R : ℝ} + {g q q' : (ι → ℂ) × ℂ → ℂ} {a a' : Fin d → (ι → ℂ) → ℂ} + (h : IsWeierstrassDivisionOn (fun z => z.2 ^ d) g q a V R) + (h' : IsWeierstrassDivisionOn (fun z => z.2 ^ d) g q' a' V R) + (hR : 0 < R) : + EqOn q q' (V ×ˢ ball 0 R) ∧ ∀ j, EqOn (a j) (a' j) V := by + have ha (j : Fin d) : EqOn (a j) (a' j) V := by + intro z hz + exact (coeff_eq_iteratedDeriv_of_coordinatePower_division h hR hz j).trans + (coeff_eq_iteratedDeriv_of_coordinatePower_division h' hR hz j).symm + refine ⟨?_, ha⟩ + intro z hz + have hrem : weierstrassRemainder a z = weierstrassRemainder a' z := by + simp [weierstrassRemainder, ha _ hz.1] + have hid : q z * z.2 ^ d + weierstrassRemainder a z = + q' z * z.2 ^ d + weierstrassRemainder a' z := + (h.eq hz).symm.trans (h'.eq hz) + have hmul : q z * z.2 ^ d = q' z * z.2 ^ d := by + simpa [hrem] using hid + by_cases hw : z.2 = 0 + · have hqA : AnalyticAt ℂ (fun w => q (z.1, w)) 0 := + ((differentiableOn_snd_slice h.differentiableOn_quotient + hz.1).analyticOnNhd_of_finiteDimensional + isOpen_ball) _ (mem_ball_self hR) + have hqA' : AnalyticAt ℂ (fun w => q' (z.1, w)) 0 := + ((differentiableOn_snd_slice h'.differentiableOn_quotient + hz.1).analyticOnNhd_of_finiteDimensional + isOpen_ball) _ (mem_ball_self hR) + have heq : (fun w => q (z.1, w)) =ᶠ[𝓝[≠] (0 : ℂ)] fun w => q' (z.1, w) := by + have hball : ∀ᶠ w in 𝓝[≠] (0 : ℂ), w ∈ ball (0 : ℂ) R := + nhdsWithin_le_nhds (isOpen_ball.mem_nhds (mem_ball_self hR)) + filter_upwards [hball, self_mem_nhdsWithin] with w hwball hw0 + have hwP : (z.1, w) ∈ V ×ˢ ball (0 : ℂ) R := ⟨hz.1, hwball⟩ + have hremw : weierstrassRemainder a (z.1, w) = weierstrassRemainder a' (z.1, w) := by + simp [weierstrassRemainder, ha _ hz.1] + have hidw : q (z.1, w) * w ^ d + weierstrassRemainder a (z.1, w) = + q' (z.1, w) * w ^ d + weierstrassRemainder a' (z.1, w) := + (h.eq hwP).symm.trans (h'.eq hwP) + have : q (z.1, w) * w ^ d = q' (z.1, w) * w ^ d := by + simpa [hremw] using hidw + exact mul_right_cancel₀ (pow_ne_zero d hw0) this + have hlim : Tendsto (fun w => q (z.1, w)) (𝓝[≠] (0 : ℂ)) (𝓝 (q (z.1, 0))) := + hqA.continuousAt.tendsto.mono_left nhdsWithin_le_nhds + have hlim' : Tendsto (fun w => q' (z.1, w)) (𝓝[≠] (0 : ℂ)) (𝓝 (q' (z.1, 0))) := + hqA'.continuousAt.tendsto.mono_left nhdsWithin_le_nhds + have heq0 : q (z.1, 0) = q' (z.1, 0) := + tendsto_nhds_unique (hlim.congr' heq) hlim' + rw [show z = (z.1, (0 : ℂ)) from Prod.ext rfl hw] + exact heq0 + · exact mul_right_cancel₀ (pow_ne_zero d hw) hmul + +omit [Fintype ι] in +/-- Mixed last-coordinate derivatives at the origin are Cauchy integrals on a smaller circle. -/ +theorem iteratedDeriv_snd_slice_circleIntegral [Finite ι] + {V : Set (ι → ℂ)} {R ρ : ℝ} {g : (ι → ℂ) × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) {z : ι → ℂ} (hz : z ∈ V) + (hρ : 0 < ρ) (hρR : ρ < R) (n : ℕ) : + iteratedDeriv n (fun w => g (z, w)) 0 = + (n.factorial : ℂ) * (2 * Real.pi * I : ℂ)⁻¹ * + ∮ s in C(0, ρ), s ^ (-(n + 1 : ℤ)) * g (z, s) := by + classical + let := Fintype.ofFinite ι + simpa [sub_zero] using + (diffContOnCl_snd_slice hg hz hρ hρR).iteratedDeriv_eq_circleIntegral_sub_zpow_mul + hρ n (mem_ball_self hρ) + +/-- The Cauchy integral of a jointly holomorphic kernel in the last coordinate remains holomorphic +in the parameters. -/ +theorem analyticOnNhd_circleIntegral_snd_zpow_mul + {V : Set (ι → ℂ)} (hV : IsOpen V) {R ρ : ℝ} {g : (ι → ℂ) × ℂ → ℂ} + (hg : AnalyticOnNhd ℂ g (V ×ˢ ball 0 R)) (hρ : 0 < ρ) (hρR : ρ < R) (n : ℕ) : + AnalyticOnNhd ℂ (fun z => ∮ s in C(0, ρ), s ^ (-(n + 1 : ℤ)) * g (z, s)) V := by + have hfθ : ContinuousOn (fun s : ℂ => s ^ (-(n + 1 : ℤ))) (sphere 0 ρ) := by + refine continuousOn_id.zpow₀ (-(n + 1 : ℤ)) fun s hs => Or.inl ?_ + intro h0 + have hsρ : ‖s‖ = ρ := by + rw [← dist_zero_right] + exact mem_sphere.mp hs + have hs00 : s = 0 := h0 + rw [hs00, norm_zero] at hsρ + linarith + have hI := analyticOnNhd_circleIntegral_kernel_mul (E := ι → ℂ) hV hg hρ.le hfθ + (fun z hz s hs => + ⟨hz, (sphere_subset_closedBall.trans (closedBall_subset_ball hρR)) hs⟩) + refine hI.congr hV fun z hz => ?_ + exact circleIntegral.integral_congr hρ.le fun s _ => mul_comm _ _ + +omit [Fintype ι] in +/-- The Taylor remainder coefficients of a last-coordinate slice depend holomorphically on the +remaining coordinates. -/ +theorem differentiableOn_iteratedDeriv_snd_slice [Finite ι] + {V : Set (ι → ℂ)} (hV : IsOpen V) {R : ℝ} {g : (ι → ℂ) × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) (hR : 0 < R) (n : ℕ) : + DifferentiableOn ℂ (fun z => iteratedDeriv n (fun w => g (z, w)) 0) V := by + classical + let := Fintype.ofFinite ι + let ρ := R / 2 + have hρ : 0 < ρ := half_pos hR + have hρR : ρ < R := half_lt_self hR + have hgA : AnalyticOnNhd ℂ g (V ×ˢ ball 0 R) := + hg.analyticOnNhd_of_finiteDimensional (hV.prod isOpen_ball) + have hI := analyticOnNhd_circleIntegral_snd_zpow_mul hV hgA hρ hρR n + have hEq : EqOn (fun z => iteratedDeriv n (fun w => g (z, w)) 0) + (fun z => (n.factorial : ℂ) * (2 * Real.pi * I : ℂ)⁻¹ * + ∮ s in C(0, ρ), s ^ (-(n + 1 : ℤ)) * g (z, s)) V := + fun z hz => iteratedDeriv_snd_slice_circleIntegral hg hz hρ hρR n + exact ((hI.const_smul (c := (n.factorial : ℂ) * (2 * Real.pi * I : ℂ)⁻¹)).congr hV + (fun z hz => (hEq hz).symm)).differentiableOn + +/-- Cauchy integral representing the Weierstrass quotient for division by `w^d`. -/ +private def weierstrassCauchyQuotient (d : ℕ) (g : (ι → ℂ) × ℂ → ℂ) (ρ : ℝ) + (z : (ι → ℂ) × ℂ) : ℂ := + (2 * Real.pi * I : ℂ)⁻¹ * ∮ s in C(0, ρ), g (z.1, s) / (s ^ d * (s - z.2)) + +/-- The Cauchy quotient is jointly holomorphic on a strictly smaller product polydisc. -/ +private theorem analyticOnNhd_weierstrassCauchyQuotient + {V : Set (ι → ℂ)} (hV : IsOpen V) {R ρ₀ ρ : ℝ} {g : (ι → ℂ) × ℂ → ℂ} + (hg : AnalyticOnNhd ℂ g (V ×ˢ ball 0 R)) + (hρ₀ : 0 < ρ₀) (hρ₀ρ : ρ₀ < ρ) (hρR : ρ < R) (d : ℕ) : + AnalyticOnNhd ℂ (weierstrassCauchyQuotient d g ρ) (V ×ˢ ball 0 ρ₀) := by + let W : Set (((ι → ℂ) × ℂ) × ℂ) := + {p | p.1.1 ∈ V ∧ p.2 ∈ ball (0 : ℂ) R ∧ p.2 ≠ 0 ∧ p.2 ≠ p.1.2} + let H : ((ι → ℂ) × ℂ) × ℂ → ℂ := fun p => + g (p.1.1, p.2) / (p.2 ^ d * (p.2 - p.1.2)) + have hH : AnalyticOnNhd ℂ H W := by + intro p hp + have hnum : AnalyticAt ℂ (fun q : ((ι → ℂ) × ℂ) × ℂ => g (q.1.1, q.2)) p := + (hg (p.1.1, p.2) ⟨hp.1, hp.2.1⟩).comp_of_eq + ((analyticAt_fst (𝕜 := ℂ)).comp (analyticAt_fst (𝕜 := ℂ)) |>.prod + (analyticAt_snd (𝕜 := ℂ))) rfl + have hden : AnalyticAt ℂ + (fun q : ((ι → ℂ) × ℂ) × ℂ => q.2 ^ d * (q.2 - q.1.2)) p := + (analyticAt_snd.pow d).mul + (analyticAt_snd.sub ((analyticAt_snd (𝕜 := ℂ)).comp (analyticAt_fst (𝕜 := ℂ)))) + exact hnum.div hden (mul_ne_zero (pow_ne_zero d hp.2.2.1) + (sub_ne_zero.mpr hp.2.2.2)) + have hfθ : ContinuousOn (fun _ : ℂ => (1 : ℂ)) (sphere 0 ρ) := continuousOn_const + have hmem : ∀ x ∈ V ×ˢ ball (0 : ℂ) ρ₀, ∀ s ∈ sphere (0 : ℂ) ρ, (x, s) ∈ W := by + intro x hx s hs + have hsρ : ‖s‖ = ρ := by + rw [← dist_zero_right] + exact mem_sphere.mp hs + have hs0 : s ≠ 0 := by + intro h0 + rw [h0, norm_zero] at hsρ + linarith + have hsw : s ≠ x.2 := by + intro h + have hxρ : ‖x.2‖ < ρ₀ := by simpa [dist_eq_norm] using hx.2 + rw [h] at hsρ + linarith + exact ⟨hx.1, (sphere_subset_closedBall.trans (closedBall_subset_ball hρR)) hs, hs0, hsw⟩ + have hI := (analyticOnNhd_circleIntegral_kernel_mul (E := (ι → ℂ) × ℂ) + (hV.prod isOpen_ball) hH (le_of_lt (hρ₀.trans hρ₀ρ)) hfθ hmem).const_smul + (c := (2 * Real.pi * I : ℂ)⁻¹) + refine hI.congr (hV.prod isOpen_ball) fun z hz => ?_ + simp [weierstrassCauchyQuotient, smul_eq_mul, H] + +/-- A bound of the form `M / ρ ^ n`, valid for every positive `ρ < R`, persists at `R` itself by +continuity of the bound in `ρ`. -/ +theorem le_div_pow_of_forall_lt {M : ℝ} {R : ℝ} (hR : 0 < R) (n : ℕ) {x : ℝ} + (h : ∀ ρ, 0 < ρ → ρ < R → x ≤ M / ρ ^ n) : x ≤ M / R ^ n := by + have hcont : ContinuousAt (fun ρ : ℝ => M / ρ ^ n) R := + continuousAt_const.div (continuousAt_id.pow n) (pow_ne_zero n hR.ne') + have htendsto : Tendsto (fun ρ : ℝ => M / ρ ^ n) (nhdsWithin R (Iio R)) (nhds (M / R ^ n)) := + hcont.continuousWithinAt + refine ge_of_tendsto htendsto ?_ + filter_upwards [self_mem_nhdsWithin, + (eventually_gt_nhds hR).filter_mono nhdsWithin_le_nhds] with ρ hρR hρ0 + exact h ρ hρ0 hρR + +omit [Fintype ι] in +/-- Cauchy's estimate for the Taylor coefficients of a last-coordinate slice, uniform up to the +boundary radius `R` even though the function is only assumed holomorphic on the open polydisc. -/ +theorem norm_iteratedDeriv_snd_slice_le [Finite ι] {V : Set (ι → ℂ)} {R : ℝ} {g : (ι → ℂ) × ℂ → ℂ} + {M : ℝ} (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) (hR : 0 < R) {z : ι → ℂ} (hz : z ∈ V) + (hM : ∀ w ∈ ball (0 : ℂ) R, ‖g (z, w)‖ ≤ M) (n : ℕ) : + ‖iteratedDeriv n (fun w => g (z, w)) 0‖ ≤ (n.factorial : ℝ) * M / R ^ n := by + classical + let := Fintype.ofFinite ι + apply le_div_pow_of_forall_lt hR + intro ρ hρ hρR + rw [iteratedDeriv_snd_slice_circleIntegral hg hz hρ hρR n, mul_assoc, norm_mul] + have hkernel : ‖(2 * Real.pi * I : ℂ)⁻¹ * ∮ s in C(0, ρ), s ^ (-(n + 1 : ℤ)) * g (z, s)‖ + ≤ M / ρ ^ n := by + rw [← smul_eq_mul ((2 * Real.pi * I : ℂ)⁻¹)] + have hb := circleIntegral.norm_two_pi_i_inv_smul_integral_le_of_norm_le_const + (f := fun s => s ^ (-(n + 1 : ℤ)) * g (z, s)) (c := (0 : ℂ)) (R := ρ) + (C := M / ρ ^ (n + 1)) hρ.le + (fun s hs => by + have hsρ : ‖s‖ = ρ := by rw [← dist_zero_right]; exact mem_sphere.mp hs + have hs0 : s ≠ 0 := by intro h; rw [h, norm_zero] at hsρ; exact hρ.ne' hsρ.symm + have hzpow : ‖s ^ (-(n + 1 : ℤ))‖ = (ρ ^ (n + 1))⁻¹ := by + have he : (-(n + 1 : ℤ)) = -((n + 1 : ℕ) : ℤ) := by push_cast; ring + rw [norm_zpow, hsρ, he, zpow_neg, zpow_natCast] + rw [norm_mul, hzpow, div_eq_inv_mul] + exact mul_le_mul_of_nonneg_left (hM s ((mem_ball.mpr (by simpa [hsρ] using hρR)))) + (by positivity)) + calc ‖(2 * Real.pi * I : ℂ)⁻¹ * ∮ s in C(0, ρ), s ^ (-(n + 1 : ℤ)) * g (z, s)‖ + ≤ ρ * (M / ρ ^ (n + 1)) := hb + _ = M / ρ ^ n := by field_simp; ring + simp only [Complex.norm_natCast] + calc (n.factorial : ℝ) * ‖(2 * Real.pi * I : ℂ)⁻¹ * ∮ s in C(0, ρ), s ^ (-(n + 1 : ℤ)) * g (z, s)‖ + ≤ (n.factorial : ℝ) * (M / ρ ^ n) := mul_le_mul_of_nonneg_left hkernel (by positivity) + _ = (n.factorial : ℝ) * M / ρ ^ n := by ring + +omit [Fintype ι] in +/-- The Cauchy coefficient of a last-coordinate slice equals a division-kernel circle integral, +matching the shape used by the coordinate-power kernel identity. -/ +theorem cauchyCoeff_eq_of_lt [Finite ι] + {V : Set (ι → ℂ)} {R ρ : ℝ} {g : (ι → ℂ) × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) {w : ι → ℂ} (hw : w ∈ V) + (hρ : 0 < ρ) (hρR : ρ < R) (j : ℕ) : + (2 * Real.pi * I : ℂ)⁻¹ * ∮ s in C(0, ρ), g (w, s) / s ^ (j + 1) = + ((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv j (fun s => g (w, s)) 0 := by + classical + let := Fintype.ofFinite ι + rw [iteratedDeriv_snd_slice_circleIntegral hg hw hρ hρR j] + have hEq : EqOn (fun s : ℂ => g (w, s) / s ^ (j + 1)) + (fun s => s ^ (-(j + 1 : ℤ)) * g (w, s)) (sphere (0 : ℂ) ρ) := by + intro s _ + change g (w, s) / s ^ (j + 1) = s ^ (-(j + 1 : ℤ)) * g (w, s) + rw [div_eq_inv_mul, show (-(j + 1 : ℤ)) = -((j + 1 : ℕ) : ℤ) by push_cast; ring, + zpow_neg, zpow_natCast] + rw [circleIntegral.integral_congr hρ.le hEq, + mul_assoc ((j : ℕ).factorial : ℂ) ((2 * Real.pi * I : ℂ)⁻¹), + inv_mul_cancel_left₀ (by exact_mod_cast j.factorial_ne_zero : + ((j : ℕ).factorial : ℂ) ≠ 0)] + +omit [Fintype ι] in +/-- The Cauchy quotient at a fixed admissible radius solves the coordinate-power division identity +there, with remainder coefficients given by Taylor coefficients of the last-coordinate slice. -/ +private theorem coordinatePower_eq_of_lt [Finite ι] + {V : Set (ι → ℂ)} {R ρ : ℝ} {g : (ι → ℂ) × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) (hρ : 0 < ρ) (hρR : ρ < R) (d : ℕ) + {w : ι → ℂ} (hw : w ∈ V) {ζ : ℂ} (hζ : ζ ∈ ball (0 : ℂ) ρ) : + g (w, ζ) = weierstrassRemainder + (fun j : Fin d => fun v : ι → ℂ => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) (w, ζ) + + ζ ^ d * weierstrassCauchyQuotient d g ρ (w, ζ) := by + classical + let := Fintype.ofFinite ι + have hζρ : ‖ζ‖ < ρ := by simpa [mem_ball, dist_eq_norm] using hζ + have hslice : DiffContOnCl ℂ (fun s => g (w, s)) (ball 0 ρ) := + diffContOnCl_snd_slice hg hw hρ hρR + have hcauchy : g (w, ζ) = (2 * Real.pi * I : ℂ)⁻¹ * ∮ s in C(0, ρ), (s - ζ)⁻¹ * g (w, s) := by + simpa using hslice.iteratedDeriv_eq_circleIntegral_sub_zpow_mul hρ 0 hζ + have hcontslice : ContinuousOn (fun s => g (w, s)) (sphere (0 : ℂ) ρ) := + hg.continuousOn.comp (continuousOn_const.prodMk continuousOn_id) + (fun s hs => ⟨hw, (sphere_subset_closedBall.trans (closedBall_subset_ball hρR)) hs⟩) + have hne0 : ∀ s ∈ sphere (0 : ℂ) ρ, s ≠ 0 := by + intro s hs hcontra + have hsρ : ‖s‖ = ρ := by rw [← dist_zero_right]; exact mem_sphere.mp hs + rw [hcontra, norm_zero] at hsρ; exact hρ.ne' hsρ.symm + have hnesw : ∀ s ∈ sphere (0 : ℂ) ρ, s ≠ ζ := by + intro s hs hcontra + have hsρ : ‖s‖ = ρ := by rw [← dist_zero_right]; exact mem_sphere.mp hs + rw [hcontra] at hsρ; linarith + have hEqOn : EqOn (fun s => (s - ζ)⁻¹ * g (w, s)) + (fun s => (∑ j ∈ range d, ζ ^ j / s ^ (j + 1)) * g (w, s) + + ζ ^ d / (s ^ d * (s - ζ)) * g (w, s)) (sphere (0 : ℂ) ρ) := by + intro s hs + change (s - ζ)⁻¹ * g (w, s) = + (∑ j ∈ range d, ζ ^ j / s ^ (j + 1)) * g (w, s) + ζ ^ d / (s ^ d * (s - ζ)) * g (w, s) + rw [← add_mul, weierstrass_kernel_identity d (hne0 s hs) (hnesw s hs)] + rw [circleIntegral.integral_congr hρ.le hEqOn] at hcauchy + have hcont1 : ContinuousOn (fun s => (∑ j ∈ range d, ζ ^ j / s ^ (j + 1)) * g (w, s)) + (sphere (0 : ℂ) ρ) := by + apply ContinuousOn.mul _ hcontslice + apply continuousOn_finsetSum + intro j _ + exact ContinuousOn.div continuousOn_const (continuousOn_pow _) + (fun s hs => pow_ne_zero _ (hne0 s hs)) + have hcont2 : ContinuousOn (fun s => ζ ^ d / (s ^ d * (s - ζ)) * g (w, s)) (sphere (0 : ℂ) ρ) := + by + apply ContinuousOn.mul _ hcontslice + exact ContinuousOn.div continuousOn_const + ((continuousOn_pow _).mul (continuousOn_id.sub continuousOn_const)) + (fun s hs => mul_ne_zero (pow_ne_zero _ (hne0 s hs)) (sub_ne_zero.mpr (hnesw s hs))) + have hcirc1 : CircleIntegrable (fun s => (∑ j ∈ range d, ζ ^ j / s ^ (j + 1)) * g (w, s)) 0 ρ := + ContinuousOn.circleIntegrable' (by rwa [abs_of_pos hρ]) + have hcirc2 : CircleIntegrable (fun s => ζ ^ d / (s ^ d * (s - ζ)) * g (w, s)) 0 ρ := + ContinuousOn.circleIntegrable' (by rwa [abs_of_pos hρ]) + rw [circleIntegral.integral_add hcirc1 hcirc2] at hcauchy + have hsum : (∮ s in C(0, ρ), (∑ j ∈ range d, ζ ^ j / s ^ (j + 1)) * g (w, s)) = + ∑ j ∈ range d, ζ ^ j * ∮ s in C(0, ρ), g (w, s) / s ^ (j + 1) := by + have hcongr : (∮ s in C(0, ρ), (∑ j ∈ range d, ζ ^ j / s ^ (j + 1)) * g (w, s)) = + ∮ s in C(0, ρ), ∑ j ∈ range d, ζ ^ j * (g (w, s) / s ^ (j + 1)) := by + apply circleIntegral.integral_congr hρ.le + intro s _ + change (∑ j ∈ range d, ζ ^ j / s ^ (j + 1)) * g (w, s) = + ∑ j ∈ range d, ζ ^ j * (g (w, s) / s ^ (j + 1)) + rw [Finset.sum_mul] + exact Finset.sum_congr rfl fun j _ => by ring + rw [hcongr, circleIntegral.integral_fun_sum (fun j _ => by + apply ContinuousOn.circleIntegrable' (R := ρ) + rw [show |ρ| = ρ from abs_of_pos hρ] + exact ContinuousOn.mul continuousOn_const + (ContinuousOn.div hcontslice (continuousOn_pow _) (fun s hs => pow_ne_zero _ (hne0 s hs))))] + exact Finset.sum_congr rfl fun j _ => circleIntegral.integral_const_mul _ _ _ _ + have hquot : (∮ s in C(0, ρ), ζ ^ d / (s ^ d * (s - ζ)) * g (w, s)) = + ζ ^ d * ∮ s in C(0, ρ), g (w, s) / (s ^ d * (s - ζ)) := by + rw [← circleIntegral.integral_const_mul] + exact circleIntegral.integral_congr hρ.le fun s _ => by ring + rw [hsum, hquot, mul_add] at hcauchy + have hstep1 : (2 * Real.pi * I : ℂ)⁻¹ * + ∑ j ∈ range d, ζ ^ j * ∮ s in C(0, ρ), g (w, s) / s ^ (j + 1) = + ∑ j ∈ range d, (((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv j (fun s => g (w, s)) 0) * ζ ^ j + := by + rw [Finset.mul_sum] + exact Finset.sum_congr rfl fun j _ => by + rw [mul_left_comm, cauchyCoeff_eq_of_lt hg hw hρ hρR j, mul_comm] + rw [hstep1] at hcauchy + rw [hcauchy, weierstrassCauchyQuotient, weierstrassRemainder, + Fin.sum_univ_eq_sum_range (fun j => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv j (fun s => g (w, s)) 0 * ζ ^ j)] + ring + +omit [Fintype ι] in +/-- The Cauchy quotient at two admissible radii agrees at every nonzero point where both are +defined. -/ +private theorem weierstrassCauchyQuotient_eq_of_ne [Finite ι] {V : Set (ι → ℂ)} {R ρ₁ ρ₂ : ℝ} + {g : (ι → ℂ) × ℂ → ℂ} (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) + (hρ₁ : 0 < ρ₁) (hρ₁R : ρ₁ < R) (hρ₂ : 0 < ρ₂) (hρ₂R : ρ₂ < R) (d : ℕ) + {w : ι → ℂ} (hw : w ∈ V) {ζ : ℂ} (hζ0 : ζ ≠ 0) + (hζ₁ : ζ ∈ ball (0 : ℂ) ρ₁) (hζ₂ : ζ ∈ ball (0 : ℂ) ρ₂) : + weierstrassCauchyQuotient d g ρ₁ (w, ζ) = weierstrassCauchyQuotient d g ρ₂ (w, ζ) := by + classical + let := Fintype.ofFinite ι + have h1 := coordinatePower_eq_of_lt hg hρ₁ hρ₁R d hw hζ₁ + have h2 := coordinatePower_eq_of_lt hg hρ₂ hρ₂R d hw hζ₂ + have heq : ζ ^ d * weierstrassCauchyQuotient d g ρ₁ (w, ζ) = + ζ ^ d * weierstrassCauchyQuotient d g ρ₂ (w, ζ) := by + rw [← add_right_inj (weierstrassRemainder + (fun j v => ((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) + (w, ζ)), ← h1, ← h2] + exact mul_left_cancel₀ (pow_ne_zero d hζ0) heq + +omit [Fintype ι] in +/-- The Cauchy quotient at two admissible radii agrees wherever both are defined. -/ +private theorem weierstrassCauchyQuotient_eq_of_lt [Finite ι] + {V : Set (ι → ℂ)} (hV : IsOpen V) {R ρ₁ ρ₂ : ℝ} + {g : (ι → ℂ) × ℂ → ℂ} (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) + (hρ₁ : 0 < ρ₁) (hρ₁R : ρ₁ < R) (hρ₂ : 0 < ρ₂) (hρ₂R : ρ₂ < R) (d : ℕ) + {w : ι → ℂ} (hw : w ∈ V) {ζ : ℂ} (hζ₁ : ζ ∈ ball (0 : ℂ) ρ₁) (hζ₂ : ζ ∈ ball (0 : ℂ) ρ₂) : + weierstrassCauchyQuotient d g ρ₁ (w, ζ) = weierstrassCauchyQuotient d g ρ₂ (w, ζ) := by + classical + let := Fintype.ofFinite ι + rcases eq_or_ne ζ 0 with hζ0 | hζ0 + · subst hζ0 + set ρ₀ := min ρ₁ ρ₂ / 2 with hρ₀def + have hρ₀pos : 0 < ρ₀ := by positivity + have hρ₀ρ₁ : ρ₀ < ρ₁ := + calc ρ₀ ≤ ρ₁ / 2 := by rw [hρ₀def]; gcongr; exact min_le_left ρ₁ ρ₂ + _ < ρ₁ := by linarith + have hρ₀ρ₂ : ρ₀ < ρ₂ := + calc ρ₀ ≤ ρ₂ / 2 := by rw [hρ₀def]; gcongr; exact min_le_right ρ₁ ρ₂ + _ < ρ₂ := by linarith + have hgA : AnalyticOnNhd ℂ g (V ×ˢ ball 0 R) := hg.analyticOnNhd_of_finiteDimensional + (hV.prod isOpen_ball) + have hA1 : AnalyticOnNhd ℂ (fun ζ' => weierstrassCauchyQuotient d g ρ₁ (w, ζ')) (ball 0 ρ₀) := + fun ζ' hζ' => ((analyticOnNhd_weierstrassCauchyQuotient hV hgA hρ₀pos hρ₀ρ₁ hρ₁R d) + (w, ζ') ⟨hw, hζ'⟩).comp_of_eq + ((analyticAt_const (v := w)).prod analyticAt_id) rfl + have hA2 : AnalyticOnNhd ℂ (fun ζ' => weierstrassCauchyQuotient d g ρ₂ (w, ζ')) (ball 0 ρ₀) := + fun ζ' hζ' => ((analyticOnNhd_weierstrassCauchyQuotient hV hgA hρ₀pos hρ₀ρ₂ hρ₂R d) + (w, ζ') ⟨hw, hζ'⟩).comp_of_eq + ((analyticAt_const (v := w)).prod analyticAt_id) rfl + have heqn : (fun ζ' => weierstrassCauchyQuotient d g ρ₁ (w, ζ')) =ᶠ[𝓝[≠] (0 : ℂ)] + (fun ζ' => weierstrassCauchyQuotient d g ρ₂ (w, ζ')) := by + filter_upwards [self_mem_nhdsWithin, + mem_nhdsWithin_of_mem_nhds (isOpen_ball.mem_nhds (mem_ball_self hρ₀pos))] + with ζ' hζ'0 hζ'0' + exact weierstrassCauchyQuotient_eq_of_ne hg hρ₁ hρ₁R hρ₂ hρ₂R d hw hζ'0 + (ball_subset_ball hρ₀ρ₁.le hζ'0') (ball_subset_ball hρ₀ρ₂.le hζ'0') + have hlim1 : Tendsto (fun ζ' => weierstrassCauchyQuotient d g ρ₁ (w, ζ')) (𝓝[≠] (0 : ℂ)) + (𝓝 (weierstrassCauchyQuotient d g ρ₁ (w, 0))) := + (hA1 0 (mem_ball_self hρ₀pos)).continuousAt.tendsto.mono_left nhdsWithin_le_nhds + have hlim2 : Tendsto (fun ζ' => weierstrassCauchyQuotient d g ρ₂ (w, ζ')) (𝓝[≠] (0 : ℂ)) + (𝓝 (weierstrassCauchyQuotient d g ρ₂ (w, 0))) := + (hA2 0 (mem_ball_self hρ₀pos)).continuousAt.tendsto.mono_left nhdsWithin_le_nhds + exact tendsto_nhds_unique (hlim1.congr' heqn) hlim2 + · exact weierstrassCauchyQuotient_eq_of_ne hg hρ₁ hρ₁R hρ₂ hρ₂R d hw hζ0 hζ₁ hζ₂ + +omit [Fintype ι] in +/-- Subtracting the Taylor polynomial of degree less than `d` from a function bounded by `M` gives a +numerator bounded by `(d + 1) * M`. The triangle inequality and Cauchy's coefficient bounds +control each of the `d` remainder terms on the smaller disc. -/ +theorem norm_sub_weierstrassRemainder_iteratedDeriv_le [Finite ι] {V : Set (ι → ℂ)} {R ρ M : ℝ} + {g : (ι → ℂ) × ℂ → ℂ} (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) (hρR : ρ < R) (d : ℕ) + (hM : ∀ z ∈ V ×ˢ ball (0 : ℂ) R, ‖g z‖ ≤ M) {w : ι → ℂ} (hw : w ∈ V) {ζ' : ℂ} + (hζ' : ζ' ∈ ball (0 : ℂ) ρ) : + ‖g (w, ζ') - weierstrassRemainder (d := by + classical + let := Fintype.ofFinite ι + exact + d) (fun j v => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) (w, ζ')‖ ≤ ((d + 1 : ℕ) : ℝ) * M := by + have hζ'ρ : ‖ζ'‖ < ρ := by simpa [mem_ball, dist_eq_norm] using hζ' + have hζ'R : ‖ζ'‖ < R := hζ'ρ.trans hρR + have hR0 : 0 < R := (norm_nonneg ζ').trans_lt hζ'R + have hgb : ‖g (w, ζ')‖ ≤ M := hM (w, ζ') ⟨hw, mem_ball_zero_iff.mpr hζ'R⟩ + have hMnn : 0 ≤ M := (norm_nonneg _).trans hgb + have haj : ∀ j : Fin d, ‖(((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (w, s)) 0)‖ ≤ M / R ^ (j : ℕ) := by + intro j + have hb := norm_iteratedDeriv_snd_slice_le hg hR0 hw (fun s hs => hM (w, s) ⟨hw, hs⟩) + (j : ℕ) + rw [norm_mul, norm_inv, Complex.norm_natCast] + calc ((j : ℕ).factorial : ℝ)⁻¹ * ‖iteratedDeriv (j : ℕ) (fun s => g (w, s)) 0‖ + ≤ ((j : ℕ).factorial : ℝ)⁻¹ * (((j : ℕ).factorial : ℝ) * M / R ^ (j : ℕ)) := + mul_le_mul_of_nonneg_left hb (by positivity) + _ = M / R ^ (j : ℕ) := by field_simp + have hrem : ‖weierstrassRemainder (d := d) (fun j v => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) (w, ζ')‖ ≤ (d : ℝ) * M := by + unfold weierstrassRemainder + calc ‖∑ j : Fin d, (((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (w, s)) 0) * ζ' ^ (j : ℕ)‖ + ≤ ∑ j : Fin d, ‖(((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (w, s)) 0) * ζ' ^ (j : ℕ)‖ := norm_sum_le _ _ + _ = ∑ j : Fin d, ‖(((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (w, s)) 0)‖ * ‖ζ'‖ ^ (j : ℕ) := by + simp [norm_pow] + _ ≤ ∑ _j : Fin d, (M / R ^ (0 : ℕ)) * R ^ (0 : ℕ) := by + apply Finset.sum_le_sum + intro j _ + calc ‖(((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv (j : ℕ) + (fun s => g (w, s)) 0)‖ * ‖ζ'‖ ^ (j : ℕ) + ≤ (M / R ^ (j : ℕ)) * R ^ (j : ℕ) := + mul_le_mul (haj j) (pow_le_pow_left₀ (norm_nonneg _) + (hζ'ρ.trans hρR).le _) (by positivity) (by positivity) + _ = M := by field_simp + _ = (M / R ^ (0 : ℕ)) * R ^ (0 : ℕ) := by simp + _ = (d : ℝ) * M := by simp [Finset.sum_const, Finset.card_univ, mul_comm] + calc ‖g (w, ζ') - weierstrassRemainder (fun j v => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) (w, ζ')‖ + ≤ ‖g (w, ζ')‖ + ‖weierstrassRemainder (fun j v => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) (w, ζ')‖ := norm_sub_le _ _ + _ ≤ M + (d : ℝ) * M := add_le_add hgb hrem + _ = ((d + 1 : ℕ) : ℝ) * M := by push_cast; ring + +omit [Fintype ι] in +/-- The **uniform coordinate-power quotient bound**: the Cauchy quotient at radius `ρ` is bounded by +`(d+1) M / ρ ^ d` throughout the disc, using a bound `M` on the numerator over the whole domain. +The proof compares the numerator to its degree-`< d` Taylor polynomial, bounded by `(d+1) M` via +`norm_sub_weierstrassRemainder_iteratedDeriv_le`, then applies the maximum modulus principle to +the quotient itself and lets the comparison radius approach `ρ`. -/ +private theorem norm_weierstrassCauchyQuotient_le [Finite ι] + {V : Set (ι → ℂ)} (hV : IsOpen V) {R ρ M : ℝ} + {g : (ι → ℂ) × ℂ → ℂ} (hg : DifferentiableOn ℂ g (V ×ˢ ball 0 R)) + (hρ : 0 < ρ) (hρR : ρ < R) (d : ℕ) + (hM : ∀ z ∈ V ×ˢ ball (0 : ℂ) R, ‖g z‖ ≤ M) {w : ι → ℂ} (hw : w ∈ V) {ζ0 : ℂ} + (hζ0 : ζ0 ∈ ball (0 : ℂ) ρ) : + ‖weierstrassCauchyQuotient d g ρ (w, ζ0)‖ ≤ ((d + 1 : ℕ) : ℝ) * M / ρ ^ d := by + classical + let := Fintype.ofFinite ι + have hR0 : 0 < R := hρ.trans hρR + have hMnn : 0 ≤ M := (norm_nonneg _).trans (hM (w, 0) ⟨hw, mem_ball_self hR0⟩) + have hgA : AnalyticOnNhd ℂ g (V ×ˢ ball 0 R) := hg.analyticOnNhd_of_finiteDimensional + (hV.prod isOpen_ball) + have hψ : ∀ ζ' : ℂ, ζ' ∈ ball (0 : ℂ) ρ → + ‖g (w, ζ') - weierstrassRemainder (d := d) (fun j v => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) (w, ζ')‖ ≤ ((d + 1 : ℕ) : ℝ) * M := + fun ζ' hζ' => norm_sub_weierstrassRemainder_iteratedDeriv_le hg hρR d hM hw hζ' + have hqbound : ∀ ρ', ‖ζ0‖ < ρ' → ρ' < ρ → + ‖weierstrassCauchyQuotient d g ρ (w, ζ0)‖ ≤ ((d + 1 : ℕ) : ℝ) * M / ρ' ^ d := by + intro ρ' hζ0ρ' hρ'ρ + have hρ'pos : 0 < ρ' := (norm_nonneg _).trans_lt hζ0ρ' + have hbdry : ∀ ζ' ∈ sphere (0 : ℂ) ρ', + ‖weierstrassCauchyQuotient d g ρ (w, ζ')‖ ≤ ((d + 1 : ℕ) : ℝ) * M / ρ' ^ d := by + intro ζ' hζ' + have hζ'ρ' : ‖ζ'‖ = ρ' := by rw [← dist_zero_right]; exact mem_sphere.mp hζ' + have hζ'0 : ζ' ≠ 0 := by intro h; rw [h, norm_zero] at hζ'ρ'; exact hρ'pos.ne' hζ'ρ'.symm + have hζ'ball : ζ' ∈ ball (0 : ℂ) ρ := by + rw [mem_ball_zero_iff, hζ'ρ']; exact hρ'ρ + have heq := coordinatePower_eq_of_lt hg hρ hρR d hw hζ'ball + have hpsi := hψ ζ' hζ'ball + have hval : ζ' ^ d * weierstrassCauchyQuotient d g ρ (w, ζ') = + g (w, ζ') - weierstrassRemainder (d := d) (fun j v => ((j : ℕ).factorial : ℂ)⁻¹ * + iteratedDeriv (j : ℕ) (fun s => g (v, s)) 0) (w, ζ') := by + rw [heq]; ring + have hnorm : ‖ζ'‖ ^ d * ‖weierstrassCauchyQuotient d g ρ (w, ζ')‖ ≤ + ((d + 1 : ℕ) : ℝ) * M := by + rw [← norm_pow, ← norm_mul, hval]; exact hpsi + rw [hζ'ρ'] at hnorm + rw [le_div_iff₀ (by positivity : (0 : ℝ) < ρ' ^ d), mul_comm] + exact hnorm + obtain ⟨ρ'', hρ'ρ'', hρ''ρ⟩ := exists_between hρ'ρ + have hAslice : AnalyticOnNhd ℂ (fun ζ' => weierstrassCauchyQuotient d g ρ (w, ζ')) + (ball (0 : ℂ) ρ'') := fun ζ' hζ' => + ((analyticOnNhd_weierstrassCauchyQuotient hV hgA (hρ'pos.trans hρ'ρ'') hρ''ρ hρR d) + (w, ζ') ⟨hw, hζ'⟩).comp_of_eq ((analyticAt_const (v := w)).prod analyticAt_id) rfl + have hslice : DiffContOnCl ℂ (fun ζ' => weierstrassCauchyQuotient d g ρ (w, ζ')) + (ball (0 : ℂ) ρ') := + ⟨(hAslice.mono (ball_subset_ball hρ'ρ''.le)).differentiableOn, by + rw [closure_ball (0 : ℂ) hρ'pos.ne'] + exact hAslice.continuousOn.mono (closedBall_subset_ball hρ'ρ'')⟩ + exact Complex.norm_le_of_forall_mem_frontier_norm_le Metric.isBounded_ball hslice + (fun ζ' hζ' => by rw [frontier_ball (0 : ℂ) hρ'pos.ne'] at hζ'; exact hbdry ζ' hζ') + (subset_closure (mem_ball_zero_iff.mpr hζ0ρ')) + have hζ0ρ : ‖ζ0‖ < ρ := by simpa [mem_ball, dist_eq_norm] using hζ0 + have hcont : ContinuousAt (fun ρ' : ℝ => ((d + 1 : ℕ) : ℝ) * M / ρ' ^ d) ρ := + continuousAt_const.div (continuousAt_id.pow d) (pow_ne_zero d hρ.ne') + have htendsto : Tendsto (fun ρ' : ℝ => ((d + 1 : ℕ) : ℝ) * M / ρ' ^ d) + (nhdsWithin ρ (Iio ρ)) (nhds (((d + 1 : ℕ) : ℝ) * M / ρ ^ d)) := + hcont.continuousWithinAt + refine ge_of_tendsto htendsto ?_ + filter_upwards [self_mem_nhdsWithin, + mem_nhdsWithin_of_mem_nhds (eventually_gt_nhds hζ0ρ)] with ρ' hρ'ρ hρ'ζ0 + exact hqbound ρ' hρ'ζ0 hρ'ρ + +/-- **Coordinate-power division ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.7.4).** Every +holomorphic function +on a polydisc has a unique quotient and polynomial remainder on division by `w^d`. +The quotient estimate applies whenever the numerator is bounded. Uniqueness follows +from the coordinate-power uniqueness theorem above. +Empty parameter index types and `d = 0` are included. -/ +theorem coordinatePower_division (d : ℕ) {r : ι → ℝ} {R : ℝ} (hR : 0 < R) + {g : (ι → ℂ) × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) : + ∃ q : (ι → ℂ) × ℂ → ℂ, ∃ a : Fin d → (ι → ℂ) → ℂ, + IsWeierstrassDivisionOn (fun z => z.2 ^ d) g q a (polydisc 0 r) R ∧ + (∀ M : ℝ, 0 ≤ M → + (∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖g z‖ ≤ M) → + ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖q z‖ ≤ ((d + 1 : ℕ) : ℝ) / R ^ d * M) ∧ + (∀ q' a', IsWeierstrassDivisionOn (fun z => z.2 ^ d) g q' a' + (polydisc 0 r) R → + EqOn q q' (polydisc 0 r ×ˢ ball 0 R) ∧ + ∀ j, EqOn (a j) (a' j) (polydisc 0 r)) := by + set V := polydisc (0 : ι → ℂ) r with hVdef + have hVo : IsOpen V := isOpen_polydisc _ _ + have hgA : AnalyticOnNhd ℂ g (V ×ˢ ball 0 R) := hg.analyticOnNhd_of_finiteDimensional + (hVo.prod isOpen_ball) + set a : Fin d → (ι → ℂ) → ℂ := fun j w => + ((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv (j : ℕ) (fun s => g (w, s)) 0 with hadef + set q : (ι → ℂ) × ℂ → ℂ := fun z => weierstrassCauchyQuotient d g ((‖z.2‖ + R) / 2) z with hqdef + have hρz : ∀ ζ : ℂ, ‖ζ‖ < R → 0 < (‖ζ‖ + R) / 2 ∧ ‖ζ‖ < (‖ζ‖ + R) / 2 ∧ + (‖ζ‖ + R) / 2 < R := fun ζ hζ => ⟨by linarith [norm_nonneg ζ], by linarith, by linarith⟩ + have hqanalytic : AnalyticOnNhd ℂ q (V ×ˢ ball 0 R) := by + rintro z ⟨hz1, hz2⟩ + have hζR : ‖z.2‖ < R := by simpa [mem_ball, dist_eq_norm] using hz2 + obtain ⟨hρ0pos, hρ0ζ, hρ0R⟩ := hρz z.2 hζR + obtain ⟨ρbig, hρ0ρbig, hρbigR⟩ := exists_between hρ0R + have hkey : ‖z.2‖ < 2 * ρbig - R := by nlinarith + obtain ⟨ρ0', hζρ0', hρ0'key⟩ := exists_between hkey + have hρ0'ρbig : ρ0' < ρbig := by linarith + have hAbig : AnalyticOnNhd ℂ (weierstrassCauchyQuotient d g ρbig) (V ×ˢ ball 0 ρ0') := + analyticOnNhd_weierstrassCauchyQuotient hVo hgA + ((norm_nonneg z.2).trans_lt hζρ0') hρ0'ρbig hρbigR d + have hzmem : z ∈ V ×ˢ ball (0 : ℂ) ρ0' := ⟨hz1, mem_ball_zero_iff.mpr hζρ0'⟩ + have heqOn : EqOn q (weierstrassCauchyQuotient d g ρbig) (V ×ˢ ball (0 : ℂ) ρ0') := by + rintro y ⟨hy1, hy2⟩ + have hy2' : ‖y.2‖ < ρ0' := by simpa [mem_ball, dist_eq_norm] using hy2 + have hy2R : ‖y.2‖ < R := hy2'.trans (hρ0'ρbig.trans hρbigR) + obtain ⟨hρypos, hρyζ, hρyR⟩ := hρz y.2 hy2R + have hyρbig : ‖y.2‖ < ρbig := hy2'.trans hρ0'ρbig + have hρylt : (‖y.2‖ + R) / 2 < ρbig := by linarith + change weierstrassCauchyQuotient d g ((‖y.2‖ + R) / 2) y = + weierstrassCauchyQuotient d g ρbig y + exact weierstrassCauchyQuotient_eq_of_lt hVo hg hρypos hρyR + ((norm_nonneg y.2).trans_lt hyρbig) hρbigR d hy1 + (mem_ball_zero_iff.mpr hρyζ) (mem_ball_zero_iff.mpr hyρbig) + have heq : q =ᶠ[𝓝 z] weierstrassCauchyQuotient d g ρbig := by + filter_upwards [(hVo.prod isOpen_ball).mem_nhds hzmem] with y hy using heqOn hy + exact (hAbig z hzmem).congr heq.symm + have haholo : ∀ j, DifferentiableOn ℂ (a j) V := fun j => + (differentiableOn_iteratedDeriv_snd_slice hVo hg hR (j : ℕ)).const_mul _ + have hqholo : DifferentiableOn ℂ q (V ×ˢ ball 0 R) := + hqanalytic.differentiableOn + have heqOnV : EqOn g (fun z => q z * (fun z => z.2 ^ d) z + weierstrassRemainder a z) + (V ×ˢ ball 0 R) := by + rintro z ⟨hz1, hz2⟩ + have hζR : ‖z.2‖ < R := by simpa [mem_ball, dist_eq_norm] using hz2 + obtain ⟨hρ0pos, hρ0ζ, hρ0R⟩ := hρz z.2 hζR + have := coordinatePower_eq_of_lt hg hρ0pos hρ0R d hz1 (mem_ball_zero_iff.mpr hρ0ζ) + change g z = q z * z.2 ^ d + weierstrassRemainder a z + rw [this]; ring + refine ⟨q, a, ⟨hqholo, haholo, heqOnV⟩, ?_, ?_⟩ + · intro M hM0 hMb z hz + obtain ⟨hz1, hz2⟩ := hz + have hζR : ‖z.2‖ < R := by simpa [mem_ball, dist_eq_norm] using hz2 + obtain ⟨hρ0pos, hρ0ζ, hρ0R⟩ := hρz z.2 hζR + have hbnd : ∀ ρ', ‖z.2‖ < ρ' → ρ' < R → ‖q z‖ ≤ ((d + 1 : ℕ) : ℝ) * M / ρ' ^ d := by + intro ρ' hζρ' hρ'R + have hle := norm_weierstrassCauchyQuotient_le hVo hg ((norm_nonneg z.2).trans_lt hζρ') + hρ'R d hMb hz1 (mem_ball_zero_iff.mpr hζρ') + rwa [show q z = weierstrassCauchyQuotient d g ρ' z from + weierstrassCauchyQuotient_eq_of_lt hVo hg hρ0pos hρ0R + ((norm_nonneg z.2).trans_lt hζρ') hρ'R d hz1 (mem_ball_zero_iff.mpr hρ0ζ) + (mem_ball_zero_iff.mpr hζρ')] + have hcont : ContinuousAt (fun ρ' : ℝ => ((d + 1 : ℕ) : ℝ) * M / ρ' ^ d) R := + continuousAt_const.div (continuousAt_id.pow d) (pow_ne_zero d hR.ne') + have htendsto : Tendsto (fun ρ' : ℝ => ((d + 1 : ℕ) : ℝ) * M / ρ' ^ d) + (nhdsWithin R (Iio R)) (nhds (((d + 1 : ℕ) : ℝ) * M / R ^ d)) := + hcont.continuousWithinAt + have hfinal : ‖q z‖ ≤ ((d + 1 : ℕ) : ℝ) * M / R ^ d := by + refine ge_of_tendsto htendsto ?_ + filter_upwards [self_mem_nhdsWithin, + mem_nhdsWithin_of_mem_nhds (eventually_gt_nhds hζR)] with ρ' hρ'R hζρ' + exact hbnd ρ' hζρ' hρ'R + rw [show ((d + 1 : ℕ) : ℝ) / R ^ d * M = ((d + 1 : ℕ) : ℝ) * M / R ^ d from by ring] + exact hfinal + · intro q' a' h' + exact unique_coordinatePower_division ⟨hqholo, haholo, heqOnV⟩ h' hR + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/Picard.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/Picard.lean new file mode 100644 index 0000000000..50bac9efd2 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassDivision/Picard.lean @@ -0,0 +1,548 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.LocallyUniform +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision.CoordinatePower + +/-! +# Picard iteration for Weierstrass division + +Starting from division by a coordinate power, we construct successive approximations for a small +perturbation of that divisor. A geometric error bound gives a holomorphic limit; convergence of +Taylor coefficients identifies its polynomial remainder. A separate contraction argument proves +uniqueness for the perturbed division equation. + +These results supply the iterative step of [Jakóbczak–Jarnicki][JakobczakJarnicki2021], Theorem +1.7.3. Normalization of a general divisor is in `SeveralComplexVariables.WeierstrassDivision`. + +## Main definitions + +* `picardApprox`: The Picard-iteration approximations to the coordinate-power quotient of `g` by a + small perturbation `h` of `z ^ d`: `s 0 = 0`, and `s (k+1)` is the coordinate-power quotient of `g + - h * s k`. +* `picardApproxCoeff`: The remainder coefficients accompanying `picardApprox`'s quotient at each + step. + +## Main results + +* `picardApprox_diff_bound`: **Contraction estimate for the Picard iteration.** Consecutive Picard + approximations of the coordinate-power quotient by `g - h * s_k` differ by a geometrically + shrinking amount, given the numerator bound `M` for `g` and the small-perturbation bound on `h`. +* `exists_tendstoUniformlyOn_picardApprox`: **Locally uniform limit of the Picard iteration.** Under + the contraction estimate of `picardApprox_diff_bound`, the Picard approximations converge + uniformly on the domain to an analytic limit, with the geometric tail bound summed over all later + steps. +* `exists_weierstrassRemainder_eq_of_tendstoUniformlyOn_picardApprox`: **The remainder of a Picard + limit is itself a Weierstrass remainder.** Given a bound on the distance from each Picard + approximation to a limit `S` (as produced by `exists_tendstoUniformlyOn_picardApprox`), the + limiting perturbed-division remainder `g - h * S - ζ ^ d * S` is the Weierstrass remainder of the + coefficients obtained by passing derivatives of the numerator's slices to the limit. +* `eqOn_of_isWeierstrassDivisionOn_selfPerturbed`: **Direct uniqueness for the perturbed + coordinate-power fixed-point equation.** If `h` is uniformly small relative to `R` on a domain, + any two decompositions of the *same* `g` against the divisor `z ^ d + h`, each individually + bounded there, agree. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Complex Filter Finset Metric Set +open scoped Real Topology + +namespace SeveralComplexVariables.WeierstrassDivision + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +variable {ι : Type*} [Fintype ι] + +/-- The Picard-iteration approximations to the coordinate-power quotient of `g` by a small +perturbation `h` of `z ^ d`: `s 0 = 0`, and `s (k+1)` is the coordinate-power quotient of `g - h +* s k`. Each approximation is holomorphic on the fixed polydisc. -/ +@[expose] noncomputable def picardApprox (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) + (hR : 0 < R) + (h g : (ι → ℂ) × ℂ → ℂ) (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) : + ℕ → {s : (ι → ℂ) × ℂ → ℂ // DifferentiableOn ℂ s (polydisc 0 r ×ˢ ball 0 R)} + | 0 => ⟨0, differentiableOn_const 0⟩ + | (k + 1) => + let prev := picardApprox d r R hr hR h g hg hh k + ⟨(coordinatePower_division d hR (hg.sub (hh.mul prev.2))).choose, + (coordinatePower_division d hR + (hg.sub (hh.mul prev.2))).choose_spec.choose_spec.1.differentiableOn_quotient⟩ + +/-- The remainder coefficients accompanying `picardApprox`'s quotient at each step. -/ +noncomputable def picardApproxCoeff (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) (hR : 0 < R) + (h g : (ι → ℂ) × ℂ → ℂ) (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) (k : ℕ) : + Fin d → (ι → ℂ) → ℂ := + (coordinatePower_division d hR + (hg.sub (hh.mul (picardApprox d r R hr hR h g hg hh k).2))).choose_spec.choose + +/-- Each Picard step genuinely divides `g - h * (previous step)` by `z ^ d`. -/ +theorem picardApprox_succ_isWeierstrassDivisionOn (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) + (hR : 0 < R) + (h g : (ι → ℂ) × ℂ → ℂ) (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) (k : ℕ) : + IsWeierstrassDivisionOn (fun z => z.2 ^ d) + (g - h * (picardApprox d r R hr hR h g hg hh k).1) + (picardApprox d r R hr hR h g hg hh (k + 1)).1 + (picardApproxCoeff d r R hr hR h g hg hh k) (polydisc 0 r) R := + (coordinatePower_division d hR + (hg.sub (hh.mul (picardApprox d r R hr hR h g hg hh k).2))).choose_spec.choose_spec.1 + +/-- The quotient bound of `coordinatePower_division`, specialized to a Picard step. -/ +theorem picardApprox_succ_bound (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) (hR : 0 < R) + (h g : (ι → ℂ) × ℂ → ℂ) (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) (k : ℕ) (M : ℝ) (hM0 : 0 ≤ M) + (hb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(g - h * (picardApprox d r R hr hR h g hg hh k).1) z‖ ≤ M) : + ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(picardApprox d r R hr hR h g hg hh (k + 1)).1 z‖ ≤ ((d + 1 : ℕ) : ℝ) / R ^ d * M := + (coordinatePower_division d hR + (hg.sub (hh.mul (picardApprox d r R hr hR h g hg hh k).2))).choose_spec.choose_spec.2.1 M + hM0 hb + +/-- Uniqueness of `coordinatePower_division`, specialized to a Picard step: any other valid +decomposition of the same numerator agrees with the Picard step's output. -/ +theorem picardApprox_succ_unique (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) (hR : 0 < R) + (h g : (ι → ℂ) × ℂ → ℂ) (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) (k : ℕ) + (q' : (ι → ℂ) × ℂ → ℂ) (a' : Fin d → (ι → ℂ) → ℂ) + (hdiv' : IsWeierstrassDivisionOn (fun z => z.2 ^ d) + (g - h * (picardApprox d r R hr hR h g hg hh k).1) q' a' (polydisc 0 r) R) : + EqOn (picardApprox d r R hr hR h g hg hh (k + 1)).1 q' + (polydisc 0 r ×ˢ ball 0 R) ∧ + ∀ j, EqOn (picardApproxCoeff d r R hr hR h g hg hh k j) (a' j) (polydisc 0 r) := + (coordinatePower_division d hR + (hg.sub (hh.mul (picardApprox d r R hr hR h g hg hh k).2))).choose_spec.choose_spec.2.2 q' a' + hdiv' + +/-- Iterated derivatives converge along a locally uniform limit of holomorphic one-variable +functions, evaluated at any point of the domain. -/ +theorem tendsto_iteratedDeriv_of_tendstoLocallyUniformlyOn {V : Set ℂ} (hV : IsOpen V) (j : ℕ) : + ∀ (F : ℕ → ℂ → ℂ) (f' : ℂ → ℂ), TendstoLocallyUniformlyOn F f' atTop V → + (∀ n, DifferentiableOn ℂ (F n) V) → ∀ {x : ℂ}, x ∈ V → + Tendsto (fun n => iteratedDeriv j (F n) x) atTop (𝓝 (iteratedDeriv j f' x)) := by + induction j with + | zero => + intro F f' hF _hFa x hx + simpa [iteratedDeriv_zero] using hF.tendsto_at hx + | succ j ih => + intro F f' hF hFa x hx + have hderiv : TendstoLocallyUniformlyOn (deriv ∘ F) (deriv f') atTop V := + hF.deriv (Filter.Eventually.of_forall hFa) hV + have hderivDiff : ∀ n, DifferentiableOn ℂ (deriv (F n)) V := fun n => + (DifferentiableOn.analyticOnNhd_of_finiteDimensional (hFa n) hV).deriv.differentiableOn + have := ih (deriv ∘ F) (deriv f') hderiv hderivDiff hx + simpa [iteratedDeriv_succ', Function.comp_def] using this + +/-- **Contraction estimate for the Picard iteration.** Consecutive Picard approximations +of the coordinate-power quotient by `g - h * s_k` differ by a geometrically shrinking +amount, given the numerator bound `M` for `g` and the small-perturbation bound on `h`. -/ +theorem picardApprox_diff_bound (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) (hR : 0 < R) + (h g : (ι → ℂ) × ℂ → ℂ) (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) + (M : ℝ) (hM0 : 0 ≤ M) (hgb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖g z‖ ≤ M) + (hhb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖h z‖ ≤ R ^ d / (2 * (d + 1))) : + ∀ k, ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(picardApprox d r R hr hR h g hg hh (k + 1)).1 z - + (picardApprox d r R hr hR h g hg hh k).1 z‖ ≤ + ((d + 1 : ℕ) : ℝ) / R ^ d * M * (1 / 2) ^ k := by + intro k + induction k with + | zero => + intro z hz + have hb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(g - h * (picardApprox d r R hr hR h g hg hh 0).1) z‖ ≤ M := by + intro z hz + change ‖g z - h z * (picardApprox d r R hr hR h g hg hh 0).1 z‖ ≤ M + simpa [picardApprox] using hgb z hz + have hbnd := picardApprox_succ_bound d r R hr hR h g hg hh 0 M hM0 hb z hz + simpa [picardApprox] using hbnd + | succ k ih => + intro z hz + set sk := (picardApprox d r R hr hR h g hg hh k).1 with hskdef + set sk1 := (picardApprox d r R hr hR h g hg hh (k + 1)).1 with hsk1def + set sk2 := (picardApprox d r R hr hR h g hg hh (k + 2)).1 with hsk2def + set ak := picardApproxCoeff d r R hr hR h g hg hh k with hakdef + set ak1 := picardApproxCoeff d r R hr hR h g hg hh (k + 1) with hak1def + have hdivk := picardApprox_succ_isWeierstrassDivisionOn d r R hr hR h g hg hh k + have hdivk1 := picardApprox_succ_isWeierstrassDivisionOn d r R hr hR h g hg hh (k + 1) + have hQA : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (h * (sk1 - sk)) + (sk1 - sk2) (fun j => ak j - ak1 j) (polydisc 0 r) R := by + refine ⟨(picardApprox d r R hr hR h g hg hh (k + 1)).2.sub + (picardApprox d r R hr hR h g hg hh (k + 2)).2, + fun j => (hdivk.differentiableOn_coeff j).sub (hdivk1.differentiableOn_coeff j), ?_⟩ + intro w hw + have e1 := hdivk.eq hw + have e2 := hdivk1.eq hw + change h w * (sk1 w - sk w) = (sk1 w - sk2 w) * w.2 ^ d + + weierstrassRemainder (fun j => ak j - ak1 j) w + rw [← weierstrassRemainder_sub] + have e1' : g w - h w * sk w = sk1 w * w.2 ^ d + weierstrassRemainder ak w := e1 + have e2' : g w - h w * sk1 w = sk2 w * w.2 ^ d + weierstrassRemainder ak1 w := e2 + have : h w * (sk1 w - sk w) = (sk1 w * w.2 ^ d + weierstrassRemainder ak w) - + (sk2 w * w.2 ^ d + weierstrassRemainder ak1 w) := by + rw [← e1', ← e2']; ring + rw [this]; ring + obtain ⟨q'', a'', hdiv'', hbound'', huniq''⟩ := coordinatePower_division d hR + (hh.mul ((picardApprox d r R hr hR h g hg hh (k + 1)).2.sub + (picardApprox d r R hr hR h g hg hh k).2)) + have hEq := (huniq'' (sk1 - sk2) (fun j => ak j - ak1 j) hQA).1 + have hbndM : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(h * (sk1 - sk)) z‖ ≤ (R ^ d / (2 * (d + 1))) * + (((d + 1 : ℕ) : ℝ) / R ^ d * M * (1 / 2) ^ k) := by + intro z hz + change ‖h z * (sk1 z - sk z)‖ ≤ _ + rw [norm_mul] + exact mul_le_mul (hhb z hz) (ih z hz) (norm_nonneg _) (by positivity) + have hq''bound := hbound'' _ (by positivity) hbndM z hz + rw [hEq hz] at hq''bound + have hQval : ‖(sk1 - sk2) z‖ = ‖sk2 z - sk1 z‖ := by + rw [show (sk1 - sk2) z = sk1 z - sk2 z from rfl, ← norm_neg] + congr 1; ring + rw [hQval] at hq''bound + calc ‖sk2 z - sk1 z‖ ≤ ((d + 1 : ℕ) : ℝ) / R ^ d * + ((R ^ d / (2 * (d + 1))) * (((d + 1 : ℕ) : ℝ) / R ^ d * M * (1 / 2) ^ k)) := hq''bound + _ = ((d + 1 : ℕ) : ℝ) / R ^ d * M * (1 / 2) ^ (k + 1) := by + rw [pow_succ] + have hRd : R ^ d ≠ 0 := by positivity + have hd1 : ((d:ℝ) + 1) ≠ 0 := by positivity + push_cast + field_simp + +/-- **Locally uniform limit of the Picard iteration.** Under the contraction estimate of +`picardApprox_diff_bound`, the Picard approximations converge uniformly on the domain to an +analytic limit, with the geometric tail bound summed over all later steps. -/ +theorem exists_tendstoUniformlyOn_picardApprox (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) + (hR : 0 < R) (h g : (ι → ℂ) × ℂ → ℂ) (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball + 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) + (M : ℝ) (hM0 : 0 ≤ M) (hgb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖g z‖ ≤ M) + (hhb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖h z‖ ≤ R ^ d / (2 * (d + 1))) : + ∃ S : (ι → ℂ) × ℂ → ℂ, + AnalyticOnNhd ℂ S (polydisc 0 r ×ˢ ball 0 R) ∧ + ∀ n, ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(picardApprox d r R hr hR h g hg hh n).1 z - S z‖ ≤ + ((d + 1 : ℕ) : ℝ) / R ^ d * M * (1 / 2) ^ n / (1 - 1 / 2) := by + set sSeq := fun k => picardApprox d r R hr hR h g hg hh k with hsSeqdef + set B : ℝ := ((d + 1 : ℕ) : ℝ) / R ^ d * M with hBdef + have hB0 : 0 ≤ B := by rw [hBdef]; positivity + have hdiff : ∀ k, ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(sSeq (k + 1)).1 z - (sSeq k).1 z‖ ≤ B * (1 / 2) ^ k := + picardApprox_diff_bound d r R hr hR h g hg hh M hM0 hgb hhb + have hpt : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, CauchySeq (fun k => (sSeq k).1 z) := by + intro z hz + apply cauchySeq_of_le_geometric (r := 1 / 2) (C := B) (by norm_num) + intro n + rw [dist_eq_norm, norm_sub_rev] + exact hdiff n z hz + have hex : ∀ z : (ι → ℂ) × ℂ, ∃ y : ℂ, + z ∈ polydisc 0 r ×ˢ ball 0 R → Tendsto (fun k => (sSeq k).1 z) atTop (𝓝 y) := by + intro z + by_cases hz : z ∈ polydisc 0 r ×ˢ ball 0 R + · obtain ⟨y, hy⟩ := cauchySeq_tendsto_of_complete (hpt z hz) + exact ⟨y, fun _ => hy⟩ + · exact ⟨0, fun hz' => absurd hz' hz⟩ + choose S hStendsto using hex + have hSbound : ∀ n, ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(sSeq n).1 z - S z‖ ≤ B * (1 / 2) ^ n / (1 - 1 / 2) := by + intro n z hz + have h := dist_le_of_le_geometric_of_tendsto (r := 1 / 2) (C := B) (by norm_num) + (f := fun k => (sSeq k).1 z) (fun k => by + rw [dist_eq_norm, norm_sub_rev]; exact hdiff k z hz) + (hStendsto z hz) n + rwa [dist_eq_norm] at h + have hTU : TendstoUniformlyOn (fun k z => (sSeq k).1 z) S atTop + (polydisc 0 r ×ˢ ball 0 R) := by + rw [Metric.tendstoUniformlyOn_iff] + intro ε hε + rcases eq_or_lt_of_le hB0 with hB0' | hB0' + · filter_upwards with n z hz + rw [dist_comm, dist_eq_norm] + calc ‖(sSeq n).1 z - S z‖ ≤ B * (1 / 2) ^ n / (1 - 1 / 2) := hSbound n z hz + _ = 0 := by rw [← hB0']; ring + _ < ε := hε + · obtain ⟨N, hN⟩ := exists_pow_lt_of_lt_one + (show (0:ℝ) < ε * (1 - 1/2) / B by positivity) (by norm_num : (1/2:ℝ) < 1) + filter_upwards [eventually_ge_atTop N] with n hn z hz + rw [dist_comm, dist_eq_norm] + calc ‖(sSeq n).1 z - S z‖ ≤ B * (1 / 2) ^ n / (1 - 1 / 2) := hSbound n z hz + _ ≤ B * (1 / 2) ^ N / (1 - 1 / 2) := by + have hpow : (1 / 2 : ℝ) ^ n ≤ (1 / 2 : ℝ) ^ N := + pow_le_pow_of_le_one (by norm_num) (by norm_num) hn + have hmul : B * (1 / 2 : ℝ) ^ n ≤ B * (1 / 2 : ℝ) ^ N := + mul_le_mul_of_nonneg_left hpow hB0 + exact div_le_div_of_nonneg_right hmul (by norm_num) + _ < ε := by + rw [div_lt_iff₀ (by norm_num : (0:ℝ) < 1 - 1/2), mul_comm] + exact (lt_div_iff₀ hB0').mp hN + have hSanalytic : AnalyticOnNhd ℂ S (polydisc 0 r ×ˢ ball 0 R) := + TendstoLocallyUniformlyOn.analyticOnNhd_of_finiteDimensional + hTU.tendstoLocallyUniformlyOn + (Filter.Eventually.of_forall fun k => + (sSeq k).2.analyticOnNhd_of_finiteDimensional (isOpen_polydisc _ _ |>.prod + isOpen_ball)) + (isOpen_polydisc _ _ |>.prod isOpen_ball) + exact ⟨S, hSanalytic, hSbound⟩ + +/-- The geometric error bound for Picard approximations also controls the remainders uniformly on +each scalar slice. -/ +private theorem tendstoUniformlyOn_picardRemainder + (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) (hR : 0 < R) + (h g : (ι → ℂ) × ℂ → ℂ) + (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) + (hhb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖h z‖ ≤ R ^ d / (2 * (d + 1))) + (M : ℝ) (hM0 : 0 ≤ M) (S : (ι → ℂ) × ℂ → ℂ) + (hSbound : ∀ k, ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(picardApprox d r R hr hR h g hg hh k).1 z - S z‖ ≤ + ((d + 1 : ℕ) : ℝ) / R ^ d * M * (1 / 2) ^ k / (1 - 1 / 2)) + {w : ι → ℂ} (hw : w ∈ polydisc 0 r) : + TendstoUniformlyOn + (fun k ζ => g (w, ζ) - h (w, ζ) * (picardApprox d r R hr hR h g hg hh k).1 (w, ζ) - + ζ ^ d * (picardApprox d r R hr hR h g hg hh (k + 1)).1 (w, ζ)) + (fun ζ => g (w, ζ) - h (w, ζ) * S (w, ζ) - ζ ^ d * S (w, ζ)) + atTop (ball (0 : ℂ) R) := by + let sSeq := fun k => picardApprox d r R hr hR h g hg hh k + let B : ℝ := ((d + 1 : ℕ) : ℝ) / R ^ d * M + let rFun := fun z => g z - h z * S z - z.2 ^ d * S z + let Fk := fun k ζ => g (w, ζ) - h (w, ζ) * (sSeq k).1 (w, ζ) - + ζ ^ d * (sSeq (k + 1)).1 (w, ζ) + have hFkbound : ∀ k, ∀ ζ' ∈ ball (0 : ℂ) R, ‖Fk k ζ' - rFun (w, ζ')‖ ≤ + (R ^ d / (2 * (d + 1))) * (B * (1 / 2) ^ k / (1 - 1 / 2)) + + R ^ d * (B * (1 / 2) ^ (k + 1) / (1 - 1 / 2)) := by + intro k ζ' hζ' + have hwz' : (w, ζ') ∈ polydisc 0 r ×ˢ ball 0 R := ⟨hw, hζ'⟩ + have hb1 := hSbound k (w, ζ') hwz' + have hb2 := hSbound (k + 1) (w, ζ') hwz' + have hζ'le : ‖ζ'‖ ≤ R := (mem_ball_zero_iff.mp hζ').le + have hhle : ‖h (w, ζ')‖ ≤ R ^ d / (2 * (d + 1)) := hhb (w, ζ') hwz' + have hdiff_eq : Fk k ζ' - rFun (w, ζ') = + -(h (w, ζ') * ((sSeq k).1 (w, ζ') - S (w, ζ'))) - + ζ' ^ d * ((sSeq (k + 1)).1 (w, ζ') - S (w, ζ')) := by + change (g (w, ζ') - h (w, ζ') * (sSeq k).1 (w, ζ') - + ζ' ^ d * (sSeq (k + 1)).1 (w, ζ')) - + (g (w, ζ') - h (w, ζ') * S (w, ζ') - ζ' ^ d * S (w, ζ')) = _ + ring + rw [hdiff_eq] + calc ‖-(h (w, ζ') * ((sSeq k).1 (w, ζ') - S (w, ζ'))) - + ζ' ^ d * ((sSeq (k + 1)).1 (w, ζ') - S (w, ζ'))‖ + = ‖h (w, ζ') * ((sSeq k).1 (w, ζ') - S (w, ζ')) + + ζ' ^ d * ((sSeq (k + 1)).1 (w, ζ') - S (w, ζ'))‖ := by + rw [← norm_neg]; congr 1; ring + _ ≤ ‖h (w, ζ') * ((sSeq k).1 (w, ζ') - S (w, ζ'))‖ + + ‖ζ' ^ d * ((sSeq (k + 1)).1 (w, ζ') - S (w, ζ'))‖ := norm_add_le _ _ + _ = ‖h (w, ζ')‖ * ‖(sSeq k).1 (w, ζ') - S (w, ζ')‖ + + ‖ζ'‖ ^ d * ‖(sSeq (k + 1)).1 (w, ζ') - S (w, ζ')‖ := by + rw [norm_mul, norm_mul, norm_pow] + _ ≤ (R ^ d / (2 * (d + 1))) * (B * (1 / 2) ^ k / (1 - 1 / 2)) + + R ^ d * (B * (1 / 2) ^ (k + 1) / (1 - 1 / 2)) := by + gcongr + have hFktendsto : Tendsto (fun k => (R ^ d / (2 * (d + 1))) * (B * (1 / 2) ^ k / (1 - 1 / 2)) + + R ^ d * (B * (1 / 2) ^ (k + 1) / (1 - 1 / 2))) atTop (𝓝 0) := by + have h1 : Tendsto (fun k : ℕ => (1 / 2 : ℝ) ^ k) atTop (𝓝 0) := + tendsto_pow_atTop_nhds_zero_of_lt_one (by norm_num) (by norm_num) + have h2 : Tendsto (fun k : ℕ => (1 / 2 : ℝ) ^ (k + 1)) atTop (𝓝 0) := + h1.comp (tendsto_add_atTop_nat 1) + have e1 : Tendsto (fun k => (R ^ d / (2 * (d + 1))) * (B * (1 / 2) ^ k / (1 - 1 / 2))) + atTop (𝓝 ((R ^ d / (2 * (d + 1))) * (B * 0 / (1 - 1 / 2)))) := + ((h1.const_mul B).div_const (1 - 1/2)).const_mul _ + have e2 : Tendsto (fun k => R ^ d * (B * (1 / 2) ^ (k + 1) / (1 - 1 / 2))) + atTop (𝓝 (R ^ d * (B * 0 / (1 - 1 / 2)))) := + ((h2.const_mul B).div_const (1 - 1/2)).const_mul _ + simpa using e1.add e2 + have hFkTU : TendstoUniformlyOn Fk (fun ζ' => rFun (w, ζ')) atTop (ball (0:ℂ) R) := by + rw [Metric.tendstoUniformlyOn_iff] + intro ε hε + have := (Metric.tendsto_atTop.mp hFktendsto) ε hε + obtain ⟨N, hN⟩ := this + filter_upwards [eventually_ge_atTop N] with k hk ζ' hζ' + rw [dist_comm, dist_eq_norm] + calc ‖Fk k ζ' - rFun (w, ζ')‖ ≤ _ := hFkbound k ζ' hζ' + _ = ‖(R ^ d / (2 * (d + 1))) * (B * (1 / 2) ^ k / (1 - 1 / 2)) + + R ^ d * (B * (1 / 2) ^ (k + 1) / (1 - 1 / 2)) - 0‖ := by + rw [sub_zero] + rw [Real.norm_of_nonneg (by positivity)] + _ < ε := hN k hk + exact hFkTU + +/-- A uniform limit of scalar polynomials of degree less than `d` is the polynomial formed from its +first `d` Taylor coefficients. Derivative convergence identifies the coefficients, and the +finite sum then passes to the limit. -/ +private theorem eq_taylorPolynomial_of_tendstoUniformlyOn {d : ℕ} {R : ℝ} (hR : 0 < R) + {F : ℕ → ℂ → ℂ} {f : ℂ → ℂ} {a : ℕ → Fin d → ℂ} + (hpoly : ∀ k, EqOn (F k) (fun ζ => ∑ j : Fin d, a k j * ζ ^ (j : ℕ)) (ball 0 R)) + (hlim : TendstoUniformlyOn F f atTop (ball 0 R)) + (hdiff : ∀ k, DifferentiableOn ℂ (F k) (ball 0 R)) + {ζ : ℂ} (hζ : ζ ∈ ball 0 R) : + f ζ = ∑ j : Fin d, (((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv (j : ℕ) f 0) * ζ ^ (j : ℕ) := by + have hcoeff (j : Fin d) : Tendsto (fun k => a k j) atTop + (𝓝 (((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv (j : ℕ) f 0)) := by + have hder := tendsto_iteratedDeriv_of_tendstoLocallyUniformlyOn isOpen_ball + (j : ℕ) F f hlim.tendstoLocallyUniformlyOn hdiff (mem_ball_self hR) + have heq (k : ℕ) : iteratedDeriv (j : ℕ) (F k) 0 = + ((j : ℕ).factorial : ℂ) * a k j := by + rw [(Filter.eventuallyEq_of_mem (ball_mem_nhds 0 hR) (hpoly k)).iteratedDeriv_eq, + iteratedDeriv_weierstrassRemainder_const, dite_eq_left j.isLt] + have h := hder.const_mul (((j : ℕ).factorial : ℂ)⁻¹) + have hfac : ((j : ℕ).factorial : ℂ) ≠ 0 := by exact_mod_cast (j : ℕ).factorial_ne_zero + simpa only [heq, ← mul_assoc, inv_mul_cancel₀ hfac, + one_mul] using h + have hsum := tendsto_finsetSum Finset.univ (fun j _ => (hcoeff j).mul_const (ζ ^ (j : ℕ))) + have hvalue : Tendsto (fun k => F k ζ) atTop + (𝓝 (∑ j : Fin d, (((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv (j : ℕ) f 0) * ζ ^ (j : ℕ))) := + hsum.congr' (.of_forall fun k => (hpoly k hζ).symm) + exact tendsto_nhds_unique (hlim.tendsto_at hζ) hvalue + +/-- **The remainder of a Picard limit is itself a Weierstrass remainder.** Given a bound +on the distance from each Picard approximation to a limit `S` (as produced by +`exists_tendstoUniformlyOn_picardApprox`), the limiting perturbed-division remainder +`g - h * S - ζ ^ d * S` is the Weierstrass remainder of the coefficients obtained by +passing derivatives of the numerator's slices to the limit. No identity theorem is used: +each Taylor coefficient of the remainder is recovered directly as the limit of the +corresponding coefficient of the finite Picard step. -/ +theorem exists_weierstrassRemainder_eq_of_tendstoUniformlyOn_picardApprox + (d : ℕ) (r : ι → ℝ) (R : ℝ) (hr : ∀ i, 0 < r i) (hR : 0 < R) (h g : (ι → ℂ) × ℂ → ℂ) + (hg : DifferentiableOn ℂ g (polydisc 0 r ×ˢ ball 0 R)) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) + (hhb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖h z‖ ≤ R ^ d / (2 * (d + 1))) + (M : ℝ) (hM0 : 0 ≤ M) (S : (ι → ℂ) × ℂ → ℂ) + (hSdiff : DifferentiableOn ℂ S (polydisc 0 r ×ˢ ball 0 R)) + (hSbound : ∀ n, ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, + ‖(picardApprox d r R hr hR h g hg hh n).1 z - S z‖ ≤ + ((d + 1 : ℕ) : ℝ) / R ^ d * M * (1 / 2) ^ n / (1 - 1 / 2)) : + ∃ a : Fin d → (ι → ℂ) → ℂ, (∀ j, DifferentiableOn ℂ (a j) (polydisc (0 : ι → ℂ) r)) ∧ + ∀ w ∈ polydisc (0 : ι → ℂ) r, ∀ ζ ∈ ball (0 : ℂ) R, + g (w, ζ) - h (w, ζ) * S (w, ζ) - ζ ^ d * S (w, ζ) = weierstrassRemainder a (w, ζ) := by + set sSeq := fun k => picardApprox d r R hr hR h g hg hh k with hsSeqdef + set rFun : (ι → ℂ) × ℂ → ℂ := fun z => g z - h z * S z - z.2 ^ d * S z with hrFundef + set aOut : Fin d → (ι → ℂ) → ℂ := fun j w => + ((j : ℕ).factorial : ℂ)⁻¹ * iteratedDeriv (j : ℕ) (fun ζ => rFun (w, ζ)) 0 with haOutdef + have hrFunDiffFull : DifferentiableOn ℂ rFun (polydisc 0 r ×ˢ ball 0 R) := by + have h4 : DifferentiableOn ℂ (fun z : (ι → ℂ) × ℂ => z.2 ^ d) + (polydisc 0 r ×ˢ ball 0 R) := (differentiableOn_snd).pow d + exact (hg.sub (hh.mul hSdiff)).sub (h4.mul hSdiff) + have haDiff : ∀ j, DifferentiableOn ℂ (aOut j) (polydisc (0 : ι → ℂ) r) := fun j => + (differentiableOn_iteratedDeriv_snd_slice (isOpen_polydisc _ _) + hrFunDiffFull hR (j : ℕ)).const_mul _ + refine ⟨aOut, haDiff, fun w hw ζ hζ => ?_⟩ + set Fk : ℕ → ℂ → ℂ := fun k ζ' => + g (w, ζ') - h (w, ζ') * (sSeq k).1 (w, ζ') - ζ' ^ d * (sSeq (k + 1)).1 (w, ζ') with hFkdef + have hFkeq : ∀ k, ∀ ζ' ∈ ball (0 : ℂ) R, Fk k ζ' = + weierstrassRemainder (picardApproxCoeff d r R hr hR h g hg hh k) (w, ζ') := by + intro k ζ' hζ' + have hthis := (picardApprox_succ_isWeierstrassDivisionOn d r R hr hR h g hg hh k).eq + (⟨hw, hζ'⟩ : (w, ζ') ∈ polydisc 0 r ×ˢ ball 0 R) + change g (w, ζ') - h (w, ζ') * (sSeq k).1 (w, ζ') - ζ' ^ d * (sSeq (k + 1)).1 (w, ζ') = _ + have hthis' : g (w, ζ') - h (w, ζ') * (sSeq k).1 (w, ζ') = + (sSeq (k + 1)).1 (w, ζ') * ζ' ^ d + + weierstrassRemainder (picardApproxCoeff d r R hr hR h g hg hh k) (w, ζ') := hthis + rw [hthis']; ring + have hFkTU : TendstoUniformlyOn Fk (fun ζ' => rFun (w, ζ')) atTop (ball (0 : ℂ) R) := + tendstoUniformlyOn_picardRemainder d r R hr hR h g hg hh hhb M hM0 S hSbound hw + have hFkDiff : ∀ k, DifferentiableOn ℂ (Fk k) (ball (0 : ℂ) R) := by + intro k + have h1 : DifferentiableOn ℂ (fun ζ' => g (w, ζ')) (ball (0:ℂ) R) := + differentiableOn_snd_slice hg hw + have h2 : DifferentiableOn ℂ (fun ζ' => h (w, ζ')) (ball (0:ℂ) R) := + differentiableOn_snd_slice hh hw + have h3 : DifferentiableOn ℂ (fun ζ' => (sSeq k).1 (w, ζ')) (ball (0:ℂ) R) := + differentiableOn_snd_slice (sSeq k).2 hw + have h4 : DifferentiableOn ℂ (fun ζ' => (sSeq (k+1)).1 (w, ζ')) (ball (0:ℂ) R) := + differentiableOn_snd_slice (sSeq (k+1)).2 hw + exact (h1.sub (h2.mul h3)).sub ((differentiableOn_pow d).mul h4) + exact eq_taylorPolynomial_of_tendstoUniformlyOn + (a := fun k j => picardApproxCoeff d r R hr hR h g hg hh k j w) + hR hFkeq hFkTU hFkDiff hζ + +/-- **Direct uniqueness for the perturbed coordinate-power fixed-point equation.** +If `h` is uniformly small relative to `R` on a domain, any two decompositions of the +*same* `g` against the divisor `z ^ d + h`, each individually bounded there, agree. -/ +theorem eqOn_of_isWeierstrassDivisionOn_selfPerturbed {d : ℕ} {r : ι → ℝ} {R : ℝ} + (hR : 0 < R) (h g s s' : (ι → ℂ) × ℂ → ℂ) (a a' : Fin d → (ι → ℂ) → ℂ) + (hh : DifferentiableOn ℂ h (polydisc 0 r ×ˢ ball 0 R)) + (hhb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖h z‖ ≤ R ^ d / (2 * (d + 1))) + (hdiv : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (g - h * s) s a (polydisc 0 r) R) + (hdiv' : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (g - h * s') s' a' + (polydisc 0 r) R) + (M : ℝ) (hM0 : 0 ≤ M) (hsb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖s z - s' z‖ ≤ M) : + EqOn s s' (polydisc 0 r ×ˢ ball 0 R) ∧ ∀ j, EqOn (a j) (a' j) (polydisc 0 r) + := by + suffices hs : EqOn s s' (polydisc 0 r ×ˢ ball 0 R) by + refine ⟨hs, ?_⟩ + have hdiv2 : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (g - h * s) s' a' + (polydisc 0 r) R := + ⟨hdiv'.differentiableOn_quotient, + hdiv'.differentiableOn_coeff, + fun z hz => by + change (g z - h z * s z) = s' z * z.2 ^ d + weierstrassRemainder a' z + rw [hs hz] + exact hdiv'.eq hz⟩ + exact (unique_coordinatePower_division hdiv hdiv2 hR).2 + have hQA : ∀ M' : ℝ, 0 ≤ M' → + (∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖s z - s' z‖ ≤ M') → + ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖s z - s' z‖ ≤ M' / 2 := by + intro M' hM'0 hM' z hz + have hQAdiv : IsWeierstrassDivisionOn (fun z => z.2 ^ d) (h * (s' - s)) (s - s') + (fun j => a j - a' j) (polydisc 0 r) R := by + refine ⟨hdiv.differentiableOn_quotient.sub hdiv'.differentiableOn_quotient, + fun j => (hdiv.differentiableOn_coeff j).sub (hdiv'.differentiableOn_coeff j), ?_⟩ + intro w hw + have e1 : g w - h w * s w = s w * w.2 ^ d + weierstrassRemainder a w := hdiv.eq hw + have e2 : g w - h w * s' w = s' w * w.2 ^ d + weierstrassRemainder a' w := hdiv'.eq hw + change h w * (s' w - s w) = (s w - s' w) * w.2 ^ d + weierstrassRemainder (fun j => a j - a' + j) w + rw [← weierstrassRemainder_sub] + have : h w * (s' w - s w) = (s w * w.2 ^ d + weierstrassRemainder a w) - + (s' w * w.2 ^ d + weierstrassRemainder a' w) := by rw [← e1, ← e2]; ring + rw [this]; ring + have hhdiff : DifferentiableOn ℂ (h * (s' - s)) (polydisc 0 r ×ˢ ball 0 R) := + hh.mul (hdiv'.differentiableOn_quotient.sub hdiv.differentiableOn_quotient) + obtain ⟨q'', a'', hdiv'', hbound'', huniq''⟩ := coordinatePower_division d hR hhdiff + have hEq := (huniq'' (s - s') (fun j => a j - a' j) hQAdiv).1 + have hb : ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖(h * (s' - s)) z‖ ≤ + (R ^ d / (2 * (d + 1))) * M' := by + intro z hz + change ‖h z * (s' z - s z)‖ ≤ _ + rw [norm_mul, ← norm_sub_rev (s z) (s' z)] + exact mul_le_mul (hhb z hz) (hM' z hz) (norm_nonneg _) (by positivity) + have hq''bound := hbound'' _ (by positivity) hb z hz + rw [hEq hz] at hq''bound + calc ‖s z - s' z‖ = ‖(s - s') z‖ := rfl + _ ≤ ((d + 1 : ℕ) : ℝ) / R ^ d * ((R ^ d / (2 * (d + 1))) * M') := hq''bound + _ = M' / 2 := by + have hRd : R ^ d ≠ 0 := by positivity + have hd1 : ((d : ℝ) + 1) ≠ 0 := by positivity + push_cast + field_simp + have hind : ∀ n, ∀ z ∈ polydisc 0 r ×ˢ ball 0 R, ‖s z - s' z‖ ≤ M * (1 / 2) ^ n := by + intro n + induction n with + | zero => simpa using hsb + | succ n ih => + intro z hz + have := hQA (M * (1/2)^n) (by positivity) ih z hz + calc ‖s z - s' z‖ ≤ M * (1/2)^n / 2 := this + _ = M * (1/2)^(n+1) := by ring + intro z hz + have htendsto : Tendsto (fun n => M * (1 / 2 : ℝ) ^ n) atTop (𝓝 0) := by + have := tendsto_pow_atTop_nhds_zero_of_lt_one (r := (1/2:ℝ)) (by norm_num) (by norm_num) + simpa using this.const_mul M + have hle : ‖s z - s' z‖ ≤ 0 := + ge_of_tendsto htendsto (Filter.Eventually.of_forall fun n => hind n z hz) + have := norm_nonneg (s z - s' z) + have heq0 : ‖s z - s' z‖ = 0 := le_antisymm hle this + exact sub_eq_zero.mp (norm_eq_zero.mp heq0) + +end SeveralComplexVariables.WeierstrassDivision + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassPreparation.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassPreparation.lean new file mode 100644 index 0000000000..12bb031e84 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/WeierstrassPreparation.lean @@ -0,0 +1,314 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.WeierstrassDivision + +/-! +# Analytic Weierstrass preparation + +A function regular of order `d` in the distinguished coordinate factors locally as a +nonvanishing holomorphic function times a monic polynomial of degree `d`. The lower coefficients +are holomorphic in the parameters and vanish at the parameter origin. + +Reference: [Jakóbczak–Jarnicki][JakobczakJarnicki2021], Theorem 1.7.2. Preparation and its +uniqueness are derived from the analytic division theorem. The proof includes degree zero, and +empty parameter types recover one-variable theory. + +## Main definitions + +* `weierstrassPolynomial`: The monic polynomial in the distinguished coordinate with prescribed + lower coefficients. +* `IsWeierstrassPreparationAt`: Local preparation consists of a unit and a monic polynomial whose + lower coefficients vanish at the parameter origin. + +## Main results + +* `exists_isWeierstrassPreparationAt`: **Weierstrass preparation for analytic germs.** Divide `w^d` + by `f`, identify the central coefficients using one-variable order factorization and division + uniqueness, and invert the resulting quotient. +* `exists_eqOn_mul_weierstrassPolynomial`: **Weierstrass preparation + ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.7.2).** On a sufficiently small polydisc, a regular + holomorphic function is a nonvanishing holomorphic factor times a monic polynomial with + holomorphic lower coefficients vanishing at the origin. +* `exists_isWeierstrassPreparationAt_of_finiteDimensional`: **Weierstrass preparation for analytic + germs on any finite-dimensional parameter space.** Obtained by transporting the coordinate version + along a basis; no choice of coordinates occurs in the statement. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public noncomputable section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- The monic polynomial in the distinguished coordinate with prescribed lower coefficients. -/ +@[expose] def weierstrassPolynomial {d : ℕ} (a : Fin d → E → ℂ) (z : E × ℂ) : ℂ := + z.2 ^ d + weierstrassRemainder a z + +omit [NormedAddCommGroup E] [NormedSpace ℂ E] in +/-- Negating the coefficient functions negates the remainder polynomial. -/ +@[simp] theorem weierstrassRemainder_neg {d : ℕ} (a : Fin d → E → ℂ) (z : E × ℂ) : + weierstrassRemainder (fun j x => -a j x) z = -weierstrassRemainder a z := by + simp [weierstrassRemainder, Finset.sum_neg_distrib] + +omit [NormedAddCommGroup E] [NormedSpace ℂ E] in +/-- A monic polynomial of degree zero is the constant one. -/ +@[simp] theorem weierstrassPolynomial_zero (a : Fin 0 → E → ℂ) : + weierstrassPolynomial a = 1 := by + funext z + simp [weierstrassPolynomial] + +/-- Analytic coefficients give a jointly analytic monic polynomial. -/ +theorem analyticAt_weierstrassPolynomial {d : ℕ} {a : Fin d → E → ℂ} {z : E × ℂ} + (ha : ∀ j, AnalyticAt ℂ (a j) z.1) : AnalyticAt ℂ (weierstrassPolynomial a) z := + (analyticAt_snd.pow d).add (analyticAt_weierstrassRemainder ha) + +omit [NormedSpace ℂ E] in +/-- Vanishing of the lower coefficients gives the central monomial. -/ +theorem weierstrassPolynomial_central {d : ℕ} {a : Fin d → E → ℂ} + (ha : ∀ j, a j 0 = 0) (w : ℂ) : weierstrassPolynomial a (0, w) = w ^ d := by + simp [weierstrassPolynomial, weierstrassRemainder, ha] + +/-- Local preparation consists of a unit and a monic polynomial whose lower coefficients vanish at +the parameter origin. Equality is equality of germs at the origin. -/ +structure IsWeierstrassPreparationAt {d : ℕ} (f u : E × ℂ → ℂ) + (a : Fin d → E → ℂ) : Prop where + /-- The unit factor is analytic at the origin. -/ + analyticAt_unit : AnalyticAt ℂ u 0 + /-- The unit factor does not vanish at the origin. -/ + unit_ne_zero : u 0 ≠ 0 + /-- Each polynomial coefficient is analytic at the parameter origin. -/ + analyticAt_coeff : ∀ j, AnalyticAt ℂ (a j) 0 + /-- All lower polynomial coefficients vanish at the parameter origin. -/ + coeff_zero : ∀ j, a j 0 = 0 + /-- As germs, the function equals the unit times the distinguished polynomial. -/ + eq : f =ᶠ[𝓝 0] fun z => u z * weierstrassPolynomial a z + +/-- A nonvanishing analytic function is already prepared in degree zero. -/ +theorem isWeierstrassPreparationAt_zero {f : E × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (h0 : f 0 ≠ 0) : + IsWeierstrassPreparationAt f f (fun j : Fin 0 => Fin.elim0 j) := by + refine ⟨hf, h0, fun j => Fin.elim0 j, fun j => Fin.elim0 j, ?_⟩ + exact .of_forall fun z => by simp + +/-- A preparation gives a division of the monomial by the original function. -/ +theorem IsWeierstrassPreparationAt.division {d : ℕ} {f u : E × ℂ → ℂ} + {a : Fin d → E → ℂ} (h : IsWeierstrassPreparationAt f u a) : + IsWeierstrassDivisionAt f (fun z => z.2 ^ d) (fun z => (u z)⁻¹) + (fun j x => -a j x) := by + refine ⟨h.analyticAt_unit.inv h.unit_ne_zero, fun j => (h.analyticAt_coeff j).neg, ?_⟩ + filter_upwards [h.eq, h.analyticAt_unit.continuousAt.eventually_ne h.unit_ne_zero] with z hz hne + rw [hz, weierstrassRemainder_neg] + simp [weierstrassPolynomial, hne] + +variable {ι : Type*} [Fintype ι] + +/-- Uniqueness of preparation follows from uniqueness of analytic division. Thus it rests on the +division theorem. -/ +theorem IsWeierstrassPreparationAt.unique {d : ℕ} {f u v : (ι → ℂ) × ℂ → ℂ} + {a b : Fin d → (ι → ℂ) → ℂ} + (h : IsWeierstrassPreparationAt f u a) (h' : IsWeierstrassPreparationAt f v b) + (hf : AnalyticAt ℂ f 0) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + u =ᶠ[𝓝 0] v ∧ ∀ j, a j =ᶠ[𝓝 0] b j := by + obtain ⟨hu, ha⟩ := h.division.unique h'.division hf (analyticAt_snd.pow d) horder + refine ⟨hu.mono (fun z hz => inv_injective hz), fun j => ?_⟩ + exact (ha j).mono (fun z hz => neg_injective hz) + +/-- Uniqueness of the factors and coefficients on a whole product domain follows from germ +uniqueness and the identity theorem. This applies to the polydisc of preparation. -/ +theorem IsWeierstrassPreparationAt.unique_on {d : ℕ} {f u v : (ι → ℂ) × ℂ → ℂ} + {a b : Fin d → (ι → ℂ) → ℂ} {V : Set (ι → ℂ)} {R : ℝ} + (h : IsWeierstrassPreparationAt f u a) (h' : IsWeierstrassPreparationAt f v b) + (hf : AnalyticAt ℂ f 0) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) + (hV : IsOpen V) (hconn : IsPreconnected V) (h0 : 0 ∈ V) (hR : 0 < R) + (hu : DifferentiableOn ℂ u (V ×ˢ ball 0 R)) + (hv : DifferentiableOn ℂ v (V ×ˢ ball 0 R)) + (ha : ∀ j, DifferentiableOn ℂ (a j) V) (hb : ∀ j, DifferentiableOn ℂ (b j) V) : + EqOn u v (V ×ˢ ball 0 R) ∧ ∀ j, EqOn (a j) (b j) V := by + obtain ⟨he, he'⟩ := h.unique h' hf horder + exact ⟨DifferentiableOn.eqOn_of_preconnected_of_eventuallyEq + (show IsOpen (V ×ˢ ball (0 : ℂ) R) from hV.prod isOpen_ball) + (hconn.prod (convex_ball (0 : ℂ) R).isPreconnected) + hu hv ⟨h0, mem_ball_self hR⟩ he, + fun j => (ha j).eqOn_of_preconnected_of_eventuallyEq hV hconn (hb j) h0 (he' j)⟩ + +/-- **Weierstrass preparation for analytic germs.** Divide `w^d` by `f`, identify the +central coefficients using one-variable order factorization and division uniqueness, +and invert the resulting quotient. This proof depends on analytic division. -/ +theorem exists_isWeierstrassPreparationAt {d : ℕ} {f : (ι → ℂ) × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (u : (ι → ℂ) × ℂ → ℂ) (a : Fin d → (ι → ℂ) → ℂ), + IsWeierstrassPreparationAt f u a ∧ + ∀ v b, IsWeierstrassPreparationAt f v b → + u =ᶠ[𝓝 0] v ∧ ∀ j, a j =ᶠ[𝓝 0] b j := by + have hp : AnalyticAt ℂ (fun z : (ι → ℂ) × ℂ => z.2 ^ d) 0 := analyticAt_snd.pow d + obtain ⟨q, a, hD, _⟩ := exists_isWeierstrassDivisionAt hf hp horder + have hs : AnalyticAt ℂ (fun w : ℂ => f (0, w)) 0 := + hf.comp_of_eq (analyticAt_const.prod analyticAt_id) rfl + obtain ⟨v, hv, hv0, hfv⟩ := hs.analyticOrderAt_eq_natCast.mp horder + have hc : AnalyticAt ℂ (fun z : (ι → ℂ) × ℂ => ((0 : ι → ℂ), z.2)) 0 := + analyticAt_const.prod analyticAt_snd + have hDc : IsWeierstrassDivisionAt (fun z : (ι → ℂ) × ℂ => f (0, z.2)) + (fun z => z.2 ^ d) (fun z => q (0, z.2)) (fun j _ => a j 0) := by + refine ⟨hD.analyticAt_quotient.comp_of_eq hc rfl, fun _ => analyticAt_const, ?_⟩ + exact hD.eq.comp_tendsto hc.continuousAt + have hDv : IsWeierstrassDivisionAt (fun z : (ι → ℂ) × ℂ => f (0, z.2)) + (fun z => z.2 ^ d) (fun z => (v z.2)⁻¹) (fun _ _ => 0 : Fin d → (ι → ℂ) → ℂ) := by + refine ⟨(hv.comp_of_eq (analyticAt_snd (𝕜 := ℂ) + (p := (0 : (ι → ℂ) × ℂ))) rfl).inv hv0, fun _ => analyticAt_const, ?_⟩ + have ht : Tendsto (Prod.snd : (ι → ℂ) × ℂ → ℂ) (𝓝 0) (𝓝 0) := + continuous_snd.tendsto 0 + filter_upwards [ht.eventually hfv, ht.eventually (hv.continuousAt.eventually_ne hv0)] + with z hz hne + simp only [sub_zero, smul_eq_mul] at hz + simp [weierstrassRemainder, hz, hne, mul_comm] + obtain ⟨hq, ha⟩ := hDc.unique hDv (hf.comp_of_eq hc rfl) hp horder + have hq0 : q 0 ≠ 0 := by + have he : q 0 = (v 0)⁻¹ := hq.eq_of_nhds + rw [he] + exact inv_ne_zero hv0 + have ha0 : ∀ j, a j 0 = 0 := fun j => (ha j).eq_of_nhds + have H : IsWeierstrassPreparationAt f (fun z => (q z)⁻¹) (fun j x => -a j x) := by + refine ⟨hD.analyticAt_quotient.inv hq0, inv_ne_zero hq0, + fun j => (hD.analyticAt_coeff j).neg, fun j => by simp [ha0], ?_⟩ + filter_upwards [hD.eq, hD.analyticAt_quotient.continuousAt.eventually_ne hq0] with z hz hne + simp only [weierstrassPolynomial, weierstrassRemainder_neg] + apply (mul_left_cancel₀ hne) + rw [← mul_assoc, mul_inv_cancel₀ hne, one_mul] + linear_combination -hz + exact ⟨_, _, H, fun v b hb => H.unique hb hf horder⟩ + +/-- **Weierstrass preparation ([Jakóbczak–Jarnicki][JakobczakJarnicki2021] 1.7.2).** On a +sufficiently small +polydisc, a regular holomorphic function is a nonvanishing holomorphic factor times a +monic polynomial with holomorphic lower coefficients vanishing at the origin. +The factorization is unique as a germ. The proof depends on analytic division. -/ +theorem exists_eqOn_mul_weierstrassPolynomial {d : ℕ} {f : (ι → ℂ) × ℂ → ℂ} + {U : Set ((ι → ℂ) × ℂ)} (hU : IsOpen U) (h0 : 0 ∈ U) + (hf : DifferentiableOn ℂ f U) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (r : ι → ℝ) (R : ℝ) (u : (ι → ℂ) × ℂ → ℂ) (a : Fin d → (ι → ℂ) → ℂ), + (∀ i, 0 < r i) ∧ 0 < R ∧ polydisc 0 r ×ˢ ball 0 R ⊆ U ∧ + DifferentiableOn ℂ u (polydisc 0 r ×ˢ ball 0 R) ∧ + (∀ z ∈ polydisc 0 r ×ˢ ball 0 R, u z ≠ 0) ∧ + (∀ j, DifferentiableOn ℂ (a j) (polydisc 0 r)) ∧ + (∀ j, a j 0 = 0) ∧ + EqOn f (fun z => u z * weierstrassPolynomial a z) (polydisc 0 r ×ˢ ball 0 R) ∧ + ∀ v b, IsWeierstrassPreparationAt f v b → + u =ᶠ[𝓝 0] v ∧ ∀ j, a j =ᶠ[𝓝 0] b j := by + obtain ⟨u, a, H, hu⟩ := exists_isWeierstrassPreparationAt + ((hf.analyticOnNhd_of_finiteDimensional hU) _ h0) horder + have ha' : ∀ᶠ x in 𝓝 (0 : ι → ℂ), ∀ j, AnalyticAt ℂ (a j) x := + Filter.eventually_all.mpr (fun j => (H.analyticAt_coeff j).eventually_analyticAt) + have ha : ∀ᶠ z : (ι → ℂ) × ℂ in 𝓝 0, ∀ j, AnalyticAt ℂ (a j) z.1 := + by + have ht : Tendsto (Prod.fst : (ι → ℂ) × ℂ → (ι → ℂ)) (𝓝 0) (𝓝 0) := + continuous_fst.tendsto 0 + exact ht.eventually ha' + have hU' : ∀ᶠ z in 𝓝 (0 : (ι → ℂ) × ℂ), z ∈ U := hU.mem_nhds h0 + have hn := hU'.and (H.analyticAt_unit.eventually_analyticAt.and + ((H.analyticAt_unit.continuousAt.eventually_ne H.unit_ne_zero).and (ha.and H.eq))) + obtain ⟨ε, hε, hball⟩ := Metric.mem_nhds_iff.mp hn + have hP : polydisc (0 : ι → ℂ) (fun _ => ε) ×ˢ ball (0 : ℂ) ε = + ball (0 : (ι → ℂ) × ℂ) ε := by + rw [polydisc_const_eq_ball _ hε, ball_prod_same] + rfl + have hprop := fun z (hz : z ∈ polydisc (0 : ι → ℂ) (fun _ => ε) ×ˢ ball (0 : ℂ) ε) => + hball (hP ▸ hz) + refine ⟨fun _ => ε, ε, u, a, fun _ => hε, hε, fun z hz => (hprop z hz).1, + fun z hz => (hprop z hz).2.1.differentiableAt.differentiableWithinAt, + fun z hz => (hprop z hz).2.2.1, ?_, H.coeff_zero, + fun z hz => (hprop z hz).2.2.2.2, hu⟩ + intro j z hz + exact ((hprop (z, 0) ⟨hz, mem_ball_self hε⟩).2.2.2.1 j).differentiableAt.differentiableWithinAt + +/-- Preparation transports along a continuous linear equivalence of the parameter space. -/ +theorem IsWeierstrassPreparationAt.comp_equiv {F : Type*} [NormedAddCommGroup F] + [NormedSpace ℂ F] (φ : F ≃L[ℂ] E) {d : ℕ} {f u : E × ℂ → ℂ} {a : Fin d → E → ℂ} + (h : IsWeierstrassPreparationAt f u a) : + IsWeierstrassPreparationAt (fun z : F × ℂ => f (φ z.1, z.2)) + (fun z : F × ℂ => u (φ z.1, z.2)) (fun j x => a j (φ x)) := by + have hφ : AnalyticAt ℂ φ (0 : F) := φ.toContinuousLinearMap.analyticAt 0 + have hφmap : φ (0 : F) = 0 := φ.map_zero + have hpair : AnalyticAt ℂ (fun z : F × ℂ => (φ z.1, z.2)) (0 : F × ℂ) := + (hφ.comp_of_eq analyticAt_fst rfl).prod analyticAt_snd + have h0 : (fun z : F × ℂ => (φ z.1, z.2)) 0 = (0 : E × ℂ) := by simp [hφmap] + have ht : Tendsto (fun z : F × ℂ => (φ z.1, z.2)) (𝓝 0) (𝓝 (0 : E × ℂ)) := by + rw [← h0]; exact hpair.continuousAt.tendsto + refine ⟨h.analyticAt_unit.comp_of_eq hpair h0, + by change u (φ 0, (0 : ℂ)) ≠ 0; rw [hφmap]; exact h.unit_ne_zero, + fun j => (h.analyticAt_coeff j).comp_of_eq hφ hφmap, + fun j => by show a j (φ (0 : F)) = 0; rw [hφmap]; exact h.coeff_zero j, + (h.eq.comp_tendsto ht).mono fun z hz => by + simpa [weierstrassPolynomial, weierstrassRemainder] using hz⟩ + +/-- **Weierstrass preparation for analytic germs on any finite-dimensional parameter space.** +Obtained by transporting the coordinate version along a basis; no choice of coordinates +occurs in the statement. -/ +theorem exists_isWeierstrassPreparationAt_of_finiteDimensional [FiniteDimensional ℂ E] {d : ℕ} + {f : E × ℂ → ℂ} + (hf : AnalyticAt ℂ f 0) (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (u : E × ℂ → ℂ) (a : Fin d → E → ℂ), + IsWeierstrassPreparationAt f u a ∧ + ∀ v b, IsWeierstrassPreparationAt f v b → + u =ᶠ[𝓝 0] v ∧ ∀ j, a j =ᶠ[𝓝 0] b j := by + set e := (Module.finBasis ℂ E).equivFunL with he_def + set g : (Fin (Module.finrank ℂ E) → ℂ) × ℂ → ℂ := fun z => f (e.symm z.1, z.2) with hg_def + have hg0 : (fun w : ℂ => g (0, w)) = fun w : ℂ => f (0, w) := by funext w; simp [hg_def] + have hgan : AnalyticAt ℂ g 0 := + hf.comp_of_eq (((e.symm.toContinuousLinearMap.analyticAt 0).comp_of_eq analyticAt_fst rfl).prod + analyticAt_snd) (by simp) + have hgorder : analyticOrderAt (fun w : ℂ => g (0, w)) 0 = d := by rw [hg0]; exact horder + obtain ⟨v, b, Hg, huniqg⟩ := exists_isWeierstrassPreparationAt hgan hgorder + have hf_eq : f = fun z : E × ℂ => g (e z.1, z.2) := by funext z; simp [hg_def] + have Hf : IsWeierstrassPreparationAt f (fun z : E × ℂ => v (e z.1, z.2)) + (fun j x => b j (e x)) := by + rw [hf_eq]; exact Hg.comp_equiv e + refine ⟨_, _, Hf, fun v' a' Hv' => ?_⟩ + have Hv'' : IsWeierstrassPreparationAt g (fun z => v' (e.symm z.1, z.2)) + (fun j x => a' j (e.symm x)) := by + rw [hg_def]; exact Hv'.comp_equiv e.symm + obtain ⟨huv, hab⟩ := huniqg _ _ Hv'' + have ht : Tendsto (fun z : E × ℂ => (e z.1, z.2)) (𝓝 0) + (𝓝 (0 : (Fin (Module.finrank ℂ E) → ℂ) × ℂ)) := by + have h0 : (fun z : E × ℂ => (e z.1, z.2)) 0 = (0 : (Fin (Module.finrank ℂ E) → ℂ) × ℂ) := by + simp + rw [← h0] + exact (((e.toContinuousLinearMap.analyticAt 0).comp_of_eq analyticAt_fst rfl).prod + analyticAt_snd).continuousAt.tendsto + refine ⟨(huv.comp_tendsto ht).mono fun z hz => ?_, fun j => ?_⟩ + · simpa using hz + · have htj : Tendsto e (𝓝 (0 : E)) (𝓝 (0 : Fin (Module.finrank ℂ E) → ℂ)) := by + simpa using (e.toContinuousLinearMap.analyticAt 0).continuousAt.tendsto + exact ((hab j).comp_tendsto htj).mono fun x hx => by simpa using hx + +/-- Preparation gives a factorization in the analytic germ ring with an invertible factor. -/ +theorem IsWeierstrassPreparationAt.germ_factorization {d : ℕ} {f u : E × ℂ → ℂ} + {a : Fin d → E → ℂ} (h : IsWeierstrassPreparationAt f u a) + (hf : AnalyticAt ℂ f 0) : + IsUnit (AnalyticGerm.ofAnalyticAt u h.analyticAt_unit) ∧ + AnalyticGerm.ofAnalyticAt f hf = AnalyticGerm.ofAnalyticAt u h.analyticAt_unit * + AnalyticGerm.ofAnalyticAt (weierstrassPolynomial a) + (analyticAt_weierstrassPolynomial h.analyticAt_coeff) := by + refine ⟨(AnalyticGerm.isUnit_iff _).mpr h.unit_ne_zero, ?_⟩ + apply Subtype.ext + exact Germ.coe_eq.mpr h.eq + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets.lean new file mode 100644 index 0000000000..1fa74bd6ff --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets.lean @@ -0,0 +1,71 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.IsolatedSingularity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Basic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Local + +/-! +# Zero sets in several complex variables + +The identity-principle consequences in `ZeroSets.Basic` and the local zero-set comparison +theorems in `ZeroSets.Local` are re-exported here. Isolated scalar zeros are excluded by the +proved puncture-removal theorem applied to the reciprocal. + +Reference: [Jakóbczak–Jarnicki][JakobczakJarnicki2021] (2021), Corollary 2.1.3. + +## Main results + +* `frequently_zero_punctured_of_analyticAt`: A scalar holomorphic function in complex dimension at + least two cannot have an isolated zero. + +## References + +* [P. Jakóbczak and M. Jarnicki, *Lectures on Holomorphic Functions of Several Complex + Variables*][JakobczakJarnicki2021] +-/ + +public section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- A scalar holomorphic function in complex dimension at least two cannot have an isolated zero. +See [Jakóbczak–Jarnicki][JakobczakJarnicki2021] Corollary 2.1.3. Applying Hartogs extension to +the reciprocal would contradict an isolated zero. The scalar target and dimension restriction +are essential: vector-valued maps and functions of one variable can have isolated zeros. -/ +theorem frequently_zero_punctured_of_analyticAt + [FiniteDimensional ℂ E] (hdim : 2 ≤ Module.finrank ℂ E) + {f : E → ℂ} {a : E} (hf : AnalyticAt ℂ f a) (ha : f a = 0) : + ∃ᶠ z in 𝓝[≠] a, f z = 0 := by + let : Nontrivial E := Module.nontrivial_of_finrank_pos (by omega : 0 < Module.finrank ℂ E) + by_contra hn + have hne : ∀ᶠ z in 𝓝[≠] a, f z ≠ 0 := not_frequently.mp hn + have hn' : ∀ᶠ z in 𝓝 a, z ≠ a → f z ≠ 0 := by + simpa only [mem_compl_iff, mem_singleton_iff] using eventually_nhdsWithin_iff.mp hne + obtain ⟨r, hr, hball⟩ := Metric.mem_nhds_iff.mp (hf.eventually_analyticAt.and hn') + have hfi : AnalyticOnNhd ℂ (fun z => (f z)⁻¹) (ball a r \ {a}) := + fun z hz => ((hball hz.1).1).inv ((hball hz.1).2 hz.2) + obtain ⟨g, hg, he⟩ := exists_analyticOnNhd_extension_diff_singleton hdim isOpen_ball + (mem_ball_self hr) hfi + have heq : (fun z => f z * g z) =ᶠ[𝓝[≠] a] (fun _ => (1 : ℂ)) := by + filter_upwards [nhdsWithin_le_nhds (ball_mem_nhds a hr), eventually_mem_nhdsWithin] with z hz + hza + rw [he ⟨hz, hza⟩] + exact mul_inv_cancel₀ ((hball hz).2 hza) + have hlim := (hf.continuousAt.mul (hg a (mem_ball_self hr)).continuousAt).tendsto.mono_left + (nhdsWithin_le_nhds (s := {a}ᶜ)) + have hval : f a * g a = 1 := tendsto_nhds_unique hlim (Tendsto.congr' heq.symm tendsto_const_nhds) + simp [ha] at hval + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Basic.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Basic.lean new file mode 100644 index 0000000000..663cbc6a7b --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Basic.lean @@ -0,0 +1,106 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Uniqueness +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.Analysis.Normed.Module.Connected + +/-! +# Identity-principle consequences for zero sets + +The nonvanishing locus of a nonzero analytic function is dense in its connected open domain, +which gives uniqueness of continuous extensions across its zero set. A product of two scalar +analytic functions vanishes near a point only if one factor does. These results support +removability and analytic germs without depending on Hartogs extension or local-ring theory. + +References: [Scheidemann][Scheidemann2005] (2005), Sections 4.1--4.2; +[Korevaar–Wiegerinck][KorevaarWiegerinck2017] (2017), Sections 4.6--4.7. The density and +extension-uniqueness results allow normed vector targets. + +## Main results + +`subset_closure_nonzero_of_analyticOnNhd` is density of the nonvanishing locus. +`eqOn_of_eqOn_nonzero_of_analyticOnNhd` is uniqueness of continuous extensions across a zero +set. `eventuallyEq_zero_or_eventuallyEq_zero_of_mul` is the product rule for vanishing germs. + +## References + +* [J. Korevaar and J. Wiegerinck, *Several Complex Variables*][KorevaarWiegerinck2017] +* [V. Scheidemann, *Introduction to Complex Analysis in Several Variables*][Scheidemann2005] +-/ + +public section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] + +/-- A nonzero analytic function on a connected open set is nonzero arbitrarily near each point of +that set. No completeness or finite-dimensionality assumption is needed. -/ +theorem exists_ne_zero_mem_ball_of_analyticOnNhd {U : Set E} {f : E → F} + (hU : IsOpen U) (hconn : IsPreconnected U) (hf : AnalyticOnNhd ℂ f U) + (hne : ∃ z ∈ U, f z ≠ 0) {x : E} (hx : x ∈ U) {r : ℝ} (hr : 0 < r) : + ∃ y ∈ U, y ∈ ball x r ∧ f y ≠ 0 := by + by_contra! h + have hzero : f =ᶠ[𝓝 x] 0 := by + filter_upwards [hU.mem_nhds hx, ball_mem_nhds x hr] with y hy hyr + exact h y hy hyr + obtain ⟨z, hz, hnz⟩ := hne + exact hnz (hf.eqOn_zero_of_preconnected_of_eventuallyEq_zero hconn hx hzero hz) + +/-- The nonvanishing locus of a nonzero analytic function is dense in its connected open domain. The +closure is taken in the ambient normed space. -/ +theorem subset_closure_nonzero_of_analyticOnNhd {U : Set E} {f : E → F} + (hU : IsOpen U) (hconn : IsPreconnected U) (hf : AnalyticOnNhd ℂ f U) + (hne : ∃ z ∈ U, f z ≠ 0) : U ⊆ closure {z | z ∈ U ∧ f z ≠ 0} := by + intro x hx + rw [Metric.mem_closure_iff] + intro r hr + obtain ⟨y, hy, hyr, hny⟩ := + exists_ne_zero_mem_ball_of_analyticOnNhd hU hconn hf hne hx hr + exact ⟨y, ⟨hy, hny⟩, by simpa [dist_comm] using hyr⟩ + +/-- Continuous extensions across the zero set of a nonzero analytic function are unique on the +domain. Their values outside the domain are unrestricted. -/ +theorem eqOn_of_eqOn_nonzero_of_analyticOnNhd + {G : Type*} [TopologicalSpace G] [T2Space G] + {U : Set E} {f : E → F} {g h : E → G} + (hU : IsOpen U) (hconn : IsPreconnected U) (hf : AnalyticOnNhd ℂ f U) + (hne : ∃ z ∈ U, f z ≠ 0) (hg : ContinuousOn g U) (hh : ContinuousOn h U) + (heq : EqOn g h {z | z ∈ U ∧ f z ≠ 0}) : EqOn g h U := + heq.of_subset_closure hg hh (fun _ hz => hz.1) + (subset_closure_nonzero_of_analyticOnNhd hU hconn hf hne) + +/-- If a product of two analytic functions vanishes near a point, one factor vanishes near that +point. This is the identity principle on a sufficiently small connected ball. -/ +theorem eventuallyEq_zero_or_eventuallyEq_zero_of_mul {𝕜 E : Type*} [RCLike 𝕜] + [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {f g : E → 𝕜} {x : E} (hf : AnalyticAt 𝕜 f x) (hg : AnalyticAt 𝕜 g x) + (hfg : (fun y => f y * g y) =ᶠ[𝓝 x] 0) : + f =ᶠ[𝓝 x] 0 ∨ g =ᶠ[𝓝 x] 0 := by + let : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 E + obtain ⟨r, hr, hball⟩ := Metric.mem_nhds_iff.mp + (hf.eventually_analyticAt.and (hg.eventually_analyticAt.and hfg)) + by_cases hzero : ∀ y ∈ ball x r, f y = 0 + · exact Or.inl (Filter.mem_of_superset (ball_mem_nhds x hr) hzero) + · push Not at hzero + obtain ⟨y, hy, hfy⟩ := hzero + have hgzero : g =ᶠ[𝓝 y] 0 := by + filter_upwards [isOpen_ball.mem_nhds hy, + (hball hy).1.continuousAt.eventually_ne hfy] with z hz hfz + exact (mul_eq_zero.mp (hball hz).2.2).resolve_left hfz + have hgon : AnalyticOnNhd 𝕜 g (ball x r) := fun z hz => (hball hz).2.1 + exact Or.inr (Filter.mem_of_superset (ball_mem_nhds x hr) + (hgon.eqOn_zero_of_preconnected_of_eventuallyEq_zero isPreconnected_ball hy hgzero)) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Connected.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Connected.lean new file mode 100644 index 0000000000..9ca9f97d42 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Connected.lean @@ -0,0 +1,104 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.RemovableSingularity.ExceptionalSet + +/-! +# Connectedness of the nonvanishing locus + +Removing a proper scalar holomorphic zero set from a connected open subset of a +finite-dimensional complex space leaves a connected set. Extend the bounded locally constant +separator of a hypothetical separation and apply the identity principle. More generally, the +same holds for relatively closed sets locally contained in proper analytic zero sets, by the +locally bounded Riemann extension theorem. This consequence is kept above removability to +preserve the dependency order. + +## Main results + +`isConnected_nonzero_of_analyticOnNhd` is connectedness of the nonvanishing locus of a nonzero +scalar holomorphic function. `isConnected_sdiff_of_locallyContainedInAnalyticZeroSet` is the +corresponding statement for a relatively closed thin exceptional set. +-/ + +public section + +open Filter Metric Set +open scoped Topology + +namespace SeveralComplexVariables + +/-- A relatively closed set locally contained in proper analytic zero sets cannot disconnect a +connected open domain. No positive-dimension hypothesis is needed. -/ +theorem isConnected_sdiff_of_locallyContainedInAnalyticZeroSet + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U S : Set E} (hc : IsConnected U) + (hUS : IsOpen (U \ S)) (hS : LocallyContainedInAnalyticZeroSet U S) : + IsConnected (U \ S) := by + classical + let V := U \ S + have hVo : IsOpen V := hUS + refine ⟨?_, ?_⟩ + · by_contra h + have he : U \ S = ∅ := Set.not_nonempty_iff_eq_empty.mp h + obtain ⟨a, ha⟩ := hc.nonempty + have := hS.subset_closure ha + simp [he] at this + change IsPreconnected V + intro s t hs ht hcover hVs hVt + by_contra hmeet + have hdis : ∀ z ∈ V, z ∈ s → z ∈ t → False := by + intro z hz hzs hzt + exact hmeet ⟨z, hz, hzs, hzt⟩ + let f : E → ℂ := fun z => if z ∈ s then 1 else 0 + have hfs : ∀ z ∈ s, f =ᶠ[𝓝 z] (fun _ => (1 : ℂ)) := by + intro z hz + filter_upwards [hs.mem_nhds hz] with y hy + simp [f, hy] + have hft : ∀ z ∈ V ∩ t, f =ᶠ[𝓝 z] (fun _ => (0 : ℂ)) := by + intro z hz + filter_upwards [(hVo.inter ht).mem_nhds hz] with y hy + simp [f, show y ∉ s from fun hys => hdis y hy.1 hys hy.2] + have hf : AnalyticOnNhd ℂ f V := by + intro z hz + rcases hcover hz with hzs | hzt + · exact (analyticAt_congr (hfs z hzs)).mpr analyticAt_const + · exact (analyticAt_congr (hft z ⟨hz, hzt⟩)).mpr analyticAt_const + have hb : ∀ a ∈ U, ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, + ∀ z ∈ ball a r ∩ V, ‖f z‖ ≤ C := by + intro a _ + refine ⟨1, zero_lt_one, 1, fun z _ => ?_⟩ + dsimp [f] + split_ifs <;> simp + obtain ⟨F, hF, hEq⟩ := exists_analyticOnNhd_extension_across_locallyContainedZeroSet hUS hS hf hb + obtain ⟨a, ha, has⟩ := hVs + have hFone : F =ᶠ[𝓝 a] (fun _ => (1 : ℂ)) := by + filter_upwards [hVo.mem_nhds ha, hfs a has] with z hz hfz + exact (hEq hz).trans hfz + have hconst := hF.eqOn_of_preconnected_of_eventuallyEq analyticOnNhd_const hc.isPreconnected + ha.1 hFone + obtain ⟨b, hbV, hbt⟩ := hVt + have hbzero : F b = 0 := (hEq hbV).trans ((hft b ⟨hbV, hbt⟩).self_of_nhds) + have hbone : F b = 1 := hconst hbV.1 + exact zero_ne_one (hbzero.symm.trans hbone) + +/-- A proper holomorphic zero set cannot disconnect a connected open domain. No positive-dimension +hypothesis is needed. -/ +theorem isConnected_nonzero_of_analyticOnNhd + {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + {U : Set E} (hU : IsOpen U) (hc : IsPreconnected U) + {g : E → ℂ} (hg : AnalyticOnNhd ℂ g U) (hne : ∃ z ∈ U, g z ≠ 0) : + IsConnected (U \ g ⁻¹' {0}) := by + obtain ⟨z, hz, hgz⟩ := hne + apply isConnected_sdiff_of_locallyContainedInAnalyticZeroSet ⟨⟨z, hz⟩, hc⟩ + (hg.continuousOn.isOpen_inter_preimage hU isClosed_singleton.isOpen_compl) + apply locallyContainedInAnalyticZeroSet_zeroSet hU hg + intro a ha hzero + exact hgz (hg.eqOn_zero_of_preconnected_of_eventuallyEq_zero hc ha hzero hz) + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Local.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Local.lean new file mode 100644 index 0000000000..c7c5fa6dd0 --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Local.lean @@ -0,0 +1,132 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Analytic.Uniqueness +public import Mathlib.Analysis.Calculus.FDeriv.Analytic +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.Analyticity +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables.ZeroSets.Persistence + +/-! +# Local structure of scalar zero sets + +Nontrivial analytic germs have a nonzero derivative of finite order. Minimizing this order along +a zero set supplies an analytic function with nonzero derivative that vanishes on that set. +Persistence of zeros supplies the converse inclusion after straightening this auxiliary +function. + +## Main results + +`AnalyticAt.eventuallyEq_zero_of_iteratedFDeriv_eq_zero` is vanishing of a germ whose iterated +derivatives all vanish. `exists_analytic_zeroSet_superset_fderiv_ne_zero` produces an analytic +function with nonzero derivative vanishing on a given zero set. +`eventually_zeroSet_eq_linear_zeroSet` is the local graph description after straightening. +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] + +/-- An analytic germ whose iterated derivatives all vanish is the zero germ. -/ +theorem _root_.AnalyticAt.eventuallyEq_zero_of_iteratedFDeriv_eq_zero {f : E → ℂ} {a : E} + (hf : AnalyticAt ℂ f a) (hzero : ∀ n, iteratedFDeriv ℂ n f a = 0) : + f =ᶠ[𝓝 a] 0 := by + obtain ⟨p, r, hp⟩ := hf + filter_upwards [eball_mem_nhds a hp.r_pos] with y hy + have hs := hp.hasSum_iteratedFDeriv (y := y - a) (by + simpa only [mem_eball, edist_zero_right, edist_eq_enorm_sub, sub_zero] using hy) + simpa [hzero] using hs.tsum_eq.symm + +/-- A nonempty proper scalar zero set is contained in the zero set of an analytic function whose +derivative is nonzero at some point of the original zero set. Choose a derivative of minimal +order that does not vanish everywhere on the set. -/ +theorem exists_analytic_zeroSet_superset_fderiv_ne_zero [FiniteDimensional ℂ E] + {U : Set E} (hU : IsOpen U) (hc : IsPreconnected U) {f : E → ℂ} + (hf : AnalyticOnNhd ℂ f U) (hne : ∃ b ∈ U, f b ≠ 0) (hz : ∃ a ∈ U, f a = 0) : + ∃ (a : E) (g : E → ℂ), a ∈ U ∧ f a = 0 ∧ AnalyticOnNhd ℂ g U ∧ + (∀ z ∈ U, f z = 0 → g z = 0) ∧ fderiv ℂ g a ≠ 0 := by + classical + have hex : ∃ n : ℕ, ∃ a ∈ U, f a = 0 ∧ iteratedFDeriv ℂ n f a ≠ 0 := by + by_contra! h + obtain ⟨a, ha, hfa⟩ := hz + have he := (hf a ha).eventuallyEq_zero_of_iteratedFDeriv_eq_zero (fun n => h n a ha hfa) + obtain ⟨b, hb, hfb⟩ := hne + exact hfb (hf.eqOn_zero_of_preconnected_of_eventuallyEq_zero hc ha he hb) + obtain ⟨a, ha, hfa, hda⟩ := Nat.find_spec hex + have hmin : ∀ n < Nat.find hex, ∀ z ∈ U, f z = 0 → iteratedFDeriv ℂ n f z = 0 := by + intro n hn z hz hfz + by_contra hd + exact Nat.find_min hex hn ⟨z, hz, hfz, hd⟩ + generalize hn : Nat.find hex = n at hda hmin + cases n with + | zero => + exact (hda (by ext v; simpa only [iteratedFDeriv_zero_apply, + zero_apply] using hfa)).elim + | succ n => + obtain ⟨v, hv⟩ : ∃ v, iteratedFDeriv ℂ (n + 1) f a v ≠ 0 := by + contrapose! hda + ext v + exact hda v + let g : E → ℂ := fun z => iteratedFDeriv ℂ n f z (Fin.tail v) + have hg : AnalyticOnNhd ℂ g U := + ((hf.iteratedFDeriv n).differentiableOn.continuousMultilinear_apply_const + (Fin.tail v)).analyticOnNhd_of_finiteDimensional hU + refine ⟨a, g, ha, hfa, hg, ?_, ?_⟩ + · intro z hz hfz + simp [g, hmin n (Nat.lt_succ_self n) z hz hfz] + · intro hd + apply hv + rw [((hf.iteratedFDeriv n) a ha).differentiableAt.iteratedFDeriv_succ_apply_left'] + change fderiv ℂ g a (v 0) = 0 + simp [hd] + +/-- If the zeros of an analytic function lie in a hyperplane and include a point of that hyperplane, +then the two zero sets agree near that point. -/ +theorem eventually_zeroSet_eq_linear_zeroSet {V : Set E} (hV : IsOpen V) + {f : E → ℂ} (hf : AnalyticOnNhd ℂ f V) {L : E →L[ℂ] ℂ} + (hL : Function.Surjective L) {a : E} (ha : a ∈ V) (hfa : f a = 0) (hLa : L a = 0) + (hsub : ∀ z ∈ V, f z = 0 → L z = 0) : + ∀ᶠ z in 𝓝 a, f z = 0 ↔ L z = 0 := by + obtain ⟨v, hv⟩ := hL 1 + let S : E × ℂ → E := fun p => p.1 + p.2 • v + have hS : Continuous S := continuous_fst.add (continuous_snd.smul continuous_const) + let W := S ⁻¹' V + have hW : IsOpen W := hV.preimage hS + have hline : Continuous (fun t : ℂ => a + t • v) := + continuous_const.add (continuous_id.smul continuous_const) + have h0 : (0 : ℂ) ∈ (fun t : ℂ => a + t • v) ⁻¹' V := by simpa using ha + obtain ⟨ε, hε, hεV⟩ := Metric.mem_nhds_iff.mp ((hV.preimage hline).mem_nhds h0) + let r := ε / 2 + have hr : 0 < r := half_pos hε + have hdisc : ∀ t ∈ closedBall (0 : ℂ) r, (a, t) ∈ W := by + intro t ht + exact hεV ((closedBall_subset_ball (half_lt_self hε)) ht) + have hboundary : ∀ t ∈ sphere (0 : ℂ) r, (f ∘ S) (a, t) ≠ 0 := by + intro t ht hft + have ht0 : t = 0 := by + simpa [S, hLa, hv] using hsub (S (a, t)) (hdisc t (sphere_subset_closedBall ht)) hft + subst t + have : r = 0 := by simpa using ht.symm + exact hr.ne' this + have hroots := eventually_exists_zero_in_fiber hW + (hf.continuousOn.comp hS.continuousOn (mapsTo_preimage _ _)) + (fun p hp => ((hf (S p) hp).differentiableAt.comp p.2 + ((differentiableAt_const p.1).add (differentiableAt_id.smul_const v)))) + hr hdisc (by simpa [S] using hfa) hboundary + filter_upwards [hV.eventually_mem ha, hroots] with z hz hroot + refine ⟨hsub z hz, fun hLz => ?_⟩ + obtain ⟨t, _, hzt, hft⟩ := hroot + have ht0 : t = 0 := by simpa [S, hLz, hv] using hsub (S (z, t)) hzt hft + simpa [S, ht0] using hft + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Persistence.lean b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Persistence.lean new file mode 100644 index 0000000000..b1d1fb0cfe --- /dev/null +++ b/LeanPool/SeveralComplexVariables/SeveralComplexVariables/ZeroSets/Persistence.lean @@ -0,0 +1,98 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import Mathlib.Analysis.Complex.AbsMax +public import Mathlib.Topology.Order.Compact + +/-! +# Persistence of zeros in holomorphic families + +A zero inside a disc persists under small continuous changes of a holomorphic function, provided +the original function has no zeros on the boundary. The proof uses the maximum modulus principle +for the reciprocal of a hypothetically nonvanishing perturbation; no root counting is required. + +## Main results + +`exists_zero_of_norm_lt_boundary` persists a zero inside a disc under a small perturbation with +no boundary zeros. `eventually_exists_zero_in_fiber` is persistence of zeros in a holomorphic +family. +-/ + +public noncomputable section + +open Set Filter Metric +open scoped Topology + +namespace SeveralComplexVariables + +/-- A holomorphic function whose value at the center is smaller in norm than all its boundary values +has a zero in the disc. -/ +theorem exists_zero_of_norm_lt_boundary {f : ℂ → ℂ} {r : ℝ} (hr : 0 < r) + (hf : DifferentiableOn ℂ f (closedBall 0 r)) + (hlt : ∀ z ∈ sphere 0 r, ‖f 0‖ < ‖f z‖) : + ∃ z ∈ ball 0 r, f z = 0 := by + by_contra! hn + have hne : ∀ z ∈ closedBall (0 : ℂ) r, f z ≠ 0 := by + intro z hz + rcases lt_or_eq_of_le (mem_closedBall.mp hz) with hz | hz + · exact hn z hz + · exact norm_pos_iff.mp ((norm_nonneg _).trans_lt (hlt z hz)) + have hi : DiffContOnCl ℂ (fun z => (f z)⁻¹) (ball 0 r) := by + refine ⟨(hf.inv hne).mono ball_subset_closedBall, ?_⟩ + rw [closure_ball (0 : ℂ) hr.ne'] + exact (hf.continuousOn.inv₀ hne) + obtain ⟨z, hz, hmax⟩ := Complex.exists_mem_frontier_isMaxOn_norm + isBounded_ball (nonempty_ball.mpr hr) hi + rw [frontier_ball (0 : ℂ) hr.ne'] at hz + have hle := hmax (subset_closure (mem_ball_self hr)) + have hpos : 0 < ‖f 0‖ := norm_pos_iff.mpr (hne 0 (mem_closedBall_self hr.le)) + have hstrict := (inv_lt_inv₀ ((hpos.le).trans_lt (hlt z hz)) hpos).2 (hlt z hz) + exact (not_le_of_gt hstrict) (by simpa [Function.comp_def, norm_inv] using hle) + +/-- A zero of a continuously varying holomorphic function persists in nearby fibers if a closed disc +in the initial fiber has no boundary zeros. The parameter space only needs a topology. -/ +theorem eventually_exists_zero_in_fiber {X : Type*} [TopologicalSpace X] + {W : Set (X × ℂ)} (hW : IsOpen W) {f : X × ℂ → ℂ} + (hf : ContinuousOn f W) + (hd : ∀ p ∈ W, DifferentiableAt ℂ (fun z => f (p.1, z)) p.2) + {a : X} {r : ℝ} (hr : 0 < r) + (hdisc : ∀ z ∈ closedBall (0 : ℂ) r, (a, z) ∈ W) + (hzero : f (a, 0) = 0) (hboundary : ∀ z ∈ sphere (0 : ℂ) r, f (a, z) ≠ 0) : + ∀ᶠ x in 𝓝 a, ∃ z ∈ ball (0 : ℂ) r, (x, z) ∈ W ∧ f (x, z) = 0 := by + have hcont (z : ℂ) (hz : z ∈ closedBall (0 : ℂ) r) : ContinuousAt f (a, z) := + hf.continuousAt (hW.mem_nhds (hdisc z hz)) + have hscont : ContinuousOn (fun z => ‖f (a, z)‖) (sphere (0 : ℂ) r) := by + intro z hz + exact ((hcont z (sphere_subset_closedBall hz)).comp + (continuousAt_const.prodMk continuousAt_id)).norm.continuousWithinAt + obtain ⟨b, hb, hmin⟩ := (isCompact_sphere (0 : ℂ) r).exists_isMinOn + ⟨(r : ℂ), by simp [Complex.norm_real, abs_of_pos hr]⟩ hscont + let c := ‖f (a, b)‖ / 2 + have hc : 0 < c := half_pos (norm_pos_iff.mpr (hboundary b hb)) + have hsmall : ∀ᶠ x in 𝓝 a, ‖f (x, 0)‖ < c := by + have hs : ContinuousAt (fun x : X => (x, (0 : ℂ))) a := + continuousAt_id.prodMk continuousAt_const + apply ((hcont 0 (mem_closedBall_self hr.le)).comp + (f := fun x : X => (x, (0 : ℂ))) hs).norm.eventually_lt continuousAt_const + simpa [hzero] using hc + have hlarge : ∀ᶠ x in 𝓝 a, ∀ z ∈ sphere (0 : ℂ) r, c < ‖f (x, z)‖ := by + apply (isCompact_sphere (0 : ℂ) r).eventually_forall_of_forall_eventually + intro z hz + apply continuousAt_const.eventually_lt (hcont z (sphere_subset_closedBall hz)).norm + exact (half_lt_self (norm_pos_iff.mpr (hboundary b hb))).trans_le (hmin hz) + have hdomain : ∀ᶠ x in 𝓝 a, ∀ z ∈ closedBall (0 : ℂ) r, (x, z) ∈ W := by + apply (isCompact_closedBall (0 : ℂ) r).eventually_forall_of_forall_eventually + exact fun z hz => hW.eventually_mem (hdisc z hz) + filter_upwards [hsmall, hlarge, hdomain] with x hxsmall hxlarge hxdomain + obtain ⟨z, hz, hzero⟩ := exists_zero_of_norm_lt_boundary (f := fun z => f (x, z)) hr + (fun z hz => (hd (x, z) (hxdomain z hz)).differentiableWithinAt) + (fun z hz => hxsmall.trans (hxlarge z hz)) + exact ⟨z, hz, hxdomain z (ball_subset_closedBall hz), hzero⟩ + +end SeveralComplexVariables + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/SeveralComplexVariables/Solution.lean b/LeanPool/SeveralComplexVariables/Solution.lean new file mode 100644 index 0000000000..4a2c1095fa --- /dev/null +++ b/LeanPool/SeveralComplexVariables/Solution.lean @@ -0,0 +1,966 @@ +/- +Copyright (c) 2026 Bastiaan J Braams. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bastiaan J Braams +-/ +module + +public import LeanPool.SeveralComplexVariables.SeveralComplexVariables + +/-! +# Several complex variables: principal statements (`Solution.lean`) + +This file states the principal results of the `SeveralComplexVariables` library in terms of Mathlib +alone. Its numbering follows the [upstream theorem catalogue][scvCatalogue] at the imported +revision: the number in each docstring is the item of that catalogue, and A–K are its sections. +The subject is classical function theory on open subsets of finite-dimensional complex normed +spaces `E`, in particular of `ℂ^ι = ι → ℂ` for a finite index type `ι`, with values in a complex +Banach space `F`. + +## Conventions + +* *Holomorphic* is `DifferentiableOn ℂ f U` and *analytic* is `AnalyticOnNhd ℂ f U`. On open subsets + of `E` the two agree (item 3), and the statements use whichever the library proves directly. +* `ι → ℂ` carries the supremum norm, so that `Metric.ball` is a polydisc with equal radii; a + polydisc with separate radii is `Set.pi univ fun i => Metric.ball (c i) (r i)`. Dimension zero and + empty index types are included unless a hypothesis excludes them. +* Domains are not assumed connected or nonempty; such hypotheses are stated where they are needed. +* Hulls are defined through all real upper bounds rather than suprema. Subharmonic and + plurisubharmonic functions are real valued, so the value `-∞` is not admitted. +* The definitions below restate those of the library and are kept few. Where a notion is used + once, it is written out in the statement instead. + +## Scope + +Of the 65 items of the catalogue, all are represented except items 42 and 43 (factors of +distinguished polynomials, and the comparison of polynomials over the germ ring with germs), which +are algebraic steps towards items 44 and 45. An item with several assertions is represented by its +principal assertion. The sources are the texts of Boas, Fritzsche–Grauert, Hörmander, +Jakóbczak–Jarnicki, Korevaar–Wiegerinck, Range, Scheidemann, Shabat and Suwa listed in +the [upstream bibliography][scvBibliography]; none of the results is new. The proofs use only +the axioms `propext`, `Quot.sound` and `Classical.choice`. + +## Related formalizations + +The development builds on Mathlib. Lean Pool already contains Bochao Kong's analytic Weierstrass +preparation theorem with germ uniqueness as +`ClassicalComplexWPT.classicalComplexWeierstrassPreparation`, and coordinate-origin germ +Noetherianity as `LocalComplexGeometry.holomorphicGerm_isNoetherian`. These overlap items 41 and +44 here. At coordinate origins, both developments model analytic germs as the subring of +Mathlib's `Filter.Germ` consisting of germs with an analytic representative. + +This import retains its independent analytic division and preparation arguments, including +quotient estimates, and transports the local statements to arbitrary finite-dimensional complex +normed spaces and base points. Its further results include germ unique factorization and relative +primality, Hartogs extension, Cartan–Thullen equivalences, and Bochner's tube theorem. These +additional results supply the project's broader scope. The local analytic Nullstellensatz in +`LeanPool.LocalComplexGeometry` is not treated here. + +[scvCatalogue]: https://github.com/bjbraams/lean-scv/blob/caef1ae776ff79933718312357980d46628d3702/SCVMainTheorems.md +[scvBibliography]: https://github.com/bjbraams/lean-scv/blob/caef1ae776ff79933718312357980d46628d3702/formalization.yaml +-/ + +@[expose] public section + + +open Complex Filter Function MeasureTheory Metric Set +open scoped Real Topology + +namespace SCV + +variable {E F : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [FiniteDimensional ℂ E] + [NormedAddCommGroup F] [NormedSpace ℂ F] [CompleteSpace F] + {ι : Type*} [Fintype ι] + +/-! ## A. Local analysis and differential calculus -/ + +/-- The derivative in the coordinate `i`, the other coordinates being fixed. -/ +noncomputable def partialDeriv [DecidableEq ι] (i : ι) (f : (ι → ℂ) → F) (z : ι → ℂ) : F := + deriv (fun w => f (update z i w)) (z i) + +/-- The iterated coordinate derivative along a list of coordinates; the leftmost acts last. -/ +noncomputable def iteratedPartialDeriv [DecidableEq ι] : List ι → ((ι → ℂ) → F) → (ι → ℂ) → F + | [], f => f + | i :: is, f => partialDeriv i (iteratedPartialDeriv is f) + +-- BEGIN SOLUTION ONLY +omit [CompleteSpace F] [Fintype ι] in +/-- The submission and library definitions of iterated coordinate derivatives agree. -/ +private theorem iteratedPartialDeriv_eq [DecidableEq ι] (is : List ι) (f : (ι → ℂ) → F) : + iteratedPartialDeriv is f = SeveralComplexVariables.iteratedPartialDeriv is f := by + induction is with + | nil => rfl + | cons i is ih => + simp only [iteratedPartialDeriv, SeveralComplexVariables.iteratedPartialDeriv, ih]; rfl +-- END SOLUTION ONLY + +/-- **1. Cauchy's integral formula on a polydisc**, for a function continuous on the closed polydisc +and analytic in each variable separately. -/ +theorem cauchy_formula_polydisc {n : ℕ} {f : (Fin n → ℂ) → F} {c w : Fin n → ℂ} {R : Fin n → ℝ} + (hR : ∀ i, 0 < R i) (hw : ∀ i, ‖w i - c i‖ < R i) + (hfc : ContinuousOn f (Set.pi univ fun i => closedBall (c i) (R i))) + (hfa : ∀ z ∈ Set.pi univ fun i => closedBall (c i) (R i), ∀ i, + AnalyticAt ℂ (fun x => f (update z i x)) (z i)) : + ((2 * π * I : ℂ) ^ n)⁻¹ • torusIntegral (fun z => (∏ i, (z i - w i)⁻¹) • f z) c R = f w := by + exact SeveralComplexVariables.two_pi_I_pow_inv_smul_torusIntegral_prod_sub_inv_smul hR hw hfc hfa + +/-- **2. Osgood's lemma**: a continuous, separately analytic function is jointly analytic. -/ +theorem osgood [DecidableEq ι] {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} (hU : IsOpen U) + (hfc : ContinuousOn f U) + (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + AnalyticOnNhd ℂ f U := by + exact SeveralComplexVariables.analyticOnNhd_pi_of_analyticOnNhd_update hU hfc hf + +/-- **3. Holomorphic is analytic** on open subsets of a finite-dimensional space, for Banach-valued +maps. -/ +theorem differentiableOn_iff_analyticOnNhd {U : Set E} {f : E → F} (hU : IsOpen U) : + DifferentiableOn ℂ f U ↔ AnalyticOnNhd ℂ f U := by + exact differentiableOn_iff_analyticOnNhd_of_finiteDimensional hU + +/-- **4. Cauchy–Riemann equations**: holomorphy is real differentiability together with the +coordinate Cauchy–Riemann equations. -/ +theorem analyticOnNhd_iff_cauchyRiemann [DecidableEq ι] {U : Set (ι → ℂ)} (hU : IsOpen U) + {f : (ι → ℂ) → F} : + AnalyticOnNhd ℂ f U ↔ (∀ z ∈ U, DifferentiableAt ℝ f z) ∧ + ∀ z ∈ U, ∀ i, fderiv ℝ f z (Pi.single i I) = I • fderiv ℝ f z (Pi.single i 1) := by + exact SeveralComplexVariables.analyticOnNhd_iff_differentiableAt_real_cauchyRiemann hU + +/-- **6. Identity theorem**: holomorphic maps on a connected open set that agree on a nonempty open +subset agree everywhere. -/ +theorem identity_theorem {U V : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) {f g : E → F} + (hf : DifferentiableOn ℂ f U) (hg : DifferentiableOn ℂ g U) (hV : IsOpen V) (hne : V.Nonempty) + (hVU : V ⊆ U) (heq : EqOn f g V) : EqOn f g U := by + exact DifferentiableOn.eqOn_of_preconnected_of_eqOn hU hconn hf hg hV hne hVU heq + +/-- **7. Maximum modulus principle**, for maps into a strictly convex Banach space, in particular +for scalar functions. -/ +theorem maximum_modulus [StrictConvexSpace ℝ F] {U : Set E} (hU : IsOpen U) + (hconn : IsPreconnected U) {f : E → F} (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) + (hmax : IsLocalMax (norm ∘ f) a) : EqOn f (const E (f a)) U := by + exact SeveralComplexVariables.eqOn_const_of_holomorphic_of_isLocalMax_norm hU hconn hf ha hmax + +/-- **9. Cauchy–Pompeiu identity** for a compactly supported `C¹` function, with +the antiholomorphic derivative `(∂φ/∂x + i ∂φ/∂y) / 2` written via the real derivative. -/ +theorem cauchy_pompeiu {φ : ℂ → F} (hφ : ContDiff ℝ 1 φ) (hsupp : HasCompactSupport φ) : + ∫ w, w⁻¹ • ((2 : ℂ)⁻¹ • (fderiv ℝ φ w 1 + I • fderiv ℝ φ w I)) = -((π : ℂ) • φ 0) := by + have h := SeveralComplexVariables.integral_inv_smul_dbarAlong_fderiv hφ hsupp + simpa [SeveralComplexVariables.dbarAlong] using h + +/-- The Taylor series at `c` of a function of `n` complex variables: the coefficient of `zᵐ` is +`∂ᵐ f (c) / m!`, the mixed derivative being taken coordinate by coordinate. -/ +noncomputable def taylorSeries {n : ℕ} (f : (Fin n → ℂ) → F) (c : Fin n → ℂ) : + MvPowerSeries (Fin n) F := + fun m => (∏ i, (m i).factorial : ℂ)⁻¹ • + iteratedPartialDeriv (List.ofFn fun i => List.replicate (m i) i).flatten f c + +-- BEGIN SOLUTION ONLY +omit [CompleteSpace F] in +/-- The submission Taylor series equals the library holomorphic Taylor series. -/ +private theorem taylorSeries_eq {n : ℕ} (f : (Fin n → ℂ) → F) (c : Fin n → ℂ) : + taylorSeries f c = SeveralComplexVariables.holomorphicTaylorSeries f c := by + funext m + simp only [taylorSeries, SeveralComplexVariables.holomorphicTaylorSeries, + SeveralComplexVariables.multiIndexDeriv, SeveralComplexVariables.multiIndexList, + iteratedPartialDeriv_eq] +-- END SOLUTION ONLY + +/-- **5. Cauchy estimates** for the Taylor coefficients of a function holomorphic near a closed +polydisc and bounded by `M` on it. -/ +theorem cauchy_estimates {n : ℕ} {U : Set (Fin n → ℂ)} (hU : IsOpen U) {f : (Fin n → ℂ) → F} + (hf : DifferentiableOn ℂ f U) {c : Fin n → ℂ} {R : Fin n → ℝ} (hR : ∀ i, 0 < R i) {M : ℝ} + (hsub : (Set.pi univ fun i => closedBall (c i) (R i)) ⊆ U) + (hM : ∀ z ∈ Set.pi univ fun i => closedBall (c i) (R i), ‖f z‖ ≤ M) (m : Fin n →₀ ℕ) : + ‖taylorSeries f c m‖ ≤ M * ∏ i, (R i)⁻¹ ^ m i := by + have hfa := hf.analyticOnNhd_of_finiteDimensional hU + have h := SeveralComplexVariables.norm_multiIndexDeriv_le (f := f) (c := c) hR + (hfa.continuousOn.mono hsub) (fun z hz i => hfa.analyticAt_update (hsub hz) i) hM m + have hpos : (0 : ℝ) < ∏ i, ((m i).factorial : ℝ) := + Finset.prod_pos fun i _ => Nat.cast_pos.mpr (Nat.factorial_pos _) + have hn : ‖(∏ i, (m i).factorial : ℂ)‖ = ∏ i, ((m i).factorial : ℝ) := by + simp [norm_prod] + rw [taylorSeries_eq, SeveralComplexVariables.holomorphicTaylorSeries, norm_smul, norm_inv, hn, + inv_mul_le_iff₀ hpos] + exact h + +/-- **8. Holomorphic dependence of integrals on parameters**, under a locally integrable bound. -/ +theorem analyticOnNhd_integral {α : Type*} [MeasurableSpace α] {μ : Measure α} {U : Set E} + {G : E → α → F} (hU : IsOpen U) (hmeas : ∀ x ∈ U, AEStronglyMeasurable (G x) μ) + (hderivmeas : ∀ x ∈ U, AEStronglyMeasurable (fun a => fderiv ℂ (G · a) x) μ) + (hhol : ∀ᵐ a ∂μ, AnalyticOnNhd ℂ (G · a) U) + (hdom : ∀ x ∈ U, ∃ (s : Set E) (bound : α → ℝ), s ∈ 𝓝 x ∧ Integrable bound μ ∧ + ∀ᵐ a ∂μ, ∀ y ∈ s, ‖G y a‖ ≤ bound a) : + AnalyticOnNhd ℂ (fun x => ∫ a, G x a ∂μ) U := by + exact analyticOnNhd_integral_of_locally_dominated hU hmeas hderivmeas hhol hdom + +/-! ## B. Convergence and spaces of holomorphic functions -/ + +/-- **10. Weierstrass convergence theorem**: a locally uniform limit of holomorphic maps is +holomorphic, and the derivatives converge locally uniformly. -/ +theorem weierstrass_convergence {U : Set E} (hU : IsOpen U) {f : ℕ → E → F} {g : E → F} + (hf : ∀ n, DifferentiableOn ℂ (f n) U) (hlim : TendstoLocallyUniformlyOn f g atTop U) : + DifferentiableOn ℂ g U ∧ + TendstoLocallyUniformlyOn (fun n => fderiv ℂ (f n)) (fderiv ℂ g) atTop U := by + have hfa : ∀ᶠ n in atTop, AnalyticOnNhd ℂ (f n) U := + .of_forall fun n => (hf n).analyticOnNhd_of_finiteDimensional hU + exact ⟨(hlim.analyticOnNhd_of_finiteDimensional hfa hU).differentiableOn, + hlim.fderiv_of_finiteDimensional hfa hU⟩ + +/-- The continuous maps on an open set `U` that are restrictions of holomorphic maps. -/ +def holomorphicMaps (U : TopologicalSpace.Opens E) (F : Type*) [NormedAddCommGroup F] + [NormedSpace ℂ F] : Set C(U, F) := + {f | ∃ g : E → F, DifferentiableOn ℂ g U ∧ ∀ z : U, g z = f z} + +/-- **11. Holomorphic function spaces**: the holomorphic maps form a closed subset of `C(U, F)` in +the compact-open topology. -/ +theorem isClosed_holomorphicMaps (U : TopologicalSpace.Opens E) : + IsClosed (holomorphicMaps U F) := by + have h : holomorphicMaps U F = + (SeveralComplexVariables.holomorphicSubmodule (F := F) U : Set C(U, F)) := by + ext f + constructor + · rintro ⟨g, hg, hgf⟩ + refine ((hg.analyticOnNhd_of_finiteDimensional U.isOpen).congr U.isOpen ?_ : + AnalyticOnNhd ℂ (SeveralComplexVariables.openExtension U f) U) + intro z hz + rw [SeveralComplexVariables.openExtension_apply U f hz] + exact hgf ⟨z, hz⟩ + · intro hf + exact ⟨_, (show AnalyticOnNhd ℂ (SeveralComplexVariables.openExtension U f) U from + hf).differentiableOn, fun z => SeveralComplexVariables.openExtension_coe U f z⟩ + rw [h] + exact SeveralComplexVariables.isClosed_holomorphicSubmodule U + +/-- **12. Montel's theorem**: a uniformly bounded sequence of holomorphic maps with values in a +finite-dimensional space has a locally uniformly convergent subsequence with holomorphic limit. -/ +theorem montel [FiniteDimensional ℂ F] {U : Set E} (hU : IsOpen U) {f : ℕ → E → F} + (hf : ∀ n, DifferentiableOn ℂ (f n) U) {M : ℝ} (hM : ∀ n, ∀ z ∈ U, ‖f n z‖ ≤ M) : + ∃ (g : E → F) (φ : ℕ → ℕ), StrictMono φ ∧ DifferentiableOn ℂ g U ∧ + TendstoLocallyUniformlyOn (fun n => f (φ n)) g atTop U := by + obtain ⟨g, φ, hφ, hg, hlim⟩ := + SeveralComplexVariables.exists_subseq_tendstoLocallyUniformlyOn_of_uniform_bound hU + (fun n => (hf n).analyticOnNhd_of_finiteDimensional hU) (fun n z hz => hM n z hz) + exact ⟨g, φ, hφ, hg.differentiableOn, hlim⟩ + +/-- **13. Vitali's theorem**: a locally bounded sequence of holomorphic maps on a connected open set +that converges pointwise on a nonempty open subset converges locally uniformly. -/ +theorem vitali [FiniteDimensional ℂ F] {D V : Set E} (hD : IsOpen D) (hconn : IsPreconnected D) + {f : ℕ → E → F} (hf : ∀ n, DifferentiableOn ℂ (f n) D) + (hb : ∀ K ⊆ D, IsCompact K → ∃ M : ℝ, ∀ n, ∀ z ∈ K, ‖f n z‖ ≤ M) (hV : IsOpen V) + (hne : V.Nonempty) (hVD : V ⊆ D) + (hp : ∀ z ∈ V, ∃ y : F, Tendsto (fun n => f n z) atTop (𝓝 y)) : + ∃ g : E → F, DifferentiableOn ℂ g D ∧ TendstoLocallyUniformlyOn f g atTop D := by + exact SeveralComplexVariables.exists_tendstoLocallyUniformlyOn_of_forall_exists_tendsto hD hconn + hf hb hV hne hVD hp + +/-- **14. Holomorphic `Lᵖ` spaces**: on compact subsets, a holomorphic representative of an `Lᵖ` +class is bounded by a constant times the `Lᵖ` norm, for `1 ≤ p ≤ ∞`. -/ +theorem holomorphic_Lp_bound (U : TopologicalSpace.Opens (ι → ℂ)) (p : ENNReal) [Fact (1 ≤ p)] + {K : Set (ι → ℂ)} (hKU : K ⊆ U) (hK : IsCompact K) : + ∃ C : ℝ, 0 < C ∧ ∀ (u : Lp F p (volume.restrict (U : Set (ι → ℂ)))) (f : (ι → ℂ) → F), + DifferentiableOn ℂ f U → f =ᵐ[volume.restrict (U : Set (ι → ℂ))] u → + ∀ z ∈ K, ‖f z‖ ≤ C * ‖u‖ := by + exact SeveralComplexVariables.exists_norm_le_mul_Lp_norm U p hKU hK + +/-! ## C. Local holomorphic mappings -/ + +/-- **15. Holomorphic inverse mapping theorem**: a holomorphic map with invertible derivative at `a` +is near `a` a homeomorphism between open sets that is holomorphic in both directions. -/ +theorem inverse_mapping {G : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] + [FiniteDimensional ℂ G] {U : Set E} (hU : IsOpen U) {f : E → G} + (hf : DifferentiableOn ℂ f U) {a : E} (ha : a ∈ U) (hinv : (fderiv ℂ f a).IsInvertible) : + ∃ e : OpenPartialHomeomorph E G, DifferentiableOn ℂ e e.source ∧ + DifferentiableOn ℂ e.symm e.target ∧ a ∈ e.source ∧ e.source ⊆ U ∧ (e : E → G) = f ∧ + fderiv ℂ e.symm (f a) = (fderiv ℂ f a).inverse := by + obtain ⟨e, he, hae, heU, hef⟩ := + SeveralComplexVariables.exists_biholomorphic_of_isInvertible_fderiv hU hf ha hinv + refine ⟨e, he.1, he.2, hae, heU, hef, ?_⟩ + rw [← hef] + exact he.fderiv_symm hae + +/-- **16. Holomorphic implicit mapping theorem**, with the derivative of the implicit map. -/ +theorem implicit_mapping {P Q R : Type*} [NormedAddCommGroup P] [NormedSpace ℂ P] + [NormedAddCommGroup Q] [NormedSpace ℂ Q] [NormedAddCommGroup R] [NormedSpace ℂ R] + [FiniteDimensional ℂ P] [FiniteDimensional ℂ Q] [CompleteSpace R] {D : Set (P × Q)} + (hD : IsOpen D) {f : P × Q → R} (hf : DifferentiableOn ℂ f D) {a : P} {b : Q} + (hab : (a, b) ∈ D) + (hi : ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).IsInvertible) : + ∃ (U : Set P) (V : Set Q) (g : P → Q), IsOpen U ∧ a ∈ U ∧ IsOpen V ∧ b ∈ V ∧ U ×ˢ V ⊆ D ∧ + DifferentiableOn ℂ g U ∧ MapsTo g U V ∧ g a = b ∧ + HasFDerivAt g (-((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inr ℂ P Q)).inverse |>.comp + ((fderiv ℂ f (a, b)).comp (ContinuousLinearMap.inl ℂ P Q))) a ∧ + ∀ x ∈ U, ∀ y ∈ V, f (x, y) = f (a, b) ↔ y = g x := by + exact SeveralComplexVariables.exists_holomorphic_implicit_mapping hD hf hab hi + +/-! ## D. Reinhardt geometry, power series, and continuation -/ + +/-- A set is Reinhardt if it is invariant under independent rotations of the coordinates. -/ +def IsReinhardt (U : Set (ι → ℂ)) : Prop := + ∀ ⦃z⦄, z ∈ U → ∀ ⦃w⦄, (∀ i, ‖w i‖ = ‖z i‖) → w ∈ U + +/-- A set is complete Reinhardt if it is closed under decreasing the coordinate moduli. -/ +def IsCompleteReinhardt (U : Set (ι → ℂ)) : Prop := + ∀ ⦃z⦄, z ∈ U → ∀ ⦃w⦄, (∀ i, ‖w i‖ ≤ ‖z i‖) → w ∈ U + +/-- Logarithmic convexity: the image of the points without zero coordinates under +`z ↦ (log |z₁|, …, log |zₙ|)` is convex. -/ +def IsLogarithmicallyConvex (U : Set (ι → ℂ)) : Prop := + Convex ℝ {x : ι → ℝ | (fun i => (Real.exp (x i) : ℂ)) ∈ U} + +/-- The convergence domain of a power series: the interior of its set of absolute convergence. -/ +def convergenceDomain {G : Type*} [NormedAddCommGroup G] (c : MvPowerSeries ι G) : Set (ι → ℂ) := + interior {z | Summable fun m : ι →₀ ℕ => ‖c m‖ * ∏ i, ‖z i‖ ^ m i} + +omit [Fintype ι] in +/-- **17. Complete Reinhardt geometry**: a complete Reinhardt set is Reinhardt and, when nonempty, +path connected. -/ +theorem IsCompleteReinhardt.isReinhardt_and_isPathConnected {U : Set (ι → ℂ)} + (hU : IsCompleteReinhardt U) : IsReinhardt U ∧ (U.Nonempty → IsPathConnected U) := by + have h : SeveralComplexVariables.IsCompleteReinhardt U := hU + exact ⟨h.isReinhardt, fun hne => h.isPathConnected hne⟩ + +omit [Fintype ι] in +/-- **18. Logarithmic convexity including zero coordinates**: for an open complete Reinhardt set, +logarithmic convexity is closure under weighted geometric means of the coordinate moduli, with the +convention `0 ^ 0 = 1`. -/ +theorem isLogarithmicallyConvex_iff_geometric [Finite ι] {U : Set (ι → ℂ)} (ho : IsOpen U) + (hc : IsCompleteReinhardt U) : + IsLogarithmicallyConvex U ↔ ∀ z ∈ U, ∀ w ∈ U, ∀ a b : ℝ, 0 ≤ a → 0 ≤ b → a + b = 1 → + ∀ v : ι → ℂ, (∀ i, ‖v i‖ = ‖z i‖ ^ a * ‖w i‖ ^ b) → v ∈ U := by + classical + let := Fintype.ofFinite ι + have hc' : SeveralComplexVariables.IsCompleteReinhardt U := hc + rw [show IsLogarithmicallyConvex U ↔ SeveralComplexVariables.IsLogarithmicallyConvex U from + Iff.rfl, ← SeveralComplexVariables.hasGeometricallyConvexModuli_iff ho hc'] + constructor + · intro h z hz w hw a b ha hb hab v hv + obtain ⟨u, hu, hue⟩ := h ⟨z, hz, rfl⟩ ⟨w, hw, rfl⟩ ha hb hab + refine hc'.isReinhardt hu fun i => ?_ + have hi := congrArg NNReal.toReal (congrFun hue i) + simp only [SeveralComplexVariables.geometricCombination, NNReal.coe_mul, NNReal.coe_rpow, + coe_nnnorm] at hi + rw [hv i, hi] + · rintro h _ ⟨z, hz, rfl⟩ _ ⟨w, hw, rfl⟩ a b ha hb hab + let u : ι → ℂ := fun i => ((‖z i‖ ^ a * ‖w i‖ ^ b : ℝ) : ℂ) + have hnn (i : ι) : 0 ≤ ‖z i‖ ^ a * ‖w i‖ ^ b := by positivity + have hu : u ∈ U := h z hz w hw a b ha hb hab u fun i => by + simp only [u, Complex.norm_real, Real.norm_of_nonneg (hnn i)] + refine ⟨u, hu, funext fun i => NNReal.eq ?_⟩ + simp only [u, SeveralComplexVariables.geometricCombination, coe_nnnorm, Complex.norm_real, + Real.norm_of_nonneg (hnn i), NNReal.coe_mul, NNReal.coe_rpow] + +/-- **19. Convergence domains of power series** are complete Reinhardt and logarithmically convex, +and the sum of the series is holomorphic there. -/ +theorem convergenceDomain_properties (c : MvPowerSeries ι F) : + IsCompleteReinhardt (convergenceDomain c) ∧ IsLogarithmicallyConvex (convergenceDomain c) ∧ + AnalyticOnNhd ℂ (fun z => ∑' m : ι →₀ ℕ, (∏ i, z i ^ m i) • c m) (convergenceDomain c) := by + exact ⟨SeveralComplexVariables.isCompleteReinhardt_powerSeriesConvergenceDomain c, + SeveralComplexVariables.isLogarithmicallyConvex_powerSeriesConvergenceDomain c, + SeveralComplexVariables.analyticOnNhd_powerSeriesSum c⟩ + +/-- **20. Taylor representation on complete Reinhardt sets**: a holomorphic function on an open +complete Reinhardt set is the sum of one power series on the whole set. -/ +theorem exists_powerSeries_eqOn_of_isCompleteReinhardt {n : ℕ} {U : Set (Fin n → ℂ)} + (ho : IsOpen U) (hc : IsCompleteReinhardt U) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) : + ∃ c : MvPowerSeries (Fin n) F, U ⊆ convergenceDomain c ∧ + EqOn (fun z => ∑' m : Fin n →₀ ℕ, (∏ i, z i ^ m i) • c m) f U := by + exact ⟨_, + SeveralComplexVariables.IsCompleteReinhardt.subset_convergenceDomain_and_eqOn_powerSeriesSum + ho hc hf⟩ + +/-- **21. Characterization of convergence domains**: every nonempty open complete logarithmically +convex Reinhardt set is the convergence domain of a scalar power series. -/ +theorem exists_convergenceDomain_eq {U : Set (ι → ℂ)} (hU : IsOpen U) (hne : U.Nonempty) + (hc : IsCompleteReinhardt U) (hl : IsLogarithmicallyConvex U) : + ∃ c : MvPowerSeries ι ℂ, convergenceDomain c = U := by + exact SeveralComplexVariables.exists_powerSeriesConvergenceDomain_eq hU hne hc hl + +/-- **22. Laurent expansion on Reinhardt domains**: a holomorphic function on a nonempty connected +open Reinhardt set has a unique locally uniformly convergent Laurent expansion. -/ +theorem existsUnique_laurent_expansion {n : ℕ} {U : Set (Fin n → ℂ)} (ho : IsOpen U) + (hc : IsPreconnected U) (hne : U.Nonempty) (hR : IsReinhardt U) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) : + ∃! c : (Fin n → ℤ) → F, + HasSumLocallyUniformlyOn (fun m z => (∏ i, z i ^ m i) • c m) f U := by + obtain ⟨z, hz⟩ := hne + have hR' : SeveralComplexVariables.IsReinhardt U := hR + obtain ⟨r, hrU, hr⟩ := hR'.exists_strict_modulus_majorant ho hz + have h := SeveralComplexVariables.multivariableLaurent_expansion ho hc hR' hf + (r := fun i => (r i : ℝ)) (fun i => lt_of_le_of_lt (NNReal.coe_nonneg _) (hr i)) hrU + exact ⟨_, h.1, fun c hc' => h.2.2.2.2 c hc'⟩ + +/-- **23. Continuation from Reinhardt domains**: a holomorphic function on a connected open +Reinhardt set containing the origin extends to the complete Reinhardt hull. -/ +theorem exists_extension_completeReinhardtHull {n : ℕ} {U : Set (Fin n → ℂ)} (ho : IsOpen U) + (hc : IsConnected U) (hR : IsReinhardt U) (hzero : 0 ∈ U) {f : (Fin n → ℂ) → F} + (hf : AnalyticOnNhd ℂ f U) : + ∃ g, AnalyticOnNhd ℂ g {w | ∃ z ∈ U, ∀ i, ‖w i‖ ≤ ‖z i‖} ∧ EqOn g f U := by + exact SeveralComplexVariables.exists_extension_completeReinhardtHull ho hc hR hzero hf + +/-- **24. Continuation from circular domains**: a holomorphic function on a connected open set +invariant under `z ↦ e^{iθ} z` and containing the origin extends to the balanced hull. -/ +theorem exists_extension_balancedHull {U : Set E} (ho : IsOpen U) (hc : IsPreconnected U) + (hrot : ∀ ⦃z⦄, z ∈ U → ∀ ⦃c : ℂ⦄, ‖c‖ = 1 → c • z ∈ U) (hzero : (0 : E) ∈ U) {f : E → F} + (hf : AnalyticOnNhd ℂ f U) : ∃ g, AnalyticOnNhd ℂ g (balancedHull ℂ U) ∧ EqOn g f U := by + exact SeveralComplexVariables.exists_extension_balancedHull ho hc hrot hzero hf + +/-! ## E. Hartogs phenomena and removable singularities -/ + +/-- **25. Hartogs–Taylor expansion**: on an open set `U ⊆ E × ℂ` whose fibres are closed under +decreasing `|w|`, a holomorphic function is the locally uniform sum of its fibre Taylor series, +whose coefficients are holomorphic on the projection of `U`. -/ +theorem hartogs_taylor_expansion {U : Set (E × ℂ)} (hU : IsOpen U) + (hH : ∀ ⦃z w⦄, (z, w) ∈ U → ∀ ⦃v : ℂ⦄, ‖v‖ ≤ ‖w‖ → (z, v) ∈ U) {f : E × ℂ → F} + (hf : DifferentiableOn ℂ f U) : + (∀ k : ℕ, DifferentiableOn ℂ + (fun z => ((k.factorial : ℂ)⁻¹) • iteratedDeriv k (fun w => f (z, w)) 0) (Prod.fst '' U)) ∧ + HasSumLocallyUniformlyOn (fun (k : ℕ) (p : E × ℂ) => + p.2 ^ k • (((k.factorial : ℂ)⁻¹) • iteratedDeriv k (fun w => f (p.1, w)) 0)) f U := by + exact SeveralComplexVariables.differentiableOn_hartogsTaylorCoeff_and_hasSumLocallyUniformlyOn + hU hH hf + +/-- **26. Hartogs' continuity theorem**: a holomorphic function on the union of an annular cylinder +over a connected base `D` and a full cylinder over a nonempty open `D₀ ⊆ D` extends to the full +cylinder over `D`. -/ +theorem hartogs_cylinder_extension {D D₀ : Set E} (hD : IsOpen D) (hc : IsPreconnected D) + (hD₀ : IsOpen D₀) (hne : D₀.Nonempty) (hsub : D₀ ⊆ D) {ρ R : ℝ} (hρ : 0 ≤ ρ) (hρR : ρ < R) + {f : E × ℂ → F} + (hf : AnalyticOnNhd ℂ f ((D ×ˢ (ball 0 R \ closedBall 0 ρ)) ∪ (D₀ ×ˢ ball 0 R))) : + ∃ g, AnalyticOnNhd ℂ g (D ×ˢ ball 0 R) ∧ + EqOn g f ((D ×ˢ (ball 0 R \ closedBall 0 ρ)) ∪ (D₀ ×ˢ ball 0 R)) := by + exact SeveralComplexVariables.exists_extension_hartogsCylinder hD hc hD₀ hne hsub hρ hρR hf + +/-- **27. Hartogs' theorem on separate analyticity**: a function on an open subset of `ℂ^ι` that is +analytic in each variable separately is analytic, with no continuity or boundedness hypothesis. -/ +theorem hartogs_separate_analyticity [DecidableEq ι] {U : Set (ι → ℂ)} {f : (ι → ℂ) → F} + (hU : IsOpen U) (hf : ∀ z ∈ U, ∀ i, AnalyticAt ℂ (fun w => f (update z i w)) (z i)) : + AnalyticOnNhd ℂ f U := by + exact SeveralComplexVariables.analyticOnNhd_of_separately_analytic hU hf + +/-- **28. Isolated singularities are removable** in dimension at least two. -/ +theorem exists_extension_diff_singleton (hdim : 2 ≤ Module.finrank ℂ E) {U : Set E} + (ho : IsOpen U) {a : E} (ha : a ∈ U) {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ {a})) : + ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ {a}) := by + exact SeveralComplexVariables.exists_analyticOnNhd_extension_diff_singleton hdim ho ha hf + +/-- **29. Zeros are not isolated** in dimension at least two. -/ +theorem frequently_zero_punctured (hdim : 2 ≤ Module.finrank ℂ E) {f : E → ℂ} {a : E} + (hf : AnalyticAt ℂ f a) (ha : f a = 0) : ∃ᶠ z in 𝓝[≠] a, f z = 0 := by + exact SeveralComplexVariables.frequently_zero_punctured_of_analyticAt hdim hf ha + +/-- **30. First Riemann extension theorem**: a holomorphic function on the complement of the zero +set of a nonzero holomorphic function `g` on a connected open set, locally bounded near that zero +set, extends holomorphically. -/ +theorem riemann_extension_first {U : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) {g : E → ℂ} + (hg : AnalyticOnNhd ℂ g U) (hne : ∃ z ∈ U, g z ≠ 0) {f : E → F} + (hf : AnalyticOnNhd ℂ f (U \ g ⁻¹' {0})) + (hb : ∀ a ∈ U, g a = 0 → ∃ r : ℝ, 0 < r ∧ ∃ C : ℝ, ∀ z ∈ ball a r ∩ (U \ g ⁻¹' {0}), + ‖f z‖ ≤ C) : + ∃ f' : E → F, AnalyticOnNhd ℂ f' U ∧ EqOn f' f (U \ g ⁻¹' {0}) := by + exact SeveralComplexVariables.exists_analyticOnNhd_extension_across_zeroSet hU hconn hg hne hf hb + +/-- **31. Hartogs' extension theorem (compact holes)**: in dimension at least two, a holomorphic +function on `U \ K`, with `K ⊆ U` compact and `U \ K` connected, extends to `U`. -/ +theorem hartogs_compact_hole (hdim : 2 ≤ Module.finrank ℂ E) {U K : Set E} (hU : IsOpen U) + (hK : IsCompact K) (hKU : K ⊆ U) (hcompl : IsPreconnected (U \ K)) {f : E → F} + (hf : AnalyticOnNhd ℂ f (U \ K)) : ∃ g : E → F, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ K) := by + exact SeveralComplexVariables.exists_analyticOnNhd_extension_of_isCompact hdim hU hK hKU hcompl hf + +/-! ## F. Elementary analytic sets -/ + +/-- `A` is an analytic subset of `U`: near every point of `U` it is the common zero set of finitely +many holomorphic functions. -/ +def IsAnalyticSet (U A : Set E) : Prop := + A ⊆ U ∧ ∀ a ∈ U, ∃ V : Set E, IsOpen V ∧ a ∈ V ∧ V ⊆ U ∧ + ∃ s : Finset (E → ℂ), (∀ f ∈ s, AnalyticOnNhd ℂ f V) ∧ + ∀ z ∈ V, z ∈ A ↔ ∀ f ∈ s, f z = 0 + +/-- `a` is a regular point of `A` of codimension `q`: a local biholomorphic change of coordinates +carries `A` to a complex linear subspace of codimension `q`. -/ +def IsRegularAnalyticSetAt (A : Set E) (a : E) (q : ℕ) : Prop := + a ∈ A ∧ ∃ (e : OpenPartialHomeomorph E E) (L : E →L[ℂ] (Fin q → ℂ)), + (DifferentiableOn ℂ e e.source ∧ DifferentiableOn ℂ e.symm e.target) ∧ a ∈ e.source ∧ + Function.Surjective L ∧ ∀ z ∈ e.source, z ∈ A ↔ L (e z) = 0 + +/-- **32. Analytic sets are thin**: a proper analytic subset of a connected open set has empty +interior and connected complement. -/ +theorem IsAnalyticSet.interior_eq_empty_and_isConnected_sdiff {U A : Set E} + (hA : IsAnalyticSet U A) (hc : IsConnected U) (hp : A ≠ U) : + interior A = ∅ ∧ IsConnected (U \ A) := by + have h : SeveralComplexVariables.IsAnalyticSet U A := hA + exact ⟨h.interior_eq_empty hc.isPreconnected hp, h.isConnected_sdiff hc hp⟩ + +/-- **33. Regular points and full-rank equations**: `a` is a regular point of codimension `q` +exactly when `A` is near `a` the zero set of `q` holomorphic equations of full rank at `a`. -/ +theorem isRegularAnalyticSetAt_iff_exists_equations {A : Set E} {a : E} {q : ℕ} : + IsRegularAnalyticSetAt A a q ↔ a ∈ A ∧ ∃ (V : Set E) (f : E → (Fin q → ℂ)), + IsOpen V ∧ a ∈ V ∧ AnalyticOnNhd ℂ f V ∧ (∀ z ∈ V, z ∈ A ↔ f z = 0) ∧ + Function.Surjective (fderiv ℂ f a) := by + exact SeveralComplexVariables.isRegularAnalyticSetAt_iff_exists_equations + +/-- **34. Removal of a coordinate plane of codimension two**. -/ +theorem exists_extension_across_coordinatePlane {U : Set ((E × ℂ) × ℂ)} (hU : IsOpen U) + {f : ((E × ℂ) × ℂ) → F} (hf : AnalyticOnNhd ℂ f (U \ {z | z.1.2 = 0 ∧ z.2 = 0})) : + ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ {z | z.1.2 = 0 ∧ z.2 = 0}) := by + exact SeveralComplexVariables.exists_extension_across_coordinatePlane hU hf + +/-- **35. Second Riemann extension theorem**: holomorphic functions extend across an analytic subset +through each point of which some complex affine plane meets it only at that point, locally. -/ +theorem riemann_extension_second {U A : Set E} (hA : IsAnalyticSet U A) + (hcodim : ∀ a ∈ A, ∃ L : (Fin 2 → ℂ) →L[ℂ] E, Function.Injective L ∧ + ∀ᶠ z in 𝓝 (0 : Fin 2 → ℂ), a + L z ∈ A → z = 0) + {f : E → F} (hf : AnalyticOnNhd ℂ f (U \ A)) : ∃ g, AnalyticOnNhd ℂ g U ∧ EqOn g f (U \ A) := by + have h : SeveralComplexVariables.IsAnalyticSet U A := hA + exact h.exists_extension_of_codimension_two hcodim hf + +/-! ## G. Germs, Weierstrass theory, and elementary local algebra -/ + +/-- The ring `𝒪ₓ` of germs at `x` of scalar analytic functions, as a subring of all germs. -/ +def analyticGermRing (x : E) : Subring (Germ (𝓝 x) ℂ) where + carrier := {φ | ∃ f : E → ℂ, AnalyticAt ℂ f x ∧ (f : Germ (𝓝 x) ℂ) = φ} + zero_mem' := ⟨0, analyticAt_const, rfl⟩ + one_mem' := ⟨1, analyticAt_const, rfl⟩ + add_mem' := by + rintro _ _ ⟨f, hf, rfl⟩ ⟨g, hg, rfl⟩ + exact ⟨f + g, hf.add hg, rfl⟩ + neg_mem' := by + rintro _ ⟨f, hf, rfl⟩ + exact ⟨-f, hf.neg, rfl⟩ + mul_mem' := by + rintro _ _ ⟨f, hf, rfl⟩ ⟨g, hg, rfl⟩ + exact ⟨f * g, hf.mul hg, rfl⟩ + +/-- The germ at `x` of a function analytic at `x`. -/ +def germ {x : E} (f : E → ℂ) (hf : AnalyticAt ℂ f x) : analyticGermRing x := ⟨f, f, hf, rfl⟩ + +/-- A remainder of degree less than `d` in the last variable, with coefficient functions `a j`. -/ +def weierstrassRemainder {d : ℕ} (a : Fin d → E → ℂ) (z : E × ℂ) : ℂ := + ∑ j : Fin d, a j z.1 * z.2 ^ (j : ℕ) + +/-- Weierstrass division at the origin: `g = q f + r` as germs, with `r` a polynomial of degree +less than `d` in the last variable. -/ +def IsWeierstrassDivisionAt {d : ℕ} (f g q : E × ℂ → ℂ) (a : Fin d → E → ℂ) : Prop := + AnalyticAt ℂ q 0 ∧ (∀ j, AnalyticAt ℂ (a j) 0) ∧ + g =ᶠ[𝓝 0] fun z => q z * f z + weierstrassRemainder a z + +/-- Weierstrass preparation at the origin: `f = u W` as germs, with `u` a unit and `W` a +distinguished polynomial of degree `d` in the last variable. -/ +def IsWeierstrassPreparationAt {d : ℕ} (f u : E × ℂ → ℂ) (a : Fin d → E → ℂ) : Prop := + AnalyticAt ℂ u 0 ∧ u 0 ≠ 0 ∧ (∀ j, AnalyticAt ℂ (a j) 0) ∧ (∀ j, a j 0 = 0) ∧ + f =ᶠ[𝓝 0] fun z => u z * (z.2 ^ d + weierstrassRemainder a z) + +-- BEGIN SOLUTION ONLY +omit [FiniteDimensional ℂ E] in +/-- The submission ring of analytic germs is the library analytic germ subring. -/ +private theorem analyticGermRing_eq (x : E) : + analyticGermRing x = SeveralComplexVariables.analyticGermSubring ℂ x := rfl + +omit [FiniteDimensional ℂ E] in +/-- The submission and library predicates for Weierstrass division are equivalent. -/ +private theorem isWeierstrassDivisionAt_iff {d : ℕ} {f g q : E × ℂ → ℂ} {a : Fin d → E → ℂ} : + IsWeierstrassDivisionAt f g q a ↔ SeveralComplexVariables.IsWeierstrassDivisionAt f g q a := + ⟨fun h => ⟨h.1, h.2.1, h.2.2⟩, fun h => ⟨h.1, h.2, h.3⟩⟩ + +omit [FiniteDimensional ℂ E] in +/-- The submission and library predicates for Weierstrass preparation are equivalent. -/ +private theorem isWeierstrassPreparationAt_iff {d : ℕ} {f u : E × ℂ → ℂ} {a : Fin d → E → ℂ} : + IsWeierstrassPreparationAt f u a ↔ SeveralComplexVariables.IsWeierstrassPreparationAt f u a := + ⟨fun h => ⟨h.1, h.2.1, h.2.2.1, h.2.2.2.1, h.2.2.2.2⟩, fun h => ⟨h.1, h.2, h.3, h.4, h.5⟩⟩ +-- END SOLUTION ONLY + +omit [FiniteDimensional ℂ E] in +/-- **36. The ring of analytic germs is a local integral domain**, and a germ is a unit exactly when +it does not vanish at the base point. -/ +theorem analyticGermRing_isDomain_isLocalRing (x : E) : + IsDomain (analyticGermRing x) ∧ IsLocalRing (analyticGermRing x) ∧ + ∀ (f : E → ℂ) (hf : AnalyticAt ℂ f x), IsUnit (germ f hf) ↔ f x ≠ 0 := by + refine ⟨inferInstanceAs (IsDomain (SeveralComplexVariables.AnalyticGerm ℂ x)), + inferInstanceAs (IsLocalRing (SeveralComplexVariables.AnalyticGerm ℂ x)), fun f hf => ?_⟩ + exact SeveralComplexVariables.AnalyticGerm.isUnit_iff + (SeveralComplexVariables.AnalyticGerm.ofAnalyticAt f hf) + +/-- **37. Coordinate normalization**: after a linear change of coordinates, a nonzero germ has +finite order in the last variable. -/ +theorem exists_regular_coordinate_change {f : E × ℂ → ℂ} (hf : AnalyticAt ℂ f 0) + (hne : ¬ f =ᶠ[𝓝 0] 0) : + ∃ (L : (E × ℂ) ≃L[ℂ] (E × ℂ)) (d : ℕ), analyticOrderAt (fun w : ℂ => f (L (0, w))) 0 = d := by + exact SeveralComplexVariables.exists_regular_coordinate_change hf hne + +/-- **38. Taylor series determine germs** and are multiplicative. -/ +theorem taylorSeries_mul_and_eq_zero_iff {n : ℕ} {x : Fin n → ℂ} {f g : (Fin n → ℂ) → ℂ} + (hf : AnalyticAt ℂ f x) (hg : AnalyticAt ℂ g x) : + taylorSeries (f * g) x = taylorSeries f x * taylorSeries g x ∧ + (taylorSeries f x = 0 ↔ f =ᶠ[𝓝 x] 0) := by + open SeveralComplexVariables.AnalyticGerm in + refine ⟨?_, ?_⟩ + · have h := taylorSeries_mul (ofAnalyticAt f hf) (ofAnalyticAt g hg) + rwa [← ofAnalyticAt_mul, taylorSeries_ofAnalyticAt, taylorSeries_ofAnalyticAt, + taylorSeries_ofAnalyticAt, ← taylorSeries_eq, ← taylorSeries_eq, ← taylorSeries_eq] at h + · have h := taylorSeries_eq_zero_iff (ofAnalyticAt f hf) + rw [taylorSeries_ofAnalyticAt, ← taylorSeries_eq, ← ofAnalyticAt_zero, + ofAnalyticAt_eq_iff] at h + exact h + +omit [Fintype ι] in +/-- **39. Division by a power of the last coordinate** on a product of a polydisc `P` and a disc, +with a bound for the quotient. -/ +theorem coordinatePower_division [Finite ι] (d : ℕ) {r : ι → ℝ} {R : ℝ} (hR : 0 < R) + {P : Set (ι → ℂ)} + (hP : P = Set.pi univ fun i => ball (0 : ℂ) (r i)) {g : (ι → ℂ) × ℂ → ℂ} + (hg : DifferentiableOn ℂ g (P ×ˢ ball 0 R)) : + ∃ (q : (ι → ℂ) × ℂ → ℂ) (a : Fin d → (ι → ℂ) → ℂ), DifferentiableOn ℂ q (P ×ˢ ball 0 R) ∧ + (∀ j, DifferentiableOn ℂ (a j) P) ∧ + EqOn g (fun z => q z * z.2 ^ d + weierstrassRemainder a z) (P ×ˢ ball 0 R) ∧ + ∀ M : ℝ, 0 ≤ M → (∀ z ∈ P ×ˢ ball (0 : ℂ) R, ‖g z‖ ≤ M) → + ∀ z ∈ P ×ˢ ball (0 : ℂ) R, ‖q z‖ ≤ ((d + 1 : ℕ) : ℝ) / R ^ d * M := by + classical + let := Fintype.ofFinite ι + subst hP + obtain ⟨q, a, hdiv, hb, -⟩ := SeveralComplexVariables.coordinatePower_division d (r := r) hR hg + exact ⟨q, a, hdiv.1, hdiv.2, hdiv.3, hb⟩ + +/-- **40. Weierstrass division theorem**, with uniqueness of quotient and remainder as germs. -/ +theorem weierstrass_division {d : ℕ} {f g : E × ℂ → ℂ} (hf : AnalyticAt ℂ f 0) + (hg : AnalyticAt ℂ g 0) (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (q : E × ℂ → ℂ) (a : Fin d → E → ℂ), IsWeierstrassDivisionAt f g q a ∧ + ∀ q' a', IsWeierstrassDivisionAt f g q' a' → q =ᶠ[𝓝 0] q' ∧ ∀ j, a j =ᶠ[𝓝 0] a' j := by + obtain ⟨q, a, h, hu⟩ := + SeveralComplexVariables.exists_isWeierstrassDivisionAt_of_finiteDimensional hf hg horder + exact ⟨q, a, isWeierstrassDivisionAt_iff.mpr h, + fun q' a' h' => hu q' a' (isWeierstrassDivisionAt_iff.mp h')⟩ + +/-- **41. Weierstrass preparation theorem**, with uniqueness of the unit and the polynomial. -/ +theorem weierstrass_preparation {d : ℕ} {f : E × ℂ → ℂ} (hf : AnalyticAt ℂ f 0) + (horder : analyticOrderAt (fun w : ℂ => f (0, w)) 0 = d) : + ∃ (u : E × ℂ → ℂ) (a : Fin d → E → ℂ), IsWeierstrassPreparationAt f u a ∧ + ∀ v b, IsWeierstrassPreparationAt f v b → u =ᶠ[𝓝 0] v ∧ ∀ j, a j =ᶠ[𝓝 0] b j := by + obtain ⟨u, a, h, hu⟩ := + SeveralComplexVariables.exists_isWeierstrassPreparationAt_of_finiteDimensional hf horder + exact ⟨u, a, isWeierstrassPreparationAt_iff.mpr h, + fun v b h' => hu v b (isWeierstrassPreparationAt_iff.mp h')⟩ + +/-- **44–45. The ring of analytic germs is Noetherian and factorial.** -/ +theorem analyticGermRing_isNoetherianRing_ufd (x : E) : + IsNoetherianRing (analyticGermRing x) ∧ UniqueFactorizationMonoid (analyticGermRing x) := by + exact ⟨inferInstanceAs (IsNoetherianRing (SeveralComplexVariables.AnalyticGerm ℂ x)), + inferInstanceAs (UniqueFactorizationMonoid (SeveralComplexVariables.AnalyticGerm ℂ x))⟩ + +/-- **45. Relative primality persists**: the set of points at which the germs of two functions are +analytic and relatively prime is open. -/ +theorem isOpen_isRelPrime_locus (f g : E → ℂ) : + IsOpen {x | ∃ (hf : AnalyticAt ℂ f x) (hg : AnalyticAt ℂ g x), + IsRelPrime (germ f hf) (germ g hg)} := by + exact SeveralComplexVariables.AnalyticGerm.isOpen_isRelPrime_locus f g + +/-! ## H. Zero-set geometry and biholomorphic rigidity -/ + +/-- **46. Regular points of hypersurfaces**: the zero set of a holomorphic function on a connected +open set, if nonempty and proper, contains a regular point of codimension one. -/ +theorem exists_regularPoint_zeroSet {U : Set E} (hU : IsOpen U) (hc : IsPreconnected U) {f : E → ℂ} + (hf : AnalyticOnNhd ℂ f U) (hne : ∃ b ∈ U, f b ≠ 0) (hz : ∃ a ∈ U, f a = 0) : + ∃ a, IsRegularAnalyticSetAt (U ∩ f ⁻¹' {0}) a 1 := by + exact SeveralComplexVariables.exists_regularPoint_zeroSet hU hc hf hne hz + +/-- **47. Injective holomorphic maps in equal dimensions are biholomorphic** onto their open +image. -/ +theorem injOn_biholomorphic {G : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] + [FiniteDimensional ℂ G] (hdim : Module.finrank ℂ E = Module.finrank ℂ G) {U : Set E} + (hU : IsOpen U) {f : E → G} (hf : DifferentiableOn ℂ f U) (hi : InjOn f U) : + ∃ e : OpenPartialHomeomorph E G, DifferentiableOn ℂ e e.source ∧ + DifferentiableOn ℂ e.symm e.target ∧ e.source = U ∧ e.target = f '' U ∧ (e : E → G) = f := by + obtain ⟨e, he, h⟩ := SeveralComplexVariables.exists_biholomorphic_of_injOn hdim hU hf hi + exact ⟨e, he.1, he.2, h⟩ + +/-- **48. Cartan's uniqueness theorem**: a holomorphic self-map of a bounded connected open set +fixing a point with identity derivative there is the identity. -/ +theorem cartan_uniqueness {U : Set E} (hU : IsOpen U) (hconn : IsPreconnected U) + (hb : Bornology.IsBounded U) {f : E → E} (hf : AnalyticOnNhd ℂ f U) (hmaps : MapsTo f U U) + {a : E} (ha : a ∈ U) (hfix : f a = a) (hderiv : fderiv ℂ f a = ContinuousLinearMap.id ℂ E) : + EqOn f id U := by + exact SeveralComplexVariables.eqOn_id_of_mapsTo_of_fderiv_eq_id hU hconn hb hf hmaps ha hfix + hderiv + +/-- **49. Biholomorphisms of circular domains fixing the origin are linear**, when the source is +bounded and connected. -/ +theorem biholomorphic_circular_linear {G : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] + [FiniteDimensional ℂ G] {e : OpenPartialHomeomorph E G} (he : DifferentiableOn ℂ e e.source) + (he' : DifferentiableOn ℂ e.symm e.target) (hc : IsPreconnected e.source) + (hb : Bornology.IsBounded e.source) + (hrot : ∀ ⦃z⦄, z ∈ e.source → ∀ ⦃c : ℂ⦄, ‖c‖ = 1 → c • z ∈ e.source) + (hrot' : ∀ ⦃z⦄, z ∈ e.target → ∀ ⦃c : ℂ⦄, ‖c‖ = 1 → c • z ∈ e.target) + (hzero : (0 : E) ∈ e.source) (hfix : e 0 = 0) : ∃ L : E ≃L[ℂ] G, EqOn e L e.source := by + have h : SeveralComplexVariables.IsBiholomorphic e := ⟨he, he'⟩ + exact h.exists_linearEquiv_of_circular hc hb hrot hrot' hzero hfix + +/-- **50. The automorphisms of the unit ball of a complex inner product space act transitively.** -/ +theorem exists_ball_automorphism {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] + {a b : H} (ha : a ∈ ball (0 : H) 1) (hb : b ∈ ball (0 : H) 1) : + ∃ e : OpenPartialHomeomorph H H, DifferentiableOn ℂ e e.source ∧ + DifferentiableOn ℂ e.symm e.target ∧ e.source = ball 0 1 ∧ e.target = ball 0 1 ∧ + e a = b := by + obtain ⟨e, he, h⟩ := SeveralComplexVariables.exists_ball_automorphism ha hb + exact ⟨e, he.1, he.2, h⟩ + +/-- **50. The unit polydisc and the Euclidean unit ball are not biholomorphic** in dimension at +least two. -/ +theorem not_biholomorphic_polydisc_ball (hdim : 2 ≤ Fintype.card ι) : + ¬ ∃ e : OpenPartialHomeomorph (ι → ℂ) (EuclideanSpace ℂ ι), DifferentiableOn ℂ e e.source ∧ + DifferentiableOn ℂ e.symm e.target ∧ e.source = ball 0 1 ∧ e.target = ball 0 1 := by + rintro ⟨e, h1, h2, h⟩ + exact SeveralComplexVariables.not_exists_isBiholomorphic_polydisc_ball hdim ⟨e, ⟨h1, h2⟩, h⟩ + +/-! ## I. Common extensions, holomorphic convexity, Cartan–Thullen, and Bochner's tube theorem -/ + +/-- The holomorphic hull of `K` relative to `U`: the points of `U` at which every holomorphic +function on `U` is bounded by each of its bounds on `K`. -/ +def holomorphicHull (U K : Set E) : Set E := + {z | z ∈ U ∧ ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → ∀ M : ℝ, (∀ w ∈ K, ‖f w‖ ≤ M) → ‖f z‖ ≤ M} + +/-- `U` is holomorphically convex: hulls of compact subsets are compact. -/ +def IsHolomorphicallyConvex (U : Set E) : Prop := + ∀ K : Set E, IsCompact K → K ⊆ U → IsCompact (holomorphicHull U K) + +/-- The generalized domain-of-holomorphy continuation property for a set `U`: there is no connected +open set `V ⊄ U` with a nonempty open `W ⊆ U ∩ V` such that every holomorphic function on `U` +agrees on `W` with one on `V`. + +Openness, connectedness, and nonemptiness of `U` are separate hypotheses. This predicate is +automatically satisfied when `interior U = ∅`, because no nonempty open overlap exists. -/ +def IsDomainOfHolomorphy (U : Set E) : Prop := + ∀ V W : Set E, IsOpen V → IsConnected V → IsOpen W → W.Nonempty → W ⊆ U → W ⊆ V → + (∀ f : E → ℂ, AnalyticOnNhd ℂ f U → ∃ g : E → ℂ, AnalyticOnNhd ℂ g V ∧ EqOn g f W) → V ⊆ U + +/-- `U` is the domain of existence of `f`: `f` is holomorphic on `U` and has no continuation in the +above sense. -/ +def IsDomainOfExistence (U : Set E) (f : E → ℂ) : Prop := + AnalyticOnNhd ℂ f U ∧ + ∀ V W : Set E, IsOpen V → IsConnected V → IsOpen W → W.Nonempty → W ⊆ U → W ⊆ V → + (∃ g, AnalyticOnNhd ℂ g V ∧ EqOn g f W) → V ⊆ U + +omit [FiniteDimensional ℂ E] in +/-- **51. Common extension domains**: if every holomorphic function on a nonempty open `U` extends +to the connected set `V ⊇ U`, then `V` lies in the convex hull of `U` and holomorphic functions on +`V` take no new values. -/ +theorem common_extension {U V : Set E} (hUV : U ⊆ V) + (hext : ∀ f : E → ℂ, AnalyticOnNhd ℂ f U → ∃ g, AnalyticOnNhd ℂ g V ∧ EqOn g f U) + (ho : IsOpen U) (hne : U.Nonempty) (hc : IsPreconnected V) : + V ⊆ convexHull ℝ U ∧ ∀ f : E → ℂ, AnalyticOnNhd ℂ f V → f '' V = f '' U := by + have h := SeveralComplexVariables.isCommonAnalyticExtension_of_forall hUV hext + exact ⟨h.subset_convexHull ho hne hc, fun f hf => h.image_eq ho hne hc hf⟩ + +/-- **52. Holomorphic hulls** are idempotent, and hulls of bounded sets are bounded. -/ +theorem holomorphicHull_idem_and_isBounded (U : Set (ι → ℂ)) {K : Set (ι → ℂ)} : + holomorphicHull U (holomorphicHull U K) = holomorphicHull U K ∧ + (Bornology.IsBounded K → Bornology.IsBounded (holomorphicHull U K)) := by + exact ⟨SeveralComplexVariables.holomorphicHull_idem U K, + SeveralComplexVariables.isBounded_holomorphicHull U⟩ + +/-- **52. Open complete logarithmically convex Reinhardt sets are holomorphically convex.** -/ +theorem isHolomorphicallyConvex_of_completeReinhardt {U : Set (ι → ℂ)} (ho : IsOpen U) + (hc : IsCompleteReinhardt U) (hl : IsLogarithmicallyConvex U) : IsHolomorphicallyConvex U := by + exact SeveralComplexVariables.isHolomorphicallyConvex_of_completeReinhardt ho hc hl + +omit [FiniteDimensional ℂ E] in +/-- **53. Elementary continuation obstructions.** Convex open sets and finite products of arbitrary +plane sets satisfy `IsDomainOfHolomorphy`, the continuation-obstruction predicate defined above. +This predicate does not require openness, connectedness, or nonemptiness. It holds vacuously +whenever the set has empty interior, because no nonempty open overlap exists. For nonempty +connected open plane factors, the product assertion recovers the classical theorem that their +product is a domain of holomorphy. -/ +theorem isDomainOfHolomorphy_of_convex_and_pi : + (∀ U : Set E, Convex ℝ U → IsOpen U → IsDomainOfHolomorphy U) ∧ + ∀ S : ι → Set ℂ, IsDomainOfHolomorphy (Set.pi univ S) := by + exact ⟨fun _ hU ho => SeveralComplexVariables.isDomainOfHolomorphy_of_convex hU ho, + fun S => SeveralComplexVariables.isDomainOfHolomorphy_pi S⟩ + +/-- **54. Escaping sequences**: an open set is holomorphically convex exactly when every sequence +leaving all its compact subsets is unbounded under some holomorphic function. -/ +theorem isHolomorphicallyConvex_iff_escaping {U : Set E} (ho : IsOpen U) : + IsHolomorphicallyConvex U ↔ ∀ p : ℕ → E, (∀ j, p j ∈ U) → + (∀ K : Set E, IsCompact K → K ⊆ U → ∀ᶠ j in atTop, p j ∉ K) → + ∃ f : E → ℂ, AnalyticOnNhd ℂ f U ∧ ¬ BddAbove (Set.range fun j => ‖f (p j)‖) := by + exact SeveralComplexVariables.isHolomorphicallyConvex_iff_unbounded_on_escaping_sequences ho + +/-- **55. Thullen's lemma, as a characterization**: an open subset of `ℂ^ι` with the supremum norm +is a domain of holomorphy exactly when polydisc radii available on a compact set remain available +on its holomorphic hull. -/ +theorem isDomainOfHolomorphy_iff_hull_radius {n : ℕ} {U : Set (Fin n → ℂ)} (ho : IsOpen U) : + IsDomainOfHolomorphy U ↔ ∀ K, IsCompact K → K ⊆ U → ∀ r : ℝ, 0 < r → + (∀ x ∈ K, ball x r ⊆ U) → ∀ a ∈ holomorphicHull U K, ball a r ⊆ U := by + exact SeveralComplexVariables.isDomainOfHolomorphy_iff_hasHolomorphicHullRadiusProperty ho + +/-- **56. Cartan–Thullen theorem**: for an open set, being a domain of holomorphy, holomorphic +convexity, and being the domain of existence of one function are equivalent. -/ +theorem cartan_thullen {U : Set E} (ho : IsOpen U) : + (IsDomainOfHolomorphy U ↔ IsHolomorphicallyConvex U) ∧ + (IsDomainOfHolomorphy U ↔ ∃ f : E → ℂ, IsDomainOfExistence U f) := by + exact ⟨SeveralComplexVariables.isDomainOfHolomorphy_iff_isHolomorphicallyConvex ho, + SeveralComplexVariables.isDomainOfHolomorphy_iff_exists_domainOfExistence ho⟩ + +/-- **57. Bochner's tube theorem**: a holomorphic function on the tube over a connected open base +`Ω ⊆ ℝ^ι` extends to the tube over the convex hull of `Ω`, and the tube is a domain of holomorphy +exactly when `Ω` is convex. -/ +theorem bochner_tube {Ω : Set (ι → ℝ)} (ho : IsOpen Ω) (hc : IsPreconnected Ω) : + (∀ f : (ι → ℂ) → F, AnalyticOnNhd ℂ f {z | (fun i => (z i).re) ∈ Ω} → + ∃ g : (ι → ℂ) → F, AnalyticOnNhd ℂ g {z | (fun i => (z i).re) ∈ convexHull ℝ Ω} ∧ + EqOn g f {z | (fun i => (z i).re) ∈ Ω}) ∧ + (IsDomainOfHolomorphy {z : ι → ℂ | (fun i => (z i).re) ∈ Ω} ↔ Convex ℝ Ω) := by + exact ⟨fun f hf => SeveralComplexVariables.exists_extension_tubeDomain_convexHull ho hc hf, + SeveralComplexVariables.isDomainOfHolomorphy_tubeDomain_iff ho hc⟩ + +/-! ## J. Plurisubharmonic functions, the Levi form, and pseudoconvexity -/ + +/-- The local submean property of `u` at `a`: on all small circles around `a`, `u` is integrable +and `u a` is at most its average. -/ +def HasSubmeanAt (u : ℂ → ℝ) (a : ℂ) : Prop := + ∀ᶠ r in 𝓝[>] (0 : ℝ), CircleIntegrable u a r ∧ u a ≤ Real.circleAverage u a r + +/-- `u` is subharmonic on `U`: upper semicontinuous with the local submean property. -/ +def SubharmonicOn (u : ℂ → ℝ) (U : Set ℂ) : Prop := + UpperSemicontinuousOn u U ∧ ∀ a ∈ U, HasSubmeanAt u a + +/-- `f` is plurisubharmonic on `U`: upper semicontinuous, and subharmonic on every complex line. -/ +def PlurisubharmonicOn (f : E → ℝ) (U : Set E) : Prop := + UpperSemicontinuousOn f U ∧ + ∀ a ∈ U, ∀ w : E, SubharmonicOn (fun t : ℂ => f (a + t • w)) {t | a + t • w ∈ U} + +/-- The Levi form of `f` at `a` in the direction `w`, through the real second derivative. -/ +noncomputable def leviForm (f : E → ℝ) (a w : E) : ℝ := + (iteratedFDeriv ℝ 2 f a ![w, w] + iteratedFDeriv ℝ 2 f a ![I • w, I • w]) / 4 + +/-- `U` is pseudoconvex: open, with a continuous plurisubharmonic exhaustion function. -/ +def IsPseudoconvex (U : Set E) : Prop := + IsOpen U ∧ ∃ φ : E → ℝ, ContinuousOn φ U ∧ PlurisubharmonicOn φ U ∧ + ∀ c : ℝ, IsCompact {z ∈ U | φ z ≤ c} + +/-- `ρ` is a local `C²` defining function of `U` on the neighbourhood `V` of the point `p`. -/ +def IsLocalDefiningFunction (U : Set E) (p : E) (ρ : E → ℝ) (V : Set E) : Prop := + IsOpen V ∧ p ∈ V ∧ ContDiffOn ℝ 2 ρ V ∧ ρ p = 0 ∧ fderiv ℝ ρ p ≠ 0 ∧ U ∩ V = {z | ρ z < 0} ∩ V + +/-- `w` is a complex tangent vector at `p` of the level set of `ρ`. -/ +def IsComplexTangent (ρ : E → ℝ) (p w : E) : Prop := + fderiv ℝ ρ p w = 0 ∧ fderiv ℝ ρ p (I • w) = 0 + +/-- The Levi condition at `p`: for every local defining function, the Levi form is positive +semidefinite on the complex tangent space. -/ +def IsLeviPseudoconvexAt (U : Set E) (p : E) : Prop := + ∀ (ρ : E → ℝ) (V : Set E), IsLocalDefiningFunction U p ρ V → + ∀ w, IsComplexTangent ρ p w → 0 ≤ leviForm ρ p w + +-- BEGIN SOLUTION ONLY +omit [FiniteDimensional ℂ E] in +/-- The submission and library predicates for local defining functions are equivalent. -/ +private theorem isLocalDefiningFunction_iff {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} : + IsLocalDefiningFunction U p ρ V ↔ SeveralComplexVariables.IsLocalDefiningFunction U p ρ V := + ⟨fun h => ⟨h.1, h.2.1, h.2.2.1, h.2.2.2.1, h.2.2.2.2.1, h.2.2.2.2.2⟩, + fun h => ⟨h.1, h.2, h.3, h.4, h.5, h.6⟩⟩ + +omit [FiniteDimensional ℂ E] in +/-- The submission and library predicates for Levi pseudoconvexity are equivalent. -/ +private theorem isLeviPseudoconvexAt_iff {U : Set E} {p : E} : + IsLeviPseudoconvexAt U p ↔ SeveralComplexVariables.IsLeviPseudoconvexAt U p := + ⟨fun h ρ V hρ => h ρ V (isLocalDefiningFunction_iff.mpr hρ), + fun h ρ V hρ => h ρ V (isLocalDefiningFunction_iff.mp hρ)⟩ +-- END SOLUTION ONLY + +/-- **58. Maximum principle for subharmonic functions.** -/ +theorem SubharmonicOn.eqOn_const_of_isMaxOn {u : ℂ → ℝ} {U : Set ℂ} {a : ℂ} (hU : IsOpen U) + (hc : IsPreconnected U) (hu : SubharmonicOn u U) (ha : a ∈ U) (hmax : ∀ z ∈ U, u z ≤ u a) : + ∀ z ∈ U, u z = u a := by + have h : SeveralComplexVariables.SubharmonicOn u U := hu + exact h.eqOn_const_of_isMaxOn hU hc ha hmax + +/-- **59. Laplacian criterion**: a `C²` function on an open subset of `ℂ` is subharmonic exactly +when its Laplacian is nonnegative. -/ +theorem subharmonicOn_iff_laplacian_nonneg {g : ℂ → ℝ} {U : Set ℂ} (hU : IsOpen U) + (hg : ContDiffOn ℝ 2 g U) : SubharmonicOn g U ↔ ∀ t ∈ U, 0 ≤ Laplacian.laplacian g t := by + refine ⟨fun h t ht => ?_, + fun h => SeveralComplexVariables.subharmonicOn_of_laplacian_nonneg hU hg h⟩ + exact SeveralComplexVariables.HasSubmeanAt.laplacian_nonneg (hg.contDiffAt (hU.mem_nhds ht)) + (h.2 t ht) + +omit [FiniteDimensional ℂ E] in +/-- **60. Levi-form criterion**: a `C²` function is plurisubharmonic exactly when its Levi form is +positive semidefinite. -/ +theorem plurisubharmonicOn_iff_leviForm_nonneg {f : E → ℝ} {U : Set E} (hU : IsOpen U) + (hf : ContDiffOn ℝ 2 f U) : + PlurisubharmonicOn f U ↔ ∀ a ∈ U, ∀ w : E, 0 ≤ leviForm f a w := by + exact SeveralComplexVariables.plurisubharmonicOn_iff_leviForm_nonneg hU hf + +/-- **61. Domains of holomorphy are pseudoconvex.** -/ +theorem IsDomainOfHolomorphy.isPseudoconvex {U : Set E} (hU : IsDomainOfHolomorphy U) + (ho : IsOpen U) : IsPseudoconvex U := by + have h : SeveralComplexVariables.IsDomainOfHolomorphy U := hU + exact h.isPseudoconvex ho + +omit [FiniteDimensional ℂ E] in +/-- **61. Pseudoconvex sets satisfy the continuity principle** for continuous families of affine +analytic discs. -/ +theorem IsPseudoconvex.continuity_principle {U : Set E} (h : IsPseudoconvex U) (a b : ℝ → E) + (ha : Continuous a) (hb : Continuous b) + (hbdry : ∀ t ∈ Icc (0 : ℝ) 1, ∀ ζ ∈ sphere (0 : ℂ) 1, a t + ζ • b t ∈ U) + (hinit : ∀ ζ ∈ closedBall (0 : ℂ) 1, a 0 + ζ • b 0 ∈ U) : + ∀ t ∈ Icc (0 : ℝ) 1, ∀ ζ ∈ closedBall (0 : ℂ) 1, a t + ζ • b t ∈ U := by + have h' : SeveralComplexVariables.IsPseudoconvex U := h + exact h'.satisfiesContinuityPrinciple a b ha hb hbdry hinit + +/-- **62. Levi's theorem**: a domain of holomorphy satisfies the Levi condition at every boundary +point admitting a local `C²` defining function. -/ +theorem IsDomainOfHolomorphy.isLeviPseudoconvexAt {U : Set E} (hU : IsDomainOfHolomorphy U) + (ho : IsOpen U) {p : E} (hp : p ∈ frontier U) : IsLeviPseudoconvexAt U p := by + have h : SeveralComplexVariables.IsDomainOfHolomorphy U := hU + exact isLeviPseudoconvexAt_iff.mpr (h.isLeviPseudoconvex ho p hp) + +omit [FiniteDimensional ℂ E] in +/-- **63. The Levi form under holomorphic maps.** -/ +theorem leviForm_comp_analytic {G : Type*} [NormedAddCommGroup G] [NormedSpace ℂ G] + [CompleteSpace G] {g : G → ℝ} + {Φ : E → G} {a : E} (hg : ContDiffAt ℝ 2 g (Φ a)) (hΦ : AnalyticAt ℂ Φ a) (w : E) : + leviForm (g ∘ Φ) a w = leviForm g (Φ a) (fderiv ℂ Φ a w) := by + exact SeveralComplexVariables.leviForm_comp_analytic hg hΦ w + +omit [FiniteDimensional ℂ E] in +/-- **64. Independence of the defining function**: the Levi condition may be tested on one local +defining function. -/ +theorem isLeviPseudoconvexAt_iff_of_defining {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + (h : IsLocalDefiningFunction U p ρ V) : + IsLeviPseudoconvexAt U p ↔ ∀ w, IsComplexTangent ρ p w → 0 ≤ leviForm ρ p w := by + rw [isLeviPseudoconvexAt_iff] + exact SeveralComplexVariables.isLeviPseudoconvexAt_iff_of_defining + (isLocalDefiningFunction_iff.mp h) + +/-- **64. Local peak functions** at strictly Levi pseudoconvex boundary points. -/ +theorem exists_local_peak_function {U : Set E} {p : E} {ρ : E → ℝ} {V : Set E} + (h : IsLocalDefiningFunction U p ρ V) + (hstrict : ∀ w, IsComplexTangent ρ p w → w ≠ 0 → 0 < leviForm ρ p w) : + ∃ W ∈ 𝓝 p, ∃ f : E → ℂ, AnalyticOnNhd ℂ f univ ∧ f p = 1 ∧ + ∀ z ∈ W, z ≠ p → ρ z ≤ 0 → ‖f z‖ < 1 := by + exact (isLocalDefiningFunction_iff.mp h).exists_peak hstrict + +/-! ## K. Runge domains and polynomial hulls -/ + +/-- The polynomial hull of `K`. -/ +def polynomialHull {n : ℕ} (K : Set (Fin n → ℂ)) : Set (Fin n → ℂ) := + {z | ∀ P : MvPolynomial (Fin n) ℂ, ∀ M : ℝ, + (∀ w ∈ K, ‖MvPolynomial.eval w P‖ ≤ M) → ‖MvPolynomial.eval z P‖ ≤ M} + +/-- `U` is a Runge domain: holomorphic functions on `U` are approximated by polynomials, uniformly +on compact subsets. -/ +def IsRungeDomain {n : ℕ} (U : Set (Fin n → ℂ)) : Prop := + ∀ f : (Fin n → ℂ) → ℂ, AnalyticOnNhd ℂ f U → ∀ K : Set (Fin n → ℂ), IsCompact K → K ⊆ U → + ∀ ε > 0, ∃ P : MvPolynomial (Fin n) ℂ, ∀ z ∈ K, ‖f z - MvPolynomial.eval z P‖ < ε + +/-- **65. Runge domains**: open complete Reinhardt sets are Runge domains, and in a Runge domain the +polynomial hull of a compact subset meets the domain in its holomorphic hull. -/ +theorem runge_domains {n : ℕ} {U : Set (Fin n → ℂ)} (ho : IsOpen U) : + (IsCompleteReinhardt U → IsRungeDomain U) ∧ + (IsRungeDomain U → ∀ K, IsCompact K → K ⊆ U → + polynomialHull K ∩ U = holomorphicHull U K) := by + refine ⟨fun hc => SeveralComplexVariables.IsCompleteReinhardt.isRungeDomain ho hc, + fun h K hK hKU => ?_⟩ + have h' : SeveralComplexVariables.IsRungeDomain U := h + exact h'.polynomialHull_inter hK hKU + +end SCV + +/- Adapted for Lean Pool: module imports and compatibility with its pinned toolchain. -/ diff --git a/LeanPool/projects.yml b/LeanPool/projects.yml index b284342cec..7e99064629 100644 --- a/LeanPool/projects.yml +++ b/LeanPool/projects.yml @@ -10645,3 +10645,41 @@ projects: - '68W30' - '15A75' - '94D10' + - slug: lean-scv + title: Classical several complex variables + summary: Formalizes Cauchy and Taylor theory, Hartogs phenomena, removable singularities, analytic + sets and germs, Weierstrass theory, holomorphic convexity, Cartan–Thullen and Bochner tube theorems, + plurisubharmonic functions, Levi convexity, and elementary Runge-domain theory. Weierstrass preparation + and coordinate-origin germ Noetherianity overlap LocalComplexGeometry; this development also supplies + germ unique factorization and global extension and convexity results. + branch: complex analysis + entry_module: LeanPool.SeveralComplexVariables + authors: + - Bastiaan J Braams + source: + url: https://github.com/bjbraams/lean-scv + github_repo: bjbraams/lean-scv + commit: caef1ae776ff79933718312357980d46628d3702 + license: Apache-2.0 + status: verified + provenance: AI + main_declarations: + - SeveralComplexVariables.analyticOnNhd_of_separately_analytic_locally_bounded + main_results: + - declaration: SCV.cauchy_formula_polydisc + informal: Holomorphic functions on a polydisc satisfy the iterated Cauchy integral formula. + - declaration: SeveralComplexVariables.analyticOnNhd_of_separately_analytic_locally_bounded + informal: On an open subset of a finite complex coordinate space, a Banach-valued separately analytic + map that is locally bounded is jointly analytic. + source_ref: Boas (2013), Section 2.7, Theorem 7 (the classical two-variable scalar case). + - declaration: SCV.identity_theorem + informal: Holomorphic functions on a connected domain that agree on a nonempty open subset agree + throughout the domain. + tags: + - complex-analysis + - several-complex-variables + - holomorphic-functions + msc: + - 32A10 + - 32D05 + - 32E10