Skip to content

Commit

Permalink
feat: allow the Open Mapping Theorem to apply to semilinear maps (#11722
Browse files Browse the repository at this point in the history
)

this generalizes the Open Mapping Theorem for Banach spaces to semilinear maps. 

For now, we don't generalize the closed graph theorem. This is not because it's impossible, but only that it's currently prohibitively difficult since `LinearMap.graph` doesn't make sense for semilinear maps.
  • Loading branch information
j-loreaux committed Apr 4, 2024
1 parent 9740087 commit d11fcd1
Showing 1 changed file with 57 additions and 46 deletions.
103 changes: 57 additions & 46 deletions Mathlib/Analysis/NormedSpace/Banach.lean
Expand Up @@ -23,8 +23,11 @@ open Function Metric Set Filter Finset Topology BigOperators NNReal

open LinearMap (range ker)

variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E]
[NormedSpace 𝕜 E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] (f : E →L[𝕜] F)
variable {𝕜 𝕜' : Type*} [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜'] {σ : 𝕜 →+* 𝕜'}
{σ' : 𝕜' →+* 𝕜} [RingHomInvPair σ σ'] [RingHomInvPair σ' σ] [RingHomIsometric σ]
[RingHomIsometric σ']
variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜' F] (f : E →SL[σ] F)

namespace ContinuousLinearMap

Expand All @@ -43,12 +46,12 @@ instance : CoeFun (NonlinearRightInverse f) fun _ => F → E :=
fun fsymm => fsymm.toFun⟩

@[simp]
theorem NonlinearRightInverse.right_inv {f : E →L[𝕜] F} (fsymm : NonlinearRightInverse f) (y : F) :
theorem NonlinearRightInverse.right_inv {f : E →SL[σ] F} (fsymm : NonlinearRightInverse f) (y : F) :
f (fsymm y) = y :=
fsymm.right_inv' y
#align continuous_linear_map.nonlinear_right_inverse.right_inv ContinuousLinearMap.NonlinearRightInverse.right_inv

theorem NonlinearRightInverse.bound {f : E →L[𝕜] F} (fsymm : NonlinearRightInverse f) (y : F) :
theorem NonlinearRightInverse.bound {f : E →SL[σ] F} (fsymm : NonlinearRightInverse f) (y : F) :
‖fsymm y‖ ≤ fsymm.nnnorm * ‖y‖ :=
fsymm.bound' y
#align continuous_linear_map.nonlinear_right_inverse.bound ContinuousLinearMap.NonlinearRightInverse.bound
Expand All @@ -57,16 +60,16 @@ end ContinuousLinearMap

/-- Given a continuous linear equivalence, the inverse is in particular an instance of
`ContinuousLinearMap.NonlinearRightInverse` (which turns out to be linear). -/
noncomputable def ContinuousLinearEquiv.toNonlinearRightInverse (f : E ≃L[𝕜] F) :
ContinuousLinearMap.NonlinearRightInverse (f : E →L[𝕜] F) where
noncomputable def ContinuousLinearEquiv.toNonlinearRightInverse (f : E ≃SL[σ] F) :
ContinuousLinearMap.NonlinearRightInverse (f : E →SL[σ] F) where
toFun := f.invFun
nnnorm := ‖(f.symm : F →L[𝕜] E)‖₊
bound' _ := ContinuousLinearMap.le_opNorm (f.symm : F →L[𝕜] E) _
nnnorm := ‖(f.symm : F →SL[σ'] E)‖₊
bound' _ := ContinuousLinearMap.le_opNorm (f.symm : F →SL[σ'] E) _
right_inv' := f.apply_symm_apply
#align continuous_linear_equiv.to_nonlinear_right_inverse ContinuousLinearEquiv.toNonlinearRightInverse

noncomputable instance (f : E ≃L[𝕜] F) :
Inhabited (ContinuousLinearMap.NonlinearRightInverse (f : E →L[𝕜] F)) :=
noncomputable instance (f : E ≃SL[σ] F) :
Inhabited (ContinuousLinearMap.NonlinearRightInverse (f : E →SL[σ] F)) :=
⟨f.toNonlinearRightInverse⟩

/-! ### Proof of the Banach open mapping theorem -/
Expand Down Expand Up @@ -100,7 +103,8 @@ theorem exists_approx_preimage_norm_le (surj : Surjective f) :
rcases eq_or_ne y 0 with rfl | hy
· use 0
simp
· rcases rescale_to_shell hc (half_pos εpos) hy with ⟨d, hd, ydlt, -, dinv⟩
· have hc' : 1 < ‖σ c‖ := by simp only [RingHomIsometric.is_iso, hc]
rcases rescale_to_shell hc' (half_pos εpos) hy with ⟨d, hd, ydlt, -, dinv⟩
let δ := ‖d‖ * ‖y‖ / 4
have δpos : 0 < δ := div_pos (mul_pos (norm_pos_iff.2 hd) (norm_pos_iff.2 hy)) (by norm_num)
have : a + d • y ∈ ball a ε := by
Expand All @@ -126,10 +130,11 @@ theorem exists_approx_preimage_norm_le (surj : Surjective f) :
_ ≤ ‖f x₁ - (a + d • y)‖ + ‖f x₂ - a‖ := (norm_sub_le _ _)
_ ≤ δ + δ := by rw [dist_eq_norm'] at h₁ h₂; gcongr
_ = 2 * δ := (two_mul _).symm
have J : ‖f (d⁻¹ • x) - y‖ ≤ 1 / 2 * ‖y‖ :=
have J : ‖f (σ' d⁻¹ • x) - y‖ ≤ 1 / 2 * ‖y‖ :=
calc
‖f (d⁻¹ • x) - y‖ = ‖d⁻¹ • f x - (d⁻¹ * d) • y‖ := by
rwa [f.map_smul _, inv_mul_cancel, one_smul]
‖f (σ' d⁻¹ • x) - y‖ = ‖d⁻¹ • f x - (d⁻¹ * d) • y‖ := by
rwa [f.map_smulₛₗ _, inv_mul_cancel, one_smul, map_inv₀, map_inv₀,
RingHomCompTriple.comp_apply, RingHom.id_apply]
_ = ‖d⁻¹ • (f x - d • y)‖ := by rw [mul_smul, smul_sub]
_ = ‖d‖⁻¹ * ‖f x - d • y‖ := by rw [norm_smul, norm_inv]
_ ≤ ‖d‖⁻¹ * (2 * δ) := by gcongr
Expand All @@ -141,14 +146,15 @@ theorem exists_approx_preimage_norm_le (surj : Surjective f) :
simp [norm_eq_zero, hd]
_ = 1 / 2 * ‖y‖ := by ring
rw [← dist_eq_norm] at J
have K : ‖d⁻¹ • x‖ ≤ (ε / 2)⁻¹ * ‖c‖ * 2 * ↑n * ‖y‖ :=
have K : ‖σ' d⁻¹ • x‖ ≤ (ε / 2)⁻¹ * ‖c‖ * 2 * ↑n * ‖y‖ :=
calc
‖d⁻¹ • x‖ = ‖d‖⁻¹ * ‖x₁ - x₂‖ := by rw [norm_smul, norm_inv]
σ' d⁻¹ • x‖ = ‖d‖⁻¹ * ‖x₁ - x₂‖ := by rw [norm_smul, RingHomIsometric.is_iso, norm_inv]
_ ≤ (ε / 2)⁻¹ * ‖c‖ * ‖y‖ * (n + n) := by
gcongr
exact le_trans (norm_sub_le _ _) (by gcongr)
· simpa using dinv
· exact le_trans (norm_sub_le _ _) (by gcongr)
_ = (ε / 2)⁻¹ * ‖c‖ * 2 * ↑n * ‖y‖ := by ring
exact ⟨d⁻¹ • x, J, K⟩
exact ⟨σ' d⁻¹ • x, J, K⟩
#align continuous_linear_map.exists_approx_preimage_norm_le ContinuousLinearMap.exists_approx_preimage_norm_le

variable [CompleteSpace E]
Expand Down Expand Up @@ -250,9 +256,10 @@ protected theorem quotientMap (surj : Surjective f) : QuotientMap f :=
(f.isOpenMap surj).to_quotientMap f.continuous surj
#align continuous_linear_map.quotient_map ContinuousLinearMap.quotientMap

theorem _root_.AffineMap.isOpenMap {P Q : Type*} [MetricSpace P] [NormedAddTorsor E P]
[MetricSpace Q] [NormedAddTorsor F Q] (f : P →ᵃ[𝕜] Q) (hf : Continuous f)
(surj : Surjective f) : IsOpenMap f :=
theorem _root_.AffineMap.isOpenMap {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
[CompleteSpace F] {P Q : Type*} [MetricSpace P] [NormedAddTorsor E P] [MetricSpace Q]
[NormedAddTorsor F Q] (f : P →ᵃ[𝕜] Q) (hf : Continuous f) (surj : Surjective f) :
IsOpenMap f :=
AffineMap.isOpenMap_linear_iff.mp <|
ContinuousLinearMap.isOpenMap { f.linear with cont := AffineMap.continuous_linear_iff.mpr hf }
(f.linear_surjective_iff.mpr surj)
Expand All @@ -275,7 +282,8 @@ theorem frontier_preimage (hsurj : Surjective f) (s : Set F) :
((f.isOpenMap hsurj).preimage_frontier_eq_frontier_preimage f.continuous s).symm
#align continuous_linear_map.frontier_preimage ContinuousLinearMap.frontier_preimage

theorem exists_nonlinearRightInverse_of_surjective (f : E →L[𝕜] F) (hsurj : LinearMap.range f = ⊤) :
theorem exists_nonlinearRightInverse_of_surjective (f : E →SL[σ] F)
(hsurj : LinearMap.range f = ⊤) :
∃ fsymm : NonlinearRightInverse f, 0 < fsymm.nnnorm := by
choose C hC fsymm h using exists_preimage_norm_le _ (LinearMap.range_eq_top.mp hsurj)
use {
Expand All @@ -290,12 +298,12 @@ theorem exists_nonlinearRightInverse_of_surjective (f : E →L[𝕜] F) (hsurj :
controlled right inverse. In general, it is not possible to ensure that such a right inverse
is linear (take for instance the map from `E` to `E/F` where `F` is a closed subspace of `E`
without a closed complement. Then it doesn't have a continuous linear right inverse.) -/
noncomputable irreducible_def nonlinearRightInverseOfSurjective (f : E →L[𝕜] F)
noncomputable irreducible_def nonlinearRightInverseOfSurjective (f : E →SL[σ] F)
(hsurj : LinearMap.range f = ⊤) : NonlinearRightInverse f :=
Classical.choose (exists_nonlinearRightInverse_of_surjective f hsurj)
#align continuous_linear_map.nonlinear_right_inverse_of_surjective ContinuousLinearMap.nonlinearRightInverseOfSurjective

theorem nonlinearRightInverseOfSurjective_nnnorm_pos (f : E →L[𝕜] F)
theorem nonlinearRightInverseOfSurjective_nnnorm_pos (f : E →SL[σ] F)
(hsurj : LinearMap.range f = ⊤) : 0 < (nonlinearRightInverseOfSurjective f hsurj).nnnorm := by
rw [nonlinearRightInverseOfSurjective]
exact Classical.choose_spec (exists_nonlinearRightInverse_of_surjective f hsurj)
Expand All @@ -309,31 +317,31 @@ variable [CompleteSpace E]

/-- If a bounded linear map is a bijection, then its inverse is also a bounded linear map. -/
@[continuity]
theorem continuous_symm (e : E ≃ₗ[𝕜] F) (h : Continuous e) : Continuous e.symm := by
theorem continuous_symm (e : E ≃ₛₗ[σ] F) (h : Continuous e) : Continuous e.symm := by
rw [continuous_def]
intro s hs
rw [← e.image_eq_preimage]
rw [← e.coe_coe] at h ⊢
exact ContinuousLinearMap.isOpenMap (𝕜 := 𝕜) ⟨↑e, h⟩ e.surjective s hs
exact ContinuousLinearMap.isOpenMap (σ := σ) ⟨↑e, h⟩ e.surjective s hs
#align linear_equiv.continuous_symm LinearEquiv.continuous_symm

/-- Associating to a linear equivalence between Banach spaces a continuous linear equivalence when
the direct map is continuous, thanks to the Banach open mapping theorem that ensures that the
inverse map is also continuous. -/
def toContinuousLinearEquivOfContinuous (e : E ≃ₗ[𝕜] F) (h : Continuous e) : E ≃L[𝕜] F :=
def toContinuousLinearEquivOfContinuous (e : E ≃ₛₗ[σ] F) (h : Continuous e) : E ≃SL[σ] F :=
{ e with
continuous_toFun := h
continuous_invFun := e.continuous_symm h }
#align linear_equiv.to_continuous_linear_equiv_of_continuous LinearEquiv.toContinuousLinearEquivOfContinuous

@[simp]
theorem coeFn_toContinuousLinearEquivOfContinuous (e : E ≃ₗ[𝕜] F) (h : Continuous e) :
theorem coeFn_toContinuousLinearEquivOfContinuous (e : E ≃ₛₗ[σ] F) (h : Continuous e) :
⇑(e.toContinuousLinearEquivOfContinuous h) = e :=
rfl
#align linear_equiv.coe_fn_to_continuous_linear_equiv_of_continuous LinearEquiv.coeFn_toContinuousLinearEquivOfContinuous

@[simp]
theorem coeFn_toContinuousLinearEquivOfContinuous_symm (e : E ≃ₗ[𝕜] F) (h : Continuous e) :
theorem coeFn_toContinuousLinearEquivOfContinuous_symm (e : E ≃ₛₗ[σ] F) (h : Continuous e) :
⇑(e.toContinuousLinearEquivOfContinuous h).symm = e.symm :=
rfl
#align linear_equiv.coe_fn_to_continuous_linear_equiv_of_continuous_symm LinearEquiv.coeFn_toContinuousLinearEquivOfContinuous_symm
Expand All @@ -346,19 +354,19 @@ variable [CompleteSpace E]

/-- An injective continuous linear map with a closed range defines a continuous linear equivalence
between its domain and its range. -/
noncomputable def equivRange (f : E →L[𝕜] F) (hinj : Injective f) (hclo : IsClosed (range f)) :
E ≃L[𝕜] LinearMap.range f :=
noncomputable def equivRange (f : E →SL[σ] F) (hinj : Injective f) (hclo : IsClosed (range f)) :
E ≃SL[σ] LinearMap.range f :=
have : CompleteSpace (LinearMap.range f) := hclo.completeSpace_coe
LinearEquiv.toContinuousLinearEquivOfContinuous (LinearEquiv.ofInjective f.toLinearMap hinj) <|
(f.continuous.codRestrict fun x ↦ LinearMap.mem_range_self f x).congr fun _ ↦ rfl

@[simp]
theorem coe_linearMap_equivRange (f : E →L[𝕜] F) (hinj : Injective f) (hclo : IsClosed (range f)) :
theorem coe_linearMap_equivRange (f : E →SL[σ] F) (hinj : Injective f) (hclo : IsClosed (range f)) :
f.equivRange hinj hclo = f.rangeRestrict :=
rfl

@[simp]
theorem coe_equivRange (f : E →L[𝕜] F) (hinj : Injective f) (hclo : IsClosed (range f)) :
theorem coe_equivRange (f : E →SL[σ] F) (hinj : Injective f) (hclo : IsClosed (range f)) :
(f.equivRange hinj hclo : E → LinearMap.range f) = f.rangeRestrict :=
rfl

Expand All @@ -368,10 +376,10 @@ namespace ContinuousLinearEquiv

variable [CompleteSpace E]

/-- Convert a bijective continuous linear map `f : E →L[𝕜] F` from a Banach space to a normed space
/-- Convert a bijective continuous linear map `f : E →SL[σ] F` from a Banach space to a normed space
to a continuous linear equivalence. -/
noncomputable def ofBijective (f : E →L[𝕜] F) (hinj : ker f = ⊥) (hsurj : LinearMap.range f = ⊤) :
E ≃L[𝕜] F :=
noncomputable def ofBijective (f : E →SL[σ] F) (hinj : ker f = ⊥) (hsurj : LinearMap.range f = ⊤) :
E ≃SL[σ] F :=
(LinearEquiv.ofBijective ↑f
⟨LinearMap.ker_eq_bot.mp hinj,
LinearMap.range_eq_top.mp hsurj⟩).toContinuousLinearEquivOfContinuous
Expand All @@ -380,25 +388,25 @@ noncomputable def ofBijective (f : E →L[𝕜] F) (hinj : ker f = ⊥) (hsurj :
#align continuous_linear_equiv.of_bijective ContinuousLinearEquiv.ofBijective

@[simp]
theorem coeFn_ofBijective (f : E →L[𝕜] F) (hinj : ker f = ⊥) (hsurj : LinearMap.range f = ⊤) :
theorem coeFn_ofBijective (f : E →SL[σ] F) (hinj : ker f = ⊥) (hsurj : LinearMap.range f = ⊤) :
⇑(ofBijective f hinj hsurj) = f :=
rfl
#align continuous_linear_equiv.coe_fn_of_bijective ContinuousLinearEquiv.coeFn_ofBijective

theorem coe_ofBijective (f : E →L[𝕜] F) (hinj : ker f = ⊥) (hsurj : LinearMap.range f = ⊤) :
theorem coe_ofBijective (f : E →SL[σ] F) (hinj : ker f = ⊥) (hsurj : LinearMap.range f = ⊤) :
↑(ofBijective f hinj hsurj) = f := by
ext
rfl
#align continuous_linear_equiv.coe_of_bijective ContinuousLinearEquiv.coe_ofBijective

@[simp]
theorem ofBijective_symm_apply_apply (f : E →L[𝕜] F) (hinj : ker f = ⊥)
theorem ofBijective_symm_apply_apply (f : E →SL[σ] F) (hinj : ker f = ⊥)
(hsurj : LinearMap.range f = ⊤) (x : E) : (ofBijective f hinj hsurj).symm (f x) = x :=
(ofBijective f hinj hsurj).symm_apply_apply x
#align continuous_linear_equiv.of_bijective_symm_apply_apply ContinuousLinearEquiv.ofBijective_symm_apply_apply

@[simp]
theorem ofBijective_apply_symm_apply (f : E →L[𝕜] F) (hinj : ker f = ⊥)
theorem ofBijective_apply_symm_apply (f : E →SL[σ] F) (hinj : ker f = ⊥)
(hsurj : LinearMap.range f = ⊤) (y : F) : f ((ofBijective f hinj hsurj).symm y) = y :=
(ofBijective f hinj hsurj).apply_symm_apply y
#align continuous_linear_equiv.of_bijective_apply_symm_apply ContinuousLinearEquiv.ofBijective_apply_symm_apply
Expand All @@ -413,20 +421,21 @@ variable [CompleteSpace E]
`ContinuousLinearMap.closed_complemented_range_of_isCompl_of_ker_eq_bot`.
This is `f.coprod G.subtypeL` as a `ContinuousLinearEquiv`. -/
noncomputable def coprodSubtypeLEquivOfIsCompl (f : E →L[𝕜] F) {G : Submodule 𝕜 F}
noncomputable def coprodSubtypeLEquivOfIsCompl {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F]
[CompleteSpace F] (f : E →L[𝕜] F) {G : Submodule 𝕜 F}
(h : IsCompl (LinearMap.range f) G) [CompleteSpace G] (hker : ker f = ⊥) : (E × G) ≃L[𝕜] F :=
ContinuousLinearEquiv.ofBijective (f.coprod G.subtypeL)
(by
rw [ker_coprod_of_disjoint_range]
· rw [hker, Submodule.ker_subtypeL, Submodule.prod_bot]
· rw [Submodule.range_subtypeL]
exact h.disjoint)
-- Porting note: was `simp only`
(by rw [range_coprod, Submodule.range_subtypeL, h.sup_eq_top])
(by simp only [range_coprod, Submodule.range_subtypeL, h.sup_eq_top])
set_option linter.uppercaseLean3 false in
#align continuous_linear_map.coprod_subtypeL_equiv_of_is_compl ContinuousLinearMap.coprodSubtypeLEquivOfIsCompl

theorem range_eq_map_coprodSubtypeLEquivOfIsCompl (f : E →L[𝕜] F) {G : Submodule 𝕜 F}
theorem range_eq_map_coprodSubtypeLEquivOfIsCompl {F : Type*} [NormedAddCommGroup F]
[NormedSpace 𝕜 F] [CompleteSpace F] (f : E →L[𝕜] F) {G : Submodule 𝕜 F}
(h : IsCompl (LinearMap.range f) G) [CompleteSpace G] (hker : ker f = ⊥) :
LinearMap.range f =
((⊤ : Submodule 𝕜 E).prod (⊥ : Submodule 𝕜 G)).map
Expand All @@ -439,7 +448,8 @@ set_option linter.uppercaseLean3 false in

/- TODO: remove the assumption `f.ker = ⊥` in the next lemma, by using the map induced by `f` on
`E / f.ker`, once we have quotient normed spaces. -/
theorem closed_complemented_range_of_isCompl_of_ker_eq_bot (f : E →L[𝕜] F) (G : Submodule 𝕜 F)
theorem closed_complemented_range_of_isCompl_of_ker_eq_bot {F : Type*} [NormedAddCommGroup F]
[NormedSpace 𝕜 F] [CompleteSpace F] (f : E →L[𝕜] F) (G : Submodule 𝕜 F)
(h : IsCompl (LinearMap.range f) G) (hG : IsClosed (G : Set F)) (hker : ker f = ⊥) :
IsClosed (LinearMap.range f : Set F) := by
haveI : CompleteSpace G := hG.completeSpace_coe
Expand All @@ -454,7 +464,8 @@ end ContinuousLinearMap

section ClosedGraphThm

variable [CompleteSpace E] (g : E →ₗ[𝕜] F)
variable [CompleteSpace E]
variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] [CompleteSpace F] (g : E →ₗ[𝕜] F)

/-- The **closed graph theorem** : a linear map between two Banach spaces whose graph is closed
is continuous. -/
Expand Down

0 comments on commit d11fcd1

Please sign in to comment.