/- Copyright (c) 2019 SΓ©bastien GouΓ«zel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: SΓ©bastien GouΓ«zel -/ module public import Mathlib.Analysis.Asymptotics.AsymptoticEquivalent public import Mathlib.Analysis.Normed.Group.Lemmas public import Mathlib.Analysis.Normed.Affine.Isometry public import Mathlib.Analysis.Normed.Operator.NormedSpace public import Mathlib.Analysis.Normed.Module.RieszLemma public import Mathlib.Analysis.Normed.Module.Ball.Pointwise public import Mathlib.Analysis.SpecificLimits.Normed public import Mathlib.Logic.Encodable.Pi public import Mathlib.Topology.Algebra.AffineSubspace public import Mathlib.Topology.Algebra.Module.FiniteDimension public import Mathlib.Topology.Algebra.InfiniteSum.Module public import Mathlib.Topology.Instances.Matrix public import Mathlib.LinearAlgebra.Dimension.LinearMap public import Mathlib.LinearAlgebra.Dual.Lemmas /-! # Finite-dimensional normed spaces over complete fields Over a complete nontrivially normed field, in finite dimension, all norms are equivalent and all linear maps are continuous. Moreover, a finite-dimensional subspace is always complete and closed. ## Main results: * `FiniteDimensional.complete` : a finite-dimensional space over a complete field is complete. This is not registered as an instance, as the field would be an unknown metavariable in typeclass resolution. * `Submodule.closed_of_finiteDimensional` : a finite-dimensional subspace over a complete field is closed * `FiniteDimensional.proper` : a finite-dimensional space over a proper field is proper. This is not registered as an instance, as the field would be an unknown metavariable in typeclass resolution. It is however registered as an instance for `π•œ = ℝ` and `π•œ = β„‚`. As properness implies completeness, there is no need to also register `FiniteDimensional.complete` on `ℝ` or `β„‚`. * `FiniteDimensional.of_isCompact_closedBall`: Riesz' theorem: if the closed unit ball is compact, then the space is finite-dimensional. ## Implementation notes The fact that all norms are equivalent is not written explicitly, as it would mean having two norms on a single space, which is not the way type classes work. However, if one has a finite-dimensional vector space `E` with a norm, and a copy `E'` of this type with another norm, then the identities from `E` to `E'` and from `E'` to `E` are continuous thanks to `LinearMap.continuous_of_finiteDimensional`. This gives the desired norm equivalence. -/ @[expose] public section universe u v w x noncomputable section open Asymptotics Filter Module Metric Module NNReal Set TopologicalSpace Topology namespace LinearIsometry open LinearMap variable {F E₁ : Type*} [SeminormedAddCommGroup F] [NormedAddCommGroup E₁] variable {R₁ : Type*} [Field R₁] [Module R₁ E₁] [Module R₁ F] [FiniteDimensional R₁ E₁] [FiniteDimensional R₁ F] /-- A linear isometry between finite-dimensional spaces of equal dimension can be upgraded to a linear isometry equivalence. -/ def toLinearIsometryEquiv (li : E₁ β†’β‚—α΅’[R₁] F) (h : finrank R₁ E₁ = finrank R₁ F) : E₁ ≃ₗᡒ[R₁] F where toLinearEquiv := li.toLinearMap.linearEquivOfInjective li.injective h norm_map' := li.norm_map' @[simp] theorem coe_toLinearIsometryEquiv (li : E₁ β†’β‚—α΅’[R₁] F) (h : finrank R₁ E₁ = finrank R₁ F) : (li.toLinearIsometryEquiv h : E₁ β†’ F) = li := rfl @[simp] theorem toLinearIsometryEquiv_apply (li : E₁ β†’β‚—α΅’[R₁] F) (h : finrank R₁ E₁ = finrank R₁ F) (x : E₁) : (li.toLinearIsometryEquiv h) x = li x := rfl end LinearIsometry namespace AffineIsometry open AffineMap variable {π•œ : Type*} {V₁ Vβ‚‚ : Type*} {P₁ Pβ‚‚ : Type*} [NormedField π•œ] [NormedAddCommGroup V₁] [SeminormedAddCommGroup Vβ‚‚] [NormedSpace π•œ V₁] [NormedSpace π•œ Vβ‚‚] [MetricSpace P₁] [PseudoMetricSpace Pβ‚‚] [NormedAddTorsor V₁ P₁] [NormedAddTorsor Vβ‚‚ Pβ‚‚] variable [FiniteDimensional π•œ V₁] [FiniteDimensional π•œ Vβ‚‚] /-- An affine isometry between finite-dimensional spaces of equal dimension can be upgraded to an affine isometry equivalence. -/ def toAffineIsometryEquiv [Inhabited P₁] (li : P₁ →ᡃⁱ[π•œ] Pβ‚‚) (h : finrank π•œ V₁ = finrank π•œ Vβ‚‚) : P₁ ≃ᡃⁱ[π•œ] Pβ‚‚ := AffineIsometryEquiv.mk' li (li.linearIsometry.toLinearIsometryEquiv h) (Inhabited.default (Ξ± := P₁)) fun p => by simp @[simp] theorem coe_toAffineIsometryEquiv [Inhabited P₁] (li : P₁ →ᡃⁱ[π•œ] Pβ‚‚) (h : finrank π•œ V₁ = finrank π•œ Vβ‚‚) : (li.toAffineIsometryEquiv h : P₁ β†’ Pβ‚‚) = li := rfl @[simp] theorem toAffineIsometryEquiv_apply [Inhabited P₁] (li : P₁ →ᡃⁱ[π•œ] Pβ‚‚) (h : finrank π•œ V₁ = finrank π•œ Vβ‚‚) (x : P₁) : (li.toAffineIsometryEquiv h) x = li x := rfl end AffineIsometry section CompleteField variable {π•œ : Type u} [NontriviallyNormedField π•œ] {E : Type v} [NormedAddCommGroup E] [NormedSpace π•œ E] {F : Type w} [NormedAddCommGroup F] [NormedSpace π•œ F] [CompleteSpace π•œ] section Affine variable {PE PF : Type*} [MetricSpace PE] [NormedAddTorsor E PE] [MetricSpace PF] [NormedAddTorsor F PF] [FiniteDimensional π•œ E] theorem AffineMap.continuous_of_finiteDimensional (f : PE →ᡃ[π•œ] PF) : Continuous f := AffineMap.continuous_linear_iff.1 f.linear.continuous_of_finiteDimensional theorem AffineEquiv.continuous_of_finiteDimensional (f : PE ≃ᡃ[π•œ] PF) : Continuous f := f.toAffineMap.continuous_of_finiteDimensional /-- Reinterpret an affine equivalence as a continuous affine equivalence in finite dimension. -/ def AffineEquiv.toContinuousAffineEquiv : (PE ≃ᡃ[π•œ] PF) ≃ (PE ≃ᴬ[π•œ] PF) where toFun f := haveI := f.linear.finiteDimensional ⟨f, f.continuous_of_finiteDimensional, f.symm.continuous_of_finiteDimensional⟩ invFun f := f.toAffineEquiv left_inv _ := rfl right_inv _ := ContinuousAffineEquiv.toAffineEquiv_injective rfl @[simp] theorem AffineEquiv.coe_toContinuousAffineEquiv (f : PE ≃ᡃ[π•œ] PF) : ⇑(toContinuousAffineEquiv f) = f := rfl @[simp] theorem AffineEquiv.toAffineEquiv_toContinuousAffineEquiv (f : PE ≃ᡃ[π•œ] PF) : (toContinuousAffineEquiv f).toAffineEquiv = f := rfl @[simp] theorem AffineEquiv.toContinuousAffineEquiv_symm_apply (f : PE ≃ᴬ[π•œ] PF) : toContinuousAffineEquiv.symm f = f.toAffineEquiv := rfl /-- Reinterpret an affine equivalence as a homeomorphism. -/ def AffineEquiv.toHomeomorphOfFiniteDimensional (f : PE ≃ᡃ[π•œ] PF) : PE β‰ƒβ‚œ PF := (toContinuousAffineEquiv f).toHomeomorph @[simp] theorem AffineEquiv.coe_toHomeomorphOfFiniteDimensional (f : PE ≃ᡃ[π•œ] PF) : ⇑f.toHomeomorphOfFiniteDimensional = f := rfl @[simp] theorem AffineEquiv.coe_toHomeomorphOfFiniteDimensional_symm (f : PE ≃ᡃ[π•œ] PF) : ⇑f.toHomeomorphOfFiniteDimensional.symm = f.symm := rfl attribute [deprecated AffineEquiv.toContinuousAffineEquiv (since := "2026-05-11")] AffineEquiv.toHomeomorphOfFiniteDimensional /-- An affine map from a finite-dimensional space is automatically Lipschitz. -/ theorem AffineMap.lipschitzWith_of_finiteDimensional (f : PE →ᡃ[π•œ] PF) : βˆƒ K : ℝβ‰₯0, LipschitzWith K f := by let fL : E β†’L[π•œ] F := f.linear.toContinuousLinearMap refine βŸ¨β€–fLβ€–β‚Š, LipschitzWith.of_dist_le_mul fun x y ↦ ?_⟩ rw [NormedAddTorsor.dist_eq_norm', NormedAddTorsor.dist_eq_norm', ← f.linearMap_vsub] exact fL.le_opNorm _ end Affine theorem ContinuousLinearMap.continuous_det : Continuous fun f : E β†’L[π•œ] E => f.det := by change Continuous fun f : E β†’L[π•œ] E => LinearMap.det (f : E β†’β‚—[π•œ] E) -- TODO: this could be easier with `det_cases` by_cases h : βˆƒ s : Finset E, Nonempty (Basis (β†₯s) π•œ E) Β· rcases h with ⟨s, ⟨b⟩⟩ haveI : FiniteDimensional π•œ E := b.finiteDimensional_of_finite classical simp_rw [LinearMap.det_eq_det_toMatrix_of_finset b] refine Continuous.matrix_det ?_ exact ((LinearMap.toMatrix b b).toLinearMap.comp (ContinuousLinearMap.coeLM π•œ)).continuous_of_finiteDimensional Β· rw [LinearMap.det] simpa only [h, MonoidHom.one_apply, dif_neg, not_false_iff] using continuous_const /-- Any `K`-Lipschitz map from a subset `s` of a metric space `Ξ±` to a finite-dimensional real vector space `E'` can be extended to a Lipschitz map on the whole space `Ξ±`, with a slightly worse constant `C * K` where `C` only depends on `E'`. We record a working value for this constant `C` as `lipschitzExtensionConstant E'`. -/ irreducible_def lipschitzExtensionConstant (E' : Type*) [NormedAddCommGroup E'] [NormedSpace ℝ E'] [FiniteDimensional ℝ E'] : ℝβ‰₯0 := let A := (Basis.ofVectorSpace ℝ E').equivFun.toContinuousLinearEquiv max (β€–A.symm.toContinuousLinearMapβ€–β‚Š * β€–A.toContinuousLinearMapβ€–β‚Š) 1 theorem lipschitzExtensionConstant_pos (E' : Type*) [NormedAddCommGroup E'] [NormedSpace ℝ E'] [FiniteDimensional ℝ E'] : 0 < lipschitzExtensionConstant E' := by rw [lipschitzExtensionConstant] exact zero_lt_one.trans_le (le_max_right _ _) /-- Any `K`-Lipschitz map from a subset `s` of a metric space `Ξ±` to a finite-dimensional real vector space `E'` can be extended to a Lipschitz map on the whole space `Ξ±`, with a slightly worse constant `lipschitzExtensionConstant E' * K`. -/ theorem LipschitzOnWith.extend_finite_dimension {Ξ± : Type*} [PseudoMetricSpace Ξ±] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace ℝ E'] [FiniteDimensional ℝ E'] {s : Set Ξ±} {f : Ξ± β†’ E'} {K : ℝβ‰₯0} (hf : LipschitzOnWith K f s) : βˆƒ g : Ξ± β†’ E', LipschitzWith (lipschitzExtensionConstant E' * K) g ∧ EqOn f g s := by /- This result is already known for spaces `ΞΉ β†’ ℝ`. We use a continuous linear equiv between `E'` and such a space to transfer the result to `E'`. -/ let ΞΉ : Type _ := Basis.ofVectorSpaceIndex ℝ E' let A := (Basis.ofVectorSpace ℝ E').equivFun.toContinuousLinearEquiv have LA : LipschitzWith β€–A.toContinuousLinearMapβ€–β‚Š A := by apply A.lipschitz have L : LipschitzOnWith (β€–A.toContinuousLinearMapβ€–β‚Š * K) (A ∘ f) s := LA.comp_lipschitzOnWith hf obtain ⟨g, hg, gs⟩ : βˆƒ g : Ξ± β†’ ΞΉ β†’ ℝ, LipschitzWith (β€–A.toContinuousLinearMapβ€–β‚Š * K) g ∧ EqOn (A ∘ f) g s := L.extend_pi refine ⟨A.symm ∘ g, ?_, ?_⟩ Β· have LAsymm : LipschitzWith β€–A.symm.toContinuousLinearMapβ€–β‚Š A.symm := by apply A.symm.lipschitz apply (LAsymm.comp hg).weaken rw [lipschitzExtensionConstant, ← mul_assoc] exact mul_le_mul' (le_max_left _ _) le_rfl Β· intro x hx have : A (f x) = g x := gs hx simp only [(Β· ∘ Β·), ← this, A.symm_apply_apply] theorem LinearMap.exists_antilipschitzWith [FiniteDimensional π•œ E] (f : E β†’β‚—[π•œ] F) (hf : LinearMap.ker f = βŠ₯) : βˆƒ K > 0, AntilipschitzWith K f := by cases subsingleton_or_nontrivial E Β· exact ⟨1, zero_lt_one, AntilipschitzWith.of_subsingleton⟩ Β· rw [LinearMap.ker_eq_bot] at hf let e : E ≃L[π•œ] LinearMap.range f := (LinearEquiv.ofInjective f hf).toContinuousLinearEquiv exact ⟨_, e.nnnorm_symm_pos, e.antilipschitz⟩ open Function in /-- A `LinearMap` on a finite-dimensional space over a complete field is injective iff it is anti-Lipschitz. -/ theorem LinearMap.injective_iff_antilipschitz [FiniteDimensional π•œ E] (f : E β†’β‚—[π•œ] F) : Injective f ↔ βˆƒ K > 0, AntilipschitzWith K f := by constructor Β· rw [← LinearMap.ker_eq_bot] exact f.exists_antilipschitzWith Β· rintro ⟨K, -, H⟩ exact H.injective /-- An injective affine map from a finite-dimensional space is automatically anti-Lipschitz. -/ theorem AffineMap.antilipschitzWith_of_finiteDimensional {PE PF : Type*} [MetricSpace PE] [NormedAddTorsor E PE] [MetricSpace PF] [NormedAddTorsor F PF] [FiniteDimensional π•œ E] {f : PE →ᡃ[π•œ] PF} (hf : Function.Injective f) : βˆƒ K : ℝβ‰₯0, AntilipschitzWith K f := by obtain ⟨K, -, hK⟩ := f.linear.injective_iff_antilipschitz.mp (f.linear_injective_iff.mpr hf) refine ⟨K, AntilipschitzWith.of_le_mul_dist fun x y ↦ ?_⟩ rw [dist_eq_norm_vsub E, dist_eq_norm_vsub F, ← f.linearMap_vsub] exact ZeroHomClass.bound_of_antilipschitz f.linear hK (x -α΅₯ y) open Function in /-- The set of injective continuous linear maps `E β†’ F` is open, if `E` is finite-dimensional over a complete field. -/ theorem ContinuousLinearMap.isOpen_injective [FiniteDimensional π•œ E] : IsOpen { L : E β†’L[π•œ] F | Injective L } := by rw [isOpen_iff_eventually] rintro Ο†β‚€ hΟ†β‚€ rcases Ο†β‚€.injective_iff_antilipschitz.mp hΟ†β‚€ with ⟨K, K_pos, H⟩ have : βˆ€αΆ  Ο† in 𝓝 Ο†β‚€, β€–Ο† - Ο†β‚€β€–β‚Š < K⁻¹ := eventually_nnnorm_sub_lt _ <| inv_pos_of_pos K_pos filter_upwards [this] with Ο† hΟ† apply Ο†.injective_iff_antilipschitz.mpr exact ⟨(K⁻¹ - β€–Ο† - Ο†β‚€β€–β‚Š)⁻¹, inv_pos_of_pos (tsub_pos_of_lt hΟ†), H.add_sub_lipschitzWith (Ο† - Ο†β‚€).lipschitz hΟ†βŸ© open ContinuousLinearMap /-- Continuous linear equivalence between continuous linear functions `π•œβΏ β†’ E` and `Eⁿ`. The spaces `π•œβΏ` and `Eⁿ` are represented as `ΞΉ β†’ π•œ` and `ΞΉ β†’ E`, respectively, where `ΞΉ` is a finite type. -/ def ContinuousLinearEquiv.piRing (ΞΉ : Type*) [Fintype ΞΉ] [DecidableEq ΞΉ] : ((ΞΉ β†’ π•œ) β†’L[π•œ] E) ≃L[π•œ] ΞΉ β†’ E := { LinearMap.toContinuousLinearMap.symm.trans (LinearEquiv.piRing π•œ E ΞΉ π•œ) with continuous_invFun := by simp_rw [LinearEquiv.invFun_eq_symm, LinearEquiv.trans_symm, LinearEquiv.symm_symm] refine AddMonoidHomClass.continuous_of_bound (LinearMap.toContinuousLinearMap.toLinearMap.comp (LinearEquiv.piRing π•œ E ΞΉ π•œ).symm.toLinearMap) (Fintype.card ΞΉ : ℝ) fun g ↦ ?_ rw [← nsmul_eq_mul] refine opNorm_le_bound _ (nsmul_nonneg (norm_nonneg g) (Fintype.card ΞΉ)) fun t ↦ ?_ simp_rw [LinearMap.coe_comp, LinearEquiv.coe_toLinearMap, Function.comp_apply, LinearMap.coe_toContinuousLinearMap', LinearEquiv.piRing_symm_apply] apply le_trans (norm_sum_le _ _) rw [smul_mul_assoc] refine Finset.sum_le_card_nsmul _ _ _ fun i _ ↦ ?_ rw [norm_smul, mul_comm] gcongr <;> apply norm_le_pi_norm } protected theorem LinearIndependent.eventually {ΞΉ} [Finite ΞΉ] {f : ΞΉ β†’ E} (hf : LinearIndependent π•œ f) : βˆ€αΆ  g in 𝓝 f, LinearIndependent π•œ g := by cases nonempty_fintype ΞΉ classical simp only [Fintype.linearIndependent_iff'] at hf ⊒ rcases LinearMap.exists_antilipschitzWith _ hf with ⟨K, K0, hK⟩ have : Tendsto (fun g : ΞΉ β†’ E => βˆ‘ i, β€–g i - f iβ€–) (𝓝 f) (𝓝 <| βˆ‘ i, β€–f i - f iβ€–) := tendsto_finsetSum _ fun i _ => Tendsto.norm <| ((continuous_apply i).tendsto _).sub tendsto_const_nhds simp only [sub_self, norm_zero, Finset.sum_const_zero] at this refine (this.eventually (gt_mem_nhds <| inv_pos.2 K0)).mono fun g hg => ?_ replace hg : βˆ‘ i, β€–g i - f iβ€–β‚Š < K⁻¹ := by rw [← NNReal.coe_lt_coe] push_cast exact hg rw [LinearMap.ker_eq_bot] refine (hK.add_sub_lipschitzWith (LipschitzWith.of_dist_le_mul fun v u => ?_) hg).injective simp only [dist_eq_norm, LinearMap.lsum_apply, Pi.sub_apply, LinearMap.sum_apply, LinearMap.comp_apply, LinearMap.proj_apply, LinearMap.smulRight_apply, LinearMap.id_apply, ← Finset.sum_sub_distrib, ← smul_sub, ← sub_smul, NNReal.coe_sum, coe_nnnorm, Finset.sum_mul] refine norm_sum_le_of_le _ fun i _ => ?_ rw [norm_smul, mul_comm] gcongr exact norm_le_pi_norm (v - u) i theorem isOpen_setOf_linearIndependent {ΞΉ : Type*} [Finite ΞΉ] : IsOpen { f : ΞΉ β†’ E | LinearIndependent π•œ f } := isOpen_iff_mem_nhds.2 fun _ => LinearIndependent.eventually theorem isOpen_setOf_nat_le_rank (n : β„•) : IsOpen { f : E β†’L[π•œ] F | ↑n ≀ (f : E β†’β‚—[π•œ] F).rank } := by simp only [LinearMap.le_rank_iff_exists_linearIndependent_finset, setOf_exists, ← exists_prop] refine isOpen_biUnion fun t _ => ?_ have : Continuous fun f : E β†’L[π•œ] F => fun x : (t : Set E) => f x := continuous_pi fun x => (ContinuousLinearMap.apply π•œ F (x : E)).continuous exact isOpen_setOf_linearIndependent.preimage this theorem isOpen_setOf_affineIndependent {ΞΉ : Type*} [Finite ΞΉ] : IsOpen {p : ΞΉ β†’ E | AffineIndependent π•œ p} := by classical rcases isEmpty_or_nonempty ΞΉ with h | ⟨⟨iβ‚€βŸ©βŸ© Β· exact isOpen_discrete _ Β· simp_rw [affineIndependent_iff_linearIndependent_vsub π•œ _ iβ‚€] let ΞΉ' := { x // x β‰  iβ‚€ } cases nonempty_fintype ΞΉ haveI : Fintype ΞΉ' := Subtype.fintype _ convert_to! IsOpen ((fun (p : ΞΉ β†’ E) (i : ΞΉ') ↦ p i -α΅₯ p iβ‚€) ⁻¹' {p : ΞΉ' β†’ E | LinearIndependent π•œ p}) exact isOpen_setOf_linearIndependent.preimage (by fun_prop) namespace Module.Basis theorem opNNNorm_le {ΞΉ : Type*} [Fintype ΞΉ] (v : Basis ΞΉ π•œ E) {u : E β†’L[π•œ] F} (M : ℝβ‰₯0) (hu : βˆ€ i, β€–u (v i)β€–β‚Š ≀ M) : β€–uβ€–β‚Š ≀ Fintype.card ΞΉ β€’ β€–v.equivFunL.toContinuousLinearMapβ€–β‚Š * M := u.opNNNorm_le_bound _ fun e => by set Ο† := v.equivFunL.toContinuousLinearMap calc β€–u eβ€–β‚Š = β€–u (βˆ‘ i, v.equivFun e i β€’ v i)β€–β‚Š := by rw [v.sum_equivFun] _ = β€–βˆ‘ i, v.equivFun e i β€’ (u <| v i)β€–β‚Š := by simp only [equivFun_apply, map_sum, map_smul] _ ≀ βˆ‘ i, β€–v.equivFun e i β€’ (u <| v i)β€–β‚Š := nnnorm_sum_le _ _ _ = βˆ‘ i, β€–v.equivFun e iβ€–β‚Š * β€–u (v i)β€–β‚Š := by simp only [nnnorm_smul] _ ≀ βˆ‘ i, β€–v.equivFun e iβ€–β‚Š * M := by gcongr; apply hu _ = (βˆ‘ i, β€–v.equivFun e iβ€–β‚Š) * M := by rw [Finset.sum_mul] _ ≀ Fintype.card ΞΉ β€’ (β€–Ο†β€–β‚Š * β€–eβ€–β‚Š) * M := by gcongr calc βˆ‘ i, β€–v.equivFun e iβ€–β‚Š ≀ Fintype.card ΞΉ β€’ β€–Ο† eβ€–β‚Š := Pi.sum_nnnorm_apply_le_nnnorm _ _ ≀ Fintype.card ΞΉ β€’ (β€–Ο†β€–β‚Š * β€–eβ€–β‚Š) := nsmul_le_nsmul_right (Ο†.le_opNNNorm e) _ _ = Fintype.card ΞΉ β€’ β€–Ο†β€–β‚Š * M * β€–eβ€–β‚Š := by simp only [smul_mul_assoc, mul_right_comm] theorem opNorm_le {ΞΉ : Type*} [Fintype ΞΉ] (v : Basis ΞΉ π•œ E) {u : E β†’L[π•œ] F} {M : ℝ} (hM : 0 ≀ M) (hu : βˆ€ i, β€–u (v i)β€– ≀ M) : β€–uβ€– ≀ Fintype.card ΞΉ β€’ β€–v.equivFunL.toContinuousLinearMapβ€– * M := by simpa using! NNReal.coe_le_coe.mpr (v.opNNNorm_le ⟨M, hM⟩ hu) /-- A weaker version of `Basis.opNNNorm_le` that abstracts away the value of `C`. -/ theorem exists_opNNNorm_le {ΞΉ : Type*} [Finite ΞΉ] (v : Basis ΞΉ π•œ E) : βˆƒ C > (0 : ℝβ‰₯0), βˆ€ {u : E β†’L[π•œ] F} (M : ℝβ‰₯0), (βˆ€ i, β€–u (v i)β€–β‚Š ≀ M) β†’ β€–uβ€–β‚Š ≀ C * M := by cases nonempty_fintype ΞΉ exact ⟨max (Fintype.card ΞΉ β€’ β€–v.equivFunL.toContinuousLinearMapβ€–β‚Š) 1, zero_lt_one.trans_le (le_max_right _ _), fun {u} M hu => (v.opNNNorm_le M hu).trans <| mul_le_mul_of_nonneg_right (le_max_left _ _) zero_le⟩ /-- A weaker version of `Basis.opNorm_le` that abstracts away the value of `C`. -/ theorem exists_opNorm_le {ΞΉ : Type*} [Finite ΞΉ] (v : Basis ΞΉ π•œ E) : βˆƒ C > (0 : ℝ), βˆ€ {u : E β†’L[π•œ] F} {M : ℝ}, 0 ≀ M β†’ (βˆ€ i, β€–u (v i)β€– ≀ M) β†’ β€–uβ€– ≀ C * M := by obtain ⟨C, hC, h⟩ := v.exists_opNNNorm_le (F := F) refine ⟨C, hC, ?_⟩ intro u M hM H simpa using! h ⟨M, hM⟩ H end Module.Basis instance [FiniteDimensional π•œ E] [SecondCountableTopology F] : SecondCountableTopology (E β†’L[π•œ] F) := by let d := Module.finrank π•œ E let e₁ : E ≃L[π•œ] Fin d β†’ π•œ := ContinuousLinearEquiv.ofFinrankEq (finrank_fin_fun π•œ).symm let eβ‚‚ : (E β†’L[π•œ] F) ≃L[π•œ] Fin d β†’ F := (e₁.arrowCongr (1 : F ≃L[π•œ] F)).trans (ContinuousLinearEquiv.piRing (Fin d)) exact eβ‚‚.toHomeomorph.secondCountableTopology theorem AffineSubspace.closed_of_finiteDimensional {P : Type*} [MetricSpace P] [NormedAddTorsor E P] (s : AffineSubspace π•œ P) [FiniteDimensional π•œ s.direction] : IsClosed (s : Set P) := s.isClosed_direction_iff.mp s.direction.closed_of_finiteDimensional section Riesz /-- In an infinite-dimensional space, given a finite number of points, one may find a point with norm at most `R` which is at distance at least `1` of all these points. -/ theorem exists_norm_le_le_norm_sub_of_finset {c : π•œ} (hc : 1 < β€–cβ€–) {R : ℝ} (hR : β€–cβ€– < R) (h : Β¬FiniteDimensional π•œ E) (s : Finset E) : βˆƒ x : E, β€–xβ€– ≀ R ∧ βˆ€ y ∈ s, 1 ≀ β€–y - xβ€– := by let F := Submodule.span π•œ (s : Set E) have hF : F.FG := ⟨s, rfl⟩ haveI : FiniteDimensional π•œ F := .of_fg hF have Fclosed : IsClosed (F : Set E) := Submodule.closed_of_finiteDimensional _ have : βˆƒ x, x βˆ‰ F := by contrapose! h have : (⊀ : Submodule π•œ E) = F := by ext x simp [h] rw [← this] at hF exact .of_fg_top hF obtain ⟨x, xR, hx⟩ : βˆƒ x : E, β€–xβ€– ≀ R ∧ βˆ€ y : E, y ∈ F β†’ 1 ≀ β€–x - yβ€– := riesz_lemma_of_norm_lt hc hR Fclosed this have hx' : βˆ€ y : E, y ∈ F β†’ 1 ≀ β€–y - xβ€– := by intro y hy rw [← norm_neg] simpa using hx y hy exact ⟨x, xR, fun y hy => hx' _ (Submodule.subset_span hy)⟩ /-- In an infinite-dimensional normed space, there exists a sequence of points which are all bounded by `R` and at distance at least `1`. For a version not assuming `c` and `R`, see `exists_seq_norm_le_one_le_norm_sub`. -/ theorem exists_seq_norm_le_one_le_norm_sub' {c : π•œ} (hc : 1 < β€–cβ€–) {R : ℝ} (hR : β€–cβ€– < R) (h : Β¬FiniteDimensional π•œ E) : βˆƒ f : β„• β†’ E, (βˆ€ n, β€–f nβ€– ≀ R) ∧ Pairwise fun m n => 1 ≀ β€–f m - f nβ€– := by have : Std.Symm fun x y : E => 1 ≀ β€–x - yβ€– := by constructor intro x y hxy rw [← norm_neg] simpa apply exists_seq_of_forall_finset_exists' (fun x : E => β€–xβ€– ≀ R) fun (x : E) (y : E) => 1 ≀ β€–x - yβ€– rintro s - exact exists_norm_le_le_norm_sub_of_finset hc hR h s theorem exists_seq_norm_le_one_le_norm_sub (h : Β¬FiniteDimensional π•œ E) : βˆƒ (R : ℝ) (f : β„• β†’ E), 1 < R ∧ (βˆ€ n, β€–f nβ€– ≀ R) ∧ Pairwise fun m n => 1 ≀ β€–f m - f nβ€– := by obtain ⟨c, hc⟩ : βˆƒ c : π•œ, 1 < β€–cβ€– := NormedField.exists_one_lt_norm π•œ have A : β€–cβ€– < β€–cβ€– + 1 := by linarith rcases exists_seq_norm_le_one_le_norm_sub' hc A h with ⟨f, hf⟩ exact βŸ¨β€–cβ€– + 1, f, hc.trans A, hf.1, hf.2⟩ variable (π•œ) /-- **Riesz's theorem**: if a closed ball with center zero of positive radius is compact in a vector space, then the space is finite-dimensional. -/ theorem FiniteDimensional.of_isCompact_closedBallβ‚€ {V : Type*} [NormedAddCommGroup V] [Module π•œ V] [ContinuousSMul π•œ V] {r : ℝ} (rpos : 0 < r) (h : IsCompact (Metric.closedBall (0 : V) r)) : FiniteDimensional π•œ V := .of_totallyBounded_nhds_zero π•œ (Metric.closedBall_mem_nhds 0 rpos) h.totallyBounded /-- **Riesz's theorem**: if a closed ball of positive radius is compact in a vector space, then the space is finite-dimensional. -/ theorem FiniteDimensional.of_isCompact_closedBall {V : Type*} [NormedAddCommGroup V] [Module π•œ V] [ContinuousSMul π•œ V] {r : ℝ} (rpos : 0 < r) {c : V} (h : IsCompact (Metric.closedBall c r)) : FiniteDimensional π•œ V := .of_isCompact_closedBallβ‚€ π•œ rpos <| by simpa using h.vadd (-c) /-- A locally compact normed vector space is proper. -/ lemma ProperSpace.of_locallyCompactSpace (π•œ : Type*) [NontriviallyNormedField π•œ] {E : Type*} [SeminormedAddCommGroup E] [NormedSpace π•œ E] [LocallyCompactSpace E] : ProperSpace E := by rcases exists_isCompact_closedBall (0 : E) with ⟨r, rpos, hr⟩ rcases NormedField.exists_one_lt_norm π•œ with ⟨c, hc⟩ have hC : βˆ€ n, IsCompact (closedBall (0 : E) (β€–cβ€– ^ n * r)) := fun n ↦ by have : c ^ n β‰  0 := pow_ne_zero _ <| fun h ↦ by simp [h, zero_le_one.not_gt] at hc simpa [_root_.smul_closedBall' this] using hr.smul (c ^ n) have hTop : Tendsto (fun n ↦ β€–cβ€– ^ n * r) atTop atTop := Tendsto.atTop_mul_const rpos (tendsto_pow_atTop_atTop_of_one_lt hc) exact .of_seq_closedBall hTop (Eventually.of_forall hC) lemma ProperSpace.of_locallyCompact_module (V : Type*) [AddCommGroup V] [TopologicalSpace V] [IsTopologicalAddGroup V] [T2Space V] [Nontrivial V] [LocallyCompactSpace V] [Module π•œ V] [ContinuousSMul π•œ V] : ProperSpace π•œ := have : LocallyCompactSpace π•œ := by obtain ⟨v, hv⟩ : βˆƒ v : V, v β‰  0 := exists_ne 0 let L : π•œ β†’ V := fun t ↦ t β€’ v have : IsClosedEmbedding L := isClosedEmbedding_smul_left hv apply IsClosedEmbedding.locallyCompactSpace this .of_locallyCompactSpace π•œ end Riesz open ContinuousLinearMap /-- A family of continuous linear maps is continuous within `s` at `x` iff all its applications are. -/ theorem continuousWithinAt_clm_apply {X : Type*} [TopologicalSpace X] [FiniteDimensional π•œ E] {f : X β†’ E β†’L[π•œ] F} {s : Set X} {x : X} : ContinuousWithinAt f s x ↔ βˆ€ y, ContinuousWithinAt (fun q ↦ f q y) s x := by refine ⟨fun h y ↦ (apply π•œ F y).continuous.continuousAt.comp_continuousWithinAt h, fun h ↦ ?_⟩ let e : (E β†’L[π•œ] F) ≃L[π•œ] Fin (finrank π•œ E) β†’ F := ((ContinuousLinearEquiv.ofFinrankEq (finrank_fin_fun π•œ).symm).arrowCongr (1 : F ≃L[π•œ] F)).trans (ContinuousLinearEquiv.piRing _) rw [e.toHomeomorph.isInducing.continuousWithinAt_iff] exact continuousWithinAt_pi.mpr fun i ↦ h _ /-- A family of continuous linear maps is continuous on `s` iff all its applications are. -/ theorem continuousOn_clm_apply {X : Type*} [TopologicalSpace X] [FiniteDimensional π•œ E] {f : X β†’ E β†’L[π•œ] F} {s : Set X} : ContinuousOn f s ↔ βˆ€ y, ContinuousOn (fun x ↦ f x y) s := by simp_rw [ContinuousOn, continuousWithinAt_clm_apply, imp_forall_iff] exact forall_comm /-- A family of continuous linear maps is continuous at a point iff all its applications are. -/ theorem continuousAt_clm_apply {X : Type*} [TopologicalSpace X] [FiniteDimensional π•œ E] {f : X β†’ E β†’L[π•œ] F} {x : X} : ContinuousAt f x ↔ βˆ€ y, ContinuousAt (fun q ↦ f q y) x := by simp_rw [← continuousWithinAt_univ, continuousWithinAt_clm_apply] theorem continuous_clm_apply {X : Type*} [TopologicalSpace X] [FiniteDimensional π•œ E] {f : X β†’ E β†’L[π•œ] F} : Continuous f ↔ βˆ€ y, Continuous (f Β· y) := by simp_rw [← continuousOn_univ, continuousOn_clm_apply] end CompleteField section LocallyCompactField variable (π•œ : Type u) [NontriviallyNormedField π•œ] (E : Type v) [NormedAddCommGroup E] [NormedSpace π•œ E] [LocallyCompactSpace π•œ] /-- Any finite-dimensional vector space over a locally compact field is proper. We do not register this as an instance to avoid an instance loop when trying to prove the properness of `π•œ`, and the search for `π•œ` as an unknown metavariable. Declare the instance explicitly when needed. -/ theorem FiniteDimensional.proper [FiniteDimensional π•œ E] : ProperSpace E := by have : ProperSpace π•œ := .of_locallyCompactSpace π•œ set e := ContinuousLinearEquiv.ofFinrankEq (@finrank_fin_fun π•œ _ _ (finrank π•œ E)).symm exact e.symm.antilipschitz.properSpace e.symm.continuous e.symm.surjective end LocallyCompactField /-- Over the real numbers, we can register the previous statement as an instance as it will not cause problems in instance resolution since the properness of `ℝ` is already known. -/ instance (priority := 900) FiniteDimensional.proper_real (E : Type u) [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] : ProperSpace E := FiniteDimensional.proper ℝ E /-- A submodule of a locally compact space over a complete field is also locally compact (and even proper). -/ instance {π•œ E : Type*} [NontriviallyNormedField π•œ] [CompleteSpace π•œ] [NormedAddCommGroup E] [NormedSpace π•œ E] [LocallyCompactSpace E] (S : Submodule π•œ E) : ProperSpace S := by nontriviality E have : ProperSpace π•œ := .of_locallyCompact_module π•œ E have : FiniteDimensional π•œ E := .of_locallyCompactSpace π•œ exact FiniteDimensional.proper π•œ S /-- If `E` is a finite-dimensional normed real vector space, `x : E`, and `s` is a neighborhood of `x` that is not equal to the whole space, then there exists a point `y ∈ frontier s` at distance `Metric.infDist x sᢜ` from `x`. See also `IsCompact.exists_mem_frontier_infDist_compl_eq_dist`. -/ theorem exists_mem_frontier_infDist_compl_eq_dist {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {x : E} {s : Set E} (hx : x ∈ s) (hs : s β‰  univ) : βˆƒ y ∈ frontier s, Metric.infDist x sᢜ = dist x y := by rcases Metric.exists_mem_closure_infDist_eq_dist (nonempty_compl.2 hs) x with ⟨y, hys, hyd⟩ rw [closure_compl] at hys refine ⟨y, ⟨Metric.closedBall_infDist_compl_subset_closure hx <| Metric.mem_closedBall.2 <| ge_of_eq ?_, hys⟩, hyd⟩ rwa [dist_comm] /-- If `K` is a compact set in a nontrivial real normed space and `x ∈ K`, then there exists a point `y` of the boundary of `K` at distance `Metric.infDist x Kᢜ` from `x`. See also `exists_mem_frontier_infDist_compl_eq_dist`. -/ nonrec theorem IsCompact.exists_mem_frontier_infDist_compl_eq_dist {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [Nontrivial E] {x : E} {K : Set E} (hK : IsCompact K) (hx : x ∈ K) : βˆƒ y ∈ frontier K, Metric.infDist x Kᢜ = dist x y := by obtain hx' | hx' : x ∈ interior K βˆͺ frontier K := by rw [← closure_eq_interior_union_frontier] exact subset_closure hx Β· rw [mem_interior_iff_mem_nhds, Metric.nhds_basis_closedBall.mem_iff] at hx' rcases hx' with ⟨r, hrβ‚€, hrK⟩ have : FiniteDimensional ℝ E := .of_isCompact_closedBall ℝ hrβ‚€ (hK.of_isClosed_subset Metric.isClosed_closedBall hrK) exact exists_mem_frontier_infDist_compl_eq_dist hx hK.ne_univ Β· refine ⟨x, hx', ?_⟩ rw [frontier_eq_closure_inter_closure] at hx' rw [Metric.infDist_zero_of_mem_closure hx'.2, dist_self] /-- In a finite-dimensional vector space over `ℝ`, the series `βˆ‘ x, β€–f xβ€–` is unconditionally summable if and only if the series `βˆ‘ x, f x` is unconditionally summable. One implication holds in any complete normed space, while the other holds only in finite-dimensional spaces. -/ theorem summable_norm_iff {Ξ± E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {f : Ξ± β†’ E} : (Summable fun x => β€–f xβ€–) ↔ Summable f := by refine ⟨Summable.of_norm, fun hf ↦ ?_⟩ -- First we use a finite basis to reduce the problem to the case `E = Fin N β†’ ℝ` suffices βˆ€ {N : β„•} {g : Ξ± β†’ Fin N β†’ ℝ}, Summable g β†’ Summable fun x => β€–g xβ€– by obtain v := Module.finBasis ℝ E set e := v.equivFunL have H : Summable fun x => β€–e (f x)β€– := this (e.summable.2 hf) refine .of_norm_bounded (H.mul_left ↑‖(e.symm : (Fin (finrank ℝ E) β†’ ℝ) β†’L[ℝ] E)β€–β‚Š) fun i ↦ ?_ simpa using (e.symm : (Fin (finrank ℝ E) β†’ ℝ) β†’L[ℝ] E).le_opNorm (e <| f i) clear! E -- Now we deal with `g : Ξ± β†’ Fin N β†’ ℝ` intro N g hg have : βˆ€ i, Summable fun x => β€–g x iβ€– := fun i => (Pi.summable.1 hg i).abs refine .of_norm_bounded (summable_sum fun i (_ : i ∈ Finset.univ) => this i) fun x => ?_ rw [norm_norm, pi_norm_le_iff_of_nonneg] Β· refine fun i => Finset.single_le_sum (f := fun i => β€–g x iβ€–) (fun i _ => ?_) (Finset.mem_univ i) exact norm_nonneg (g x i) Β· exact Finset.sum_nonneg fun _ _ => norm_nonneg _ alias ⟨_, Summable.norm⟩ := summable_norm_iff theorem summable_of_sum_range_norm_le {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {c : ℝ} {f : β„• β†’ E} (h : βˆ€ n, βˆ‘ i ∈ Finset.range n, β€–f iβ€– ≀ c) : Summable f := summable_norm_iff.mp <| summable_of_sum_range_le (fun _ ↦ norm_nonneg _) h theorem summable_of_isBigO' {ΞΉ E F : Type*} [NormedAddCommGroup E] [CompleteSpace E] [NormedAddCommGroup F] [NormedSpace ℝ F] [FiniteDimensional ℝ F] {f : ΞΉ β†’ E} {g : ΞΉ β†’ F} (hg : Summable g) (h : f =O[cofinite] g) : Summable f := summable_of_isBigO hg.norm h.norm_right lemma Asymptotics.IsBigO.comp_summable {ΞΉ E F : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] [NormedAddCommGroup F] [CompleteSpace F] {f : E β†’ F} (hf : f =O[𝓝 0] id) {g : ΞΉ β†’ E} (hg : Summable g) : Summable (f ∘ g) := .of_norm <| hf.comp_summable_norm hg.norm theorem summable_of_isBigO_nat' {E F : Type*} [NormedAddCommGroup E] [CompleteSpace E] [NormedAddCommGroup F] [NormedSpace ℝ F] [FiniteDimensional ℝ F] {f : β„• β†’ E} {g : β„• β†’ F} (hg : Summable g) (h : f =O[atTop] g) : Summable f := summable_of_isBigO_nat hg.norm h.norm_right open Nat Asymptotics in /-- This is a version of `summable_norm_mul_geometric_of_norm_lt_one` for more general codomains. We keep the original one due to import restrictions. -/ theorem summable_norm_mul_geometric_of_norm_lt_one' {F : Type*} [NormedRing F] [NormOneClass F] [NormMulClass F] {k : β„•} {r : F} (hr : β€–rβ€– < 1) {u : β„• β†’ F} (hu : u =O[atTop] fun n ↦ ((n ^ k : β„•) : F)) : Summable fun n : β„• ↦ β€–u n * r ^ nβ€– := by rcases exists_between hr with ⟨r', hrr', h⟩ apply summable_of_isBigO_nat (summable_geometric_of_lt_one ((norm_nonneg _).trans hrr'.le) h).norm calc fun n ↦ β€–(u n) * r ^ nβ€– _ =O[atTop] fun n ↦ β€–u nβ€– * β€–rβ€– ^ n := by apply (IsBigOWith.of_bound (c := β€–(1 : ℝ)β€–) ?_).isBigO filter_upwards [eventually_norm_pow_le r] with n hn simp _ =O[atTop] fun n ↦ β€–((n : F) ^ k)β€– * β€–rβ€– ^ n := by simpa [Nat.cast_pow] using (isBigO_norm_left.mpr (isBigO_norm_right.mpr hu)).mul (isBigO_refl (fun n ↦ (β€–rβ€– ^ n)) atTop) _ =O[atTop] fun n ↦ β€–r' ^ nβ€– := by convert! isBigO_norm_right.mpr (isBigO_norm_left.mpr (isLittleO_pow_const_mul_const_pow_const_pow_of_norm_lt k hrr').isBigO) simp only [norm_pow, norm_mul] theorem summable_of_isEquivalent {ΞΉ E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {f : ΞΉ β†’ E} {g : ΞΉ β†’ E} (hg : Summable g) (h : f ~[cofinite] g) : Summable f := summable_of_isBigO' hg h.isBigO theorem summable_of_isEquivalent_nat {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {f : β„• β†’ E} {g : β„• β†’ E} (hg : Summable g) (h : f ~[atTop] g) : Summable f := summable_of_isBigO_nat' hg h.isBigO theorem Asymptotics.IsTheta.summable_iff {ΞΉ E F : Type*} [NormedAddCommGroup E] [NormedAddCommGroup F] [NormedSpace ℝ E] [NormedSpace ℝ F] [FiniteDimensional ℝ E] [FiniteDimensional ℝ F] {f : ΞΉ β†’ E} {g : ΞΉ β†’ F} (h : f =Θ[cofinite] g) : Summable f ↔ Summable g := ⟨fun hf => summable_of_isBigO' hf h.isBigO_symm, fun hg => summable_of_isBigO' hg h.isBigO⟩ theorem Asymptotics.IsTheta.summable_iff_nat {E F : Type*} [NormedAddCommGroup E] [NormedAddCommGroup F] [NormedSpace ℝ E] [NormedSpace ℝ F] [FiniteDimensional ℝ E] [FiniteDimensional ℝ F] {f : β„• β†’ E} {g : β„• β†’ F} (h : f =Θ[atTop] g) : Summable f ↔ Summable g := IsTheta.summable_iff <| by simpa [← Nat.cofinite_eq_atTop] using h theorem Asymptotics.IsEquivalent.summable_iff {ΞΉ E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {f : ΞΉ β†’ E} {g : ΞΉ β†’ E} (h : f ~[cofinite] g) : Summable f ↔ Summable g := h.isTheta.summable_iff @[deprecated (since := "2026-02-07")] alias IsEquivalent.summable_iff := Asymptotics.IsEquivalent.summable_iff theorem Asymptotics.IsEquivalent.summable_iff_nat {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {f : β„• β†’ E} {g : β„• β†’ E} (h : f ~[atTop] g) : Summable f ↔ Summable g := h.isTheta.summable_iff_nat @[deprecated (since := "2026-02-07")] alias IsEquivalent.summable_iff_nat := Asymptotics.IsEquivalent.summable_iff_nat namespace Module.Basis variable {ΞΉ R M : Type*} [Finite ΞΉ] [NontriviallyNormedField R] [CompleteSpace R] [AddCommGroup M] [TopologicalSpace M] [IsTopologicalAddGroup M] [T2Space M] [Module R M] [ContinuousSMul R M] (B : Module.Basis ΞΉ R M) -- Note that Finsupp has no topology so we need the coercion, see -- https://leanprover.zulipchat.com/#narrow/channel/217875-Is-there-code-for-X.3F/topic/TVS.20and.20NormedSpace.20on.20Finsupp.2C.20DFinsupp.2C.20DirectSum.2C.20.2E.2E/near/512890984 theorem continuous_coe_repr : Continuous (fun m : M => ⇑(B.repr m)) := have := Finite.of_basis B LinearMap.continuous_of_finiteDimensional B.equivFun.toLinearMap -- Note: this could be generalized if we had some typeclass to indicate "each of the projections -- into the basis is continuous". theorem continuous_toMatrix : Continuous fun (v : ΞΉ β†’ M) => B.toMatrix v := let _ := Fintype.ofFinite ΞΉ have := Finite.of_basis B LinearMap.continuous_of_finiteDimensional B.toMatrixEquiv.toLinearMap end Module.Basis