Skip to content

Commit

Permalink
chore: generalize IsBoundedBilinearMap to seminormed spaces (#17011)
Browse files Browse the repository at this point in the history
The claim in `Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean` that

> This file contains statements about operator norm for which it really matters that the
> underlying space has a norm (rather than just a seminorm).

was not entirely true.

The main trick is to case on whether the norm of an element is zero, rather than on that element itself being zero.

Unfortunately this causes some minor elaboration issues downstream, but they are easy to work around.
  • Loading branch information
eric-wieser committed Sep 23, 2024
1 parent 20d470b commit ac537a4
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 72 deletions.
2 changes: 1 addition & 1 deletion Mathlib/Analysis/Calculus/ContDiff/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ theorem ContDiff.clm_comp {g : X → F →L[𝕜] G} {f : X → E →L[𝕜] F}
theorem ContDiffOn.clm_comp {g : X → F →L[𝕜] G} {f : X → E →L[𝕜] F} {s : Set X}
(hg : ContDiffOn 𝕜 n g s) (hf : ContDiffOn 𝕜 n f s) :
ContDiffOn 𝕜 n (fun x => (g x).comp (f x)) s :=
isBoundedBilinearMap_comp.contDiff.comp_contDiff_on₂ hg hf
(isBoundedBilinearMap_comp (𝕜 := 𝕜) (E := E) (F := F) (G := G)).contDiff.comp_contDiff_on₂ hg hf

theorem ContDiff.clm_apply {f : E → F →L[𝕜] G} {g : E → F} {n : ℕ∞} (hf : ContDiff 𝕜 n f)
(hg : ContDiff 𝕜 n g) : ContDiff 𝕜 n fun x => (f x) (g x) :=
Expand Down
15 changes: 8 additions & 7 deletions Mathlib/Analysis/Calculus/FDeriv/Mul.lean
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,20 @@ variable {H : Type*} [NormedAddCommGroup H] [NormedSpace 𝕜 H] {c : E → G
theorem HasStrictFDerivAt.clm_comp (hc : HasStrictFDerivAt c c' x) (hd : HasStrictFDerivAt d d' x) :
HasStrictFDerivAt (fun y => (c y).comp (d y))
((compL 𝕜 F G H (c x)).comp d' + ((compL 𝕜 F G H).flip (d x)).comp c') x :=
(isBoundedBilinearMap_comp.hasStrictFDerivAt (c x, d x)).comp x <| hc.prod hd
(isBoundedBilinearMap_comp.hasStrictFDerivAt (c x, d x) :).comp x <| hc.prod hd

@[fun_prop]
theorem HasFDerivWithinAt.clm_comp (hc : HasFDerivWithinAt c c' s x)
(hd : HasFDerivWithinAt d d' s x) :
HasFDerivWithinAt (fun y => (c y).comp (d y))
((compL 𝕜 F G H (c x)).comp d' + ((compL 𝕜 F G H).flip (d x)).comp c') s x :=
(isBoundedBilinearMap_comp.hasFDerivAt (c x, d x)).comp_hasFDerivWithinAt x <| hc.prod hd
(isBoundedBilinearMap_comp.hasFDerivAt (c x, d x) :).comp_hasFDerivWithinAt x <| hc.prod hd

@[fun_prop]
theorem HasFDerivAt.clm_comp (hc : HasFDerivAt c c' x) (hd : HasFDerivAt d d' x) :
HasFDerivAt (fun y => (c y).comp (d y))
((compL 𝕜 F G H (c x)).comp d' + ((compL 𝕜 F G H).flip (d x)).comp c') x :=
(isBoundedBilinearMap_comp.hasFDerivAt (c x, d x)).comp x <| hc.prod hd
(isBoundedBilinearMap_comp.hasFDerivAt (c x, d x) :).comp x <| hc.prod hd

@[fun_prop]
theorem DifferentiableWithinAt.clm_comp (hc : DifferentiableWithinAt 𝕜 c s x)
Expand Down Expand Up @@ -107,12 +107,12 @@ theorem HasStrictFDerivAt.clm_apply (hc : HasStrictFDerivAt c c' x)
theorem HasFDerivWithinAt.clm_apply (hc : HasFDerivWithinAt c c' s x)
(hu : HasFDerivWithinAt u u' s x) :
HasFDerivWithinAt (fun y => (c y) (u y)) ((c x).comp u' + c'.flip (u x)) s x :=
(isBoundedBilinearMap_apply.hasFDerivAt (c x, u x)).comp_hasFDerivWithinAt x (hc.prod hu)
(isBoundedBilinearMap_apply.hasFDerivAt (c x, u x) :).comp_hasFDerivWithinAt x (hc.prod hu)

@[fun_prop]
theorem HasFDerivAt.clm_apply (hc : HasFDerivAt c c' x) (hu : HasFDerivAt u u' x) :
HasFDerivAt (fun y => (c y) (u y)) ((c x).comp u' + c'.flip (u x)) x :=
(isBoundedBilinearMap_apply.hasFDerivAt (c x, u x)).comp x (hc.prod hu)
(isBoundedBilinearMap_apply.hasFDerivAt (c x, u x) :).comp x (hc.prod hu)

@[fun_prop]
theorem DifferentiableWithinAt.clm_apply (hc : DifferentiableWithinAt 𝕜 c s x)
Expand Down Expand Up @@ -239,12 +239,13 @@ theorem HasStrictFDerivAt.smul (hc : HasStrictFDerivAt c c' x) (hf : HasStrictFD
@[fun_prop]
theorem HasFDerivWithinAt.smul (hc : HasFDerivWithinAt c c' s x) (hf : HasFDerivWithinAt f f' s x) :
HasFDerivWithinAt (fun y => c y • f y) (c x • f' + c'.smulRight (f x)) s x :=
(isBoundedBilinearMap_smul.hasFDerivAt (c x, f x)).comp_hasFDerivWithinAt x <| hc.prod hf
(isBoundedBilinearMap_smul.hasFDerivAt (𝕜 := 𝕜) (c x, f x) :).comp_hasFDerivWithinAt x <|
hc.prod hf

@[fun_prop]
theorem HasFDerivAt.smul (hc : HasFDerivAt c c' x) (hf : HasFDerivAt f f' x) :
HasFDerivAt (fun y => c y • f y) (c x • f' + c'.smulRight (f x)) x :=
(isBoundedBilinearMap_smul.hasFDerivAt (c x, f x)).comp x <| hc.prod hf
(isBoundedBilinearMap_smul.hasFDerivAt (𝕜 := 𝕜) (c x, f x) :).comp x <| hc.prod hf

@[fun_prop]
theorem DifferentiableWithinAt.smul (hc : DifferentiableWithinAt 𝕜 c s x)
Expand Down
9 changes: 6 additions & 3 deletions Mathlib/Analysis/InnerProductSpace/Calculus.lean
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,18 @@ theorem HasFDerivWithinAt.inner (hf : HasFDerivWithinAt f f' s x)
(hg : HasFDerivWithinAt g g' s x) :
HasFDerivWithinAt (fun t => ⟪f t, g t⟫) ((fderivInnerCLM 𝕜 (f x, g x)).comp <| f'.prod g') s
x :=
(isBoundedBilinearMap_inner.hasFDerivAt (f x, g x)).comp_hasFDerivWithinAt x (hf.prod hg)
isBoundedBilinearMap_inner (𝕜 := 𝕜) (E := E)
|>.hasFDerivAt (f x, g x) |>.comp_hasFDerivWithinAt x (hf.prod hg)

theorem HasStrictFDerivAt.inner (hf : HasStrictFDerivAt f f' x) (hg : HasStrictFDerivAt g g' x) :
HasStrictFDerivAt (fun t => ⟪f t, g t⟫) ((fderivInnerCLM 𝕜 (f x, g x)).comp <| f'.prod g') x :=
(isBoundedBilinearMap_inner.hasStrictFDerivAt (f x, g x)).comp x (hf.prod hg)
isBoundedBilinearMap_inner (𝕜 := 𝕜) (E := E)
|>.hasStrictFDerivAt (f x, g x) |>.comp x (hf.prod hg)

theorem HasFDerivAt.inner (hf : HasFDerivAt f f' x) (hg : HasFDerivAt g g' x) :
HasFDerivAt (fun t => ⟪f t, g t⟫) ((fderivInnerCLM 𝕜 (f x, g x)).comp <| f'.prod g') x :=
(isBoundedBilinearMap_inner.hasFDerivAt (f x, g x)).comp x (hf.prod hg)
isBoundedBilinearMap_inner (𝕜 := 𝕜) (E := E)
|>.hasFDerivAt (f x, g x) |>.comp x (hf.prod hg)

theorem HasDerivWithinAt.inner {f g : ℝ → E} {f' g' : E} {s : Set ℝ} {x : ℝ}
(hf : HasDerivWithinAt f f' s x) (hg : HasDerivWithinAt g g' s x) :
Expand Down
25 changes: 16 additions & 9 deletions Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ open Filter (Tendsto)

open Metric ContinuousLinearMap

variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E]
[NormedSpace 𝕜 E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*}
[NormedAddCommGroup G] [NormedSpace 𝕜 G]
variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [SeminormedAddCommGroup E]
[NormedSpace 𝕜 E] {F : Type*} [SeminormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*}
[SeminormedAddCommGroup G] [NormedSpace 𝕜 G]

/-- A function `f` satisfies `IsBoundedLinearMap 𝕜 f` if it is linear and satisfies the
inequality `‖f x‖ ≤ M * ‖x‖` for some positive constant `M`. -/
structure IsBoundedLinearMap (𝕜 : Type*) [NormedField 𝕜] {E : Type*} [NormedAddCommGroup E]
[NormedSpace 𝕜 E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] (f : E → F) extends
structure IsBoundedLinearMap (𝕜 : Type*) [NormedField 𝕜] {E : Type*} [SeminormedAddCommGroup E]
[NormedSpace 𝕜 E] {F : Type*} [SeminormedAddCommGroup F] [NormedSpace 𝕜 F] (f : E → F) extends
IsLinearMap 𝕜 f : Prop where
bound : ∃ M, 0 < M ∧ ∀ x : E, ‖f x‖ ≤ M * ‖x‖

Expand Down Expand Up @@ -186,7 +186,7 @@ variable {ι : Type*} [Fintype ι]

/-- Taking the cartesian product of two continuous multilinear maps is a bounded linear
operation. -/
theorem isBoundedLinearMap_prod_multilinear {E : ι → Type*} [∀ i, NormedAddCommGroup (E i)]
theorem isBoundedLinearMap_prod_multilinear {E : ι → Type*} [∀ i, SeminormedAddCommGroup (E i)]
[∀ i, NormedSpace 𝕜 (E i)] :
IsBoundedLinearMap 𝕜 fun p : ContinuousMultilinearMap 𝕜 E F × ContinuousMultilinearMap 𝕜 E G =>
p.1.prod p.2 where
Expand Down Expand Up @@ -244,7 +244,7 @@ variable {R : Type*}
variable {𝕜₂ 𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NontriviallyNormedField 𝕜₂]
variable {M : Type*} [TopologicalSpace M]
variable {σ₁₂ : 𝕜 →+* 𝕜₂}
variable {G' : Type*} [NormedAddCommGroup G'] [NormedSpace 𝕜₂ G'] [NormedSpace 𝕜' G']
variable {G' : Type*} [SeminormedAddCommGroup G'] [NormedSpace 𝕜₂ G'] [NormedSpace 𝕜' G']
variable [SMulCommClass 𝕜₂ 𝕜' G']

section Semiring
Expand Down Expand Up @@ -374,7 +374,7 @@ theorem IsBoundedBilinearMap.isBoundedLinearMap_right (h : IsBoundedBilinearMap
(h.toContinuousLinearMap x).isBoundedLinearMap

theorem isBoundedBilinearMap_smul {𝕜' : Type*} [NormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] {E : Type*}
[NormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedSpace 𝕜' E] [IsScalarTower 𝕜 𝕜' E] :
[SeminormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedSpace 𝕜' E] [IsScalarTower 𝕜 𝕜' E] :
IsBoundedBilinearMap 𝕜 fun p : 𝕜' × E => p.1 • p.2 :=
(lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] E →L[𝕜] E).isBoundedBilinearMap

Expand Down Expand Up @@ -436,7 +436,7 @@ variable (𝕜)

/-- The function `ContinuousLinearMap.mulLeftRight : 𝕜' × 𝕜' → (𝕜' →L[𝕜] 𝕜')` is a bounded
bilinear map. -/
theorem ContinuousLinearMap.mulLeftRight_isBoundedBilinear (𝕜' : Type*) [NormedRing 𝕜']
theorem ContinuousLinearMap.mulLeftRight_isBoundedBilinear (𝕜' : Type*) [SeminormedRing 𝕜']
[NormedAlgebra 𝕜 𝕜'] :
IsBoundedBilinearMap 𝕜 fun p : 𝕜' × 𝕜' => ContinuousLinearMap.mulLeftRight 𝕜 𝕜' p.1 p.2 :=
(ContinuousLinearMap.mulLeftRight 𝕜 𝕜').isBoundedBilinearMap
Expand Down Expand Up @@ -471,9 +471,16 @@ theorem ContinuousOn.clm_apply {X} [TopologicalSpace X] {f : X → (E →L[𝕜]
ContinuousOn (fun x ↦ f x (g x)) s :=
isBoundedBilinearMap_apply.continuous.comp_continuousOn (hf.prod hg)

end

namespace ContinuousLinearEquiv

variable {𝕜 : Type*} [NontriviallyNormedField 𝕜]
variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E]
variable {F : Type*} [SeminormedAddCommGroup F] [NormedSpace 𝕜 F]

open Set
open scoped Topology

/-!
### The set of continuous linear equivalences between two Banach spaces is open
Expand Down
48 changes: 48 additions & 0 deletions Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,54 @@ theorem map_add_add (f : E →L[𝕜] Fₗ →L[𝕜] Gₗ) (x x' : E) (y y' : F
simp only [map_add, add_apply, coe_deriv₂, add_assoc]
abel

/-- The norm of the tensor product of a scalar linear map and of an element of a normed space
is the product of the norms. -/
@[simp]
theorem norm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖ = ‖c‖ * ‖f‖ := by
refine le_antisymm ?_ ?_
· refine opNorm_le_bound _ (mul_nonneg (norm_nonneg _) (norm_nonneg _)) fun x => ?_
calc
‖c x • f‖ = ‖c x‖ * ‖f‖ := norm_smul _ _
_ ≤ ‖c‖ * ‖x‖ * ‖f‖ := mul_le_mul_of_nonneg_right (le_opNorm _ _) (norm_nonneg _)
_ = ‖c‖ * ‖f‖ * ‖x‖ := by ring
· obtain hf | hf := (norm_nonneg f).eq_or_gt
· simp [hf]
· rw [← le_div_iff₀ hf]
refine opNorm_le_bound _ (div_nonneg (norm_nonneg _) (norm_nonneg f)) fun x => ?_
rw [div_mul_eq_mul_div, le_div_iff₀ hf]
calc
‖c x‖ * ‖f‖ = ‖c x • f‖ := (norm_smul _ _).symm
_ = ‖smulRight c f x‖ := rfl
_ ≤ ‖smulRight c f‖ * ‖x‖ := le_opNorm _ _

/-- The non-negative norm of the tensor product of a scalar linear map and of an element of a normed
space is the product of the non-negative norms. -/
@[simp]
theorem nnnorm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖₊ = ‖c‖₊ * ‖f‖₊ :=
NNReal.eq <| c.norm_smulRight_apply f

variable (𝕜 E Fₗ) in
/-- `ContinuousLinearMap.smulRight` as a continuous trilinear map:
`smulRightL (c : E →L[𝕜] 𝕜) (f : F) (x : E) = c x • f`. -/
def smulRightL : (E →L[𝕜] 𝕜) →L[𝕜] Fₗ →L[𝕜] E →L[𝕜] Fₗ :=
LinearMap.mkContinuous₂
{ toFun := smulRightₗ
map_add' := fun c₁ c₂ => by
ext x
simp only [add_smul, coe_smulRightₗ, add_apply, smulRight_apply, LinearMap.add_apply]
map_smul' := fun m c => by
ext x
dsimp
rw [smul_smul] }
1 fun c x => by
simp only [coe_smulRightₗ, one_mul, norm_smulRight_apply, LinearMap.coe_mk, AddHom.coe_mk,
le_refl]


@[simp]
theorem norm_smulRightL_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRightL 𝕜 E Fₗ c f‖ = ‖c‖ * ‖f‖ :=
norm_smulRight_apply c f

end ContinuousLinearMap

end SemiNormed
52 changes: 0 additions & 52 deletions Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean
Original file line number Diff line number Diff line change
Expand Up @@ -200,58 +200,6 @@ theorem opNorm_comp_linearIsometryEquiv (f : F →SL[σ₂₃] G) (g : F' ≃ₛ
@[deprecated (since := "2024-02-02")]
alias op_norm_comp_linearIsometryEquiv := opNorm_comp_linearIsometryEquiv

/-- The norm of the tensor product of a scalar linear map and of an element of a normed space
is the product of the norms. -/
@[simp]
theorem norm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖ = ‖c‖ * ‖f‖ := by
refine le_antisymm ?_ ?_
· refine opNorm_le_bound _ (mul_nonneg (norm_nonneg _) (norm_nonneg _)) fun x => ?_
calc
‖c x • f‖ = ‖c x‖ * ‖f‖ := norm_smul _ _
_ ≤ ‖c‖ * ‖x‖ * ‖f‖ := mul_le_mul_of_nonneg_right (le_opNorm _ _) (norm_nonneg _)
_ = ‖c‖ * ‖f‖ * ‖x‖ := by ring
· by_cases h : f = 0
· simp [h]
· have : 0 < ‖f‖ := norm_pos_iff.2 h
rw [← le_div_iff₀ this]
refine opNorm_le_bound _ (div_nonneg (norm_nonneg _) (norm_nonneg f)) fun x => ?_
rw [div_mul_eq_mul_div, le_div_iff₀ this]
calc
‖c x‖ * ‖f‖ = ‖c x • f‖ := (norm_smul _ _).symm
_ = ‖smulRight c f x‖ := rfl
_ ≤ ‖smulRight c f‖ * ‖x‖ := le_opNorm _ _

/-- The non-negative norm of the tensor product of a scalar linear map and of an element of a normed
space is the product of the non-negative norms. -/
@[simp]
theorem nnnorm_smulRight_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRight c f‖₊ = ‖c‖₊ * ‖f‖₊ :=
NNReal.eq <| c.norm_smulRight_apply f

variable (𝕜 E Fₗ)


/-- `ContinuousLinearMap.smulRight` as a continuous trilinear map:
`smulRightL (c : E →L[𝕜] 𝕜) (f : F) (x : E) = c x • f`. -/
def smulRightL : (E →L[𝕜] 𝕜) →L[𝕜] Fₗ →L[𝕜] E →L[𝕜] Fₗ :=
LinearMap.mkContinuous₂
{ toFun := smulRightₗ
map_add' := fun c₁ c₂ => by
ext x
simp only [add_smul, coe_smulRightₗ, add_apply, smulRight_apply, LinearMap.add_apply]
map_smul' := fun m c => by
ext x
dsimp
rw [smul_smul] }
1 fun c x => by
simp only [coe_smulRightₗ, one_mul, norm_smulRight_apply, LinearMap.coe_mk, AddHom.coe_mk,
le_refl]

variable {𝕜 E Fₗ}

@[simp]
theorem norm_smulRightL_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRightL 𝕜 E Fₗ c f‖ = ‖c‖ * ‖f‖ :=
norm_smulRight_apply c f

@[simp]
theorem norm_smulRightL (c : E →L[𝕜] 𝕜) [Nontrivial Fₗ] : ‖smulRightL 𝕜 E Fₗ c‖ = ‖c‖ :=
ContinuousLinearMap.homothety_norm _ c.norm_smulRight_apply
Expand Down

0 comments on commit ac537a4

Please sign in to comment.